docs: RELEASES.md entry for 8.2.3 (transact durability barrier)
This commit is contained in:
parent
3b8fa51161
commit
be5ce0bcc3
1 changed files with 28 additions and 0 deletions
28
RELEASES.md
28
RELEASES.md
|
|
@ -10,6 +10,34 @@ Full auto-generated changelog: `CHANGELOG.md` · Releases: https://github.com/so
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## v8.2.3 — 2026-07-12 (a committed transaction is durable on return)
|
||||||
|
|
||||||
|
Durability fix. A `transact()` reported "committed" while its canonical entity writes were still
|
||||||
|
only in the OS page cache (written via tmp+rename, not yet `fsync`'d), even though the generation
|
||||||
|
counter and manifest WERE fsync'd. A hard kill (power loss, SIGKILL) in that window could leave the
|
||||||
|
durable generation counter **ahead of** the persisted entity bytes — so a consumer resuming from the
|
||||||
|
counter would see "phantom progress": a generation that claims writes the disk never kept. Reported
|
||||||
|
from a downstream migration's crash-lifecycle forensics.
|
||||||
|
|
||||||
|
`commitTransaction` now runs a **durability barrier**: it records every canonical write and delete
|
||||||
|
the batch's operations make, then `fsync`s that entire footprint (file contents, the rename
|
||||||
|
directory entries, and the parent directories of any deletes) **before** advancing the generation
|
||||||
|
counter and manifest. A committed transaction is therefore durable the moment `transact()` returns —
|
||||||
|
the counter can never outrun the entity bytes.
|
||||||
|
|
||||||
|
**Durability contract, now explicit.** `transact()` is durable-on-return (above). A **single-op**
|
||||||
|
write (`add`/`update`/`remove`/`relate`/…) is Model-B group-commit: its live bytes are written but
|
||||||
|
become durable at the next `flush()` or `close()`, not the instant the call resolves — the counter
|
||||||
|
is buffered alongside the data, so a crash loses both together (never a torn counter-ahead-of-state
|
||||||
|
store). Need per-write durability? Use `transact()` (even for one op), or `flush()` after the write.
|
||||||
|
This deliberately trades single-op fsync latency (a 3-5x write regression) for throughput.
|
||||||
|
|
||||||
|
No API change; no accelerator involvement (the barrier is in the filesystem storage adapter). In-memory
|
||||||
|
and durable-per-call (cloud object-PUT) adapters treat the barrier as a no-op. Regression:
|
||||||
|
`tests/integration/transact-durability-barrier.test.ts` proves entity writes fsync in an earlier
|
||||||
|
batch than the manifest, for single-op and multi-op (add+relate) transactions, and that a
|
||||||
|
precommit-rejected batch opens no barrier and advances nothing.
|
||||||
|
|
||||||
## v8.2.2 — 2026-07-11 (P0: a timed-out transaction now rolls back — no torn state)
|
## v8.2.2 — 2026-07-11 (P0: a timed-out transaction now rolls back — no torn state)
|
||||||
|
|
||||||
Data-integrity fix. A transaction that exceeded its time budget **mid-flight** (e.g. a bulk
|
Data-integrity fix. A transaction that exceeded its time budget **mid-flight** (e.g. a bulk
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue