cache: add negative cache; router: skip race for cached 404s

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ibeb44b313850395898bb20f2d947b0b76a6a6964
This commit is contained in:
raf 2026-03-06 21:30:24 +03:00
commit b0ea022dc2
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
7 changed files with 147 additions and 4 deletions

31
internal/cache/db.go vendored
View file

@ -80,6 +80,11 @@ func migrate(db *sql.DB) error {
total_queries INTEGER DEFAULT 0,
success_rate REAL DEFAULT 1.0
);
CREATE TABLE IF NOT EXISTS negative_cache (
store_path TEXT PRIMARY KEY,
expires_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_negative_expires ON negative_cache(expires_at);
`)
return err
}
@ -178,6 +183,32 @@ func (d *DB) RouteCount() (int, error) {
return count, err
}
// Records a negative cache entry for storePath with the given TTL.
func (d *DB) SetNegative(storePath string, ttl time.Duration) error {
_, err := d.db.Exec(
`INSERT INTO negative_cache (store_path, expires_at) VALUES (?, ?)
ON CONFLICT(store_path) DO UPDATE SET expires_at = excluded.expires_at`,
storePath, time.Now().Add(ttl).Unix(),
)
return err
}
// Returns true if a non-expired negative entry exists for storePath.
func (d *DB) IsNegative(storePath string) (bool, error) {
var count int
err := d.db.QueryRow(
`SELECT COUNT(*) FROM negative_cache WHERE store_path = ? AND expires_at > ?`,
storePath, time.Now().Unix(),
).Scan(&count)
return count > 0, err
}
// Deletes expired negative cache entries.
func (d *DB) ExpireNegatives() error {
_, err := d.db.Exec(`DELETE FROM negative_cache WHERE expires_at < ?`, time.Now().Unix())
return err
}
// Deletes the oldest routes (by last_verified) when over capacity.
func (d *DB) evictIfNeeded() error {
count, err := d.RouteCount()