cache

package
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Jan 26, 2026 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package cache provides ephemeral graph caching with LRU eviction.

The cache package implements an in-memory cache for code graphs with:

  • Reference counting for safe eviction
  • Copy-on-write incremental updates
  • Singleflight deduplication of concurrent builds
  • LRU eviction with configurable limits

Design Principles

Graphs are ephemeral and always rebuildable from source code files. The cache is a performance optimization, not a source of truth.

Thread Safety

GraphCache is safe for concurrent use. Individual CacheEntry structs are safe for concurrent reads but require the entry's mutex for writes.

Index

Constants

View Source
const (
	// DefaultMaxEntries is the default maximum number of cached graphs.
	DefaultMaxEntries = 5

	// DefaultMaxAge is the default TTL for cached entries.
	DefaultMaxAge = 30 * time.Minute

	// DefaultErrorCacheTTL is how long build errors are cached.
	DefaultErrorCacheTTL = 5 * time.Second
)

Default configuration values.

Variables

View Source
var (
	// ErrCacheEntryInUse is returned when attempting to evict an entry
	// that has active references.
	ErrCacheEntryInUse = errors.New("cache entry in use")

	// ErrEntryNotFound is returned when the requested entry doesn't exist.
	ErrEntryNotFound = errors.New("cache entry not found")

	// ErrCacheStale is returned when an entry has been marked as stale.
	ErrCacheStale = errors.New("cache entry is stale")
)

Sentinel errors for cache operations.

Functions

func GenerateGraphID

func GenerateGraphID(projectRoot string) string

GenerateGraphID creates a stable ID for a project root.

Uses full SHA256 (64 hex chars) to eliminate collision risk.

Types

type BuildFunc

type BuildFunc func(ctx context.Context, projectRoot string) (*graph.Graph, *manifest.Manifest, error)

BuildFunc is the function signature for building a graph.

type CacheEntry

type CacheEntry struct {
	// GraphID is the unique identifier for this cache entry.
	// Format: full SHA256 of project root (64 hex chars).
	GraphID string

	// ProjectRoot is the absolute path to the project.
	ProjectRoot string

	// Graph is the cached code graph.
	Graph *graph.Graph

	// Manifest contains the file hashes at build time.
	// Used for change detection.
	Manifest *manifest.Manifest

	// BuiltAtMilli is when the graph was built.
	BuiltAtMilli int64

	// LastAccessMilli is when the entry was last accessed.
	LastAccessMilli int64
	// contains filtered or unexported fields
}

CacheEntry represents a cached graph with its metadata.

Thread Safety:

CacheEntry is safe for concurrent reads. The mu mutex must be
held for write operations like Refresh.

func (*CacheEntry) Acquire

func (e *CacheEntry) Acquire()

Acquire increments the reference count.

Must be paired with a call to Release when done using the entry.

func (*CacheEntry) EstimatedMemoryBytes

func (e *CacheEntry) EstimatedMemoryBytes() int64

EstimatedMemoryBytes returns an approximate memory usage for this entry.

Description:

Estimates memory usage based on graph node/edge counts and manifest
file counts. Uses conservative estimates per element.

Inputs:

None. Reads from entry state.

Outputs:

int64 - Estimated memory usage in bytes.

Memory Estimation:

  • Per node: ~500 bytes (Node struct + Symbol pointer + slices)
  • Per edge: ~100 bytes (Edge struct + Location)
  • Per manifest file: ~200 bytes (FileEntry with path/hash)
  • Base overhead: ~1KB

Limitations:

Estimates are heuristic. Actual memory may differ due to:
- Go allocator overhead and alignment
- Varying string lengths in Symbol/FileEntry
- Runtime memory fragmentation

Assumptions:

Graph and Manifest are not nil, or method handles nil gracefully.

Thread Safety:

Safe for concurrent reads. Does not modify entry state.

func (*CacheEntry) InUse

func (e *CacheEntry) InUse() bool

InUse returns true if the entry has active references.

func (*CacheEntry) IsStale

func (e *CacheEntry) IsStale() bool

IsStale returns true if the entry has been marked as stale.

func (*CacheEntry) RefCount

func (e *CacheEntry) RefCount() int32

RefCount returns the current reference count.

func (*CacheEntry) Release

func (e *CacheEntry) Release()

Release decrements the reference count.

type CacheOption

type CacheOption func(*CacheOptions)

CacheOption is a functional option for configuring GraphCache.

func WithErrorCacheTTL

func WithErrorCacheTTL(d time.Duration) CacheOption

WithErrorCacheTTL sets how long build errors are cached.

func WithMaxAge

func WithMaxAge(d time.Duration) CacheOption

WithMaxAge sets the TTL for cached entries.

func WithMaxEntries

func WithMaxEntries(n int) CacheOption

WithMaxEntries sets the maximum number of cached entries.

func WithMaxMemoryMB

func WithMaxMemoryMB(mb int) CacheOption

WithMaxMemoryMB sets the soft memory limit.

type CacheOptions

type CacheOptions struct {
	// MaxEntries is the maximum number of cached graphs.
	MaxEntries int

	// MaxAge is the TTL for cached entries.
	MaxAge time.Duration

	// MaxMemoryMB is the soft memory limit (0 = unlimited).
	MaxMemoryMB int

	// ErrorCacheTTL is how long build errors are cached.
	ErrorCacheTTL time.Duration
}

CacheOptions configures GraphCache behavior.

func DefaultCacheOptions

func DefaultCacheOptions() CacheOptions

DefaultCacheOptions returns sensible defaults.

type CacheStats

type CacheStats struct {
	// EntryCount is the number of entries in the cache.
	EntryCount int

	// Hits is the number of cache hits.
	Hits int64

	// Misses is the number of cache misses.
	Misses int64

	// Evictions is the number of entries evicted.
	Evictions int64

	// MemoryEvictions is the number of entries evicted due to memory pressure.
	MemoryEvictions int64

	// BuildCount is the number of graphs built.
	BuildCount int64

	// RefreshCount is the number of incremental updates.
	RefreshCount int64

	// ErrorCount is the number of build errors.
	ErrorCount int64

	// MaxEntries is the configured maximum entries.
	MaxEntries int

	// MaxAge is the configured TTL.
	MaxAge time.Duration

	// MaxMemoryMB is the configured memory limit (0 = unlimited).
	MaxMemoryMB int

	// EstimatedMemoryMB is the current estimated memory usage.
	EstimatedMemoryMB int
}

CacheStats contains statistics about the cache.

func (CacheStats) HitRate

func (s CacheStats) HitRate() float64

HitRate returns the cache hit rate as a percentage.

type ErrBuildFailed

type ErrBuildFailed struct {
	// Err is the underlying build error.
	Err error

	// FailedAt is when the build failed.
	FailedAt time.Time

	// RetryAt is when a retry is allowed.
	RetryAt time.Time
}

ErrBuildFailed wraps a build error with timing information.

When a build fails, the error is cached to prevent retry storms. This error type includes when the failure occurred and when a retry is allowed.

func (*ErrBuildFailed) CanRetry

func (e *ErrBuildFailed) CanRetry() bool

CanRetry returns true if the retry time has passed.

func (*ErrBuildFailed) Error

func (e *ErrBuildFailed) Error() string

Error implements the error interface.

func (*ErrBuildFailed) Unwrap

func (e *ErrBuildFailed) Unwrap() error

Unwrap returns the underlying error for errors.Is/As support.

type GraphCache

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

GraphCache provides LRU caching for code graphs with reference counting.

Thread Safety:

GraphCache is safe for concurrent use. Uses RWMutex for the entry map
and per-entry mutexes for refresh operations.

func NewGraphCache

func NewGraphCache(opts ...CacheOption) *GraphCache

NewGraphCache creates a new GraphCache with the given options.

func (*GraphCache) Clear

func (c *GraphCache) Clear()

Clear removes all entries from the cache.

Entries with active references are marked as stale.

func (*GraphCache) ForceInvalidate

func (c *GraphCache) ForceInvalidate(projectRoot string)

ForceInvalidate marks an entry as stale.

The entry will be removed when all references are released. Stale entries are not returned by Get().

func (*GraphCache) Get

func (c *GraphCache) Get(projectRoot string) (*CacheEntry, func(), bool)

Get retrieves a cached entry by project root.

Returns the entry, a release function, and whether the entry was found. The release function MUST be called when done using the entry.

If the entry is stale or expired, returns false.

func (*GraphCache) GetOrBuild

func (c *GraphCache) GetOrBuild(ctx context.Context, projectRoot string, build BuildFunc) (*CacheEntry, func(), error)

GetOrBuild retrieves a cached entry or builds a new one.

Uses singleflight to deduplicate concurrent builds for the same project. Build errors are cached for ErrorCacheTTL to prevent retry storms.

The release function MUST be called when done using the entry.

func (*GraphCache) Invalidate

func (c *GraphCache) Invalidate(projectRoot string) error

Invalidate removes an entry from the cache.

Returns ErrCacheEntryInUse if the entry has active references. Use ForceInvalidate to mark the entry as stale instead.

func (*GraphCache) Refresh

func (c *GraphCache) Refresh(ctx context.Context, projectRoot string, refresh RefreshFunc) error

Refresh performs a copy-on-write incremental update of a cached entry.

Description:

Uses the provided RefreshFunc to detect and apply changes to the
cached graph. The update is performed atomically using copy-on-write:
concurrent readers see either the old or new state, never partial.

Inputs:

ctx - Context for cancellation.
projectRoot - Absolute path to the project root.
refresh - Function that performs the incremental update.

Outputs:

error - Non-nil if the entry doesn't exist or refresh failed.

Errors:

ErrEntryNotFound - No cached entry for this project
Other errors from the RefreshFunc

Behavior:

  1. Acquires the entry and its refresh mutex
  2. Calls RefreshFunc with current graph/manifest
  3. If no changes, returns immediately
  4. Creates new entry with updated graph/manifest
  5. Atomically swaps the entry in the cache
  6. Marks old entry as stale

Thread Safety:

Safe for concurrent use. Concurrent readers see consistent state.
Only one Refresh can run at a time per entry (protected by entry mutex).

func (*GraphCache) Stats

func (c *GraphCache) Stats() CacheStats

Stats returns current cache statistics.

type RefreshFunc

type RefreshFunc func(ctx context.Context, projectRoot string, currentGraph *graph.Graph, currentManifest *manifest.Manifest) (*graph.Graph, *manifest.Manifest, error)

RefreshFunc is the function signature for incrementally updating a graph.

Description:

Called during Refresh to handle the incremental update logic.
The function receives the current graph/manifest and should return
updated versions based on file system changes.

Inputs:

ctx - Context for cancellation.
projectRoot - Absolute path to the project root.
currentGraph - The current graph (will be cloned by caller).
currentManifest - The current manifest for change detection.

Outputs:

*graph.Graph - The updated graph (may be same if no changes).
*manifest.Manifest - The new manifest reflecting current state.
error - Non-nil if refresh failed.

Behavior:

The RefreshFunc should:
1. Scan for file changes (added/modified/deleted)
2. Clone the graph if changes exist
3. Remove deleted files from clone
4. Re-parse and merge modified/added files
5. Return the updated graph and new manifest

Jump to

Keyboard shortcuts

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