Persistence
FrogDB persists every shard to its own RocksDB instance. This page covers the three durability modes, the WAL failure policy, how forkless snapshots work and what triggers them, what startup recovery actually does, and the tiered (hot/warm) storage tier. Copying data off-host is covered separately in Backup & restore; how replicas bootstrap from a checkpoint is covered in Replication.
Durability modes
Section titled “Durability modes”FrogDB’s “WAL” is RocksDB’s own write-ahead log — FrogDB does not maintain a separate log
file. Writes are batched on a per-shard flush thread, and the durability-mode setting
([persistence] in the TOML file) controls how that thread commits each batch:
sync— every batch write is issued with RocksDB’ssyncwrite option set, which fsyncs the write before the call returns. An acknowledged write is durable immediately.async— writes are not synced; the OS decides when buffered data reaches disk. There is no background sync task in this mode.periodic(default) — writes are not synced individually either, but a background task flushes each shard’s RocksDB memtable to disk on a fixed interval (sync-interval-ms, default1000), bounding how much recently-written data can be lost if the process crashes between flushes.
Choose based on the data-loss window you can tolerate, not on measured latency (FrogDB
does not publish latency numbers for these modes): async favors throughput for
data you can afford to lose, sync favors safety for data you cannot, and periodic
is the default middle ground, comparable to Redis’s appendfsync everysec.
[persistence]durability-mode = "periodic" # "async" | "periodic" | "sync"sync-interval-ms = 1000 # periodic mode onlyThe registry (frogdb-server/crates/config/src/params.rs) marks both durability-mode
and sync-interval-ms as runtime-mutable, and CONFIG SET accepts changes to either. In
practice, the periodic-sync background task captures its mode and interval once at
startup (frogdb-server/crates/server/src/server/startup.rs) and is not restarted when
these values change, so a runtime change to either does not take effect until the server
restarts. Treat them as effectively startup-only despite being marked mutable.
Write visibility
Section titled “Write visibility”In async and periodic modes, a write is visible to other clients (a GET after a
SET succeeds) before it is durable on disk — a successful read does not guarantee the
value survives a crash. This matches standard Redis behavior for the equivalent
appendfsync settings.
WAL failure policy
Section titled “WAL failure policy”wal-failure-policy ([persistence], default continue) controls what happens when a
WAL write fails after a command has already executed in memory:
continue— logs the failure and returns success to the client. The write stays visible in memory but may be lost on restart.rollback— undoes the in-memory change and returns an error to the client instead.
Unlike durability-mode/sync-interval-ms above, wal-failure-policy is genuinely live:
it is stored as a shared atomic that the flush thread reads on every write, so
CONFIG SET wal-failure-policy rollback takes effect immediately. One caveat: rollback
only catches failures raised by the flush thread itself in non-sync modes — document
this as the current behavior rather than a general corruption guarantee.
Snapshots
Section titled “Snapshots”FrogDB snapshots are forkless: rather than forking the process (as Redis does for RDB),
a snapshot is a RocksDB checkpoint — RocksDB hard-links the current SST files into a new
directory at the filesystem level instead of copying them
(frogdb-server/crates/persistence/src/rocks/checkpoint.rs,
frogdb-server/crates/persistence/src/snapshot/rocks_coordinator.rs). Each snapshot
directory also gets a metadata.json and a copy of the Tantivy search indexes if any
exist. Because the low overhead comes from hard-links rather than an in-memory
copy-on-write buffer, there is no memory spike from taking a snapshot; the mechanism does
mean a snapshot’s marginal disk cost grows over time as later compaction rewrites the
hard-linked SSTs out from under it.
[snapshot]snapshot-dir = "./snapshots" # default; sibling of the data directorysnapshot-interval-secs = 3600 # 0 disables automatic snapshotsmax-snapshots = 5 # 0 keeps every snapshotBGSAVE (and BGSAVE SCHEDULE) trigger a snapshot on demand in addition to the automatic
interval.
Recovery
Section titled “Recovery”On startup, FrogDB (frogdb-server/crates/server/src/server/startup.rs and
frogdb-server/crates/persistence/src/recovery.rs):
- Installs a staged replica checkpoint if a
checkpoint_readysibling directory is present next to the data directory; otherwise this step is a no-op. - Opens RocksDB at
data-dir. RocksDB replays its own internal WAL as part of opening. - If data exists, iterates every key in every column family (hot tier, then warm tier) and restores it into the in-memory store, skipping keys whose TTL already expired and counting (and logging) any values that fail to deserialize. Recovery continues past deserialize failures rather than aborting — this is the only corruption-handling behavior that exists. A warm-tier key is only restored if no hot-tier copy of the same key was already loaded (a hot copy always wins).
There is no snapshot-load step at startup: the data-dir directory is the live RocksDB
instance, not a directory that gets reconstructed from a snapshot on every boot.
Snapshots in snapshot-dir are a separate, standalone copy of the data used for backup
and replica bootstrap (see Backup & restore and
Replication) — primary recovery never reads them.
Tiered storage
Section titled “Tiered storage”FrogDB has an optional warm storage tier: cold values, instead of being evicted outright, can be demoted into a second RocksDB column family per shard. This is enabled with a single flag:
[tiered-storage]enabled = falseEnabling it makes two additional maxmemory-policy values available, tiered-lru and
tiered-lfu, which demote (rather than delete) least-recently/least-frequently-used
values into the warm tier (frogdb-server/crates/core/src/eviction/policy.rs). Warm-tier
entries are recovered at startup the same way hot-tier entries are (see
Recovery above). There are no additional tuning knobs beyond the enabled
flag today — see Configuration and
Configuration reference for maxmemory-policy and the rest
of the [memory] section.
Persistence metrics
Section titled “Persistence metrics”The full metric catalog is in Metrics reference. The persistence- relevant subset:
| Metric | Type | Description |
|---|---|---|
frogdb_wal_writes_total | Counter | WAL writes issued |
frogdb_wal_bytes_total | Counter | WAL bytes written |
frogdb_wal_flush_duration_seconds | Histogram | Flush-thread batch duration |
frogdb_wal_durability_lag_ms | Gauge | How far behind durable state is from in-memory state |
frogdb_persistence_errors_total | Counter | Persistence errors (disk full, I/O failures) |
frogdb_snapshot_in_progress | Gauge | 1 while a snapshot is running |
frogdb_snapshot_duration_seconds | Histogram | Snapshot duration |
frogdb_snapshot_size_bytes | Gauge | Size of the last snapshot |
See also
Section titled “See also”- Backup & restore — copying data off-host and restoring it.
- Replication — how replicas use checkpoints for full sync.
- Configuration — the four configuration surfaces and runtime mutability in general.
- Architecture → Storage and Persistence — the on-disk format and storage engine design.