// Copyright (C) 2022 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later package rebuildmappings import ( "context" "strings" "github.com/datawire/dlib/dlog" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfssum" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsinspect" "git.lukeshu.com/btrfs-progs-ng/lib/maps" ) func MapLogicalSums(ctx context.Context, scanResults btrfsinspect.ScanDevicesResult) btrfssum.SumRunWithGaps[btrfsvol.LogicalAddr] { dlog.Info(ctx, "Mapping the logical address space...") type record struct { Gen btrfs.Generation Sum btrfssum.ShortSum } addrspace := make(map[btrfsvol.LogicalAddr]record) var sumSize int for _, devResults := range scanResults { sumSize = devResults.Checksums.ChecksumSize for _, sumItem := range devResults.FoundExtentCSums { _ = sumItem.Sums.Walk(ctx, func(pos btrfsvol.LogicalAddr, sum btrfssum.ShortSum) error { new := record{ Gen: sumItem.Generation, Sum: sum, } if old, ok := addrspace[pos]; ok { switch { case old.Gen > new.Gen: // do nothing case old.Gen < new.Gen: addrspace[pos] = new case old.Gen == new.Gen: if old != new { dlog.Errorf(ctx, "mismatch of laddr=%v sum: %v != %v", pos, old, new) } } } else { addrspace[pos] = new } return nil }) } } dlog.Info(ctx, "... done mapping") var flattened btrfssum.SumRunWithGaps[btrfsvol.LogicalAddr] if len(addrspace) == 0 { return flattened } dlog.Info(ctx, "Flattening the map ...") var curAddr btrfsvol.LogicalAddr var curSums strings.Builder for _, laddr := range maps.SortedKeys(addrspace) { if laddr != curAddr+(btrfsvol.LogicalAddr(curSums.Len()/sumSize)*btrfssum.BlockSize) { if curSums.Len() > 0 { flattened.Runs = append(flattened.Runs, btrfssum.SumRun[btrfsvol.LogicalAddr]{ ChecksumSize: sumSize, Addr: curAddr, Sums: btrfssum.ShortSum(curSums.String()), }) } curAddr = laddr curSums.Reset() } curSums.WriteString(string(addrspace[laddr].Sum)) } if curSums.Len() > 0 { flattened.Runs = append(flattened.Runs, btrfssum.SumRun[btrfsvol.LogicalAddr]{ ChecksumSize: sumSize, Addr: curAddr, Sums: btrfssum.ShortSum(curSums.String()), }) } flattened.Addr = flattened.Runs[0].Addr last := flattened.Runs[len(flattened.Runs)-1] end := last.Addr.Add(last.Size()) flattened.Size = end.Sub(flattened.Addr) dlog.Info(ctx, "... done flattening") return flattened }