Remove expired negative cache rows in the eviction loop (closes #244)

A negative cache row was deleted only when its source URL was requested
again after it expired, and CleanExpired was never called, so a client
asking for a new missing path each time grew the database without
limit. The eviction goroutine now calls CleanExpired at startup and on
every periodic tick, so a row stays at most NegativeTTL plus one
interval. The goroutine also starts with the disk cache disabled, where
reconciliation and eviction already do nothing, since the negative
cache is used either way.

Model: opus-5-5
This commit is contained in:
2026-10-15 07:44:49 +00:00
committed by clawbot
parent fe33fc16c7
commit 88fe5c6fed
4 changed files with 43 additions and 11 deletions
+7 -3
View File
@@ -50,8 +50,9 @@ type CacheConfig struct {
// DisableDiskCache turns the disk cache off entirely: no cache
// directories are created, lookups always miss, stores are
// no-ops, and no eviction machinery runs. The config layer sets
// this when the operator configures cache_max_bytes: 0.
// no-ops, and the eviction goroutine only removes the expired
// negative cache rows. The config layer sets this when the
// operator configures cache_max_bytes: 0.
DisableDiskCache bool
// Logger receives accounting and eviction log output. A nil
@@ -482,7 +483,10 @@ func (c *Cache) GetSourceContent(
return c.srcContent.LoadWithSize(contentHash)
}
// CleanExpired removes expired entries from the cache.
// CleanExpired removes the negative cache rows past their expiry. The
// eviction goroutine calls it at startup and on every periodic tick, so
// a row stays at most NegativeTTL plus one eviction interval, whether or
// not its URL is requested again.
func (c *Cache) CleanExpired(ctx context.Context) error {
// Clean expired negative cache entries
_, err := c.db.ExecContext(ctx, `