From 1bc243ca607c22e232017b0f1b4badcde288a9b3 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Thu, 16 Mar 2023 09:17:35 -0600 Subject: btrfstree: Have ReadNode return a *Node rather than a *diskio.Ref[Addr, Node] ... and take a ReaderAt instead of a diskio.File. --- lib/btrfs/btrfstree/btree.go | 10 +-- lib/btrfs/btrfstree/btree_tree.go | 184 +++++++++++++++++++------------------- lib/btrfs/btrfstree/readnode.go | 4 +- lib/btrfs/btrfstree/types_node.go | 80 +++++++---------- 4 files changed, 129 insertions(+), 149 deletions(-) (limited to 'lib/btrfs/btrfstree') diff --git a/lib/btrfs/btrfstree/btree.go b/lib/btrfs/btrfstree/btree.go index 89d4f9d..c71aad5 100644 --- a/lib/btrfs/btrfstree/btree.go +++ b/lib/btrfs/btrfstree/btree.go @@ -11,8 +11,6 @@ import ( "fmt" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" - "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" - "git.lukeshu.com/btrfs-progs-ng/lib/diskio" ) type TreeSearcher interface { @@ -72,9 +70,9 @@ type TreeWalkHandler struct { // or BadNode return io/fs.SkipDir then key pointers and items // within the node are not processed. PreNode func(TreePath) error - Node func(TreePath, *diskio.Ref[btrfsvol.LogicalAddr, Node]) error - BadNode func(TreePath, *diskio.Ref[btrfsvol.LogicalAddr, Node], error) error - PostNode func(TreePath, *diskio.Ref[btrfsvol.LogicalAddr, Node]) error + Node func(TreePath, *Node) error + BadNode func(TreePath, *Node, error) error + PostNode func(TreePath, *Node) error // Callbacks for items on interior nodes PreKeyPointer func(TreePath, KeyPointer) error PostKeyPointer func(TreePath, KeyPointer) error @@ -96,5 +94,5 @@ func (e *TreeError) Error() string { type NodeSource interface { Superblock() (*Superblock, error) - ReadNode(TreePath) (*diskio.Ref[btrfsvol.LogicalAddr, Node], error) + ReadNode(TreePath) (*Node, error) } diff --git a/lib/btrfs/btrfstree/btree_tree.go b/lib/btrfs/btrfstree/btree_tree.go index 1e3c789..7561314 100644 --- a/lib/btrfs/btrfstree/btree_tree.go +++ b/lib/btrfs/btrfstree/btree_tree.go @@ -15,8 +15,6 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" - "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" - "git.lukeshu.com/btrfs-progs-ng/lib/diskio" "git.lukeshu.com/btrfs-progs-ng/lib/slices" ) @@ -72,7 +70,7 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl } } node, err := fs.ReadNode(path) - defer FreeNodeRef(node) + defer node.Free() if ctx.Err() != nil { return } @@ -97,17 +95,17 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl return } if node != nil { - for i, item := range node.Data.BodyInterior { + for i, item := range node.BodyInterior { toMaxKey := path.Node(-1).ToMaxKey - if i+1 < len(node.Data.BodyInterior) { - toMaxKey = node.Data.BodyInterior[i+1].Key.Mm() + if i+1 < len(node.BodyInterior) { + toMaxKey = node.BodyInterior[i+1].Key.Mm() } itemPath := append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: i, ToNodeAddr: item.BlockPtr, ToNodeGeneration: item.Generation, - ToNodeLevel: node.Data.Head.Level - 1, + ToNodeLevel: node.Head.Level - 1, ToKey: item.Key, ToMaxKey: toMaxKey, }) @@ -129,9 +127,9 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl } } } - for i, item := range node.Data.BodyLeaf { + for i, item := range node.BodyLeaf { itemPath := append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: i, ToKey: item.Key, ToMaxKey: item.Key, @@ -169,7 +167,7 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl } } -func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, uint32) int) (TreePath, *diskio.Ref[btrfsvol.LogicalAddr, Node], error) { +func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, uint32) int) (TreePath, *Node, error) { path := TreePath{{ FromTree: treeRoot.TreeID, FromItemSlot: -1, @@ -184,15 +182,15 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, } node, err := fs.ReadNode(path) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } switch { - case node.Data.Head.Level > 0: + case node.Head.Level > 0: // interior node - // Search for the right-most node.Data.BodyInterior item for which + // Search for the right-most node.BodyInterior item for which // `fn(item.Key) >= 0`. // // + + + + 0 - - - - @@ -200,31 +198,31 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, // There may or may not be a value that returns '0'. // // i.e. find the highest value that isn't too high. - lastGood, ok := slices.SearchHighest(node.Data.BodyInterior, func(kp KeyPointer) int { + lastGood, ok := slices.SearchHighest(node.BodyInterior, func(kp KeyPointer) int { return slices.Min(fn(kp.Key, math.MaxUint32), 0) // don't return >0; a key can't be "too low" }) if !ok { - FreeNodeRef(node) + node.Free() return nil, nil, ErrNoItem } toMaxKey := path.Node(-1).ToMaxKey - if lastGood+1 < len(node.Data.BodyInterior) { - toMaxKey = node.Data.BodyInterior[lastGood+1].Key.Mm() + if lastGood+1 < len(node.BodyInterior) { + toMaxKey = node.BodyInterior[lastGood+1].Key.Mm() } path = append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: lastGood, - ToNodeAddr: node.Data.BodyInterior[lastGood].BlockPtr, - ToNodeGeneration: node.Data.BodyInterior[lastGood].Generation, - ToNodeLevel: node.Data.Head.Level - 1, - ToKey: node.Data.BodyInterior[lastGood].Key, + ToNodeAddr: node.BodyInterior[lastGood].BlockPtr, + ToNodeGeneration: node.BodyInterior[lastGood].Generation, + ToNodeLevel: node.Head.Level - 1, + ToKey: node.BodyInterior[lastGood].Key, ToMaxKey: toMaxKey, }) - FreeNodeRef(node) + node.Free() default: // leaf node - // Search for a member of node.Data.BodyLeaf for which + // Search for a member of node.BodyLeaf for which // `fn(item.Head.Key) == 0`. // // + + + + 0 - - - - @@ -234,25 +232,25 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, // is returned. // // Implement this search as a binary search. - slot, ok := slices.Search(node.Data.BodyLeaf, func(item Item) int { + slot, ok := slices.Search(node.BodyLeaf, func(item Item) int { return fn(item.Key, item.BodySize) }) if !ok { - FreeNodeRef(node) + node.Free() return nil, nil, ErrNoItem } path = append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: slot, - ToKey: node.Data.BodyLeaf[slot].Key, - ToMaxKey: node.Data.BodyLeaf[slot].Key, + ToKey: node.BodyLeaf[slot].Key, + ToMaxKey: node.BodyLeaf[slot].Key, }) return path, node, nil } } } -func (fs TreeOperatorImpl) prev(path TreePath, node *diskio.Ref[btrfsvol.LogicalAddr, Node]) (TreePath, *diskio.Ref[btrfsvol.LogicalAddr, Node], error) { +func (fs TreeOperatorImpl) prev(path TreePath, node *Node) (TreePath, *Node, error) { var err error path = path.DeepCopy() @@ -266,139 +264,139 @@ func (fs TreeOperatorImpl) prev(path TreePath, node *diskio.Ref[btrfsvol.Logical // go left path.Node(-1).FromItemSlot-- if path.Node(-1).ToNodeAddr != 0 { - if node.Addr != path.Node(-2).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-2).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path.Parent()) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } - path.Node(-1).ToNodeAddr = node.Data.BodyInterior[path.Node(-1).FromItemSlot].BlockPtr + path.Node(-1).ToNodeAddr = node.BodyInterior[path.Node(-1).FromItemSlot].BlockPtr } } // go down for path.Node(-1).ToNodeAddr != 0 { - if node.Addr != path.Node(-1).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-1).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } } - if node.Data.Head.Level > 0 { + if node.Head.Level > 0 { path = append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, - FromItemSlot: len(node.Data.BodyInterior) - 1, - ToNodeAddr: node.Data.BodyInterior[len(node.Data.BodyInterior)-1].BlockPtr, - ToNodeGeneration: node.Data.BodyInterior[len(node.Data.BodyInterior)-1].Generation, - ToNodeLevel: node.Data.Head.Level - 1, - ToKey: node.Data.BodyInterior[len(node.Data.BodyInterior)-1].Key, + FromTree: node.Head.Owner, + FromItemSlot: len(node.BodyInterior) - 1, + ToNodeAddr: node.BodyInterior[len(node.BodyInterior)-1].BlockPtr, + ToNodeGeneration: node.BodyInterior[len(node.BodyInterior)-1].Generation, + ToNodeLevel: node.Head.Level - 1, + ToKey: node.BodyInterior[len(node.BodyInterior)-1].Key, ToMaxKey: path.Node(-1).ToMaxKey, }) } else { path = append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, - FromItemSlot: len(node.Data.BodyLeaf) - 1, - ToKey: node.Data.BodyLeaf[len(node.Data.BodyLeaf)-1].Key, - ToMaxKey: node.Data.BodyLeaf[len(node.Data.BodyLeaf)-1].Key, + FromTree: node.Head.Owner, + FromItemSlot: len(node.BodyLeaf) - 1, + ToKey: node.BodyLeaf[len(node.BodyLeaf)-1].Key, + ToMaxKey: node.BodyLeaf[len(node.BodyLeaf)-1].Key, }) } } // return - if node.Addr != path.Node(-2).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-2).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path.Parent()) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } } return path, node, nil } -func (fs TreeOperatorImpl) next(path TreePath, node *diskio.Ref[btrfsvol.LogicalAddr, Node]) (TreePath, *diskio.Ref[btrfsvol.LogicalAddr, Node], error) { +func (fs TreeOperatorImpl) next(path TreePath, node *Node) (TreePath, *Node, error) { var err error path = path.DeepCopy() // go up - if node.Addr != path.Node(-2).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-2).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path.Parent()) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } - path.Node(-2).ToNodeLevel = node.Data.Head.Level + path.Node(-2).ToNodeLevel = node.Head.Level } - for path.Node(-1).FromItemSlot+1 >= int(node.Data.Head.NumItems) { + for path.Node(-1).FromItemSlot+1 >= int(node.Head.NumItems) { path = path.Parent() if len(path) == 1 { return nil, nil, nil } - if node.Addr != path.Node(-2).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-2).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path.Parent()) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } - path.Node(-2).ToNodeLevel = node.Data.Head.Level + path.Node(-2).ToNodeLevel = node.Head.Level } } // go right path.Node(-1).FromItemSlot++ if path.Node(-1).ToNodeAddr != 0 { - if node.Addr != path.Node(-2).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-2).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path.Parent()) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } - path.Node(-1).ToNodeAddr = node.Data.BodyInterior[path.Node(-1).FromItemSlot].BlockPtr + path.Node(-1).ToNodeAddr = node.BodyInterior[path.Node(-1).FromItemSlot].BlockPtr } } // go down for path.Node(-1).ToNodeAddr != 0 { - if node.Addr != path.Node(-1).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-1).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } - path.Node(-1).ToNodeLevel = node.Data.Head.Level + path.Node(-1).ToNodeLevel = node.Head.Level } - if node.Data.Head.Level > 0 { + if node.Head.Level > 0 { toMaxKey := path.Node(-1).ToMaxKey - if len(node.Data.BodyInterior) > 1 { - toMaxKey = node.Data.BodyInterior[1].Key.Mm() + if len(node.BodyInterior) > 1 { + toMaxKey = node.BodyInterior[1].Key.Mm() } path = append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: 0, - ToNodeAddr: node.Data.BodyInterior[0].BlockPtr, - ToNodeGeneration: node.Data.BodyInterior[0].Generation, - ToNodeLevel: node.Data.Head.Level - 1, - ToKey: node.Data.BodyInterior[0].Key, + ToNodeAddr: node.BodyInterior[0].BlockPtr, + ToNodeGeneration: node.BodyInterior[0].Generation, + ToNodeLevel: node.Head.Level - 1, + ToKey: node.BodyInterior[0].Key, ToMaxKey: toMaxKey, }) } else { path = append(path, TreePathElem{ - FromTree: node.Data.Head.Owner, + FromTree: node.Head.Owner, FromItemSlot: 0, - ToKey: node.Data.BodyInterior[0].Key, - ToMaxKey: node.Data.BodyInterior[0].Key, + ToKey: node.BodyInterior[0].Key, + ToMaxKey: node.BodyInterior[0].Key, }) } } // return - if node.Addr != path.Node(-2).ToNodeAddr { - FreeNodeRef(node) + if node.Head.Addr != path.Node(-2).ToNodeAddr { + node.Free() node, err = fs.ReadNode(path.Parent()) if err != nil { - FreeNodeRef(node) + node.Free() return nil, nil, err } } @@ -419,9 +417,9 @@ func (fs TreeOperatorImpl) TreeSearch(treeID btrfsprim.ObjID, searcher TreeSearc if err != nil { return Item{}, fmt.Errorf("item with %s: %w", searcher, err) } - item := node.Data.BodyLeaf[path.Node(-1).FromItemSlot] + item := node.BodyLeaf[path.Node(-1).FromItemSlot] item.Body = item.Body.CloneItem() - FreeNodeRef(node) + node.Free() return item, nil } @@ -444,7 +442,7 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, searcher TreeSe if err != nil { return nil, fmt.Errorf("items with %s: %w", searcher, err) } - middleItem := middleNode.Data.BodyLeaf[middlePath.Node(-1).FromItemSlot] + middleItem := middleNode.BodyLeaf[middlePath.Node(-1).FromItemSlot] ret := []Item{middleItem} var errs derror.MultiError @@ -458,7 +456,7 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, searcher TreeSe if len(prevPath) == 0 { break } - prevItem := prevNode.Data.BodyLeaf[prevPath.Node(-1).FromItemSlot] + prevItem := prevNode.BodyLeaf[prevPath.Node(-1).FromItemSlot] if searcher.Search(prevItem.Key, prevItem.BodySize) != 0 { break } @@ -467,11 +465,11 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, searcher TreeSe ret = append(ret, item) } slices.Reverse(ret) - if prevNode.Addr != middlePath.Node(-1).ToNodeAddr { - FreeNodeRef(prevNode) + if prevNode.Head.Addr != middlePath.Node(-1).ToNodeAddr { + prevNode.Free() middleNode, err = fs.ReadNode(middlePath) if err != nil { - FreeNodeRef(middleNode) + middleNode.Free() return nil, fmt.Errorf("items with %s: %w", searcher, err) } } @@ -485,7 +483,7 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, searcher TreeSe if len(nextPath) == 0 { break } - nextItem := nextNode.Data.BodyLeaf[nextPath.Node(-1).FromItemSlot] + nextItem := nextNode.BodyLeaf[nextPath.Node(-1).FromItemSlot] if searcher.Search(nextItem.Key, nextItem.BodySize) != 0 { break } @@ -493,7 +491,7 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, searcher TreeSe item.Body = item.Body.CloneItem() ret = append(ret, item) } - FreeNodeRef(nextNode) + nextNode.Free() if errs != nil { err = errs } diff --git a/lib/btrfs/btrfstree/readnode.go b/lib/btrfs/btrfstree/readnode.go index 4ccc17b..1c242ac 100644 --- a/lib/btrfs/btrfstree/readnode.go +++ b/lib/btrfs/btrfstree/readnode.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -34,7 +34,7 @@ type NodeFile interface { func FSReadNode( fs NodeFile, path TreePath, -) (*diskio.Ref[btrfsvol.LogicalAddr, Node], error) { +) (*Node, error) { sb, err := fs.Superblock() if err != nil { return nil, fmt.Errorf("btrfs.FS.ReadNode: %w", err) diff --git a/lib/btrfs/btrfstree/types_node.go b/lib/btrfs/btrfstree/types_node.go index 8295ccb..2147f5b 100644 --- a/lib/btrfs/btrfstree/types_node.go +++ b/lib/btrfs/btrfstree/types_node.go @@ -8,7 +8,6 @@ import ( "encoding/binary" "errors" "fmt" - "unsafe" "git.lukeshu.com/go/typedsync" "github.com/datawire/dlib/derror" @@ -308,12 +307,16 @@ type ItemHeader struct { var itemPool containers.SlicePool[Item] func (node *Node) Free() { + if node == nil { + return + } for i := range node.BodyLeaf { node.BodyLeaf[i].Body.Free() node.BodyLeaf[i] = Item{} } itemPool.Put(node.BodyLeaf) *node = Node{} + nodePool.Put(node) } func (node *Node) unmarshalLeaf(bodyBuf []byte) (int, error) { @@ -440,32 +443,19 @@ func (e *IOError) Unwrap() error { return e.Err } var bytePool containers.SlicePool[byte] -var nodePool = typedsync.Pool[*diskio.Ref[int64, Node]]{ - New: func() *diskio.Ref[int64, Node] { - return new(diskio.Ref[int64, Node]) +var nodePool = typedsync.Pool[*Node]{ + New: func() *Node { + return new(Node) }, } -func FreeNodeRef[Addr ~int64](ref *diskio.Ref[Addr, Node]) { - if ref == nil { - return - } - ref.Data.Free() - nodePool.Put((*diskio.Ref[int64, Node])(unsafe.Pointer(ref))) //nolint:gosec // I know it's unsafe. -} - -func newNodeRef[Addr ~int64]() *diskio.Ref[Addr, Node] { - ret, _ := nodePool.Get() - return (*diskio.Ref[Addr, Node])(unsafe.Pointer(ret)) //nolint:gosec // I know it's unsafe. -} - // ReadNode reads a node from the given file. // // It is possible that both a non-nil diskio.Ref and an error are // returned. The error returned (if non-nil) is always of type // *NodeError[Addr]. Notable errors that may be inside of the // NodeError are ErrNotANode and *IOError. -func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp NodeExpectations) (*diskio.Ref[Addr, Node], error) { +func ReadNode[Addr ~int64](fs diskio.ReaderAt[Addr], sb Superblock, addr Addr, exp NodeExpectations) (*Node, error) { if int(sb.NodeSize) < nodeHeaderSize { return nil, &NodeError[Addr]{ Op: "btrfstree.ReadNode", NodeAddr: addr, @@ -481,16 +471,10 @@ func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp N // parse (early) - nodeRef := newNodeRef[Addr]() - *nodeRef = diskio.Ref[Addr, Node]{ - File: fs, - Addr: addr, - Data: Node{ - Size: sb.NodeSize, - ChecksumType: sb.ChecksumType, - }, - } - if _, err := binstruct.Unmarshal(nodeBuf, &nodeRef.Data.Head); err != nil { + node, _ := nodePool.Get() + node.Size = sb.NodeSize + node.ChecksumType = sb.ChecksumType + if _, err := binstruct.Unmarshal(nodeBuf, &node.Head); err != nil { // If there are enough bytes there (and we checked // that above), then it shouldn't be possible for this // unmarshal to fail. @@ -499,20 +483,20 @@ func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp N // sanity checking (that prevents the main parse) - if nodeRef.Data.Head.MetadataUUID != sb.EffectiveMetadataUUID() { + if node.Head.MetadataUUID != sb.EffectiveMetadataUUID() { bytePool.Put(nodeBuf) - return nodeRef, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: ErrNotANode} + return node, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: ErrNotANode} } - stored := nodeRef.Data.Head.Checksum - calced, err := nodeRef.Data.ChecksumType.Sum(nodeBuf[csumSize:]) + stored := node.Head.Checksum + calced, err := node.ChecksumType.Sum(nodeBuf[csumSize:]) if err != nil { bytePool.Put(nodeBuf) - return nodeRef, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: err} + return node, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: err} } if stored != calced { bytePool.Put(nodeBuf) - return nodeRef, &NodeError[Addr]{ + return node, &NodeError[Addr]{ Op: "btrfstree.ReadNode", NodeAddr: addr, Err: fmt.Errorf("looks like a node but is corrupt: checksum mismatch: stored=%v calculated=%v", stored, calced), @@ -530,9 +514,9 @@ func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp N // garbage data that is was never a valid node, so parsing it // isn't useful. - if _, err := binstruct.Unmarshal(nodeBuf, &nodeRef.Data); err != nil { + if _, err := binstruct.Unmarshal(nodeBuf, node); err != nil { bytePool.Put(nodeBuf) - return nodeRef, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: err} + return node, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: err} } bytePool.Put(nodeBuf) @@ -540,40 +524,40 @@ func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp N // sanity checking (that doesn't prevent parsing) var errs derror.MultiError - if exp.LAddr.OK && nodeRef.Data.Head.Addr != exp.LAddr.Val { + if exp.LAddr.OK && node.Head.Addr != exp.LAddr.Val { errs = append(errs, fmt.Errorf("read from laddr=%v but claims to be at laddr=%v", - exp.LAddr.Val, nodeRef.Data.Head.Addr)) + exp.LAddr.Val, node.Head.Addr)) } - if exp.Level.OK && nodeRef.Data.Head.Level != exp.Level.Val { + if exp.Level.OK && node.Head.Level != exp.Level.Val { errs = append(errs, fmt.Errorf("expected level=%v but claims to be level=%v", - exp.Level.Val, nodeRef.Data.Head.Level)) + exp.Level.Val, node.Head.Level)) } - if exp.Generation.OK && nodeRef.Data.Head.Generation != exp.Generation.Val { + if exp.Generation.OK && node.Head.Generation != exp.Generation.Val { errs = append(errs, fmt.Errorf("expected generation=%v but claims to be generation=%v", - exp.Generation.Val, nodeRef.Data.Head.Generation)) + exp.Generation.Val, node.Head.Generation)) } if exp.Owner != nil { - if err := exp.Owner(nodeRef.Data.Head.Owner); err != nil { + if err := exp.Owner(node.Head.Owner); err != nil { errs = append(errs, err) } } - if nodeRef.Data.Head.NumItems == 0 { + if node.Head.NumItems == 0 { errs = append(errs, fmt.Errorf("has no items")) } else { - if minItem, _ := nodeRef.Data.MinItem(); exp.MinItem.OK && exp.MinItem.Val.Compare(minItem) > 0 { + if minItem, _ := node.MinItem(); exp.MinItem.OK && exp.MinItem.Val.Compare(minItem) > 0 { errs = append(errs, fmt.Errorf("expected minItem>=%v but node has minItem=%v", exp.MinItem, minItem)) } - if maxItem, _ := nodeRef.Data.MaxItem(); exp.MaxItem.OK && exp.MaxItem.Val.Compare(maxItem) < 0 { + if maxItem, _ := node.MaxItem(); exp.MaxItem.OK && exp.MaxItem.Val.Compare(maxItem) < 0 { errs = append(errs, fmt.Errorf("expected maxItem<=%v but node has maxItem=%v", exp.MaxItem, maxItem)) } } if len(errs) > 0 { - return nodeRef, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: errs} + return node, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: errs} } // return - return nodeRef, nil + return node, nil } -- cgit v1.2.3-2-g168b From 3d5689be1f38ce4d76af5c1a9b6ad1193e6bff67 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Thu, 16 Mar 2023 09:21:41 -0600 Subject: btrfstree: Factor out NodeExpectations.Check() from ReadNode() --- lib/btrfs/btrfstree/types_node.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'lib/btrfs/btrfstree') diff --git a/lib/btrfs/btrfstree/types_node.go b/lib/btrfs/btrfstree/types_node.go index 2147f5b..622f23c 100644 --- a/lib/btrfs/btrfstree/types_node.go +++ b/lib/btrfs/btrfstree/types_node.go @@ -523,6 +523,16 @@ func ReadNode[Addr ~int64](fs diskio.ReaderAt[Addr], sb Superblock, addr Addr, e // sanity checking (that doesn't prevent parsing) + if err := exp.Check(node); err != nil { + return node, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: err} + } + + // return + + return node, nil +} + +func (exp NodeExpectations) Check(node *Node) error { var errs derror.MultiError if exp.LAddr.OK && node.Head.Addr != exp.LAddr.Val { errs = append(errs, fmt.Errorf("read from laddr=%v but claims to be at laddr=%v", @@ -554,10 +564,7 @@ func ReadNode[Addr ~int64](fs diskio.ReaderAt[Addr], sb Superblock, addr Addr, e } } if len(errs) > 0 { - return node, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: errs} + return errs } - - // return - - return node, nil + return nil } -- cgit v1.2.3-2-g168b From 17e5d1366a77bbe0e8d32b7bf16829a4f855e854 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Fri, 10 Mar 2023 15:22:07 -0700 Subject: tree-wide: s/TreePath/Path/g btrfstree.TreePath stutters. --- lib/btrfs/btrfstree/btree.go | 20 ++++++++++---------- lib/btrfs/btrfstree/btree_tree.go | 32 ++++++++++++++++---------------- lib/btrfs/btrfstree/path.go | 22 +++++++++++----------- lib/btrfs/btrfstree/readnode.go | 2 +- 4 files changed, 38 insertions(+), 38 deletions(-) (limited to 'lib/btrfs/btrfstree') diff --git a/lib/btrfs/btrfstree/btree.go b/lib/btrfs/btrfstree/btree.go index c71aad5..e91fcc1 100644 --- a/lib/btrfs/btrfstree/btree.go +++ b/lib/btrfs/btrfstree/btree.go @@ -69,20 +69,20 @@ type TreeWalkHandler struct { // node immediately stops getting processed; if PreNode, Node, // or BadNode return io/fs.SkipDir then key pointers and items // within the node are not processed. - PreNode func(TreePath) error - Node func(TreePath, *Node) error - BadNode func(TreePath, *Node, error) error - PostNode func(TreePath, *Node) error + PreNode func(Path) error + Node func(Path, *Node) error + BadNode func(Path, *Node, error) error + PostNode func(Path, *Node) error // Callbacks for items on interior nodes - PreKeyPointer func(TreePath, KeyPointer) error - PostKeyPointer func(TreePath, KeyPointer) error + PreKeyPointer func(Path, KeyPointer) error + PostKeyPointer func(Path, KeyPointer) error // Callbacks for items on leaf nodes - Item func(TreePath, Item) error - BadItem func(TreePath, Item) error + Item func(Path, Item) error + BadItem func(Path, Item) error } type TreeError struct { - Path TreePath + Path Path Err error } @@ -94,5 +94,5 @@ func (e *TreeError) Error() string { type NodeSource interface { Superblock() (*Superblock, error) - ReadNode(TreePath) (*Node, error) + ReadNode(Path) (*Node, error) } diff --git a/lib/btrfs/btrfstree/btree_tree.go b/lib/btrfs/btrfstree/btree_tree.go index 7561314..459f481 100644 --- a/lib/btrfs/btrfstree/btree_tree.go +++ b/lib/btrfs/btrfstree/btree_tree.go @@ -26,11 +26,11 @@ type TreeOperatorImpl struct { func (fs TreeOperatorImpl) TreeWalk(ctx context.Context, treeID btrfsprim.ObjID, errHandle func(*TreeError), cbs TreeWalkHandler) { sb, err := fs.Superblock() if err != nil { - errHandle(&TreeError{Path: TreePath{{FromTree: treeID, ToMaxKey: btrfsprim.MaxKey}}, Err: err}) + errHandle(&TreeError{Path: Path{{FromTree: treeID, ToMaxKey: btrfsprim.MaxKey}}, Err: err}) } rootInfo, err := LookupTreeRoot(fs, *sb, treeID) if err != nil { - errHandle(&TreeError{Path: TreePath{{FromTree: treeID, ToMaxKey: btrfsprim.MaxKey}}, Err: err}) + errHandle(&TreeError{Path: Path{{FromTree: treeID, ToMaxKey: btrfsprim.MaxKey}}, Err: err}) return } fs.RawTreeWalk(ctx, *rootInfo, errHandle, cbs) @@ -39,7 +39,7 @@ func (fs TreeOperatorImpl) TreeWalk(ctx context.Context, treeID btrfsprim.ObjID, // RawTreeWalk is a utility method to help with implementing the // 'TreeOperator' interface. func (fs TreeOperatorImpl) RawTreeWalk(ctx context.Context, rootInfo TreeRoot, errHandle func(*TreeError), cbs TreeWalkHandler) { - path := TreePath{{ + path := Path{{ FromTree: rootInfo.TreeID, FromItemSlot: -1, ToNodeAddr: rootInfo.RootNode, @@ -50,7 +50,7 @@ func (fs TreeOperatorImpl) RawTreeWalk(ctx context.Context, rootInfo TreeRoot, e fs.treeWalk(ctx, path, errHandle, cbs) } -func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandle func(*TreeError), cbs TreeWalkHandler) { +func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path Path, errHandle func(*TreeError), cbs TreeWalkHandler) { if ctx.Err() != nil { return } @@ -100,7 +100,7 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl if i+1 < len(node.BodyInterior) { toMaxKey = node.BodyInterior[i+1].Key.Mm() } - itemPath := append(path, TreePathElem{ + itemPath := append(path, PathElem{ FromTree: node.Head.Owner, FromItemSlot: i, ToNodeAddr: item.BlockPtr, @@ -128,7 +128,7 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl } } for i, item := range node.BodyLeaf { - itemPath := append(path, TreePathElem{ + itemPath := append(path, PathElem{ FromTree: node.Head.Owner, FromItemSlot: i, ToKey: item.Key, @@ -167,8 +167,8 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl } } -func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, uint32) int) (TreePath, *Node, error) { - path := TreePath{{ +func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, uint32) int) (Path, *Node, error) { + path := Path{{ FromTree: treeRoot.TreeID, FromItemSlot: -1, ToNodeAddr: treeRoot.RootNode, @@ -209,7 +209,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, if lastGood+1 < len(node.BodyInterior) { toMaxKey = node.BodyInterior[lastGood+1].Key.Mm() } - path = append(path, TreePathElem{ + path = append(path, PathElem{ FromTree: node.Head.Owner, FromItemSlot: lastGood, ToNodeAddr: node.BodyInterior[lastGood].BlockPtr, @@ -239,7 +239,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, node.Free() return nil, nil, ErrNoItem } - path = append(path, TreePathElem{ + path = append(path, PathElem{ FromTree: node.Head.Owner, FromItemSlot: slot, ToKey: node.BodyLeaf[slot].Key, @@ -250,7 +250,7 @@ func (fs TreeOperatorImpl) treeSearch(treeRoot TreeRoot, fn func(btrfsprim.Key, } } -func (fs TreeOperatorImpl) prev(path TreePath, node *Node) (TreePath, *Node, error) { +func (fs TreeOperatorImpl) prev(path Path, node *Node) (Path, *Node, error) { var err error path = path.DeepCopy() @@ -285,7 +285,7 @@ func (fs TreeOperatorImpl) prev(path TreePath, node *Node) (TreePath, *Node, err } } if node.Head.Level > 0 { - path = append(path, TreePathElem{ + path = append(path, PathElem{ FromTree: node.Head.Owner, FromItemSlot: len(node.BodyInterior) - 1, ToNodeAddr: node.BodyInterior[len(node.BodyInterior)-1].BlockPtr, @@ -295,7 +295,7 @@ func (fs TreeOperatorImpl) prev(path TreePath, node *Node) (TreePath, *Node, err ToMaxKey: path.Node(-1).ToMaxKey, }) } else { - path = append(path, TreePathElem{ + path = append(path, PathElem{ FromTree: node.Head.Owner, FromItemSlot: len(node.BodyLeaf) - 1, ToKey: node.BodyLeaf[len(node.BodyLeaf)-1].Key, @@ -315,7 +315,7 @@ func (fs TreeOperatorImpl) prev(path TreePath, node *Node) (TreePath, *Node, err return path, node, nil } -func (fs TreeOperatorImpl) next(path TreePath, node *Node) (TreePath, *Node, error) { +func (fs TreeOperatorImpl) next(path Path, node *Node) (Path, *Node, error) { var err error path = path.DeepCopy() @@ -373,7 +373,7 @@ func (fs TreeOperatorImpl) next(path TreePath, node *Node) (TreePath, *Node, err if len(node.BodyInterior) > 1 { toMaxKey = node.BodyInterior[1].Key.Mm() } - path = append(path, TreePathElem{ + path = append(path, PathElem{ FromTree: node.Head.Owner, FromItemSlot: 0, ToNodeAddr: node.BodyInterior[0].BlockPtr, @@ -383,7 +383,7 @@ func (fs TreeOperatorImpl) next(path TreePath, node *Node) (TreePath, *Node, err ToMaxKey: toMaxKey, }) } else { - path = append(path, TreePathElem{ + path = append(path, PathElem{ FromTree: node.Head.Owner, FromItemSlot: 0, ToKey: node.BodyInterior[0].Key, diff --git a/lib/btrfs/btrfstree/path.go b/lib/btrfs/btrfstree/path.go index b9ab5bc..c07d8a0 100644 --- a/lib/btrfs/btrfstree/path.go +++ b/lib/btrfs/btrfstree/path.go @@ -13,7 +13,7 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) -// TreePath is a path from the superblock (i.e. the root of the btrfs +// Path is a path from the superblock (i.e. the root of the btrfs // system) to the a node or item within one of the btrees in the // system. // @@ -61,10 +61,10 @@ import ( // | <--------------- pathElem={from_tree:A, from_slot:1, // | to_addr:0, to_gen: 0, to_lvl:0} // [item] -type TreePath []TreePathElem +type Path []PathElem -// A TreePathElem essentially represents a KeyPointer. -type TreePathElem struct { +// A PathElem essentially represents a KeyPointer. +type PathElem struct { // FromTree is the owning tree ID of the parent node; or the // well-known tree ID if this is the root. FromTree btrfsprim.ObjID @@ -94,17 +94,17 @@ type TreePathElem struct { ToMaxKey btrfsprim.Key } -func (elem TreePathElem) writeNodeTo(w io.Writer) { +func (elem PathElem) writeNodeTo(w io.Writer) { fmt.Fprintf(w, "node:%d@%v", elem.ToNodeLevel, elem.ToNodeAddr) } -func (path TreePath) String() string { +func (path Path) String() string { if len(path) == 0 { return "(empty-path)" } var ret strings.Builder fmt.Fprintf(&ret, "%s->", path[0].FromTree.Format(btrfsprim.ROOT_TREE_OBJECTID)) - if len(path) == 1 && path[0] == (TreePathElem{FromTree: path[0].FromTree, FromItemSlot: -1}) { + if len(path) == 1 && path[0] == (PathElem{FromTree: path[0].FromTree, FromItemSlot: -1}) { ret.WriteString("(empty-path)") } else { path[0].writeNodeTo(&ret) @@ -119,11 +119,11 @@ func (path TreePath) String() string { return ret.String() } -func (path TreePath) DeepCopy() TreePath { - return append(TreePath(nil), path...) +func (path Path) DeepCopy() Path { + return append(Path(nil), path...) } -func (path TreePath) Parent() TreePath { +func (path Path) Parent() Path { return path[:len(path)-1] } @@ -131,7 +131,7 @@ func (path TreePath) Parent() TreePath { // `&path[x]`, but negative values of x move down from the end of path // (similar to how lists work in many other languages, such as // Python). -func (path TreePath) Node(x int) *TreePathElem { +func (path Path) Node(x int) *PathElem { if x < 0 { x += len(path) } diff --git a/lib/btrfs/btrfstree/readnode.go b/lib/btrfs/btrfstree/readnode.go index 1c242ac..c5d9145 100644 --- a/lib/btrfs/btrfstree/readnode.go +++ b/lib/btrfs/btrfstree/readnode.go @@ -33,7 +33,7 @@ type NodeFile interface { // 'NodeSource' interface. func FSReadNode( fs NodeFile, - path TreePath, + path Path, ) (*Node, error) { sb, err := fs.Superblock() if err != nil { -- cgit v1.2.3-2-g168b From 33de7f09d31063ef2a4380bb2f2692653a6de06c Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Thu, 9 Mar 2023 16:43:39 -0700 Subject: containers: Add OptionalValue and OptionalNil --- lib/btrfs/btrfstree/readnode.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib/btrfs/btrfstree') diff --git a/lib/btrfs/btrfstree/readnode.go b/lib/btrfs/btrfstree/readnode.go index c5d9145..c2e3b0f 100644 --- a/lib/btrfs/btrfstree/readnode.go +++ b/lib/btrfs/btrfstree/readnode.go @@ -63,11 +63,11 @@ func FSReadNode( } return ReadNode[btrfsvol.LogicalAddr](fs, *sb, path.Node(-1).ToNodeAddr, NodeExpectations{ - LAddr: containers.Optional[btrfsvol.LogicalAddr]{OK: true, Val: path.Node(-1).ToNodeAddr}, - Level: containers.Optional[uint8]{OK: true, Val: path.Node(-1).ToNodeLevel}, - Generation: containers.Optional[btrfsprim.Generation]{OK: true, Val: path.Node(-1).ToNodeGeneration}, + LAddr: containers.OptionalValue(path.Node(-1).ToNodeAddr), + Level: containers.OptionalValue(path.Node(-1).ToNodeLevel), + Generation: containers.OptionalValue(path.Node(-1).ToNodeGeneration), Owner: checkOwner, - MinItem: containers.Optional[btrfsprim.Key]{OK: true, Val: path.Node(-1).ToKey}, - MaxItem: containers.Optional[btrfsprim.Key]{OK: true, Val: path.Node(-1).ToMaxKey}, + MinItem: containers.OptionalValue(path.Node(-1).ToKey), + MaxItem: containers.OptionalValue(path.Node(-1).ToMaxKey), }) } -- cgit v1.2.3-2-g168b