Documentation
¶
Overview ¶
Package store provides the composed open and teardown of a WAL-backed store. Open / OpenCtx run the one correct reopen sequence (recovery, the clean gate, the WAL open, and the transactional store built from the recovery result); DB bundles the durability pieces — a wal.Writer and an optional background [checkpoint.Checkpointer] — and closes them in the single crash-safe order.
Why a composed Open exists ¶
Reopening a directory by hand is four steps (recovery, the clean gate, wal.Open, building the store from the recovery result), and every step carries state the next one must not drop: the recovered transaction sequence, the replay op cap, the codecs, and the schema. rmp #2522 measured that every hand-written reopen in the module dropped the sequence. Open performs the sequence once, so recovered state cannot be dropped by omission. See docs/persistence.md ("Composed open").
Why a composed Close exists ¶
The persistence pieces each have their own lifecycle method (wal.Writer.Close, [checkpoint.Checkpointer.Stop]), but closing them in the wrong order is a silent correctness bug: if the WAL is closed BEFORE the checkpoint goroutine is stopped, the still-running checkpoint loop calls wal.Writer.Sync / wal.Writer.Truncate on a closed writer, those calls return wal.ErrWriterClosed, and the error is swallowed into the checkpointer's [checkpoint.Stats.LastError] rather than surfaced to the caller — and the goroutine keeps running past the process's shutdown intent until its own ticker happens to observe a stop signal. DB.Close performs the one correct order so every embedder gets it right without re-deriving it.
Teardown order ¶
DB.Close runs these steps, each idempotent and safe under a concurrent second DB.Close:
- Optionally take a FINAL checkpoint (best-effort) while the checkpoint loop is still alive, so a clean shutdown leaves the smallest possible WAL tail to replay on the next open. Enabled with WithFinalCheckpoint; off by default. It must run BEFORE step 2 because once the loop is stopped a checkpoint can no longer be requested ([checkpoint.ErrCheckpointerStopped]).
- Stop the checkpoint goroutine ([checkpoint.Checkpointer.Stop]). After this returns the loop is gone, so no later WAL call can race the close.
- Close the WAL (wal.Writer.Close), flushing and fsyncing any buffered tail first.
Stopping the checkpointer before closing the WAL is the invariant: it guarantees the checkpoint loop can never touch a closed WAL, so wal.ErrWriterClosed is never produced on the shutdown path and the goroutine never outlives the process's intent.
Quiescing writers ¶
A txn.Store transaction is a registered writer from Begin until Commit/Rollback, and a [cypher.Engine] write registers for the statement. Registration does not exclude other writers — since rmp #2306 concurrency control is MVCC alone — but it is exactly what a quiesce drains. DB.Close called concurrently with an in-flight commit would otherwise race wal.Writer.Close (flush + fsync + refuse appends) against the commit's append/sync, risking a transaction whose frames were flushed durable by Close while its Commit returned an error — in-memory/durable divergence at shutdown. Wire WithQuiesce with txn.Store.RunUnderCommitLock so step 3 (the WAL close) runs while holding the store's commit lock: the in-flight commit finishes first, and any commit that starts afterwards gets a clean wal.ErrWriterClosed.
Without WithQuiesce, DB.Close does NOT drain in-flight transactions and the embedder is responsible for stopping new writes and letting the active one finish before calling Close (a Bolt server does this by draining its connections in bolt/server.Server.Shutdown before tearing down the DB). See docs/persistence.md ("Composed shutdown").
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrReadOnlyStore = txn.ErrReadOnlyStore
ErrReadOnlyStore is returned by every commit that would write through a store opened read-only (Options.AllowUnclean on a recovery that was not clean): the txn.Tx commit methods, and therefore every write through a Cypher engine built over it. It is the same value as txn.ErrReadOnlyStore, so errors.Is matches either.
var ErrUncleanRecovery = errors.New("store: recovery did not complete cleanly; refusing to append to the WAL")
ErrUncleanRecovery is returned by Open and OpenCtx, wrapped in an *UncleanRecoveryError, when recovery of the directory did not complete cleanly (recovery.Result.IsClean reported false). Test for it with errors.Is.
Functions ¶
This section is empty.
Types ¶
type Checkpointer ¶
type Checkpointer interface {
// Stop signals the checkpoint goroutine to exit and blocks until it has.
// It must be idempotent.
Stop()
// TriggerCtx requests one checkpoint and blocks until it completes,
// honouring ctx. It returns a non-nil error once the loop has stopped
// (e.g. [checkpoint.ErrCheckpointerStopped]); [DB] treats that as benign.
TriggerCtx(ctx context.Context) error
}
Checkpointer is the behavioural view of a background checkpointer that a DB needs to tear it down: stop its goroutine and (for the optional final checkpoint) trigger one last fold. A *[checkpoint.Checkpointer] satisfies it, so DB need not be generic over the checkpointer's key/weight type parameters merely to own it. The interface is exported so WithCheckpointer has a named, documented parameter type rather than an opaque one.
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB is a composed owner of a WAL-backed store's durability pieces — the WAL writer and an optional background checkpointer — that closes them in the one crash-safe order (see the package documentation). It does not own the in-memory graph or the txn.Store/[cypher.Engine] driving it: those carry no goroutine or file handle of their own and need no teardown.
To reopen an existing directory, use Open / OpenCtx: the returned Opened embeds a DB with the store's commit lock already wired as the quiesce. To assemble the pieces by hand (for example over a fresh graph), construct a DB with New after wiring the WAL, store, engine, and (if used) the checkpointer; hand the DB to whatever owns the shutdown sequence (e.g. a bolt/server.Server via bolt/server.Options.Closer) and call DB.Close exactly where you would otherwise have hand-written "stop the checkpointer, then close the WAL".
Concurrency: DB.Close is safe to call from any number of goroutines and any number of times; the underlying work runs once and every caller observes the same result.
Example ¶
ExampleDB wires the full WAL-backed durability stack — WAL writer, typed store, and a background checkpointer — into a composed store.DB, commits a transaction, then closes the whole stack with a single DB.Close. Close runs the one crash-safe teardown order (stop the checkpoint goroutine, then close the WAL), so no goroutine outlives the call and the WAL is durably closed: a subsequent append is rejected with wal.ErrWriterClosed.
package main
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"sync"
"github.com/FlavioCFOliveira/GoGraph/graph/adjlist"
"github.com/FlavioCFOliveira/GoGraph/graph/lpg"
"github.com/FlavioCFOliveira/GoGraph/store"
"github.com/FlavioCFOliveira/GoGraph/store/checkpoint"
"github.com/FlavioCFOliveira/GoGraph/store/txn"
"github.com/FlavioCFOliveira/GoGraph/store/wal"
)
func main() {
dir, err := os.MkdirTemp("", "store-db-example")
if err != nil {
panic(err)
}
defer func() { _ = os.RemoveAll(dir) }()
wlog, err := wal.Open(filepath.Join(dir, "wal"))
if err != nil {
panic(err)
}
g := lpg.New[string, int64](adjlist.Config{Directed: true})
st := txn.NewStoreWithCodec(g, wlog, txn.NewStringCodec())
// Background checkpointer, wired the production way: the commit serialiser
// excludes the store's commit window while it snapshots, and the mapper
// codec makes the snapshot self-sufficient so the WAL can be truncated.
var unusedMu sync.Mutex
cp := checkpoint.New(checkpoint.Config{Dir: dir}, g, wlog, &unusedMu,
checkpoint.WithCommitSerialiser[string, int64](st.RunUnderCommitLock),
checkpoint.WithMapperCodec[string, int64](txn.NewStringCodec()))
cp.Start(context.Background())
// Commit one transaction so the stack is live.
tx := st.Begin()
if err := tx.AddEdge("alice", "bob", 0); err != nil {
panic(err)
}
if err := tx.Commit(); err != nil {
panic(err)
}
// One composed Close tears the whole stack down in the crash-safe order.
db := store.New(wlog, store.WithCheckpointer(cp), store.WithFinalCheckpoint())
if err := db.Close(); err != nil {
panic(err)
}
// The WAL is durably closed: a further append is rejected.
appendErr := wlog.Append([]byte("after-close"))
fmt.Println("append after Close is ErrWriterClosed:", errors.Is(appendErr, wal.ErrWriterClosed))
}
Output: append after Close is ErrWriterClosed: true
func New ¶
New returns a composed DB that owns wal and, when WithCheckpointer is supplied, the background checkpointer, and closes them in the crash-safe order on DB.Close. wal must not be nil.
Typical wiring (string-keyed, WAL + engine + checkpointer):
wlog, _ := wal.Open(walPath)
st := txn.NewStoreWithOptions[string, float64](g, wlog, txn.Options[string, float64]{
Codec: txn.NewStringCodec(),
WeightCodec: txn.NewFloat64WeightCodec(),
})
eng := cypher.NewEngineWithStore(st)
cp := checkpoint.New(cfg, g, wlog, &unusedMu,
checkpoint.WithCommitSerialiser[string, float64](st.RunUnderCommitLock),
checkpoint.WithMapperCodec[string, float64](st.Codec()),
checkpoint.WithWeightCodec[string, float64](st.WeightCodec()),
checkpoint.WithConstraintSpecs[string, float64](eng.ConstraintSpecsForSnapshot),
checkpoint.WithIndexSpecs[string, float64](eng.IndexSpecsForSnapshot))
cp.Start(ctx)
db := store.New(wlog,
store.WithCheckpointer(cp),
store.WithFinalCheckpoint(),
store.WithQuiesce(st.RunUnderCommitLock))
defer db.Close() // or db.CloseCtx(ctx) to bound the final checkpoint
The WeightCodec is NOT optional in this wiring, and this recipe used to omit it by calling txn.NewStoreWithCodec (rmp #2747). A store without one makes txn.Tx.AddEdgeWithHandle refuse EVERY edge, whatever its weight, and that is the call the Cypher engine's relationship path uses — so every CREATE of a relationship was durably lost while the commit was acknowledged. [checkpoint.WithWeightCodec] would also have been handed a nil codec here.
func (*DB) Close ¶
Close tears the store's durability pieces down (see DB.CloseCtx) using a background context, so the optional final checkpoint runs unbounded. It is the io.Closer implementation, which is why its signature carries no context: this is the method a generic owner such as bolt/server.Options.Closer (an io.Closer) calls. Callers that want to bound the final checkpoint with a deadline call DB.CloseCtx directly.
func (*DB) CloseCtx ¶
CloseCtx tears the store's durability pieces down in the single crash-safe order and returns the first error that matters for durability — the WAL close error.
The order (see the package documentation):
- If WithFinalCheckpoint is set and a checkpointer is owned, take one best-effort final checkpoint, honouring ctx, while the loop is alive. Its error is intentionally discarded.
- Stop the checkpoint goroutine, if any, so it can no longer touch the WAL.
- Close the WAL.
CloseCtx is idempotent and safe under concurrent callers: the teardown runs exactly once (guarded by a sync.Once); a second or racing call (including a later DB.Close) returns the same error the first run produced, never a spurious wal.ErrWriterClosed from a double WAL close.
ctx bounds only the optional final checkpoint (step 1); steps 2 and 3 run to completion regardless of ctx so the goroutine is always joined and the WAL always closed — abandoning them on ctx cancellation would reintroduce the goroutine/file-handle leak this type exists to prevent.
type Opened ¶ added in v0.16.0
type Opened[N comparable, W any] struct { *DB // contains filtered or unexported fields }
Opened is a durable store directory opened for reading and writing by Open or OpenCtx: the recovered graph, the transactional store bound to the WAL, and the recovery result, assembled in one step so no recovered piece can be dropped by omission.
It embeds the composed teardown owner *DB, so DB.Close and DB.CloseCtx close it in the crash-safe order, and the store's commit lock is already wired as the quiesce (WithQuiesce), so a Close concurrent with an in-flight commit lets that commit finish first.
Concurrency: Opened is safe for concurrent use. Its accessors return values fixed at open and may be called from any goroutine at any time. The returned txn.Store and lpg.Graph carry their own contracts (both are safe for concurrent use as documented on those types). Close is safe from any number of goroutines, as documented on DB.
func Open ¶ added in v0.16.0
Open is OpenCtx with a background context.
Example ¶
ExampleOpen opens a store directory, commits a transaction, closes it, and reopens it with store.Open: recovery, the clean gate, the WAL open, and the transactional store built from the recovery result happen in one call, so the reopened store resumes the transaction sequence the WAL already spent.
package main
import (
"fmt"
"os"
"github.com/FlavioCFOliveira/GoGraph/store"
"github.com/FlavioCFOliveira/GoGraph/store/txn"
)
func main() {
dir, err := os.MkdirTemp("", "store-open-example")
if err != nil {
panic(err)
}
defer func() { _ = os.RemoveAll(dir) }()
opts := store.Options[string, float64]{
Codec: txn.NewStringCodec(),
WeightCodec: txn.NewFloat64WeightCodec(),
}
for _, key := range []string{"alice", "bob"} {
o, err := store.Open(dir, opts)
if err != nil {
panic(err)
}
tx := o.Store().Begin()
if err := tx.AddNode(key); err != nil {
panic(err)
}
if err := tx.Commit(); err != nil {
panic(err)
}
if err := o.Close(); err != nil {
panic(err)
}
}
o, err := store.Open(dir, opts)
if err != nil {
panic(err)
}
defer func() { _ = o.Close() }()
_, hasAlice := o.Graph().AdjList().Mapper().Lookup("alice")
_, hasBob := o.Graph().AdjList().Mapper().Lookup("bob")
fmt.Println(hasAlice, hasBob, o.Recovery().MaxTxnSeq)
}
Output: true true 2
func OpenCtx ¶ added in v0.16.0
func OpenCtx[N comparable, W any](ctx context.Context, dir string, opts Options[N, W]) (*Opened[N, W], error)
OpenCtx opens the durable store in dir for reading and writing. It is the composed counterpart of DB.Close: the one correct reopen sequence, so an embedder no longer hand-writes it and cannot drop recovered state.
It runs, in order:
- Recovery (recovery.OpenCtx) over dir: the snapshot, if any, then the WAL tail at dir/wal. A recovery error is returned wrapped, and nothing is opened for writing.
- The clean gate. When recovery.Result.IsClean is false the open is refused with an *UncleanRecoveryError wrapping ErrUncleanRecovery and the recovery's TailErr, and no WAL writer is opened, unless Options.AllowUnclean is set, in which case the directory is opened read-only and steps 3 to 5 are replaced (see below). The check is on IsClean, not on the recovery error alone: one not-clean outcome (recovery.ErrCommittedTxnCorruptOp) returns a nil error from recovery.
- The WAL is opened for append (wal.Open), which takes the directory's WAL lock and truncates a benign torn tail.
- The transactional store is built from the recovery result (recovery.Result.NewStoreCapped), carrying the recovered graph (and with it the graph configuration, the restored MVCC clock, labels, properties, tombstones and edge handles), the transaction-sequence floor (recovery.Result.MaxTxnSeq, ratcheted with Options.ResumeTxnSeq), the producer op cap clamped to the replay bound (recovery.Result.MaxTxnOps), and the codecs recovery used.
- The DB teardown owner is assembled over the WAL, with the store's commit lock wired as the quiesce, followed by Options.CloseOptions.
The recovered schema and index payloads live in Opened.Recovery; the query layer consumes them from there (cypher.NewEngineWithOpened).
When any step after the WAL open fails, the WAL is closed before OpenCtx returns, so a failed open leaks no file handle and no lock.
Why an unclean directory is refused, or opened read-only ¶
Appending to a WAL that did not replay cleanly does not repair it: every later recovery stops at the same damaged frame, so each commit appended after it is acknowledged and then discarded at the next open. Refusing the open keeps those commits from being acknowledged at all.
With Options.AllowUnclean the directory is opened READ-ONLY instead: the store is a txn.NewReadOnlyStore over the recovered graph, no WAL writer is opened (so no lock is taken and the directory is not modified), and the embedded DB owns no WAL (DB.Close then only stops a checkpointer, if Options.CloseOptions supplied one). Reads, Opened.Recovery and Opened.ReadOnly work; every commit that would write fails with ErrReadOnlyStore, so no write is ever acknowledged. The refused UncleanRecoveryError.Result carries the same committed prefix for a caller that does not want an Opened at all.
Prior art ¶
The shape follows two reference engines' single open entry point. bbolt (go.etcd.io/bbolt, db.go, func Open) takes the file lock, reads or initialises the meta pages, maps the file, and on every failure path calls db.close() before returning, so a failed open releases what it took. Badger (github.com/dgraph-io/badger, db.go, func Open) acquires the directory lock, replays the manifest, levels and value log, and seeds its transaction-timestamp oracle from the replayed maximum (orc.nextTxnTs = db.MaxVersion(), then incrementNextTs) inside Open, rather than returning the maximum for the caller to apply. OpenCtx takes the same two decisions: the recovered counters are applied inside the open, and a failed open unwinds what it opened.
Concurrency ¶
OpenCtx is a one-shot bootstrap step. It must not run concurrently with another OpenCtx, recovery.Open, or a writer on the same directory: the WAL lock is taken at step 3, after recovery has read (and, for an interrupted snapshot publish, repaired) the directory. A second process that reaches step 3 while the first holds the lock fails with wal.ErrWALLocked. Opens of distinct directories are independent and may run concurrently.
ctx bounds recovery (step 1); it is checked by recovery at the snapshot boundary and periodically during WAL replay.
func (*Opened[N, W]) Graph ¶ added in v0.16.0
Graph returns the recovered in-memory graph the store writes to. It is the same graph as Store().Graph() and Recovery().Graph. Mutating it directly bypasses the store and is never durable; on a read-only Opened, read it only.
func (*Opened[N, W]) ReadOnly ¶ added in v0.16.0
ReadOnly reports whether the directory was opened read-only: its recovery was not clean and Options.AllowUnclean was set. A read-only Opened has no WAL writer, and every commit that would write returns ErrReadOnlyStore.
func (*Opened[N, W]) Recovery ¶ added in v0.16.0
Recovery returns the recovery result this store was built from: the recovered schema (recovery.Result.Constraints, recovery.Result.Indexes), the index payloads, the derived counters, and the replay diagnostics. Hand it whole to the query layer (for the string/float64 Cypher engine, cypher.NewEngineWithOpened) so the schema is re-registered.
func (*Opened[N, W]) Store ¶ added in v0.16.0
Store returns the transactional store bound to the WAL. Its transaction sequence resumes from the recovered maximum, its op cap is clamped to the replay bound, and it carries the codecs the directory was recovered with. On a read-only Opened it is a txn.NewReadOnlyStore, whose commits that would write return ErrReadOnlyStore.
func (*Opened[N, W]) WAL ¶ added in v0.16.0
WAL returns the WAL writer the store appends to. It is exposed so a background checkpointer can be wired to it. Do not close it directly: the embedded DB owns it, and closing it out of order is the defect DB.Close exists to prevent. It is nil on a read-only Opened.
type Option ¶
type Option func(*DB)
Option customises a DB at construction. Options are applied in order by New.
func WithCheckpointer ¶
func WithCheckpointer(cp Checkpointer) Option
WithCheckpointer makes the DB own the background checkpointer cp and stop it (before the WAL is closed) on DB.Close. Pass the same *[checkpoint.Checkpointer] that was [checkpoint.Checkpointer.Start]ed for this store. When omitted the DB owns no checkpointer and DB.Close closes only the WAL.
A nil checkpointer is ignored (the DB keeps owning no checkpointer), so a caller can pass a possibly-nil checkpointer without a guard.
func WithFinalCheckpoint ¶
func WithFinalCheckpoint() Option
WithFinalCheckpoint makes DB.Close take one best-effort checkpoint, while the checkpoint loop is still alive, before stopping it — so a clean shutdown folds the WAL tail into the snapshot and the next open replays the minimum. It has no effect unless the DB also owns a checkpointer (WithCheckpointer).
The final checkpoint is best-effort: its error (including a benign [checkpoint.ErrCheckpointerStopped] if the loop has already exited) does NOT fail DB.Close; only the WAL-close error is returned, because durability of already-committed transactions does not depend on the final checkpoint running. Off by default to keep Close cheap and side-effect-free for callers that do not need a compacted shutdown.
func WithQuiesce ¶ added in v0.3.0
WithQuiesce supplies a callback that DB.Close uses to drain in-flight writers before closing the WAL: step 3 of the teardown runs the WAL close inside fn, so an in-flight txn.Tx.Commit/txn.Tx.CommitWALOnly finishes (or a pending one starts and finishes) before the writer is flushed and closed, and no commit can interleave between the flush and the close. Pass txn.Store.RunUnderCommitLock — the store's single-writer commit lock is exactly the mutual exclusion required. Any commit that begins after the close releases the lock receives wal.ErrWriterClosed, the correct error for post-close calls.
Holding the lock across the WAL close is safe: wal.Writer.Close is a short flush+fsync+close sequence, and fn must not begin a transaction on the same store (see txn.Store.RunUnderCommitLock; the DB only ever passes the WAL close as fn, which opens no transaction).
Without this option DB.Close does not quiesce writers — safe only when the embedder guarantees no concurrent commits at shutdown. A nil fn is ignored (the DB keeps not quiescing), so a caller can pass a possibly-nil callback without a guard.
type Options ¶ added in v0.16.0
type Options[N comparable, W any] struct { // Codec serialises node identifiers. It must not be nil, and it must be the // codec the directory was written with: it is used both to replay the WAL // and to encode every later append, so recovery and the store cannot // disagree. Codec txn.Codec[N] // WeightCodec serialises edge weights. It must mirror the producer that // wrote the directory: non-nil for a weight-codec store, nil for a // codec-only store. It is used for both replay and appends. WeightCodec txn.WeightCodec[W] // ReplayMaxTxnOps bounds the ops recovery buffers for one transaction // ([recovery.Options.MaxTxnOps]): 0 selects [txn.DefaultMaxTxnOps], // [txn.MaxTxnOpsUnlimited] disables the bound, any other positive value is // the bound verbatim. ReplayMaxTxnOps int // MaxTxnOps is the producer's per-transaction op cap, in the same // convention. It is clamped down to the replay bound by // [recovery.Result.NewStoreCapped], so the reopened store can never commit // a transaction its own next recovery would refuse. MaxTxnOps int // ResumeTxnSeq is an optional caller floor for the transaction sequence. // It is ratcheted with the recovered [recovery.Result.MaxTxnSeq] and never // lowers it; leave it 0 unless a floor is required for another reason. ResumeTxnSeq uint64 // CloseOptions are applied to the returned [DB] after the options [Open] // always applies ([WithQuiesce] bound to the store's commit lock). CloseOptions []Option // AllowUnclean opens a directory whose recovery was not clean // ([recovery.Result.IsClean] false) in READ-ONLY mode instead of refusing // it: the recovered graph (the committed prefix), [Opened.Recovery] and // reads are available, no WAL writer is opened (no lock is taken and no // byte is written), and every commit that would write fails with // [ErrReadOnlyStore]. It covers both not-clean outcomes, the fail-stop // corruption recovery returns as its error and the nil-error // [recovery.ErrCommittedTxnCorruptOp]. A recovery error that is not a // corruption (an I/O error, a cancelled ctx) is returned whatever this // says, and a clean recovery opens for writing whatever this says. AllowUnclean bool // SyncLatency, when non-nil, delays every WAL data fsync and directory fsync // of the opened store by a seeded random duration ([wal.SyncLatency]). It is // a TESTING instrument that restores a real device's fsync window on a RAM // drive (rmp #3022); leave it nil in production, where it costs one // nil-pointer test per fsync. SyncLatency *wal.SyncLatency }
Options configures Open and OpenCtx. It is a plain configuration value: populate it before the call and do not mutate it while the call is in flight.
type UncleanRecoveryError ¶ added in v0.16.0
type UncleanRecoveryError[N comparable, W any] struct { // Dir is the directory that was refused. Dir string // TailErr is the recovery's [recovery.Result.TailErr]. TailErr error // Result is the refused recovery, for diagnostics. Result recovery.Result[N, W] }
UncleanRecoveryError reports that Open refused a directory whose recovery did not complete cleanly. It wraps both ErrUncleanRecovery and the recovery's recovery.Result.TailErr, so errors.Is matches the refusal and the specific corruption sentinel (for example wal.ErrCRCMismatch or recovery.ErrCommittedTxnCorruptOp).
Result is the recovery that was refused. Its graph holds the committed prefix and is provided for diagnostics only; no WAL writer was opened, so nothing was appended and the directory is byte-for-byte as recovery left it.
Concurrency: an UncleanRecoveryError is read-only once returned and safe for concurrent reads; Result.Graph follows the lpg.Graph contract.
func (*UncleanRecoveryError[N, W]) Error ¶ added in v0.16.0
func (e *UncleanRecoveryError[N, W]) Error() string
Error implements error.
func (*UncleanRecoveryError[N, W]) Unwrap ¶ added in v0.16.0
func (e *UncleanRecoveryError[N, W]) Unwrap() []error
Unwrap returns ErrUncleanRecovery and the recovery's TailErr, so errors.Is matches either.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package bulk implements the bulk-loading path that bypasses the transactional WAL stack and writes a Tier 2 csrfile directly from a stream of edges.
|
Package bulk implements the bulk-loading path that bypasses the transactional WAL stack and writes a Tier 2 csrfile directly from a stream of edges. |
|
Package bulkimport builds a labelled property graph from a stream of node and edge records, at bulk-loader speed, so that the result can be published as a store snapshot.
|
Package bulkimport builds a labelled property graph from a stream of node and edge records, at bulk-loader speed, so that the result can be published as a store snapshot. |
|
Package checkpoint runs a background goroutine that periodically folds the WAL tail into a fresh snapshot and truncates the WAL.
|
Package checkpoint runs a background goroutine that periodically folds the WAL tail into a fresh snapshot and truncates the WAL. |
|
Package csrfile defines the on-disk binary format used by GoGraph's Tier 2 (out-of-core, mmap-backed) CSR storage.
|
Package csrfile defines the on-disk binary format used by GoGraph's Tier 2 (out-of-core, mmap-backed) CSR storage. |
|
Package recovery rebuilds the in-memory graph state from a snapshot (when present) plus the WAL tail, and exposes the harness used to fuzz crash semantics in tests.
|
Package recovery rebuilds the in-memory graph state from a snapshot (when present) plus the WAL tail, and exposes the harness used to fuzz crash semantics in tests. |
|
Package snapshot serialises the durable on-disk representation of a gograph snapshot (CSR + LPG + schema) and reads it back into a fresh process.
|
Package snapshot serialises the durable on-disk representation of a gograph snapshot (CSR + LPG + schema) and reads it back into a fresh process. |
|
Package txn provides the transactional surface (Begin / Commit / Rollback) layered over an lpg.Graph and a wal.Writer.
|
Package txn provides the transactional surface (Begin / Commit / Rollback) layered over an lpg.Graph and a wal.Writer. |
|
Package wal implements a versioned, length-prefixed, CRC32C-checksummed Write-Ahead Log for the gograph durability stack.
|
Package wal implements a versioned, length-prefixed, CRC32C-checksummed Write-Ahead Log for the gograph durability stack. |