Use this page when you want to enable VersionLog and call history, point-in-time read, or rollback APIs. For storage layout, recovery, sidecars, retention, and operational limits, see VersionLog Architecture and VersionLog Operations.
Enable History
Section titled “Enable History”Version history is disabled by default. Enable it before opening the engine.
akkaradb::engine::AkkEngineOptions opts;opts.paths.dataDir = "data/history";opts.components.versionLogEnabled = true;opts.vlog.syncMode = akkaradb::engine::vlog::VLogSyncMode::BATCHED_SYNC;
auto db = akkaradb::engine::AkkEngine::open(std::move(opts));When paths.dataDir is set, paths.versionLogPath is derived as <dataDir>/history.akvlog. If you set opts.vlog.logPath directly, it overrides the derived path.
Choose Durability
Section titled “Choose Durability”VersionLog and WAL are separate components. A durable latest-value path does not automatically mean every history entry has crossed a VersionLog sync boundary.
| Mode | Behavior | Typical use |
|---|---|---|
SYNC | Writes and durability-syncs each VersionLog entry before returning. | Strongest history durability, lower write throughput. |
ASYNC | Updates the readable history immediately and flushes the file through a background worker. | Higher throughput when a small history durability window is acceptable. |
BATCHED_SYNC | Uses the background worker, then durability-syncs grouped batches. | Balanced mode for durable history without one sync per write. |
groupN, groupMicros, and groupBytes control async and batched flush grouping. asyncMaxPendingBytes limits queued history bytes and can apply backpressure to writers.
Use AkkEngine::forceSync() at application checkpoint boundaries when recent history must cross the durable boundary before continuing.
Optional Compression
Section titled “Optional Compression”VersionLog compression is opt-in.
opts.vlog.codec = akkaradb::engine::vlog::VLogCodec::ZSTD;opts.vlog.zstdCompressionLevel = 1;Compressed records retain their original value size internally and are decompressed before VersionEntry values are returned. A record is stored compressed only when the compressed payload plus its size prefix is smaller than the raw value.
Segmentation And Retention
Section titled “Segmentation And Retention”By default, VersionLog uses segmented storage with segmentBytes = 64 MiB. Set retention boundaries when old history should be pruned from closed segments.
opts.vlog.segmentBytes = 64ULL * 1024ULL * 1024ULL;opts.vlog.retentionDays = 30;opts.vlog.retentionMinCommitSeq = 0;retentionDays and retentionMinCommitSeq are ORed. A closed segment is eligible when either boundary matches. Before deletion, VersionLog writes synthetic retention-base entries for keys whose boundary state would otherwise disappear, so retained history still has a usable starting point.
Queries before the retained base boundary are unavailable. history() may return a synthetic first entry marked with VLOG_FLAG_RETENTION_BASE.
Parallel Write Admission
Section titled “Parallel Write Admission”For write-heavy local workloads, PARALLEL admission can persist VersionLog records through independent lane workers.
opts.vlog.syncMode = akkaradb::engine::vlog::VLogSyncMode::ASYNC;opts.vlog.writeAdmission = akkaradb::engine::vlog::VLogWriteAdmissionMode::PARALLEL;opts.vlog.parallelWriteLanes = 4;opts.vlog.parallelPendingLimitScope = akkaradb::engine::vlog::VLogParallelPendingLimitScope::GLOBAL;PARALLEL requires syncMode = ASYNC. Writes for the same key remain ordered by stable key fingerprint lane selection. GLOBAL applies asyncMaxPendingBytes once across all lanes; PER_LANE applies it independently per lane.
Read Key History
Section titled “Read Key History”Every successful write appends a VersionEntry for the key.
db->put(bytes("profile:1"), bytes("v1"));db->put(bytes("profile:1"), bytes("v2"));db->remove(bytes("profile:1"));
auto history = db->history(bytes("profile:1"));for (const auto& entry : history) { const uint64_t seq = entry.seq; const uint64_t sourceNodeId = entry.sourceNodeId; const uint64_t timestampNs = entry.timestampNs; const uint8_t flags = entry.flags;}history(key) returns entries ordered by sequence number. If VersionLog is disabled or the key has no history, it returns an empty vector.
Interpret Version Entries
Section titled “Interpret Version Entries”| Field | Meaning |
|---|---|
seq | Monotonic engine sequence number for the mutation. Use this as the input to getAt() or rollback APIs. |
sourceNodeId | Origin of the mutation. Local writes use the local source, replica-applied writes carry the source node, and rollback writes use ROLLBACK_NODE. |
timestampNs | Append timestamp recorded by the engine. Useful for diagnostics; not the ordering key. |
flags | Storage flags. Rollback and retention-base entries are marked here. |
value | Public value bytes. Compressed VersionLog records are decompressed before exposure. |
Treat seq as the stable history cursor. Wall-clock time is metadata; it is not used to resolve getAt().
Read At A Sequence
Section titled “Read At A Sequence”getAt(key, seq) returns the latest historical value whose sequence is less than or equal to seq.
db->put(bytes("profile:1"), bytes("v1"));auto h1 = db->history(bytes("profile:1"));
db->put(bytes("profile:1"), bytes("v2"));
auto previous = db->getAt(bytes("profile:1"), h1.front().seq);if (previous) { // previous == "v1"}If the matching historical entry is a tombstone, getAt() returns std::nullopt. If VersionLog is disabled, it also returns std::nullopt.
API Semantics
Section titled “API Semantics”| API | VersionLog disabled | Missing key or no visible value | Closed engine |
|---|---|---|---|
history(key) | Empty vector | Empty vector | Throws |
getAt(key, seq) | std::nullopt | std::nullopt | Throws |
rollbackKey(key, seq) | Throws | Writes a tombstone if no older value exists | Throws |
rollbackTo(seq) | Throws | Skips keys already at or before the target | Throws |
The rollback APIs are write APIs. They reserve new sequence numbers, append WAL and VersionLog records when enabled, update MemTable, and ship through Cluster when replication is enabled.
Roll Back One Key
Section titled “Roll Back One Key”rollbackKey(key, targetSeq) writes a new record that restores the key to its state at targetSeq.
auto history = db->history(bytes("profile:1"));if (!history.empty()) { db->rollbackKey(bytes("profile:1"), history.front().seq);}Rollback is not an in-place rewrite of the history file. It appends a new engine mutation, marks the VersionLog entry with the rollback flag, and preserves the previous history.
Roll Back All Changed Keys
Section titled “Roll Back All Changed Keys”rollbackTo(targetSeq) scans VersionLog history and restores every key whose latest known version is newer than targetSeq.
db->rollbackTo(checkpointSeq);Use this carefully. It creates new writes for all affected keys, and in cluster mode those rollback writes are shipped through the replication runtime.
Sync And Close
Section titled “Sync And Close”AkkEngine::forceSync() syncs both WAL and VersionLog when they are enabled.
db->forceSync();db->close();close() stops VersionLog workers, flushes files, writes derived sidecars where applicable, and surfaces any async write error that occurred earlier.