// 一次性探针:把一份 .fwss 与 PG 里的 fog_blocks 逐块比对,量化「叠加 / 替换」两种模式的影响。 package main import ( "database/sql" "encoding/hex" "fmt" "os" "strconv" "strings" _ "github.com/jackc/pgx/v5/stdlib" "rond-with-you/internal/fog" ) func main() { if len(os.Args) < 3 { fmt.Println("用法: fogprobe [userID]") os.Exit(2) } uid := int64(1) if len(os.Args) > 3 { uid, _ = strconv.ParseInt(os.Args[3], 10, 64) } data, err := os.ReadFile(os.Args[1]) must(err) inc, incCells, err := fog.Decode(data) must(err) fmt.Printf("快照 %s: %d 块 / %d 格\n", os.Args[1], len(inc), incCells) pg, err := sql.Open("pgx", os.Args[2]) must(err) defer pg.Close() rows, err := pg.Query(`SELECT gbx, gby, bitmap FROM fog_blocks WHERE user_id=$1`, uid) must(err) local := map[[2]int][]byte{} localCells := 0 for rows.Next() { var gx, gy int var bm []byte must(rows.Scan(&gx, &gy, &bm)) local[[2]int{gx, gy}] = bm localCells += popcount(bm) } rows.Close() fmt.Printf("库内: %d 块 / %d 格\n", len(local), localCells) var newBlocks, newCells int var novBlock, overlap int var overlapGain int for _, b := range inc { k := [2]int{b.GX, b.GY} old, ok := local[k] if !ok { newBlocks++ newCells += popcount(b.Bitmap) continue } novBlock++ gain := 0 for i := range b.Bitmap { gain += poptab[b.Bitmap[i]&^old[i]] } if gain > 0 { overlap++ overlapGain += gain } } var lostBlocks, lostCells, lostFull int for k, bm := range local { found := false for _, b := range inc { if b.GX == k[0] && b.GY == k[1] { found = true break } } if !found { lostBlocks++ lostCells += popcount(bm) lostFull++ } } fmt.Printf("\n【叠加合并 overlay】\n") fmt.Printf(" 新增整块: %d 块(+%d 格)\n", newBlocks, newCells) fmt.Printf(" 与已有块重叠: %d 块,其中 %d 块含新格(+%d 格)\n", novBlock, overlap, overlapGain) fmt.Printf(" 合计新增格: %d,合并后总量: %d 块 / %d 格\n", newCells+overlapGain, len(local)+newBlocks, localCells+newCells+overlapGain) fmt.Printf("\n【整体替换 cover】\n") fmt.Printf(" 库里现有 %d 块会被丢弃(快照里完全没有这些块),损失 %d 格\n", lostFull, lostCells) fmt.Printf(" 替换后总量: %d 块 / %d 格\n", len(inc), incCells) fmt.Printf(" 净变化: %+d 块 / %+d 格\n", len(inc)-len(local), incCells-localCells) fmt.Printf("\n【其它图层】\n") layers, err := fog.RawLayers(data) if err == nil { for k, v := range layers { fmt.Printf(" %s (%d 字节, %s)\n", k, len(v), hex.EncodeToString(v[:min(8, len(v))])) } } } func min(a, b int) int { if a < b { return a } return b } var poptab = func() [256]int { var t [256]int for i := range t { t[i] = strings.Count(strconv.FormatUint(uint64(i), 2), "1") } return t }() func popcount(b []byte) int { n := 0 for _, v := range b { n += poptab[v] } return n } func must(err error) { if err != nil { fmt.Fprintln(os.Stderr, "错误:", err) os.Exit(1) } }