Snapshots
Snapshots store a complete serialized copy of a room's authoritative state at a known event position.
They allow recovery to begin from a recent state instead of replaying the complete event stream.
events
1 2 3 4 5
|
v
snapshotThe event stream remains authoritative. A snapshot is a recovery checkpoint.
Create a snapshot
A room can create a snapshot explicitly:
auto snapshot = room->snapshot();By default, this forces snapshot creation.
The room must have a configured SnapshotStore.
Snapshot contents
A RoomSnapshot contains:
- room ID
- room version
- last event ID
- serialized room state
- schema version
- creation time
- optional checksum
- metadata
For example:
auto snapshot = room->snapshot();
if (snapshot)
{
auto version =
snapshot->room_version();
auto eventId =
snapshot->last_event_id();
}The snapshot state is available with:
snapshot->state();Room version and event position
A snapshot records both:
RoomVersion
logical state version
EventId
last persisted event included in the snapshotFor example:
RoomVersion = 5
EventId = 5These positions tell recovery where the serialized state ends and where event replay should continue.
Schema version
A snapshot also records the room state's schema version:
auto schema =
snapshot->schema_version();The runtime obtains this value from:
state.schema_version();Schema version 0 is invalid.
The schema version allows RoomState::restore() to determine whether it can understand the stored state.
Automatic snapshots
Realtime can create snapshots automatically as the room processes events.
The interval is configured with:
config.snapshotEveryEvents = 100;With this configuration, a snapshot becomes eligible after 100 new persisted events since the previous snapshot.
For example:
snapshot at event 100
|
+---- 100 new events
|
snapshot at event 200Disable periodic snapshots
Set the interval to zero:
config.snapshotEveryEvents = 0;This disables periodic snapshot creation.
Explicit snapshots and snapshots created during room closing can still be used.
Snapshot on room close
By default:
config.snapshotOnRoomClose = true;When a room closes successfully, Realtime can save a final snapshot if the authoritative state has advanced since the latest snapshot.
Disable this behavior with:
config.snapshotOnRoomClose = false;Snapshot retention
The number of recent snapshots retained for each room is configured with:
config.snapshotsToKeep = 3;After a room saves a snapshot, older snapshots are pruned according to this value.
For example:
stored snapshots
version 10
version 20
version 30
version 40With:
config.snapshotsToKeep = 3;the oldest snapshot is removed:
version 20
version 30
version 40snapshotsToKeep must be greater than zero.
Create a snapshot only when needed
Room::snapshot() also accepts a force argument.
auto snapshot =
room->snapshot(false);When force is false, the normal snapshot policy decides whether a new snapshot is needed.
If no snapshot is required, the method returns no value.
The default call:
room->snapshot();uses force = true.
Snapshot store
Snapshots are persisted through the SnapshotStore interface.
SnapshotStore
|
+---- MemorySnapshotStore
|
+---- PostgresSnapshotStoreThe configured store is available through:
auto store =
server.manager()->snapshot_store();A snapshot store is optional.
If no snapshot store is configured, normal room operation and event persistence can still work.
Calling a forced snapshot without a configured store fails with ErrorCode::MissingDependency.
MemorySnapshotStore
The default runtime uses:
vix::realtime::MemorySnapshotStoreIt stores snapshots in process memory.
It is suitable for:
- tests
- examples
- development
- applications that do not require snapshots to survive process restart
For durable snapshots, Realtime also provides PostgresSnapshotStore.
See PostgreSQL for PostgreSQL persistence.
Save a snapshot directly
A snapshot store can be used directly:
vix::realtime::MemorySnapshotStore store;
vix::realtime::RoomSnapshot snapshot{
roomId,
roomVersion,
eventId,
state,
1};
store.save(std::move(snapshot));Normal applications usually let Room create and save snapshots so the room position and serialized state remain coordinated.
Load the latest snapshot
Use:
auto snapshot =
store.load_latest(roomId);If no snapshot exists:
snapshot.has_value(); // falseThe latest snapshot is normally the starting point for room restoration.
Load a historical snapshot
Load the newest snapshot at or before a specific room version:
auto snapshot =
store.load_at_or_before(
roomId,
vix::realtime::RoomVersion{20});For these stored snapshots:
version 10
version 20
version 30requesting version 25 returns:
version 20This operation is useful when recovery must not move beyond a specific room position.
Load recent snapshots
Use:
auto snapshots =
store.load_recent(
roomId,
3);Snapshots are returned from newest to oldest.
version 30
version 20
version 10A limit of zero returns an empty list.
Count snapshots
Get the number of snapshots stored for a room:
auto count =
store.count(roomId);An unknown room returns 0.
Prune snapshots
Keep only the newest snapshots with:
auto removed =
store.prune(
roomId,
3);A keep count of zero removes every snapshot for that room:
store.prune(
roomId,
0);The normal room snapshot workflow performs retention automatically using config.snapshotsToKeep.
Clear snapshots
Remove all snapshots belonging to one room:
store.clear_room(roomId);This is an explicit deletion operation.
Normal room closing and server shutdown do not automatically delete stored snapshots.
Room recovery
When restoration is enabled, a room first attempts to load a usable snapshot.
open room
|
v
load snapshot
|
v
RoomState::restore()
|
v
load later events
|
v
RoomState::apply()
|
v
current stateSuppose the event stream contains:
1 2 3 4 5 6and the snapshot contains state through event 4.
Recovery only needs:
snapshot at 4
|
+---- event 5
+---- event 6instead of replaying all six events.
Snapshots do not replace events
A snapshot is not a replacement for the event stream.
The relationship is:
EventStore
authoritative history
SnapshotStore
recovery checkpointAfter restoring a snapshot, Realtime still loads and applies events that occurred after its last_event_id().
Automatic snapshot failures
Periodic snapshots are attempted after authoritative event processing.
If an automatic snapshot fails after the event has already been persisted and applied, the committed command remains successful.
event persisted
|
v
state applied
|
v
automatic snapshot fails
|
v
event remains authoritativeThe runtime does not undo an already committed state transition because an automatic snapshot could not be saved.
Close snapshot failures
A snapshot created as part of room closing is different.
If the configured close snapshot operation fails, closing fails and the room enters its failure path.
This makes failures during an explicit room lifecycle operation visible instead of silently reporting a successful close.
Snapshot consistency
A valid snapshot must describe a consistent room position.
For example, an initial room state cannot reference a persisted event:
RoomVersion = 0
EventId = 5
invalidLikewise, a versioned snapshot must reference an event position:
RoomVersion = 5
EventId = 0
invalidThe snapshot store also prevents newer snapshots from moving backward relative to already stored snapshots.
Main model
The snapshot workflow is:
RoomState
|
v
serialize()
|
v
RoomSnapshot
|
v
SnapshotStoreRecovery reverses that process:
SnapshotStore
|
v
RoomSnapshot
|
v
RoomState::restore()
|
v
later events
|
v
current RoomStateSnapshots reduce recovery work while the persisted event stream remains the authoritative history.
Continue with Replay and Recovery for how snapshots and events are combined to reconstruct room state.