negcache

package
v0.1.19 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 25, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package negcache implements the per-puller, in-memory negative cache described in the design doc of the Gantry design.

When a puller's origin fetch fails terminally, the failure is classified (FailureAuth, FailureNotFound, FailureRateLimited, FailureTransient) and recorded against the digest. Subsequent pull_intent_query / please_pull RPCs for that digest must surface the cooldown state so requesters can short-circuit (the step: "Signal propagation via the existing probe RPCs").

Cooldown ladder (configurable, defaults from the design doc):

1st failure -> 10 s (Initial)
2nd failure -> 30 s (Initial × Multiplier)
3rd failure -> 90 s (Initial × Multiplier^2 capped at Max)
4th+ -> 10 min (Max)

The first successful pull clears the entry (the design doc "Self-healing").

The cache is local-only. The design (the design doc "Why the negative cache is local-only, not propagated via DHT") explicitly forbids cluster-wide propagation because a stale "this digest failed" marker outliving an actual recovery would be a serious correctness bug.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Cache

type Cache struct {
	// contains filtered or unexported fields
}

Cache is the per-puller the design doc negative cache. Safe for concurrent use.

func New

func New(opts Options) *Cache

New returns an empty Cache. Required options that are zero get the the design doc defaults (Initial=10s, Max=10min, Multiplier=3, Now=time.Now).

func (*Cache) Len

func (c *Cache) Len() int

Len returns the current entry count. Cheap (single mutex acquisition) and side-effect-free: opportunistic eviction happens on the mutation and lookup paths, not here, so Len stays a pure read for gauges/tests.

func (*Cache) Lookup

func (c *Cache) Lookup(d digest.Digest) (Entry, bool)

Lookup implements coord.NegativeCache. Returns (Entry, true) if a non-expired entry exists. Expired entries are evicted on access.

func (*Cache) RecordFailure

func (c *Cache) RecordFailure(d digest.Digest, class ifaces.FailureClass) Entry

RecordFailure registers a fresh terminal failure for d. The cooldown grows geometrically with successive failures, capped at Options.Max. Idempotent for the same call site; multiple calls within a single cooldown window keep extending it (the puller is expected to call this exactly once per terminal failure).

func (*Cache) RecordSuccess

func (c *Cache) RecordSuccess(d digest.Digest)

RecordSuccess clears any negative-cache entry for d. The the design doc spec says "the first successful pull of the digest clears the entry". Idempotent: a no-op when no entry exists.

type Entry

type Entry struct {
	LastFailure   time.Time
	FailureCount  int
	Class         ifaces.FailureClass
	CooldownUntil time.Time
}

Entry mirrors the design doc's recent_failures[digest] record.

type Options

type Options struct {
	// Initial is the cooldown applied on the first failure.
	Initial time.Duration
	// Max caps the cooldown after exponential growth.
	Max time.Duration
	// Multiplier is the geometric factor between successive cooldowns.
	// Spec default is 3× (10 s -> 30 s -> 90 s -> ... -> Max).
	Multiplier int
	// Now is the clock used for cooldown comparisons. Tests override to
	// inject a deterministic time source. Defaults to time.Now.
	Now func() time.Time
	// SweepInterval controls how often ordinary cache operations do a full
	// expired-entry sweep. Zero picks the default; negative disables full
	// opportunistic sweeps (Lookup still evicts the requested key).
	SweepInterval time.Duration
	// OnEnter and OnHit are optional metric callbacks. nil-safe.
	OnEnter func(class ifaces.FailureClass)
	OnHit   func(class ifaces.FailureClass)
	// OnSize is called after every mutation with the new entry count
	// so a GaugeFunc reader can expose `p2p_negative_cache_entries`
	// without locking the map. nil-safe.
	OnSize func(count int)
}

Options configures the cooldown ladder. Zero values pick the defaults; callers should still pass an explicit value to make tests deterministic.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL