Page Checksums & Seqlock Snapshots
CRC32C torn-page detection on every page, paired with a lock-free seqlock so checkpoints snapshot live pages without blocking writers.
Status: โ Implemented ยท Visibility: Public ยท Level: ๐ฃ Advanced ยท Category: Durability
๐ฏ What it solves
An 8 KB page can be physically torn by a power loss mid-write (consumer NVMe write-atomicity unit is typically smaller than 8 KB), or silently bit-rot on the storage medium. Without a checksum, that corruption is invisible until the bad bytes are interpreted as live data. Separately, the checkpoint needs to copy a page's bytes to disk while application transactions may be actively writing that same page โ a snapshot taken mid-write would itself encode torn data with a checksum that looks valid. Typhon needs both corruption detection and a copy mechanism that is provably consistent, without making writers wait on the checkpoint.
โ๏ธ How it works (in brief)
Every page carries a CRC32C checksum (hardware-accelerated via the SSE4.2/ARMv8 CRC32 instruction) covering its contents. The checksum is recomputed whenever a page is written and verified whenever a page is read, depending on the configured mode. To let the checkpoint copy a page without locking it against writers, each page also carries a seqlock counter: a writer bumps it to odd before mutating the page and back to even after, under the page's exclusive latch. The checkpoint reads the counter, copies the page, then re-reads the counter โ if it changed or was caught odd, the copy is discarded and retried (or the page is skipped for that cycle). A torn-page failure is never silently repaired in place: on-load mismatches throw, and a torn page reachable only through crash recovery is healed or fails the open loudly โ see the Crash Recovery and Checkpoint entries.
๐ป Usage
CRC verification is on by default and requires no code changes. The only knob is when it runs:
services.AddScopedDatabaseEngine(o =>
{
// Default: verify CRC on every page load โ catches corruption at first access.
o.Resources.PageChecksumVerification = PageChecksumVerification.OnLoad;
// Lower overhead: skip on-load checks, verify only during crash recovery.
// o.Resources.PageChecksumVerification = PageChecksumVerification.RecoveryOnly;
});
A mismatch under OnLoad surfaces as a normal exception you can catch at the call site that touched the page:
try
{
using var tx = uow.CreateTransaction();
var view = tx.Open(soldier);
_ = view.Read(Unit.Health);
}
catch (PageCorruptionException ex)
{
// ex.PageIndex, ex.ExpectedCrc, ex.ComputedCrc โ log and escalate (restore from backup).
}
| Option | Default | Effect |
|---|---|---|
PageChecksumVerification.OnLoad |
default | Verify CRC on every page load from disk; throws PageCorruptionException on mismatch. |
PageChecksumVerification.RecoveryOnly |
opt-in | Skip CRC checks during normal operation; verify only while replaying crash recovery. |
โ ๏ธ Guarantees & limits
- Detection, not repair โ a CRC mismatch under
OnLoadis reported, never silently patched; there is no in-place page repair (the old Full-Page-Image mechanism was retired โ see ADR for the rationale). Recovery from a confirmed bad page means restoring from backup or letting crash recovery rebuild what it can. - Whole-page coverage โ the checksum covers the entire page except the 4-byte checksum field itself; any single- or multi-bit corruption in the page is detected.
- Non-blocking checkpoint snapshots โ the seqlock lets the checkpoint copy a page that is concurrently being written without taking a lock writers must wait on; a page with a writer in flight for an unreasonably long time is skipped for that checkpoint cycle rather than stalling it.
- Hardware-accelerated โ CRC32C uses the CPU's native CRC32 instruction; cost is roughly constant per 8 KB page and negligible next to the I/O it accompanies.
RecoveryOnlytrades safety for overhead โ normal reads skip verification entirely, so a torn page introduced outside the recovery window can go undetected until it's next touched during a future recovery pass.- Same mechanism backs WAL records โ WAL record framing uses the same CRC32C algorithm, so a single, consistently-tested corruption-detection primitive covers both pages and the log.
๐งช Tests
- PageCrcVerificationTests โ lazy CRC verification on page load (
OnLoadmode), mismatch throwsPageCorruptionException - SeqlockProtocolTests โ modification-counter seqlock protocol, checkpoint CRC stamping, concurrent snapshot consistency
- Crc32CUtilTests โ the CRC32C algorithm itself against known test vectors
๐ Related
- Sibling: Page Integrity โ CRC32C, Seqlock Snapshots & A/B Page Pairing โ storage-layer description of this same CRC32C + seqlock mechanism
- Sibling: Checkpoint v2 (SnapshotStore pipeline) โ checkpoint is the primary consumer of the seqlock snapshot copy