Add TMessageBase.Sync for crash-safe per-message acknowledgement
NR caught a real durability gap during migration prep: the sequence base.WriteMessage(msg); source.MarkSent(srcMsg); looks atomic, but the OS write buffer hasn't necessarily reached the platter when MarkSent runs. Crash in that window = silent message drop. Add `Sync` virtual on TMessageBase (default no-op for read-only and in-memory backends). Six writable backends override and flush every open stream they own via SysUtils.FileFlush (fpfsync on Unix, FlushFileBuffers on Windows): JAM .JHR / .JDT / .JDX / .JLR Squish .SQD / .SQI / .SQL Hudson msginfo / msgidx / msghdr / msgtxt / msgtoidx / LASTREAD.BBS PCBoard MSGS file + index EzyCom header + text GoldBase msginfo / msgidx / msghdr / msgtxt / msgtoidx / LASTREAD.DAT MSG inherits no-op (per-write open/close — buffer flushes on close, but dir entry isn't fsynced; future enhancement). Wildcat inherits no-op (legacy `file` IO, not TFileStream). Helper for backend authors: TMessageBase.FlushStream(S: TStream) class method that handles the TFileStream cast + nil-safety. `Sync` raises after Close (data is finalized; nothing to flush). Test: TestSyncWriteable in test_consumer_round1 -- writes a message via JAM and Squish, calls Sync (no raise), Close, calls Sync again (raise expected). docs/API.md: new "Sync (durability)" section explaining the commit-after-fsync pattern with the canonical example. Symmetric to fpc-ftn-transport TPktWriter.Sync (commit ee8c6ad) that NR's review prompted on the transport side. Suite: 48/48 (added TestSyncWriteable to test_consumer_round1).
This commit is contained in:
29
docs/API.md
29
docs/API.md
@@ -214,6 +214,35 @@ Common keys — see [`docs/attributes-registry.md`](attributes-registry.md):
|
||||
| `intl` / `fmpt` / `topt` | string | FSC-4008 cross-zone routing |
|
||||
| `kludge.<name>` | string | unknown FTSC kludge passthrough |
|
||||
|
||||
### Sync (durability)
|
||||
|
||||
`TMessageBase.Sync` forces every open writer stream to durable
|
||||
storage (`fpfsync` on Unix, `FlushFileBuffers` on Windows).
|
||||
Override default no-op for read-only / in-memory backends; six of
|
||||
the nine backends (JAM, Squish, Hudson, PCBoard, EzyCom, GoldBase)
|
||||
flush every open stream they own. MSG inherits no-op (each
|
||||
WriteMessage opens / closes its own .msg file — the OS write
|
||||
buffer is flushed but not fsynced; Sync would have to fsync the
|
||||
directory entry which is a future enhancement). Wildcat inherits
|
||||
no-op (legacy `file` IO, not TFileStream).
|
||||
|
||||
Tossers needing crash-safe per-message acknowledgement use the
|
||||
commit-after-fsync pattern:
|
||||
|
||||
```pascal
|
||||
base.WriteMessage(msg);
|
||||
base.Sync; { msg on platter }
|
||||
source.MarkSent(srcMsg); { commit the source pointer }
|
||||
```
|
||||
|
||||
Without Sync, a crash after MarkSent but before the OS flushes
|
||||
the write buffer = silent message drop. Same durability problem
|
||||
fpc-ftn-transport's `TPktWriter.Sync` solves on the transport
|
||||
side; the symmetric surface is here for tossers writing to
|
||||
message bases.
|
||||
|
||||
`Sync` raises after `Close` (data is finalized; nothing to flush).
|
||||
|
||||
### Capabilities API
|
||||
|
||||
Each backend declares the canonical list of attribute keys it
|
||||
|
||||
Reference in New Issue
Block a user