persistence

package
v1.0.30 Latest Latest
Warning

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

Go to latest
Published: Aug 1, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package persistence provides bounded local Store references for CRDT checkpoints.

A checkpoint saves one complete CRDT snapshot, its frontier and HLC state, a durable-transport cursor, and an application-owned opaque outbox in one local durability boundary. BoltStore uses one bbolt transaction; FileStore uses a private file replacement. Both are intended for one process owning a protected local path. They are neither clustered databases nor authenticated replication protocols.

Each Store has one concrete StateValidator. The validator runs before a checkpoint is committed and whenever one is loaded, so a damaged file or a codec/schema mismatch fails closed before a caller restores a replica. The caller must still make its local CRDT mutation and its call to Save part of its own failure policy, and must not retire tombstones merely because a checkpoint exists. Delete only retires one local recovery boundary; it does not retire CRDT tombstones, relay history, or another replica's state.

Index

Constants

View Source
const (
	// KeyMaxRecordBytes is the required maximum encoded checkpoint record size.
	KeyMaxRecordBytes = "PERSISTENCE_MAX_RECORD_BYTES"
	// KeyMaxStateBytes is the required maximum canonical CRDT state size.
	KeyMaxStateBytes = "PERSISTENCE_MAX_STATE_BYTES"
	// KeyMaxFrontierEntries is the required maximum snapshot frontier size.
	KeyMaxFrontierEntries = "PERSISTENCE_MAX_FRONTIER_ENTRIES"
	// KeyMaxReplicaIDBytes is the required maximum replica identifier size.
	KeyMaxReplicaIDBytes = "PERSISTENCE_MAX_REPLICA_ID_BYTES"
	// KeyMaxOutboxBytes is the required maximum opaque outbox size.
	KeyMaxOutboxBytes = "PERSISTENCE_MAX_OUTBOX_BYTES"
	// KeyMaxNameBytes is the required maximum checkpoint name size.
	KeyMaxNameBytes = "PERSISTENCE_MAX_NAME_BYTES"
	// KeyOpenTimeout is an optional positive bbolt lock timeout.
	KeyOpenTimeout = "PERSISTENCE_OPEN_TIMEOUT"
	// KeyFormatVersion is an optional local checkpoint record format version.
	KeyFormatVersion = "PERSISTENCE_FORMAT_VERSION"
	// KeyFormatCompatibility is an optional local record compatibility policy.
	KeyFormatCompatibility = "PERSISTENCE_FORMAT_COMPATIBILITY"
	// KeyMigrateOnLoad enables optional transactional migration of legacy local
	// records. Migration functions themselves remain code-only.
	KeyMigrateOnLoad = "PERSISTENCE_MIGRATE_ON_LOAD"
	// KeyMaxStoreBytes is the required maximum complete FileStore size.
	KeyMaxStoreBytes = "PERSISTENCE_MAX_STORE_BYTES"
)
View Source
const (
	// RecordFormatV1 is the original checkpoint record envelope.
	RecordFormatV1 byte = 1
	// RecordFormatV2 is the current checkpoint record envelope. Its payload is
	// intentionally equivalent to v1, so applications can roll out the
	// versioned configuration before introducing a schema-specific transform.
	RecordFormatV2 byte = 2
	// CurrentRecordFormat is the format written when Config.Format.Version is
	// not set.
	CurrentRecordFormat = RecordFormatV2
)

Variables

View Source
var (
	// ErrInvalidConfig reports a missing or unsafe persistence configuration.
	ErrInvalidConfig = errors.New("crdt persistence: invalid configuration")
	// ErrInvalidCheckpoint reports a checkpoint that cannot safely be stored.
	ErrInvalidCheckpoint = errors.New("crdt persistence: invalid checkpoint")
	// ErrCorruptStore reports a damaged, unknown-version, or semantically
	// invalid record. Callers must restore from an independently verified backup
	// or checkpoint rather than accept a partial record.
	ErrCorruptStore = errors.New("crdt persistence: corrupt store")
	// ErrClosed reports use of a store after Close.
	ErrClosed = errors.New("crdt persistence: closed")
	// ErrMigration reports a record that is valid in its source format but
	// cannot be safely transformed to the configured format. The source bytes
	// are left untouched.
	ErrMigration = errors.New("crdt persistence: migration failed")
)

Functions

This section is empty.

Types

type BoltStore added in v1.0.25

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

BoltStore owns a bbolt file containing checkpoints for one concrete CRDT state codec. bbolt serializes writes and permits concurrent read transactions; callers must still run one active process for a database path.

func Open

func Open(path string, config Config) (*BoltStore, error)

Open opens or creates a checkpoint store at path with mode 0600. The parent directory must already exist and be protected by the host. A store is bound to Config.Validate, so a type or codec change must use an explicit migration rather than silently reinterpreting old bytes.

func OpenBolt added in v1.0.25

func OpenBolt(path string, config Config) (*BoltStore, error)

OpenBolt opens or creates a bbolt-backed checkpoint Store. It is the compatibility entry point for callers that previously used Open.

func (*BoltStore) Close added in v1.0.25

func (store *BoltStore) Close() error

Close releases the database file lock. Calls after Close return ErrClosed.

func (*BoltStore) Delete added in v1.0.25

func (store *BoltStore) Delete(name string) (found bool, err error)

Delete atomically removes name's local recovery boundary. found is false when no checkpoint exists. A successful deletion does not acknowledge a peer, retire a durable-relay event, or permit CRDT tombstone collection.

func (*BoltStore) Load added in v1.0.25

func (store *BoltStore) Load(name string) (checkpoint Checkpoint, found bool, err error)

Load returns one validated checkpoint. found is false when name has not been saved. A malformed or semantically invalid stored value returns ErrCorruptStore and never returns a partial checkpoint. If configured, accepted legacy records are migrated and rewritten atomically before Load returns them.

func (*BoltStore) Save added in v1.0.25

func (store *BoltStore) Save(name string, checkpoint Checkpoint) error

Save validates and atomically replaces name's complete checkpoint. The return from Save is the durable boundary for its snapshot, frontier, clock, cursor, and outbox; it does not acknowledge a remote peer or a separate database transaction.

type Checkpoint

type Checkpoint struct {
	Snapshot snapshot.Snapshot
	Cursor   uint64
	Outbox   []byte
}

Checkpoint is one atomically stored local recovery boundary. Snapshot already contains the canonical state, frontier, and (when required) HLC state. Cursor is normally the last durable-relay sequence whose effects are represented by Snapshot. Outbox remains opaque so the application can retain its canonical pending payloads in the same transaction without this package inventing transport or authorization semantics.

type CheckpointMigration added in v1.0.25

type CheckpointMigration func(Checkpoint) (Checkpoint, error)

CheckpointMigration transforms a checkpoint that was decoded and validated with its source-format validator. It must return a complete replacement checkpoint suitable for validation by Config.Validate. It must not retain aliases to caller-owned bytes or maps.

type Compatibility added in v1.0.25

type Compatibility uint8

Compatibility controls which checkpoint record envelopes a store accepts. It affects only the local persistence envelope; CRDT frame, TypeID, codec, and Manifest compatibility remain separate negotiated contracts.

const (
	// CompatibilityDefault accepts the configured format and its immediately
	// preceding supported format. It is the safe upgrade default for v1 to v2.
	CompatibilityDefault Compatibility = iota
	// CompatibilityCurrentOnly rejects every record format other than Version.
	CompatibilityCurrentOnly
	// CompatibilityCurrentAndPrevious accepts Version and its immediately
	// preceding supported format.
	CompatibilityCurrentAndPrevious
)

type Config

type Config struct {
	// Format controls local checkpoint envelope compatibility and optional
	// transactional migration. It does not change CRDT wire formats.
	Format FormatConfig
	// MaxRecordBytes bounds the complete encoded record, including metadata and
	// its checksum.
	MaxRecordBytes int
	// MaxStateBytes bounds the canonical CRDT state frame retained per record.
	MaxStateBytes int
	// MaxFrontierEntries bounds the number of replica tags retained with one
	// snapshot.
	MaxFrontierEntries int
	// MaxReplicaIDBytes bounds a frontier or HLC replica ID before allocating or
	// converting it to a string.
	MaxReplicaIDBytes int
	// MaxOutboxBytes bounds the application-owned opaque outbox retained with a
	// checkpoint. It is not a substitute for a bounded retry policy.
	MaxOutboxBytes int
	// MaxNameBytes bounds a checkpoint name. Names use a deliberately small
	// ASCII namespace so callers cannot accidentally treat them as file paths.
	MaxNameBytes int
	// OpenTimeout bounds waiting for bbolt's exclusive file lock. A zero value
	// uses five seconds.
	OpenTimeout time.Duration
	// Validate must perform concrete, bounded CRDT decoding for this store's
	// state type and codec. It runs on Save and Load.
	Validate snapshot.StateValidator
}

Config bounds every record before it is written or decoded. Limits are intentionally required rather than hidden defaults because a checkpoint's state, frontier, and outbox are application capacity decisions.

func ConfigFrom added in v1.0.25

func ConfigFrom(loader configuration.Loader, validator snapshot.StateValidator, migrations ...Migration) (Config, error)

ConfigFrom resolves one normalized persistence Config from an explicit configuration Loader. Capacity limits remain required because their safe values depend on the application's documents and retry policy. validator and migrations are code-owned contracts, not untrusted configuration data.

type FileConfig added in v1.0.25

type FileConfig struct {
	Config
	MaxStoreBytes int
}

FileConfig configures the single-file Store reference. MaxStoreBytes bounds every complete file before it is read into memory or atomically replaced. It is independent from Config.MaxRecordBytes because a file can contain multiple named checkpoints.

func FileConfigFrom added in v1.0.25

func FileConfigFrom(loader configuration.Loader, validator snapshot.StateValidator, migrations ...Migration) (FileConfig, error)

FileConfigFrom resolves a FileStore configuration from an explicit Loader. It retains the same required record bounds as ConfigFrom and adds the required complete-file budget.

type FileStore added in v1.0.25

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

FileStore is a dependency-free local Store reference. It keeps canonical records in memory and atomically replaces one private file with fsync and rename on each Save. It is appropriate only when one active process owns a protected local path; unlike bbolt it provides no inter-process lock.

func OpenFile added in v1.0.25

func OpenFile(path string, config FileConfig) (*FileStore, error)

OpenFile opens or creates a file-backed checkpoint Store at path. Existing files must be regular, private (at most 0600), and valid under config. The parent directory must already exist and be protected by the host.

func (*FileStore) Close added in v1.0.25

func (store *FileStore) Close() error

Close marks the Store closed. FileStore has no open file descriptor; the method exists so callers can treat it like every other Store backend.

func (*FileStore) Delete added in v1.0.25

func (store *FileStore) Delete(name string) (found bool, err error)

Delete atomically removes name's local recovery boundary by replacing the complete file. found is false when name was never saved. A successful delete does not retire relay data or CRDT tombstones; callers must enforce their own retention and rejoin policy before removing a checkpoint.

func (*FileStore) Load added in v1.0.25

func (store *FileStore) Load(name string) (checkpoint Checkpoint, found bool, err error)

Load returns one freshly validated checkpoint. found is false when name was never saved. Invalid stored bytes fail closed with ErrCorruptStore.

func (*FileStore) Save added in v1.0.25

func (store *FileStore) Save(name string, checkpoint Checkpoint) error

Save validates and atomically replaces name's complete checkpoint. A Save does not coordinate any other application database or acknowledge a peer.

type FormatConfig added in v1.0.25

type FormatConfig struct {
	Version       byte
	Compatibility Compatibility
	MigrateOnLoad bool
	Migrations    []Migration
}

FormatConfig keeps local-record version policy together. Version is the format written by Save; zero selects CurrentRecordFormat. Older records are read only when Compatibility permits them. When MigrateOnLoad is set, an accepted older record is transformed and atomically rewritten in Version.

type Migration added in v1.0.25

type Migration struct {
	FromVersion byte
	Validate    snapshot.StateValidator
	Transform   CheckpointMigration
}

Migration describes one accepted older record format. Validate is optional; when omitted, Config.Validate validates both source and target records. Transform is optional for envelope-only migrations such as v1 to v2.

type Store

type Store interface {
	Save(name string, checkpoint Checkpoint) error
	Load(name string) (checkpoint Checkpoint, found bool, err error)
	Delete(name string) (found bool, err error)
	Close() error
}

Store is the local recovery-store contract. Save must atomically replace one complete checkpoint: its snapshot, frontier, HLC state (when required), relay cursor, and outbox either all become durable or none do. Load must validate stored data before returning it and must never return a partial checkpoint.

Store deliberately does not model a distributed transaction, remote acknowledgement, identity, encryption, backup, or tombstone collection. Applications own its lifetime and must not use a closed Store.

Jump to

Keyboard shortcuts

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