Persistence

Graphersal keeps the graph in memory. The persist feature keeps it on disk too: in Graphersal's own binary format, losslessly, with every committed change made durable before the commit returns, so nothing committed is lost on a restart or a crash.

Looking for a command? The Command Cheat Sheet has every one of them, ready to copy.

What to choose

You wantUseAPIPage
save a graph now and load it later (a script, the browser, a download)a packed snapshot: the whole graph in one file or stream (.gsnap)graph.write_snapshot(w), TraversalGraph::read_snapshot(r); DSL g.export_snapshot(path); CLI --graph g.gsnapPacked Snapshots
durability over streams you manage yourself (a socket, an upload, any Write), also in WebAssemblya snapshot plus a journal (write-ahead log) and recoverypersist::Journal, persist::recoverJournal and Recovery
an application that simply keeps its graph ("SQLite for graphs")the Store: one directory (or one file) = one graph; recovery on open, checkpoints, marks, point-in-time views, fork, rollback, backups, verify, repairpersist::Store; CLI graphersal store ..., --graph data/The Store

GraphML and GraphSON stay the exchange formats. The snapshot is the lossless one: every value type (uuid, nested arrays and objects, NaN payloads, property order), multi-label and unlabeled vertices, unlabeled edges, the schema, the catalog of definitions (saved queries), and the graph's position (commit sequence number, commit time, auto-id sequences).

graphersal = { version = "0.1", features = ["persist"] }        # LZ4 chunks, the Store, journals
graphersal = { version = "0.1", features = ["persist-zstd"] }   # also zstd chunks (pure Rust)
graphersal = { version = "0.1", features = ["persist-zip"] }    # also ZIP backups of a Store

Where it runs:

Packed snapshotJournal and recoveryStore
Rust, nativeyesyesdirectory, single file, memory
Rust, WebAssemblyyesyes (no fsync)in memory (MemDir)
CLI--graph g.gsnap, g.export_snapshotgraphersal store ..., --graph data/
Dev server.gsnap download--graph data/ --server, the Store menu
Web playgroundSave as snapshot, load .gsnapevery loaded graph is a store in memory
Pythongraph.save, Graph.loadgraph.start_journal, Graph.recovergraphersal.Store

Concepts

TermMeaning
commitone committed unit of change. Every traversal is one (see Transactions); so is an explicit transaction(..), a whole playground script, an import
commit sequence number (commit_seq)the number of a commit: 1, 2, 3, ... per graph, never reused. The position of a graph is the number of its last commit (0 = nothing committed yet)
commit timethe time of a commit (UTC, microseconds); monotonic within a history
snapshotthe whole graph at one position. In a Store it is a directory under snapshots/, packed it is one .gsnap file
WAL (journal)the write-ahead log: one record per commit with every change, its before and after values, in order; one record per mark
checkpointwriting a new snapshot of the current state, so the next open replays less WAL
marka name for a position ("before-import"); costs a few bytes
targeta point to go back to: a commit, a time, or a mark
lineage (graph_id)a UUID that names one history. A fork, an in-place rollback and a repair start a new lineage that records its parent
atticwhere an in-place rollback keeps the history it rolled back, so the rollback can be undone
backupa consistent copy of a store; marked, so it opens read-only until it is restored
donoran intact older copy (an older snapshot plus the WAL) that damaged data can be rebuilt from
maintenance modehow a damaged store opens: read-only, with a damage report

Guarantees

  • Durable commits. A Store commit (and a journal commit with Durability::EveryCommit, the default) is written and fsynced before it returns. A failed write or sync rolls the commit back: the caller never gets "ok" for a commit that is not on disk, and the WAL never holds a commit that did not happen.
  • Crash safety. Opening a store after a crash (or kill -9) brings back exactly the last committed state: an interrupted last write is cut off, an interrupted multi-file operation is completed.
  • Damage is found, never silently lost. Every header, chunk and record carries a CRC-32C; the small critical metadata exists twice. A damaged store opens read-only in maintenance mode with a report, and repair writes a new store elsewhere, never in place.
  • Nothing is deleted implicitly. History goes away only through an explicit prune, a rollback with --delete, or removing an attic entry.
  • Point in time. Every commit, time and mark that the retained history covers can be viewed read-only, forked into a new store, or rolled back to.
  • Portable bytes. Little-endian, the same bytes on every platform and in WebAssembly; no file holds an absolute path, so a store can be moved or copied anywhere. The format is a public specification.
  • One writer. A store has at most one writer (an operating-system lock); readers, backups and forks work while it runs.

This part of the book