cache

package
v0.4.2 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package cache implements sqlc's on-disk cache, designed after Bazel's local disk cache.

It has two halves:

  • A content-addressable store (CAS) holding blobs keyed by the SHA-256 hash of their contents, laid out as cas/<xx>/<hash>.
  • An action cache (AC) mapping the digest of an action — a description of cacheable work and all of its inputs — to the digests of the outputs that work produced, laid out as ac/<xx>/<hash>.

Work whose output is not derivable from its inputs, like query analysis, uses both halves, just like Bazel: hash the action, look its digest up in the action cache, then fetch the referenced output blobs from the CAS.

Remote fetches with a declared checksum, like WASM plugins, need no action cache entry at all: the declared sha256 is itself a content address, so the blob is stored and loaded directly from the CAS keyed by that checksum.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotFound = errors.New("cache: not found")

ErrNotFound is returned when a blob or action result is not in the cache.

Functions

func Dir

func Dir() (string, error)

Dir returns the cache root, defaulting to os.UserCacheDir(). The location can be overridden with the SQLCCACHE environment variable.

Types

type Action

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

An Action describes a unit of cacheable work, playing the role of Bazel's Action message: a mnemonic naming the kind of work plus the complete set of inputs that determine its outputs. Two actions with the same digest are assumed to produce the same outputs.

Inputs are hashed incrementally with length-prefixed framing so that the boundary between inputs is unambiguous ("ab"+"c" hashes differently from "a"+"bc").

func (*Action) AddInput

func (a *Action) AddInput(name string, data []byte) *Action

AddInput mixes a named input into the action key. Order matters: callers must add inputs in a deterministic order.

func (*Action) Digest

func (a *Action) Digest() Digest

Digest returns the action's digest, used as the action cache key.

type ActionCache

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

ActionCache maps action digests to ActionResults, stored as JSON files at ac/<xx>/<hash> under the cache root. Unlike CAS entries, action cache entries are not self-validating — the value is not derivable from the key — so Get additionally checks that every referenced output still exists in the CAS before reporting a hit, exactly like Bazel's disk cache does.

Entry I/O goes through the same os.Root as the CAS, confining every read and write to the cache directory.

func (*ActionCache) Get

func (a *ActionCache) Get(action Digest) (*ActionResult, error)

Get returns the cached result for an action, or ErrNotFound on a miss. An entry whose outputs are missing or corrupt in the CAS is treated as a miss and evicted.

func (*ActionCache) GetTree

func (a *ActionCache) GetTree(action Digest, dir string) error

GetTree materializes a cached action's outputs as files under dir, or returns ErrNotFound on a miss. A file already present is reused only if its contents still hash to the expected digest; otherwise it is rewritten from the CAS. Writes are staged, fsynced, and renamed, so a crash cannot leave a right-sized but torn file that later reads would trust.

func (*ActionCache) Put

func (a *ActionCache) Put(action Digest, result *ActionResult) error

Put records the result of an action. All outputs must already be in the CAS; writes are staged and renamed so concurrent processes never observe a partial entry.

func (*ActionCache) PutTree

func (a *ActionCache) PutTree(action Digest, dir string) error

PutTree stores every file under dir in the CAS and records them as the action's outputs, named by their paths relative to dir. Use this for actions whose tool writes an output directory, like WASM compilation.

type ActionResult

type ActionResult struct {
	// Outputs maps an output name (e.g. "analysis.pb", "plugin.wasm") to the
	// CAS digest of its contents.
	Outputs map[string]Digest `json:"outputs"`
}

ActionResult records the outputs of a completed action, mirroring Bazel's ActionResult message. Outputs are not stored inline: each named output is a digest pointing into the CAS.

type CAS

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

CAS is an on-disk content-addressable store keyed by SHA-256, modeled on Bazel's disk cache. Blobs live at cas/<xx>/<hash> under the cache root, where <xx> is the first two hex characters of the hash. Because a blob's name is derived from its contents, entries never change once written: writers race benignly and readers can detect corruption by re-hashing.

Content with an externally declared checksum (remotely fetched plugins) needs no action cache entry: the declared sha256 is the address, so it is stored and loaded directly — see SHA256Digest.

All I/O goes through an os.Root, so no entry name — hash-derived or read from an action cache entry — can escape the cache directory.

func (*CAS) Contains

func (c *CAS) Contains(d Digest) bool

Contains reports whether a blob with the given digest is present, checking size when the digest carries one. It does not verify contents; Get performs full verification.

func (*CAS) Filename

func (c *CAS) Filename(d Digest) (string, bool)

Filename returns the path of a stored blob, for a consumer that needs the file rather than its bytes — SQLite, for one, opens a database by name. A blob is named after the hash of its contents, so the file at this path never changes and any number of processes may read it at once.

It reports false when the blob is not stored.

func (*CAS) Get

func (c *CAS) Get(d Digest) ([]byte, error)

Get returns the blob for a digest. Contents are re-hashed before being returned; a corrupt entry is evicted and reported as ErrNotFound so callers simply redo the work that produced it.

func (*CAS) Put

func (c *CAS) Put(data []byte) (Digest, error)

Put stores a blob and returns its digest. Writing is atomic: the blob is staged in a temp file and renamed into place, so concurrent sqlc processes never observe partial entries.

type Cache

type Cache struct {
	CAS     *CAS
	Actions *ActionCache
	// contains filtered or unexported fields
}

Cache bundles the CAS and the action cache that shares it. All storage I/O is confined to the cache directory through an os.Root; callers should Close the cache when finished with it to release the root.

func Open

func Open() (*Cache, error)

Open returns the cache rooted at Dir().

func OpenAt

func OpenAt(dir string) (*Cache, error)

OpenAt returns the cache rooted at the given directory, creating it if necessary.

func (*Cache) Close

func (c *Cache) Close() error

Close releases the cache's handle on its root directory.

func (*Cache) ExecDir

func (c *Cache) ExecDir(action Digest) (string, error)

ExecDir creates a fresh, private scratch directory for materializing the output tree of the given action, for tools that need their outputs on disk (like wazero's compilation cache). Each call returns a new directory under exec/, so two concurrent processes never share one — otherwise a tool staging files there (wazero writes <key>.tmp files in place) could be swept into the other's PutTree. The caller must remove it when done; its contents are always reproducible from the CAS, so losing it is harmless.

func (*Cache) NewAction

func (c *Cache) NewAction(mnemonic string) *Action

NewAction starts building an action key for the given mnemonic, e.g. "QueryAnalysis". The sha256 of the sqlc binary itself is always the first input: the tool that executes an action determines its outputs just as much as the declared inputs do, so a rebuilt sqlc never reuses stale entries. The binary's digest is memoized in the cache — see toolDigest — which is why actions are created through a Cache.

type Digest

type Digest struct {
	// Hash is the lowercase hex-encoded SHA-256 hash of the blob.
	Hash string `json:"hash"`
	// SizeBytes is the length of the blob in bytes, or negative if unknown.
	SizeBytes int64 `json:"size_bytes"`
}

Digest identifies a blob by its SHA-256 hash and size, mirroring the Digest message from Bazel's remote execution API. The size is stored alongside the hash so that entries can be validated without reading blob contents; a negative size means the size is unknown, as with a checksum declared in a configuration file.

func DigestOf

func DigestOf(data []byte) Digest

DigestOf returns the Digest of a blob.

func SHA256Digest

func SHA256Digest(hexhash string) Digest

SHA256Digest returns a Digest referencing a blob by a declared SHA-256 checksum whose size is not known, suitable for looking up remotely fetched content in the CAS.

func (Digest) String

func (d Digest) String() string

Jump to

Keyboard shortcuts

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