| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 |
- package page
- import "unsafe"
- // =============================================================================
- // WALPageHdr —— WAL 页头, 首页与续页共用同一布局。
- //
- // 磁盘布局 (40B):
- //
- // off 0 PageHdr 20B 公共页头
- // off 20 _ 4B 对齐填充: TxnID 需 8 字节对齐
- // off 24 TxnID 8B 事务 ID (仅首页有效, 续页为 0)
- // off 32 TotalEntries 4B 本事务条目总数 (仅首页有效)
- // off 36 State 1B WAL 状态 (仅首页有效)
- // off 37 _ 1B 对齐填充: EntryCount 需 2 字节对齐
- // off 38 EntryCount 2B 本页条目数
- //
- // 合并前首页 35B / 续页 22B, 二者 EntryCount 落在不同偏移 (33/20), 于是读写到处
- // 都要带 isFirst 分支, 并派生出一整组手工偏移常量。这里让续页也保留 TxnID/
- // TotalEntries/State 三个字段 (填 0), 头部等长 40B —— 换来整条链可以用同一个
- // 结构体解析。代价是续页每页多花 18B, 占 16KB 的 0.11%。
- //
- // WAL 条目 (变长, 紧跟在页头之后) 不在此结构体内, 因为它以 13B 为步长紧密排列,
- // 而任何包含它的 struct 都会被编译器对齐到 16B (见 WALEntryMeta 注释)。
- // =============================================================================
- type WALPageHdr struct {
- PageHdr
- _ [4]byte // off 20 对齐填充 (勿删: TxnID 需 8 字节对齐)
- TxnID uint64 // off 24 事务 ID (仅首页)
- TotalEntries uint32 // off 32 条目总数 (仅首页)
- State byte // off 36 WAL 状态 (仅首页)
- _ [1]byte // off 37 对齐填充 (勿删: EntryCount 需 2 字节对齐)
- EntryCount uint16 // off 38 本页条目数
- }
- // WALPageHdrSize WAL 页头长度; 条目区从该偏移开始
- const WALPageHdrSize = uint32(unsafe.Sizeof(WALPageHdr{})) // 40
- // WALEntryMeta WAL 条目元数据长度: TargetPageID(4) + DataLen(4) + Checksum(4) + OpType(1)。
- //
- // ⚠️ 条目在页内以 13B 为步长紧密排列, 所以不能用 struct 的 unsafe.Sizeof 来定位
- // 下一条 —— 任何含 uint32 的 struct 都会被对齐到 16B, 每条的步长会凭空多出 3B。
- // 条目字段的读写请继续用 binary.LittleEndian 手工编解码。
- const WALEntryMeta = 4 + 4 + 4 + 1 // 13
- // 编译期布局断言
- var (
- _ [40]byte = [unsafe.Sizeof(WALPageHdr{})]byte{} // 页头必须 40 字节
- _ [24]byte = [unsafe.Offsetof(WALPageHdr{}.TxnID)]byte{} // TxnID 必须偏移 24
- _ [32]byte = [unsafe.Offsetof(WALPageHdr{}.TotalEntries)]byte{} // TotalEntries 必须偏移 32
- _ [36]byte = [unsafe.Offsetof(WALPageHdr{}.State)]byte{} // State 必须偏移 36
- _ [38]byte = [unsafe.Offsetof(WALPageHdr{}.EntryCount)]byte{} // EntryCount 必须偏移 38
- _ [13]byte = [WALEntryMeta]byte{} // 条目元数据必须 13 字节
- )
- // WalHdrOf 把页缓冲区按 WALPageHdr 解析 (页头固定在偏移 0)。
- func WalHdrOf(buf []byte) *WALPageHdr {
- return (*WALPageHdr)(unsafe.Pointer(&buf[0]))
- }
- // Init 把一个 WAL 页初始化为空页: 类型 WALIndex, 清空首页元数据, UseSize 指向页头之后。
- func (h *WALPageHdr) Init(pageID, prevPageID uint32) {
- h.Type = WALIndex
- h.Flags = 0
- h.RefCount = 0
- h.PageID = pageID
- h.PrePage = prevPageID
- h.NextPage = 0
- h.UseSize = WALPageHdrSize
- h.TxnID = 0
- h.TotalEntries = 0
- h.State = 0
- h.EntryCount = 0
- }
|