|
|
@@ -14,22 +14,51 @@ package main
|
|
|
// ============================================================================
|
|
|
|
|
|
import (
|
|
|
+ "cmp"
|
|
|
"encoding/binary"
|
|
|
"fmt"
|
|
|
"log"
|
|
|
"os"
|
|
|
"runtime/debug"
|
|
|
- "cmp"
|
|
|
"slices"
|
|
|
"strings"
|
|
|
"sync"
|
|
|
"sync/atomic"
|
|
|
+
|
|
|
+ "git.ycl.pub/yl32940/TsDB2/DB/core"
|
|
|
)
|
|
|
|
|
|
// ---- HeaderPage 额外字段 ----
|
|
|
// v11 起头页重排: FreePageStart(56) 与 FreePageEnd(60) 紧邻, 尾指针不再排在 Comment 之后。
|
|
|
const HDR_FREE_END = 60
|
|
|
|
|
|
+// HDR_CRC HeaderCrc 字段偏移 (84): 整页 XXH32, 覆盖除该字段自身外的 4096 字节。
|
|
|
+// 与 core/header_page.go 的编译期断言互相独立地钉住同一布局 —— 任一侧改了都编译失败。
|
|
|
+const HDR_CRC = 84
|
|
|
+
|
|
|
+// checkHeaderCrc 校验头页整页 XXH32。返回 (结论, 说明):
|
|
|
+// - v11 且 CRC==0: 旧库无校验, ("跳过", "旧 v11 库, 首次写头页自动生成 CRC")
|
|
|
+// - 匹配: ("OK", "整页 XXH32 与 HeaderCrc 一致")
|
|
|
+// - 失配: ("CRC 不符", "期望/实际值 —— 头页写坏或文件非 VRTX")
|
|
|
+//
|
|
|
+// b 必须是完整的头页字节 (>= 4096); 计算在副本上进行, 不改动调用方数据。
|
|
|
+// 算法直接复用 core.XXH32, 与引擎写入侧 (PrepareWrite) 同源, 不存在两套实现漂移。
|
|
|
+func checkHeaderCrc(b []byte, version uint32) (string, string) {
|
|
|
+ stored := le32(b[HDR_CRC : HDR_CRC+4])
|
|
|
+ if version == 11 && stored == 0 {
|
|
|
+ return "跳过", "旧 v11 库 (HeaderCrc=0 为 ExtConfig 预留区), 首次写头页自动生成 CRC"
|
|
|
+ }
|
|
|
+ page := make([]byte, 4096)
|
|
|
+ copy(page, b[:4096])
|
|
|
+ for i := HDR_CRC; i < HDR_CRC+4; i++ {
|
|
|
+ page[i] = 0 // CRC 覆盖范围: 除自身外的整页
|
|
|
+ }
|
|
|
+ if got := core.XXH32(page); got != stored {
|
|
|
+ return "CRC 不符", fmt.Sprintf("HeaderCrc=%08x, 实算=%08x —— 头页损坏或文件非 VRTX", stored, got)
|
|
|
+ }
|
|
|
+ return "OK", "整页 XXH32 与 HeaderCrc 一致"
|
|
|
+}
|
|
|
+
|
|
|
// ---- IndexHead (索引页头) 字段偏移 ----
|
|
|
const (
|
|
|
IX_TYP = 20 // IndexType
|
|
|
@@ -679,6 +708,8 @@ type AuditResult struct {
|
|
|
Reserved int `json:"reserved"` // 页 1: 引擎预留, 从不分配
|
|
|
NeverUsed int `json:"neverUsed"` // 从未分配过的尾页
|
|
|
Free *FreeChainInfo `json:"free"`
|
|
|
+ HeaderCrc string `json:"hdrCrc"` // 头页整页 XXH32 校验结论 (OK/CRC 不符/跳过)
|
|
|
+ HeaderCrcD string `json:"hdrCrcDetail"` // 校验说明 (期望/实算值等)
|
|
|
Tables []TableAudit `json:"tables"`
|
|
|
SumRows uint64 `json:"sumRows"`
|
|
|
SumHeapDecl uint64 `json:"sumHeapDecl"`
|
|
|
@@ -735,6 +766,8 @@ func runAuditStructural() (*AuditResult, *walker, map[uint32]bool, []TInfo, bool
|
|
|
}
|
|
|
R.TotalPages = totalPages()
|
|
|
R.Free = rFreeChain()
|
|
|
+ // 头页整页 XXH32 校验 (core.PrepareWrite 写入侧的同源复核)
|
|
|
+ R.HeaderCrc, R.HeaderCrcD = checkHeaderCrc(hdr[:], le32(hdr[4:8]))
|
|
|
freeSet := make(map[uint32]bool, R.Free.Total)
|
|
|
for _, p := range R.Free.Pages {
|
|
|
freeSet[p] = true
|