| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071 |
- package page
- import (
- "encoding/binary"
- "unsafe"
- )
- // =============================================================================
- // DataPageHdr —— 数据页头: 公共页头 + 行计数 + pkID 极值 + 存活/失效统计。
- //
- // 磁盘布局 (48B):
- //
- // off 0 PageHdr 20B 公共页头
- // off 20 Count 4B 行数 (本机字节序, 含墓碑)
- // off 24 Min 8B 页内最小 pkID ★BigEndian 编码★
- // off 32 Max 8B 页内最大 pkID ★BigEndian 编码★
- // off 40 LiveCnt 4B 未删除行数 (本机字节序)
- // off 44 Dead 4B 失效字节数 = Σ(4B前缀 + 墓碑行) (本机字节序)
- //
- // 行数据区紧接在偏移 48 之后, 每行 [len(4B)][rowData...], len 的最高位是软删除标志。
- //
- // ⚠️ Min/Max 刻意按 BigEndian 存放 (pkID 本身也按 BE 比较), 所以这里声明成
- // [8]byte 而不是 uint64 —— 若声明成 uint64, unsafe 映射在小端机上会读到字节反转
- // 的值。读写必须走 GetMin/SetMin/GetMax/SetMax。
- //
- // LiveCnt/Dead 由所有写路径增量维护 (追加/软删/整理页/页内重建/WAL 行级恢复),
- // Load 直接读走 —— 无条件 COUNT(*) 从"逐行走链"降到 O(1) 读页头, MaybeCompact
- // 的失效占比判断也不再要求 Load 时全页重算。
- //
- // 这份布局原先在 wal.go(dpHdrSize/dpCountOffset/dpUseSizeOffset)、transaction.go、
- // index/datapage 三处各写一遍, 现在只有这里一处定义。
- // =============================================================================
- type DataPageHdr struct {
- PageHdr
- Count uint32 // off 20 行数 (含墓碑)
- Min [8]byte // off 24 最小 pkID (BigEndian)
- Max [8]byte // off 32 最大 pkID (BigEndian)
- LiveCnt uint32 // off 40 未删除行数
- Dead uint32 // off 44 失效字节数
- }
- // DataPageHdrSize 数据页头长度; 行数据区从该偏移开始
- const DataPageHdrSize = uint32(unsafe.Sizeof(DataPageHdr{})) // 48
- // 编译期布局断言
- var (
- _ [48]byte = [unsafe.Sizeof(DataPageHdr{})]byte{} // 头必须 48 字节
- _ [20]byte = [unsafe.Offsetof(DataPageHdr{}.Count)]byte{} // Count 必须偏移 20
- _ [24]byte = [unsafe.Offsetof(DataPageHdr{}.Min)]byte{} // Min 必须偏移 24
- _ [32]byte = [unsafe.Offsetof(DataPageHdr{}.Max)]byte{} // Max 必须偏移 32
- _ [40]byte = [unsafe.Offsetof(DataPageHdr{}.LiveCnt)]byte{} // LiveCnt 必须偏移 40
- _ [44]byte = [unsafe.Offsetof(DataPageHdr{}.Dead)]byte{} // Dead 必须偏移 44
- )
- // DataHdrOf 把页缓冲区按 DataPageHdr 解析 (页头固定在偏移 0)。
- func DataHdrOf(buf []byte) *DataPageHdr {
- return (*DataPageHdr)(unsafe.Pointer(&buf[0]))
- }
- // GetMin 读页内最小 pkID。
- func (h *DataPageHdr) GetMin() uint64 { return binary.BigEndian.Uint64(h.Min[:]) }
- // SetMin 写页内最小 pkID。
- func (h *DataPageHdr) SetMin(v uint64) { binary.BigEndian.PutUint64(h.Min[:], v) }
- // GetMax 读页内最大 pkID。
- func (h *DataPageHdr) GetMax() uint64 { return binary.BigEndian.Uint64(h.Max[:]) }
- // SetMax 写页内最大 pkID。
- func (h *DataPageHdr) SetMax(v uint64) { binary.BigEndian.PutUint64(h.Max[:], v) }
|