backend

package
v0.28.0 Latest Latest
Warning

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

Go to latest
Published: Jul 2, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package backend defines the L1 storage seam (DESIGN.md §3, §5): a common Backend interface (Read/Write/List/Delete over whole-object keys) with interchangeable implementations. The in-memory backend (Memory, in this package) is first-class — the reference and test default — so the whole engine runs with no disk or object store. The file backend lives in backend/file. The s3 backend and compare-and-swap (CAS) are M5.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotExist = errors.New("backend: key does not exist")

ErrNotExist is the sentinel returned (wrapped) by Backend.Read and Backend.Delete when a key is absent. Test for it with errors.Is.

Functions

func ReadView added in v0.25.0

func ReadView(ctx context.Context, b Backend, key string) ([]byte, error)

ReadView returns key's value without a defensive copy when b implements Viewer, falling back to a plain (caller-owned) Read otherwise. Either way the caller must treat the result as read-only — that is the contract that lets implementations skip the copy.

func SizeOf added in v0.12.0

func SizeOf(ctx context.Context, b Backend, key string) (int64, error)

SizeOf returns key's stored byte size. It uses the backend's Sizer fast path when available and otherwise falls back to reading the whole object and measuring it — so it is correct over any backend, and cheap over those (and the wrappers) that implement Sizer. It is intended for introspection (part byte accounting), not the hot path.

Types

type Backend

type Backend interface {
	// IsEphemeral reports whether the backend stores data only in RAM (dropped on
	// process exit). [Memory] is ephemeral; file and s3 are not.
	IsEphemeral() bool

	// PutIfAbsent stores data under key only if the key does not already exist. It
	// returns true if the write happened, false if the key was already present (no
	// change). Like [Backend.Write] it is atomic per object. It is the compare-and-swap
	// primitive for manifest commits.
	PutIfAbsent(ctx context.Context, key string, data []byte) (bool, error)

	// Write stores data under key, overwriting any existing value. The write is
	// atomic per object: a reader never observes a partially written value. The
	// implementation takes ownership semantics by copying data as needed; callers may
	// reuse the buffer after Write returns.
	Write(ctx context.Context, key string, data []byte) error

	// Read returns the value stored under key. It returns an error satisfying
	// errors.Is(err, [ErrNotExist]) if the key is absent. The returned slice is owned
	// by the caller (implementations return a fresh copy, never aliased state).
	Read(ctx context.Context, key string) ([]byte, error)

	// List returns, sorted ascending, every key with the given prefix (empty prefix
	// lists all keys).
	List(ctx context.Context, prefix string) ([]string, error)

	// Delete removes key. It returns an error satisfying errors.Is(err, [ErrNotExist])
	// if the key is absent.
	Delete(ctx context.Context, key string) error
}

Backend is the L1 storage seam (DESIGN.md §3, §5): a common interface over interchangeable implementations — memory (ephemeral, the reference), file, and (later) s3. The same engine code path runs over all three.

Data is addressed by an opaque, slash-delimited string key (e.g. a time-bucketed object path or a file-relative path). Values are whole objects: the part format (`block`) maps one part to a key prefix and one object per column/marks/manifest, so whole-object Read/Write is sufficient and gives per-object write atomicity. All methods are safe for concurrent use.

Ranged/streaming reads are deliberately not part of this interface: a part column is read whole, and the multi-key layout already gives projection pushdown (read only the referenced column objects) without ranged reads.

Backend.PutIfAbsent is the conditional-write primitive (added in M5) on which atomic manifest / block-list commits build: a versioned manifest key is written only if no writer has claimed that version, so single-writer-wins coordination needs no Raft (it maps to S3 If-None-Match, a filesystem exclusive create, and a guarded map insert).

func Cached added in v0.6.0

func Cached(inner Backend, maxBytes int64) Backend

Cached wraps a Backend with a bounded in-memory LRU over read objects — the object-store read cache. It targets the cold tier (file/S3), where a part column is otherwise re-read over the network on every query: because part objects are write-once immutable, a cached value is never stale, so the only invalidation is eviction (by byte budget) and an explicit Write/Delete of the same key (manifest/index objects, which the wrapper keeps coherent). List and PutIfAbsent are passed through.

maxBytes is the cache's total value-byte budget; objects larger than it are not cached (they would evict everything else). maxBytes ≤ 0 disables caching (the inner backend is returned unchanged). The wrapper preserves the Backend copy semantics: stored and returned slices are private copies, so a caller may retain or mutate them freely.

func Memory

func Memory() Backend

Memory returns an ephemeral in-memory Backend (DESIGN.md §5): the whole engine runs over it with no disk or object store; objects live in RAM and are dropped when the process exits. It is the reference implementation and the default in tests.

type CacheStats added in v0.6.0

type CacheStats struct {
	Hits, Misses int64
	Bytes        int64 // resident value bytes
	Items        int   // resident objects
}

CacheStats is a snapshot of a cached backend's effectiveness.

type Sizer added in v0.12.0

type Sizer interface {
	// Size returns the stored byte size of key, or an [ErrNotExist]-wrapping error if absent.
	Size(ctx context.Context, key string) (int64, error)
}

Sizer is an optional Backend capability: report an object's stored byte size without reading its contents. Backends that can answer cheaply implement it (memory: the in-RAM length; file: os.Stat). Use SizeOf rather than asserting directly — it falls back to a full Read for backends that do not implement Sizer, so callers stay correct everywhere.

type Viewer added in v0.25.0

type Viewer interface {
	// ReadView returns the value stored under key as a read-only view (do not mutate). Absent keys
	// error like [Backend.Read].
	ReadView(ctx context.Context, key string) ([]byte, error)
}

Viewer is an optional Backend capability: ReadView returns the value stored under key as a **read-only view** that may alias shared state (a cache entry, the in-memory store) instead of Backend.Read's defensive copy. The caller MUST NOT mutate the returned slice; it MAY retain it indefinitely — a stored value is never mutated in place (Write/Delete replace or drop the map entry, they never rewrite the old array), so a view stays valid even after the key is overwritten, evicted, or deleted. It exists for hot read paths (part column objects, read once per query per column) where the copy is a measured allocation cost; use ReadView rather than asserting directly so callers stay correct over any backend.

Directories

Path Synopsis
Package backendtest provides a shared conformance suite that every backend.Backend implementation must pass, proving the implementations are interchangeable (DESIGN.md §2: "backends are interchangeable behind backend.Backend").
Package backendtest provides a shared conformance suite that every backend.Backend implementation must pass, proving the implementations are interchangeable (DESIGN.md §2: "backends are interchangeable behind backend.Backend").
Package bucketindex maintains a compact, incremental index of the immutable parts under a key prefix, so a stateless reader enumerates a tenant's parts (and prunes them by time) from a single object instead of a full, expensive bucket LIST (DESIGN.md §11, the object-store-native read path).
Package bucketindex maintains a compact, incremental index of the immutable parts under a key prefix, so a stateless reader enumerates a tenant's parts (and prunes them by time) from a single object instead of a full, expensive bucket LIST (DESIGN.md §11, the object-store-native read path).
Package file implements a backend.Backend over a local directory tree.
Package file implements a backend.Backend over a local directory tree.
Package s3 implements a backend.Backend over an S3-compatible object store.
Package s3 implements a backend.Backend over an S3-compatible object store.

Jump to

Keyboard shortcuts

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