diff options
Diffstat (limited to 'lib/btrfsprogs/btrfsinspect/rebuildnodes/bak_s3_reinit.go')
-rw-r--r-- | lib/btrfsprogs/btrfsinspect/rebuildnodes/bak_s3_reinit.go | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/bak_s3_reinit.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/bak_s3_reinit.go new file mode 100644 index 0000000..5983e2f --- /dev/null +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/bak_s3_reinit.go @@ -0,0 +1,139 @@ +// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package rebuildnodes + +/* +import ( + "fmt" + "reflect" + + "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" + "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfstree" + "git.lukeshu.com/btrfs-progs-ng/lib/containers" + "git.lukeshu.com/btrfs-progs-ng/lib/slices" +) + +type RebuiltNode struct { + Errs containers.Set[string] + MinKey, MaxKey btrfsprim.Key + InTrees containers.Set[btrfsprim.ObjID] + btrfstree.Node +} + +func (a RebuiltNode) Compat(b RebuiltNode) bool { + a.Node.Head.Generation = b.Node.Head.Generation + return reflect.DeepEqual(a.Node, b.Node) +} + +func (a RebuiltNode) Merge(b RebuiltNode) (RebuiltNode, error) { + if !a.Compat(b) { + switch { + case a.Node.Head.Generation > b.Node.Head.Generation: + return a, nil + case a.Node.Head.Generation < b.Node.Head.Generation: + return b, nil + default: + return a, fmt.Errorf("mismatch: %v != %v", a, b) + } + } + + // take the broadest region + if a.MinKey.Cmp(b.MinKey) > 0 { // if a.MinKey > b.MinKey { + a.MinKey = b.MinKey // take the min of the two + } + if a.MaxKey.Cmp(b.MaxKey) < 0 { // if a.MaxKey < b.MaxKey { + a.MaxKey = b.MaxKey // take the min of the two + } + + // take the highest generation + a.Node.Head.Generation = slices.Max(a.Node.Head.Generation, b.Node.Head.Generation) + + // take the union + a.InTrees.InsertFrom(b.InTrees) + a.Errs.InsertFrom(b.Errs) + + return a, nil +} + +func reInitBrokenNodes(ctx context.Context, fs _FS, badNodes []badNode) (map[btrfsvol.LogicalAddr]*RebuiltNode, error) { + dlog.Info(ctx, "Re-initializing bad nodes...") + + sb, err := fs.Superblock() + if err != nil { + return nil, err + } + chunkTreeUUID, ok := getChunkTreeUUID(ctx, fs) + if !ok { + return nil, fmt.Errorf("could not look up chunk tree UUID") + } + + sort.Slice(badNodes, func(i, j int) bool { + iGen := badNodes[i].Path.Node(-1).ToNodeGeneration + jGen := badNodes[j].Path.Node(-1).ToNodeGeneration + switch { + case iGen < jGen: + return true + case iGen > jGen: + return false + default: + iAddr := badNodes[i].Path.Node(-1).ToNodeAddr + jAddr := badNodes[j].Path.Node(-1).ToNodeAddr + return iAddr < jAddr + } + }) + + lastPct := -1 + progress := func(done int) { + pct := int(100 * float64(done) / float64(len(badNodes))) + if pct != lastPct || done == len(badNodes) { + dlog.Infof(ctx, "... %v%% (%v/%v)", + pct, done, len(badNodes)) + lastPct = pct + } + } + + rebuiltNodes := make(map[btrfsvol.LogicalAddr]*RebuiltNode) + for i, badNode := range badNodes { + progress(i) + path := badNode.Path + + min, max := spanOfTreePath(fs, path) + node := RebuiltNode{ + Errs: containers.NewSet[string]( + badNode.Err, + ), + MinKey: min, + MaxKey: max, + InTrees: containers.NewSet[btrfsprim.ObjID]( + path.Node(-1).FromTree, + ), + Node: btrfstree.Node{ + Size: sb.NodeSize, + ChecksumType: sb.ChecksumType, + Head: btrfstree.NodeHeader{ + MetadataUUID: sb.EffectiveMetadataUUID(), + Addr: path.Node(-1).ToNodeAddr, + ChunkTreeUUID: chunkTreeUUID, + //Owner: TBD, // see RebuiltNode.InTrees + Generation: path.Node(-1).ToNodeGeneration, + Level: path.Node(-1).ToNodeLevel, + }, + }, + } + if other, ok := rebuiltNodes[path.Node(-1).ToNodeAddr]; ok { + *other, err = other.Merge(node) + if err != nil { + dlog.Errorf(ctx, "... %v", err) + } + } else { + rebuiltNodes[path.Node(-1).ToNodeAddr] = &node + } + } + progress(len(badNodes)) + + dlog.Infof(ctx, "... initialized %d nodes", len(rebuiltNodes)) + return rebuiltNodes, nil +} +*/ |