Snapshots
A snapshot is a logical point-in-time view of the database. Reads issued through a snapshot ignore every write made after it was taken. Snapshots are cheap to create — they're just a sequence number plus a reference count — but they pin SST files until they're released.
Upstream reference: Snapshot wiki.
Creating a snapshot
using var snap = db.CreateSnapshot();
var ro = new ReadOptions().SetSnapshot(snap);
db.Put("k", "after");
string v = db.Get("k", readOptions: ro); // value as of snapshot — may be older
Snapshot implements IDisposable. Always dispose it — every undisposed snapshot prevents the corresponding SST files from being garbage-collected by compaction.
Use cases
| Pattern | Why a snapshot helps |
|---|---|
| Consistent multi-key read | All reads see the same state, even if writers are concurrent. |
| Long-running scan | An iterator built on a snapshot won't see partial in-flight updates. |
| Backup / export | Walk the entire database without freezing writes. |
| Replication | Stream the state at a specific sequence number to a follower. |
Snapshots and iterators
Pass a ReadOptions with the snapshot when creating the iterator:
using var snap = db.CreateSnapshot();
var ro = new ReadOptions().SetSnapshot(snap);
using var it = db.NewIterator(readOptions: ro);
for (it.SeekToFirst(); it.Valid(); it.Next())
{
// … sees the database as of `snap`
}
Without an explicit snapshot, an iterator captures one implicitly at construction time — so reads through one iterator are still consistent with themselves.
Lifecycle and storage cost
Internally, a snapshot pins every SST file containing writes newer than the next-deleted obsolete file. While the snapshot is alive, compaction can't drop tombstones or older versions in those files, so disk usage stays elevated.
Snapshots aren't free
A snapshot that sits open for hours can pin gigabytes of obsolete data and inflate rocksdb.estimate-pending-compaction-bytes. Open snapshots short, dispose them as soon as the consistent read is done.
Worked example: consistent multi-key read
public static Dictionary<string, string> SnapshotRead(
RocksDb db,
IEnumerable<string> keys)
{
using var snap = db.CreateSnapshot();
var ro = new ReadOptions().SetSnapshot(snap);
var result = new Dictionary<string, string>();
foreach (var k in keys)
{
var v = db.Get(k, readOptions: ro);
if (v is not null) result[k] = v;
}
return result;
}
Every key in result was observed at the same sequence number, so cross-key invariants hold.
Pairing snapshots with sequence numbers
db.GetLatestSequenceNumber() is the engine's monotonically-increasing write counter. Combined with a snapshot, you can record exactly which state you observed:
ulong seq;
using (var snap = db.CreateSnapshot())
{
seq = db.GetLatestSequenceNumber();
// … do the work …
}
Console.WriteLine($"Backup taken at sequence {seq}");
The Replication guide builds on this: pair a snapshot with GetUpdatesSince(seq) to ship the base state and then stream the diff.