fix: use CRC-32C (Castagnoli) instead of IEEE for WAL (C1)
Per design §3.2 line 359, all WAL CRC computations must use crc32c
(Castagnoli polynomial 0x82F63B78). The previous code used crc32.IEEE
(Ethernet/PNG polynomial 0xEDB88320) in 5 places. While the system was
self-consistent (encode + decode both used IEEE), it diverged from the
design spec and lost SSE4.2 hardware acceleration (the native CRC32
instruction only supports Castagnoli).
Changes:
- wal/crc32c.go (new): package-level crc32cTable = crc32.MakeTable(
crc32.Castagnoli). Central definition prevents future drift.
- wal/header.go: 2 ChecksumIEEE calls replaced with crc32.Checksum(
data, crc32cTable). Comment updated to reference design §3.2 line 341, 359.
- wal/record.go: 2 ChecksumIEEE calls replaced.
- wal/block_writer_test.go: 1 ChecksumIEEE call in test helper replaced.
- wal/crc32c_test.go (new): 4 regression guards:
- TestCRC32CStandardVector: RFC 3720 fixed vector (crc32c("123456789")
= 0xE3069283).
- TestCRC32CEdistinctFromIEEE: confirms IEEE produces different value.
- TestHeaderCRCUsesCastagnoli: direct assertion on stored header CRC
(catches paired encode/decode reversion that round-trip tests miss).
- TestPhysicalRecordCRCUsesCastagnoli: same for physical record CRC.
BREAKING CHANGE: WAL files written before this fix (with IEEE CRC)
cannot be read after this fix (expects crc32c). Phase 1 has not been
released, so no real data migration is needed. Production users
post-release would need to drain + re-create the database.
Developers pulling this change should delete any local Phase-1 WAL
directories (`rm -rf <db-dir>/segment-*.wal`) before running the code;
old IEEE-encoded WALs will fail recovery on local dev machines.
Verified: all existing round-trip tests pass (encode + decode both use
crc32c, still self-consistent). Full suite green including
go test -race ./... .
Audit context: docs/audit-3.2.md C1.
This commit is contained in:
+3
-3
@@ -40,8 +40,8 @@ func EncodeWalHeader(h *WalFileHeader) [walFileHeaderSize]byte {
|
||||
le.PutUint64(buf[12:20], h.SegmentID)
|
||||
le.PutUint64(buf[20:28], h.StartSequence)
|
||||
|
||||
// CRC32 IEEE over bytes 0–27 (excludes the CRC field itself)
|
||||
h.HeaderCRC = crc32.ChecksumIEEE(buf[0:28])
|
||||
// CRC32C over bytes 0–27 (per design §3.2 line 341, 359)
|
||||
h.HeaderCRC = crc32.Checksum(buf[0:28], crc32cTable)
|
||||
le.PutUint32(buf[28:32], h.HeaderCRC)
|
||||
|
||||
return buf
|
||||
@@ -80,7 +80,7 @@ func DecodeWalHeader(data []byte) (*WalFileHeader, error) {
|
||||
}
|
||||
|
||||
// Verify CRC before trusting any other fields
|
||||
gotCRC := crc32.ChecksumIEEE(data[0:28])
|
||||
gotCRC := crc32.Checksum(data[0:28], crc32cTable)
|
||||
storedCRC := le.Uint32(data[28:32])
|
||||
if gotCRC != storedCRC {
|
||||
return nil, errCRCMismatch
|
||||
|
||||
Reference in New Issue
Block a user