Quick Start
Command line
cargo build -p graphersal-cli # target/debug/graphersal
graphersal store create data/ --from modern # a store with the modern graph, at commit 0
graphersal --graph data/ -e 'g.add_v("person").property("name", "zoe").to_list()'
graphersal store mark data/ before-import # name this position
graphersal --graph data/ -e 'g.add_v("person").property("name", "ada").to_list()'
graphersal store info data/ # commit 2, 1 snapshot, 1 mark
graphersal store fork data/ branch/ --at-mark before-import # the state at the mark, as a new store
graphersal store backup data/ backup/ # a consistent copy, also while in use
graphersal --graph data/ --server # the playground UI on the store: http://127.0.0.1:8080/
Every commit to data/ is durable before the command returns; the REPL (graphersal --graph data/) and the dev server keep it open and commit every query. Ctrl+C closes the store
cleanly; a crash or kill -9 loses nothing committed either.
Without a store, a packed snapshot saves and loads the whole graph:
graphersal -e 'g.export_snapshot("m.gsnap")' # Exported a snapshot to m.gsnap (6 vertices, 6 edges, commit 0)
graphersal --graph m.gsnap -e 'g.v().count().next()' # 6
Rust
graphersal = { version = "0.1", features = ["persist"] }
#![allow(unused)] fn main() { use graphersal::persist::{RecoveryTarget, Store, StoreOptions}; let store = Store::create("data", StoreOptions::new())?; // later: Store::open("data", ..) store.graph().write().traversal_mut().add_v("person").property("name", "ann").to_list()?; store.mark("after-ann")?; // a point-in-time target store.checkpoint(Some("nightly"))?; // a snapshot of the current state store.close()?; // a clean close (Drop does it too) let store = Store::open("data", StoreOptions::new())?; // recovery: snapshot + WAL replay assert_eq!(store.graph().read().vertex_count(), 1); let past = Store::open_read_only("data", RecoveryTarget::Mark("after-ann".into()))?; assert_eq!(past.graph.vertex_count(), 1); Ok::<(), Box<dyn std::error::Error>>(()) }
store.graph() is the shared graph (Graph, a TraversalGraph behind a read-write lock); every commit of it
is written to the store's write-ahead log and synced before it returns.
A packed snapshot over any Write / Read:
#![allow(unused)] fn main() { use graphersal::prelude::*; let graph = TraversalGraph::tinkerpop_modern(); let mut bytes = Vec::new(); graph.write_snapshot(&mut bytes).unwrap(); let loaded = TraversalGraph::read_snapshot(bytes.as_slice()).unwrap(); assert_eq!(loaded.vertex_count(), 6); }
Python
import graphersal
graph = graphersal.Graph.tinkerpop_modern()
graph.save("g.gsnap") # {"commit_seq", "vertex_count", "edge_count"}
graph = graphersal.Graph.load("g.gsnap")
with graphersal.Store.create("data") as store: # later: graphersal.Store.open("data")
store.graph.execute('g.addV("person").property("name", "ann").next()')
store.mark("after-ann")
store.checkpoint("nightly")
Web playground
Every graph you load in the playground is a Store in memory: the Store menu in the top bar checkpoints, marks, opens past states read-only, forks and rolls back, exactly as the dev server does on a directory (The Store in the Playground). Everything in memory is lost on a page reload: Download current state (.gsnap) keeps a state, and the start page loads it back.