Files
simplexmq/spec/modules/Simplex/Messaging/Server/StoreLog.md
Evgeny @ SimpleX Chat f7be44981a SMP router specs
2026-03-12 18:13:12 +00:00

37 lines
2.6 KiB
Markdown

# Simplex.Messaging.Server.StoreLog
> Append-only log for queue state changes: write, read/replay, compaction, crash recovery, backup retention.
**Source**: [`StoreLog.hs`](../../../../../src/Simplex/Messaging/Server/StoreLog.hs)
## writeStoreLogRecord — atomicity via manual write
See comment in `writeStoreLogRecord`. `hPutStrLn` breaks writes larger than 1024 bytes into multiple system calls on `LineBuffered` handles, which could interleave with concurrent writes. The solution is manual `B.hPut` (single call for the complete record + newline) plus `hFlush`. `E.uninterruptibleMask_` prevents async exceptions between write and flush — ensures a complete record is always written.
## readWriteStoreLog — crash recovery state machine
The `.start` temp backup file provides crash recovery during compaction. The sequence:
1. Read existing log, replay into memory
2. Rename log to `.start` (atomic rename = backup point)
3. Write compacted state to new file
4. Rename `.start` to timestamped backup, remove old backups
If the router crashes during step 3, the next startup detects `.start` and restores from it instead of the incomplete new file. Any partially-written current file is preserved as `.bak`. The comment says "do not terminate" during compaction — there is no safe interrupt point between steps 2 and 4.
## removeStoreLogBackups — layered retention policy
Backup retention is layered: (1) keep all backups newer than 24 hours, (2) of the rest, keep at least 3, (3) of those eligible for deletion, only delete backups older than 21 days. This means a router with infrequent restarts accumulates many backups (only cleaned on startup), while a frequently-restarting router keeps a rolling window. Backup timestamps come from ISO 8601 suffixes parsed from filenames.
## QueueRec StrEncoding — backward-compatible parsing
The `strP` parser handles two field name generations: old format `sndSecure=` (boolean, mapping `True``QMMessaging`, `False``QMContact`) and new format `queue_mode=`. Missing queue mode defaults to `Nothing` with the comment "unknown queue mode, we cannot imply that it is contact address." `EntityActive` status is implicit — not written to the log, and parsed as default when `status=` is absent.
## openReadStoreLog — creates file if missing
`openReadStoreLog` creates an empty file if it doesn't exist. Callers never need to handle "file not found."
## foldLogLines — EOF flag for batching
The `action` callback receives a `Bool` indicating whether the current line is the last one. This allows consumers (like `readQueueStore`) to batch operations and flush only on the final line.