diff options
-rw-r--r-- | cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go | 10 | ||||
-rw-r--r-- | lib/btrfsutil/rebuilt_forrest.go | 19 | ||||
-rw-r--r-- | lib/btrfsutil/rebuilt_readitem.go | 53 | ||||
-rw-r--r-- | lib/btrfsutil/rebuilt_tree.go | 2 |
4 files changed, 33 insertions, 51 deletions
diff --git a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go index 4937ee3..01e4e3c 100644 --- a/cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go +++ b/cmd/btrfs-rec/inspect/rebuildtrees/rebuild.go @@ -47,8 +47,7 @@ func (o keyAndTree) String() string { } type rebuilder struct { - scan ScanDevicesResult - keyIO *btrfsutil.KeyIO + scan ScanDevicesResult rebuilt *btrfsutil.RebuiltForrest @@ -83,13 +82,10 @@ func NewRebuilder(ctx context.Context, fs *btrfs.FS, nodeList []btrfsvol.Logical return nil, err } - keyIO := btrfsutil.NewKeyIO(fs, scanData.Superblock, scanData.Graph) - o := &rebuilder{ - scan: scanData, - keyIO: keyIO, + scan: scanData, } - o.rebuilt = btrfsutil.NewRebuiltForrest(scanData.Superblock, scanData.Graph, keyIO, forrestCallbacks{o}) + o.rebuilt = btrfsutil.NewRebuiltForrest(fs, scanData.Superblock, scanData.Graph, forrestCallbacks{o}) return o, nil } diff --git a/lib/btrfsutil/rebuilt_forrest.go b/lib/btrfsutil/rebuilt_forrest.go index 0e8f5ad..25d953b 100644 --- a/lib/btrfsutil/rebuilt_forrest.go +++ b/lib/btrfsutil/rebuilt_forrest.go @@ -6,6 +6,7 @@ package btrfsutil import ( "context" + "sync" "github.com/datawire/dlib/dlog" @@ -14,6 +15,7 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfstree" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" "git.lukeshu.com/btrfs-progs-ng/lib/containers" + "git.lukeshu.com/btrfs-progs-ng/lib/diskio" "git.lukeshu.com/btrfs-progs-ng/lib/slices" "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) @@ -57,26 +59,30 @@ type RebuiltForrestCallbacks interface { // NewRebuiltForrest(). type RebuiltForrest struct { // static + file diskio.File[btrfsvol.LogicalAddr] sb btrfstree.Superblock graph Graph - keyIO *KeyIO cb RebuiltForrestCallbacks // mutable + treesMu nestedMutex trees map[btrfsprim.ObjID]*RebuiltTree // must hold .treesMu to access leafs containers.ARCache[btrfsprim.ObjID, map[btrfsvol.LogicalAddr]containers.Set[btrfsvol.LogicalAddr]] incItems containers.ARCache[btrfsprim.ObjID, *itemIndex] excItems containers.ARCache[btrfsprim.ObjID, *itemIndex] + + nodesMu sync.Mutex + nodes containers.ARCache[btrfsvol.LogicalAddr, *btrfstree.Node] } // NewRebuiltForrest returns a new RebuiltForrest instance. All of // the callbacks must be non-nil. -func NewRebuiltForrest(sb btrfstree.Superblock, graph Graph, keyIO *KeyIO, cb RebuiltForrestCallbacks) *RebuiltForrest { +func NewRebuiltForrest(file diskio.File[btrfsvol.LogicalAddr], sb btrfstree.Superblock, graph Graph, cb RebuiltForrestCallbacks) *RebuiltForrest { return &RebuiltForrest{ + file: file, sb: sb, graph: graph, - keyIO: keyIO, cb: cb, trees: make(map[btrfsprim.ObjID]*RebuiltTree), @@ -89,6 +95,13 @@ func NewRebuiltForrest(sb btrfstree.Superblock, graph Graph, keyIO *KeyIO, cb Re excItems: containers.ARCache[btrfsprim.ObjID, *itemIndex]{ MaxLen: textui.Tunable(8), }, + + nodes: containers.ARCache[btrfsvol.LogicalAddr, *btrfstree.Node]{ + MaxLen: textui.Tunable(8), + OnRemove: func(_ btrfsvol.LogicalAddr, node *btrfstree.Node) { + node.Free() + }, + }, } } diff --git a/lib/btrfsutil/rebuilt_readitem.go b/lib/btrfsutil/rebuilt_readitem.go index 7e9be09..68aabdd 100644 --- a/lib/btrfsutil/rebuilt_readitem.go +++ b/lib/btrfsutil/rebuilt_readitem.go @@ -7,7 +7,6 @@ package btrfsutil import ( "context" "fmt" - "sync" "github.com/datawire/dlib/dlog" @@ -16,8 +15,6 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfstree" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" "git.lukeshu.com/btrfs-progs-ng/lib/containers" - "git.lukeshu.com/btrfs-progs-ng/lib/diskio" - "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) type ItemPtr struct { @@ -29,43 +26,19 @@ func (ptr ItemPtr) String() string { return fmt.Sprintf("node@%v[%v]", ptr.Node, ptr.Slot) } -type KeyIO struct { - rawFile diskio.File[btrfsvol.LogicalAddr] - sb btrfstree.Superblock - graph Graph - - mu sync.Mutex - cache containers.ARCache[btrfsvol.LogicalAddr, *btrfstree.Node] -} - -func NewKeyIO(file diskio.File[btrfsvol.LogicalAddr], sb btrfstree.Superblock, graph Graph) *KeyIO { - return &KeyIO{ - rawFile: file, - sb: sb, - graph: graph, - - cache: containers.ARCache[btrfsvol.LogicalAddr, *btrfstree.Node]{ - MaxLen: textui.Tunable(8), - OnRemove: func(_ btrfsvol.LogicalAddr, node *btrfstree.Node) { - node.Free() - }, - }, - } -} - -func (o *KeyIO) readNode(ctx context.Context, laddr btrfsvol.LogicalAddr) *btrfstree.Node { - if cached, ok := o.cache.Load(laddr); ok { +func (ts *RebuiltForrest) readNode(ctx context.Context, laddr btrfsvol.LogicalAddr) *btrfstree.Node { + if cached, ok := ts.nodes.Load(laddr); ok { dlog.Tracef(ctx, "cache-hit node@%v", laddr) return cached } - graphInfo, ok := o.graph.Nodes[laddr] + graphInfo, ok := ts.graph.Nodes[laddr] if !ok { panic(fmt.Errorf("should not happen: node@%v is not mentioned in the in-memory graph", laddr)) } dlog.Debugf(ctx, "cache-miss node@%v, reading...", laddr) - node, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](o.rawFile, o.sb, laddr, btrfstree.NodeExpectations{ + node, err := btrfstree.ReadNode[btrfsvol.LogicalAddr](ts.file, ts.sb, laddr, btrfstree.NodeExpectations{ LAddr: containers.Optional[btrfsvol.LogicalAddr]{OK: true, Val: laddr}, Level: containers.Optional[uint8]{OK: true, Val: graphInfo.Level}, Generation: containers.Optional[btrfsprim.Generation]{OK: true, Val: graphInfo.Generation}, @@ -83,23 +56,23 @@ func (o *KeyIO) readNode(ctx context.Context, laddr btrfsvol.LogicalAddr) *btrfs panic(fmt.Errorf("should not happen: i/o error: %w", err)) } - o.cache.Store(laddr, node) + ts.nodes.Store(laddr, node) return node } -func (o *KeyIO) ReadItem(ctx context.Context, ptr ItemPtr) btrfsitem.Item { - o.mu.Lock() - defer o.mu.Unlock() - if o.graph.Nodes[ptr.Node].Level != 0 { - panic(fmt.Errorf("should not happen: btrfsutil.KeyIO.ReadItem called for non-leaf node@%v", ptr.Node)) +func (ts *RebuiltForrest) readItem(ctx context.Context, ptr ItemPtr) btrfsitem.Item { + ts.nodesMu.Lock() + defer ts.nodesMu.Unlock() + if ts.graph.Nodes[ptr.Node].Level != 0 { + panic(fmt.Errorf("should not happen: btrfsutil.RebuiltForrest.readItem called for non-leaf node@%v", ptr.Node)) } if ptr.Slot < 0 { - panic(fmt.Errorf("should not happen: btrfsutil.KeyIO.ReadItem called for negative item slot: %v", ptr.Slot)) + panic(fmt.Errorf("should not happen: btrfsutil.RebuiltForrest.readItem called for negative item slot: %v", ptr.Slot)) } - items := o.readNode(ctx, ptr.Node).BodyLeaf + items := ts.readNode(ctx, ptr.Node).BodyLeaf if ptr.Slot >= len(items) { - panic(fmt.Errorf("should not happen: btrfsutil.KeyIO.ReadItem called for out-of-bounds item slot: slot=%v len=%v", + panic(fmt.Errorf("should not happen: btrfsutil.RebuiltForrest.readItem called for out-of-bounds item slot: slot=%v len=%v", ptr.Slot, len(items))) } return items[ptr.Slot].Body.CloneItem() diff --git a/lib/btrfsutil/rebuilt_tree.go b/lib/btrfsutil/rebuilt_tree.go index 3133a9e..820913e 100644 --- a/lib/btrfsutil/rebuilt_tree.go +++ b/lib/btrfsutil/rebuilt_tree.go @@ -329,7 +329,7 @@ func (tree *RebuiltTree) ReadItem(ctx context.Context, key btrfsprim.Key) btrfsi if !ok { panic(fmt.Errorf("should not happen: btrfsutil.RebuiltTree.ReadItem called for not-included key: %v", key)) } - return tree.forrest.keyIO.ReadItem(ctx, ptr) + return tree.forrest.readItem(ctx, ptr) } // LeafToRoots returns the list of potential roots (to pass to |