summaryrefslogtreecommitdiff
path: root/lib/btrfsprogs/btrfsinspect/rebuildnodes/bak_s3_reinit.go
blob: 5983e2f7fea8c124426ef3c3b303324acb6410e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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
}
*/