Choose a durability mode
Pick full, everysecond, or snapshot durability for a relate store, see what each can lose in a crash, and set it per run, environment, or server.
clipythonnode
Before you start: Install relate
This guide shows you how to choose and set a durability mode When a commit counts as safe on disk: full (the default) syncs the WAL first, everysecond about once a second, and snapshot only at checkpoints. Read more in the glossary: the rule for when a commit counts as safe on disk. The default, full, syncs the WAL Append-only log each commit goes to before it applies; under the default full durability mode it is synced first, so a crash loses no acknowledged write. Read more in the glossary to disk before a commit returns, so a crash loses no acknowledged write. everysecond and snapshot return before that sync, and a crash can lose writes they already acknowledged.
Prerequisites
relateon yourPATH(Install relate).- A store A relate database: a directory, a single
.rlfile, or:memory:, opened with--database. Read more in the glossary on disk, a directory or a.rlfile. An in-memory store forgets everything at exit in every mode.
Compare the modes
To sync is to force written data out of the operating system's cache onto the disk (fsync). Each mode decides when the WAL is synced relative to the moment a commit returns:
| Mode | A commit returns | The WAL is synced | A crash can lose |
|---|---|---|---|
full (default) | After its WAL record is synced | Before each commit, or group of commits, is acknowledged | No acknowledged write |
everysecond | After it applies in memory | About once a second, in the background | About the last second of acknowledged writes; slow storage or a delayed sync makes the window longer |
snapshot | After it applies in memory | Never on commit; only a completed checkpoint is durable | Every write since the last completed checkpoint, up to 300 seconds of writes under the default timer |
A killed process can lose the window too, not only a power cut. In a test on this release, a write to a .rl store was acknowledged and the process was killed with kill -9 half a second later, three times per mode. Under full the write was there on the next open every time; under everysecond and snapshot it was gone every time. In one more snapshot run, it was still gone with 3 seconds between the write and the kill.
The mode is a setting of the process that opens the store, not of the store. The next open picks its own, and an open that sets nothing gets full.
Each mode's loss window for one crash, a few seconds after a completed checkpoint.
What a crash can lose. The durability mode decides when a commit is acknowledged relative to the WAL sync. It is a setting of the process that opens the store (--durability-mode or RELATE_DURABILITY_MODE, default full), not of the store.
The picture's timeline: 8 writes are acknowledged in the 4.6 s after a completed checkpoint, then the process crashes. A killed process can lose the window as well as a power cut.
| Mode | The WAL is synced | Acknowledged writes the crash at 4.6 s can lose |
|---|---|---|
full | Before each commit, or group of commits, is acknowledged | None: all 8 come back |
everysecond | About once a second, in the background | The 2 writes after the last sync, at 4 s |
snapshot | Never on commit; only a completed checkpoint is durable | All 8, every write since the checkpoint |
Under everysecond, slow storage or a delayed sync makes the window longer than about a second. Under snapshot, the window runs until the next completed checkpoint: up to 300 seconds of writes under the default timer, fewer when a WAL segment fills first.
Live: Commit, Checkpoint and Crash step through what relate does with the WAL, the in-memory graph and the snapshot (inside one .rl file in the file view), and a mode switch with a crash slider shades what full, everysecond and snapshot can lose; under reduced motion each step waits for Next. It is a diagram of documented behaviour: no engine runs.
Choose one
- If every acknowledged write must survive a crash, keep
full. It is the only mode with no loss window. - If losing about the last second of writes is acceptable, such as a cache you can rebuild, choose
everysecond. Commits stop waiting for each sync. - If the writes can be redone from their source, such as a bulk load you can rerun, choose
snapshot. Pair it with a checkpoint interval that bounds what a rerun has to redo.
Set it for one run
--durability-mode applies to the run it's on. To follow along, create the shared example graph as team.rl first:
cat > team.cypher <<'EOF'
CREATE (ada:Person {name: 'Ada', role: 'engineer'}),
(grace:Person {name: 'Grace', role: 'engineer'}),
(noor:Person {name: 'Noor', role: 'maintainer'}),
(relate:Project {name: 'relate', language: 'Rust'}),
(tck:Project {name: 'opencypher-tck', language: 'Gherkin'}),
(ada)-[:WORKS_ON {since: 2024}]->(relate),
(grace)-[:WORKS_ON {since: 2023}]->(relate),
(grace)-[:WORKS_ON {since: 2022}]->(tck),
(noor)-[:MAINTAINS]->(relate),
(ada)-[:KNOWS]->(grace);
EOF
relate query --database ./team.rl < team.cypherThis run writes to team.rl under everysecond: it records that Noor maintains opencypher-tck too.
relate --database ./team.rl --durability-mode everysecond --mode envelope "MATCH (noor:Person {name: 'Noor'}), (tck:Project {name: 'opencypher-tck'}) CREATE (noor)-[:MAINTAINS]->(tck) RETURN noor.name AS person, tck.name AS project"{"columnTypes":["STRING","STRING"],"columns":["person","project"],"notifications":[],"planCache":"miss","rows":[{"person":"Noor","project":"opencypher-tck"}],"timings":{"elapsed_ms":0.657292,"execute_ms":0.431542,"lex_parse_ms":0.006583,"lower_ms":0.011,"parse_ms":0.212583,"plan_ms":0.008417,"result_generation_ms":0.00020800000000000001,"rewrite_ms":0.000375},"truncated":false}A one-shot run checkpoints when it exits cleanly, so this write is on disk by the time the command returns. The window matters for processes that stay open, such as relate serve, an app that uses a client, or a long script.
Set it for an environment
RELATE_DURABILITY_MODE sets the mode for every open that doesn't set one itself. The flag wins over the variable. The Python and Node.js clients read the same variable when they open a store, so it is how an app chooses a mode.
This run writes to team.rl under snapshot, set by the variable: Grace maintains relate now.
RELATE_DURABILITY_MODE=snapshot relate --database ./team.rl --mode envelope "MATCH (grace:Person {name: 'Grace'}), (r:Project {name: 'relate'}) CREATE (grace)-[:MAINTAINS]->(r) RETURN grace.name AS person, r.name AS project"{"columnTypes":["STRING","STRING"],"columns":["person","project"],"notifications":[],"planCache":"miss","rows":[{"person":"Grace","project":"relate"}],"timings":{"elapsed_ms":0.6042909999999999,"execute_ms":0.364666,"lex_parse_ms":0.008749999999999999,"lower_ms":0.011375,"parse_ms":0.224375,"plan_ms":0.009792,"result_generation_ms":0.00041600000000000003,"rewrite_ms":0.000458},"truncated":false}Set it for a server
relate serve takes the same flag, with the same order: the flag, then RELATE_DURABILITY_MODE, then full. This server is writable on purpose, since the mode only matters for writes:
relate serve --database ./team.rl --http 7474 --durability-mode everysecondBound the snapshot window
Under snapshot, the time between checkpoints is the loss window. A one-shot run or relate query takes --checkpoint-interval-secs N; relate serve doesn't accept that flag and takes only RELATE_CHECKPOINT_INTERVAL_SECS. The default is 300 seconds. 0 turns off only the timer: checkpoints still run when a WAL segment fills, on a clean exit, and on .checkpoint.
RELATE_CHECKPOINT_INTERVAL_SECS=30 relate serve --database ./team.rl --http 7474 --durability-mode snapshotVerify
Read the store back read-only. Both writes are there, next to the example's original MAINTAINS relationship:
relate --database ./team.rl --read-only --mode envelope "MATCH (p:Person)-[:MAINTAINS]->(project:Project) RETURN p.name AS person, project.name AS project ORDER BY person, project"{"columnTypes":["STRING","STRING"],"columns":["person","project"],"notifications":[],"planCache":"miss","rows":[{"person":"Grace","project":"relate"},{"person":"Noor","project":"opencypher-tck"},{"person":"Noor","project":"relate"}],"timings":{"elapsed_ms":0.40049999999999997,"execute_ms":0.22204200000000002,"lex_parse_ms":0.033457999999999995,"lower_ms":0.040958,"parse_ms":0.109625,"plan_ms":0.059834,"result_generation_ms":0.000209,"rewrite_ms":0.008208},"truncated":false}If it goes wrong
Error: invalid --durability-mode: semantic error: invalid durability mode "<value>"; expected full, everysecond, or snapshot, exit code 2. The flag's value is misspelled. Use one of the three names.Error: invalid RELATE_DURABILITY_MODE: semantic error: invalid durability mode "<value>"; expected full, everysecond, or snapshot, exit code 2. The variable holds something else. Fix it or unset it (the variable's error). The clients refuse to open too: Python'srelate.connect()raisesOperationalErrorand Node.js throws, each with a message that namesRELATE_DURABILITY_MODE.- Writes acknowledged just before a crash are missing. The process ran under
everysecondorsnapshot, and the crash fell inside the loss window. Switch tofullif those writes matter (Recover from a crash).
Related
--durability-modein the flags reference.- Recover from a crash: what an open restores after a crash.
- Storage and durability: the WAL, snapshots, and checkpoints, and why there are three modes.