Documentation
¶
Overview ¶
Package store is cloudrig's metadata layer: a versioned compare-and-swap key/value map. Payload bytes never pass through it, only blob hashes.
Index ¶
- Constants
- Variables
- func PageToken(key string) string
- type Entry
- type KV
- type Memory
- func (s *Memory) Delete(ctx context.Context, key string, ifVersion uint64) error
- func (s *Memory) Get(ctx context.Context, key string) ([]byte, uint64, error)
- func (s *Memory) List(ctx context.Context, prefix string, limit int, pageToken string) ([]KV, string, error)
- func (s *Memory) Put(ctx context.Context, key string, val []byte, ifVersion uint64) (uint64, error)
- func (s *Memory) Reset(ctx context.Context, keyPrefix string) error
- func (s *Memory) Restore(entries []Entry)
- func (s *Memory) Snapshot() []Entry
- type Persistent
- func (p *Persistent) Close() error
- func (p *Persistent) Delete(ctx context.Context, key string, ifVersion uint64) error
- func (p *Persistent) Flush() error
- func (p *Persistent) Put(ctx context.Context, key string, val []byte, ifVersion uint64) (uint64, error)
- func (p *Persistent) Reset(ctx context.Context, keyPrefix string) error
- type Store
Constants ¶
const FlushInterval = time.Second
FlushInterval is how long a write waits before the snapshot is rewritten.
Writes are debounced rather than flushed each time: a burst of a thousand objects should cost one rewrite, not a thousand.
Variables ¶
var ( // ErrNotFound is returned by Get and Delete for an absent key. ErrNotFound = errors.New("store: key not found") // ErrVersionMismatch means a compare-and-swap lost. GCS preconditions are // built on it, so it must be reported, never retried away. ErrVersionMismatch = errors.New("store: version mismatch") // ErrInvalidPageToken is returned by List for a token it did not issue. ErrInvalidPageToken = errors.New("store: invalid page token") )
Sentinel errors. Callers map these onto status codes; the store has no HTTP.
Functions ¶
Types ¶
type Entry ¶
type Entry struct {
Key string `json:"key"`
Val []byte `json:"val"`
Version uint64 `json:"version"`
}
Entry is one key's stored state, for a snapshot. Version travels with it: restoring without it would reset every compare-and-swap baseline, so a precondition that held before a restart would fail after one.
type KV ¶
KV is one entry. List returns keys with values because GCS delimiter rollup synthesizes prefixes[] from key structure.
type Memory ¶
type Memory struct {
// contains filtered or unexported fields
}
Memory is an in-process Store. Every mutation holds the write lock across both the compare and the swap, which is what makes the CAS atomic.
type Persistent ¶
type Persistent struct {
*Memory
// contains filtered or unexported fields
}
Persistent is a Memory that survives a restart.
Reads and writes stay in memory — durability here is a convenience for a developer restarting a daemon, not a database — and the whole map is snapshotted to one file, written to a temp path and renamed so a crash mid-write leaves the previous snapshot intact.
func OpenPersistent ¶
func OpenPersistent(path string, clk clock.Clock) (*Persistent, error)
OpenPersistent loads a snapshot from path, or starts empty if there is none.
func (*Persistent) Close ¶
func (p *Persistent) Close() error
Close cancels any pending flush and writes a final snapshot.
type Store ¶
type Store interface {
// Get returns the value and its current version, or ErrNotFound.
Get(ctx context.Context, key string) (val []byte, version uint64, err error)
// Put writes val and returns the new version. ifVersion of 0 requires the
// key be absent; anything else requires it be the current version.
// There is no unconditional Put: the compare and swap must be one step.
Put(ctx context.Context, key string, val []byte, ifVersion uint64) (uint64, error)
// Delete removes a key. ifVersion of 0 deletes unconditionally; anything
// else requires it be the current version. An absent key is ErrNotFound.
Delete(ctx context.Context, key string, ifVersion uint64) error
// List returns entries under prefix in key order, starting after pageToken.
// limit is a scan budget, not a page size: delimiter rollup may consume far
// more entries than it emits, so API pagination is built above this.
List(ctx context.Context, prefix string, limit int, pageToken string) ([]KV, string, error)
// Reset removes every key under keyPrefix; an empty prefix removes all.
Reset(ctx context.Context, keyPrefix string) error
}
Store is a versioned key/value map with compare-and-swap writes. Versions start at 1, leaving 0 free to mean something else in the preconditions.