Expand description
On-disk layout of the double-write buffer file.
offset 0 one aligned block: file header
[magic:4][count:4][write_pos:4][zero padding to DWB_HEADER_STRIDE]
offset DWB_HEADER_STRIDE + i * DWB_SLOT_STRIDE slot i
[slot_magic:4][seq:8][total_size:4][prefix_crc:4][record header][payload]§Slot sequence numbers
The ring is fixed-size, so one LSN can legitimately occupy two slots: a
crash between the DWB fsync and the WAL fsync leaves an LSN durable in the
DWB but absent from the WAL, recovery resumes at that LSN, and the next
record written under it lands in a different slot. Both copies pass CRC, so
nothing in the record itself says which one the WAL actually committed.
seq breaks that tie: it increases with every slot write, so the highest
seq is always the copy written last. Without it, recovery can hand back a
payload that was never acknowledged to any client.
§Format change
Slots begin with slot_magic, not a bare [total_size:4]. Its value is
far outside the range a total_size could ever hold, so a slot written
by an older build that used the bare format fails the prefix check and
is treated as unusable rather than being misread as a sequence-numbered
slot. A DWB only ever holds records from the tail of the log — the worst
case is that torn-write recovery falls back to “no copy available” for
records written before the upgrade.
Functions§
- slot_
record_ max - Largest record — WAL header plus payload — the buffer can mirror. Records above this size are appended to the WAL without torn-write protection.
- slot_
stride - Slot stride in bytes. Exposed for tests and for callers that want to size DWB files ahead of time.