force pushed <https://jausoft.com/cgit/cgit.git/commit/?id=23bce8965897c21213da1a2882e0b04392f8428a>
Removed redundant logging, add useful logging (un-cached fill). +++ >From 23bce8965897c21213da1a2882e0b04392f8428a Mon Sep 17 00:00:00 2001 From: Sven Göthel <[email protected]> Date: Sun, 19 Jul 2026 16:47:26 +0200 Subject: Add cfg cache-lock-fail behavior if failing to acquire cache-file lock New default is http-response 503 and simply serve an error page to avoid server lockup. cache-lock-fail can be configured to 200 for old behavior, i.e. producing an off-cache content page. diff --git a/cache.c b/cache.c index 3f93aa9..7f11fa7 100644 --- a/cache.c +++ b/cache.c @@ -16,6 +16,7 @@ #include "cgit.h" #include "cache.h" #include "html.h" +#include "ui-shared.h" #include <stdio.h> #include <fcntl.h> #include <time.h> @@ -300,10 +301,20 @@ static int lock_slot(struct cache_slot *slot, time_t tStart) }; size_t wait_count = 0; - slot->lock_fd = open(slot->lock_name, O_RDWR | O_CREAT, - S_IRUSR | S_IWUSR); - if (slot->lock_fd == -1) - return errno; + if (0 == strncmp("cgit_test_key_no_lock", slot->key, 21)) { + cache_log("[cgit] Lock (%ds): Test-Key: %s -> forced fail\n", + (int)(time(NULL) - tStart), slot->key); + return ENOENT; + } + slot->lock_fd = + open(slot->lock_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if (slot->lock_fd == -1) { + int saved_errno = errno; + cache_log("[cgit] Lock (%ds): Unable to open/create lock slot %s (%s): %s (%d)\n", + (int)(time(NULL) - tStart), slot->lock_name, + slot->key, strerror(saved_errno), saved_errno); + return saved_errno; + } while (fcntl(slot->lock_fd, F_SETLK, &lock) < 0) { int saved_errno = errno; time_t tNow = time(NULL); @@ -502,17 +513,37 @@ static int process_slot(struct cache_slot *slot) close_slot(slot); if ((err = lock_slot(slot, tStart)) != 0) { time_t tNow1 = time(NULL); - slot->fn(); + if (ctx.cfg.cache_lock_fail != 200) { + ctx.page.title = "cgit error"; + cgit_print_error_page(503, "Service Unavailable", + "Service Unavailable. Cache: Could not lock new-slot within %ds.", + (int)(tNow1 - tStart)); + } else { + slot->fn(); + cache_log("[cgit] Uncached fill took %ds %s (failed lock %s)\n", + (int)(time(NULL) - tNow1), slot->key, slot->lock_name); + } return 0; } if (slot->cache_fd <= 0) { // first concurrent process lock if ((err = fill_slot(slot)) != 0) { - cache_log("[cgit] Unable to fill slot %s (%s): %s (%d)\n", - slot->lock_name, slot->key, strerror(err), err); + time_t tNow1 = time(NULL); + cache_log("[cgit] Unable to fill slot (%ds) %s (%s): %d: %s (%d)\n", + (int)(tNow1 - tStart), slot->lock_name, slot->key, + ctx.cfg.cache_lock_fail, strerror(err), err); unlock_slot(slot, UNLINK_LOCK_FILE); close_lock(slot); - slot->fn(); + if (ctx.cfg.cache_lock_fail != 200) { + ctx.page.title = "cgit error"; + cgit_print_error_page(503, "Service Unavailable", + "Service Unavailable. Cache: Could not fill slot within %ds.", + (int)(time(NULL) - tStart)); + } else { + slot->fn(); + cache_log("[cgit] Uncached fill took %ds %s (failed locked fill %s)\n", + (int)(time(NULL) - tNow1), slot->key, slot->lock_name); + } return 0; } // We've got a valid cache slot in the lock file, which diff --git a/cgit.c b/cgit.c index 25e29f9..83665ca 100644 --- a/cgit.c +++ b/cgit.c @@ -217,6 +217,8 @@ static void config_cb(const char *name, const char *value) ctx.cfg.cache_scanrc_ttl = atoi(value); else if (!strcmp(name, "cache-static-ttl")) ctx.cfg.cache_static_ttl = atoi(value); + else if (!strcmp(name, "cache-lock-fail")) + ctx.cfg.cache_lock_fail = atoi(value); else if (!strcmp(name, "cache-lock-timeout")) ctx.cfg.cache_lock_timeout = atoi(value); else if (!strcmp(name, "client-io-idle-timeout")) @@ -390,6 +392,7 @@ static void prepare_context(void) ctx.cfg.cache_scanrc_ttl = 15; ctx.cfg.cache_dynamic_ttl = 5; ctx.cfg.cache_static_ttl = -1; + ctx.cfg.cache_lock_fail = 503; ctx.cfg.cache_lock_timeout = 10; ctx.cfg.client_io_idle_timeout = 20; ctx.cfg.client_io_min_rate = 500; @@ -890,6 +893,7 @@ static void print_config(FILE *f, const char *prefix) fprintf(f, "%slog-level=%d\n", prefix, ctx.cfg.log_level); fprintf(f, "%sproject-list=%s\n", prefix, ctx.cfg.project_list); fprintf(f, "%sscan-path=%s\n", prefix, ctx.cfg.scan_path); + fprintf(f, "%scache-lock-fail=%d\n", prefix, ctx.cfg.cache_lock_fail); fprintf(f, "%scache-lock-timeout=%d\n", prefix, ctx.cfg.cache_lock_timeout); fprintf(f, "%sclient-io-idle-timeout=%d\n", prefix, ctx.cfg.client_io_idle_timeout); fprintf(f, "%sclient-io-min-rate=%ld\n", prefix, ctx.cfg.client_io_min_rate); diff --git a/cgit.h b/cgit.h index 4aed96c..df6a6c1 100644 --- a/cgit.h +++ b/cgit.h @@ -229,6 +229,8 @@ struct cgit_config { int cache_static_ttl; int cache_about_ttl; int cache_snapshot_ttl; + /* cache lock fail action as http-response code. 200 returns un-cached processed content (old behavior), otherwise an error page is served (new default). Defaults to 503. */ + int cache_lock_fail; /* cache lock timeout in seconds to acquire the cache lock-file against concurrent processes. Defaults to 10s. */ int cache_lock_timeout; /* idle timeout in seconds between sending/receiving chunks of the cached body to/from the client. Defaults to 20s. */ diff --git a/cgitrc.5.txt b/cgitrc.5.txt index d3a8ae8..de25244 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -100,6 +100,11 @@ cache-static-ttl:: version of repository pages accessed with a fixed SHA1. See also: "CACHE". Default value: -1". +cache-lock-fail:: + Cache lock fail action as http-response code. + 200 returns un-cached processed content (old behavior), + otherwise an error page is served (new default). Default value: "503". + cache-lock-timeout:: Timeout in seconds to acquire the cache lock-file against concurrent processes. Default value: "10".
