diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2023-04-16 14:22:34 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2023-04-16 14:22:34 -0600 |
commit | 4adcf5f67965bf355cc7e16ec11e2293c2506700 (patch) | |
tree | 951abfa0b0bd9cb98c2bfe25b7f3e973d6abf960 /lib | |
parent | c2c6fa42233cd3911b81bb9449329816f645cec5 (diff) | |
parent | 2300adb18820d09f73746f00df0e64ccbba25052 (diff) |
Merge branch 'lukeshu/rebuilt-misc'
Diffstat (limited to 'lib')
-rw-r--r-- | lib/btrfsutil/rebuilt_callbacks.go | 28 | ||||
-rw-r--r-- | lib/btrfsutil/rebuilt_forrest.go | 24 | ||||
-rw-r--r-- | lib/btrfsutil/rebuilt_readitem.go | 5 | ||||
-rw-r--r-- | lib/btrfsutil/rebuilt_tree.go | 97 |
4 files changed, 76 insertions, 78 deletions
diff --git a/lib/btrfsutil/rebuilt_callbacks.go b/lib/btrfsutil/rebuilt_callbacks.go index fdc826c..0b51d08 100644 --- a/lib/btrfsutil/rebuilt_callbacks.go +++ b/lib/btrfsutil/rebuilt_callbacks.go @@ -10,6 +10,7 @@ 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/btrfstree" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" ) @@ -25,34 +26,25 @@ type RebuiltForrestExtendedCallbacks interface { } type noopRebuiltForrestCallbacks struct { - forrest *RebuiltForrest + forrest btrfstree.Forrest } func (noopRebuiltForrestCallbacks) AddedRoot(context.Context, btrfsprim.ObjID, btrfsvol.LogicalAddr) { } func (cb noopRebuiltForrestCallbacks) LookupRoot(ctx context.Context, tree btrfsprim.ObjID) (offset btrfsprim.Generation, _item btrfsitem.Root, ok bool) { - rootTree, err := cb.forrest.RebuiltTree(ctx, btrfsprim.ROOT_TREE_OBJECTID) + rootTree, err := cb.forrest.ForrestLookup(ctx, btrfsprim.ROOT_TREE_OBJECTID) if err != nil { return 0, btrfsitem.Root{}, false } - tgt := btrfsprim.Key{ - ObjectID: tree, - ItemType: btrfsprim.ROOT_ITEM_KEY, - } - itemKey, itemPtr, ok := rootTree.RebuiltAcquireItems(ctx).Search(func(key btrfsprim.Key, _ ItemPtr) int { - key.Offset = 0 - return tgt.Compare(key) - }) - rootTree.RebuiltReleaseItems() - if !ok { + item, err := rootTree.TreeSearch(ctx, btrfstree.SearchRootItem(tree)) + if err != nil { return 0, btrfsitem.Root{}, false } - item := cb.forrest.readItem(ctx, itemPtr) defer item.Body.Free() switch itemBody := item.Body.(type) { case *btrfsitem.Root: - return btrfsprim.Generation(itemKey.Offset), *itemBody, true + return btrfsprim.Generation(item.Key.Offset), *itemBody, true case *btrfsitem.Error: return 0, btrfsitem.Root{}, false default: @@ -63,17 +55,15 @@ func (cb noopRebuiltForrestCallbacks) LookupRoot(ctx context.Context, tree btrfs } func (cb noopRebuiltForrestCallbacks) LookupUUID(ctx context.Context, uuid btrfsprim.UUID) (id btrfsprim.ObjID, ok bool) { - uuidTree, err := cb.forrest.RebuiltTree(ctx, btrfsprim.UUID_TREE_OBJECTID) + uuidTree, err := cb.forrest.ForrestLookup(ctx, btrfsprim.UUID_TREE_OBJECTID) if err != nil { return 0, false } tgt := btrfsitem.UUIDToKey(uuid) - itemPtr, ok := uuidTree.RebuiltAcquireItems(ctx).Load(tgt) - uuidTree.RebuiltReleaseItems() - if !ok { + item, err := uuidTree.TreeLookup(ctx, tgt) + if err != nil { return 0, false } - item := cb.forrest.readItem(ctx, itemPtr) defer item.Body.Free() switch itemBody := item.Body.(type) { case *btrfsitem.UUIDMap: diff --git a/lib/btrfsutil/rebuilt_forrest.go b/lib/btrfsutil/rebuilt_forrest.go index b935d85..019d824 100644 --- a/lib/btrfsutil/rebuilt_forrest.go +++ b/lib/btrfsutil/rebuilt_forrest.go @@ -124,6 +124,7 @@ func (ts *RebuiltForrest) RebuiltTree(ctx context.Context, treeID btrfsprim.ObjI if tree.rootErr != nil { return nil, tree.rootErr } + tree.initRoots(ctx) return tree, nil } @@ -156,27 +157,26 @@ func (ts *RebuiltForrest) rebuildTree(ctx context.Context, treeID btrfsprim.ObjI Roots: make(containers.Set[btrfsvol.LogicalAddr]), forrest: ts, } - var root btrfsvol.LogicalAddr switch treeID { case btrfsprim.ROOT_TREE_OBJECTID: - sb, _ := ts.inner.Superblock() - root = sb.RootTree + sb, _ := ts.Superblock() + ts.trees[treeID].Root = sb.RootTree case btrfsprim.CHUNK_TREE_OBJECTID: - sb, _ := ts.inner.Superblock() - root = sb.ChunkTree + sb, _ := ts.Superblock() + ts.trees[treeID].Root = sb.ChunkTree case btrfsprim.TREE_LOG_OBJECTID: - sb, _ := ts.inner.Superblock() - root = sb.LogTree + sb, _ := ts.Superblock() + ts.trees[treeID].Root = sb.LogTree case btrfsprim.BLOCK_GROUP_TREE_OBJECTID: - sb, _ := ts.inner.Superblock() - root = sb.BlockGroupRoot + sb, _ := ts.Superblock() + ts.trees[treeID].Root = sb.BlockGroupRoot default: rootOff, rootItem, ok := ts.cb.LookupRoot(ctx, treeID) if !ok { ts.trees[treeID].rootErr = btrfstree.ErrNoTree return } - root = rootItem.ByteNr + ts.trees[treeID].Root = rootItem.ByteNr ts.trees[treeID].UUID = rootItem.UUID if rootItem.ParentUUID != (btrfsprim.UUID{}) { ts.trees[treeID].ParentGen = rootOff @@ -197,10 +197,6 @@ func (ts *RebuiltForrest) rebuildTree(ctx context.Context, treeID btrfsprim.ObjI } } } - - if root != 0 { - ts.trees[treeID].RebuiltAddRoot(ctx, root) - } } func (ts *RebuiltForrest) flushNegativeCache(ctx context.Context) { diff --git a/lib/btrfsutil/rebuilt_readitem.go b/lib/btrfsutil/rebuilt_readitem.go index e5faa45..841b04a 100644 --- a/lib/btrfsutil/rebuilt_readitem.go +++ b/lib/btrfsutil/rebuilt_readitem.go @@ -35,7 +35,7 @@ func (ts *RebuiltForrest) readItem(ctx context.Context, ptr ItemPtr) btrfstree.I panic(fmt.Errorf("should not happen: btrfsutil.RebuiltForrest.readItem called for negative item slot: %v", ptr.Slot)) } - node, err := ts.inner.AcquireNode(ctx, ptr.Node, btrfstree.NodeExpectations{ + node, err := ts.AcquireNode(ctx, ptr.Node, btrfstree.NodeExpectations{ LAddr: containers.OptionalValue(ptr.Node), Level: containers.OptionalValue(graphInfo.Level), Generation: containers.OptionalValue(graphInfo.Generation), @@ -50,13 +50,12 @@ func (ts *RebuiltForrest) readItem(ctx context.Context, ptr ItemPtr) btrfstree.I MinItem: containers.OptionalValue(graphInfo.MinItem(ts.graph)), MaxItem: containers.OptionalValue(graphInfo.MaxItem(ts.graph)), }) - defer ts.inner.ReleaseNode(node) + defer ts.ReleaseNode(node) if err != nil { panic(fmt.Errorf("should not happen: i/o error: %w", err)) } items := node.BodyLeaf - if ptr.Slot >= len(items) { panic(fmt.Errorf("should not happen: btrfsutil.RebuiltForrest.readItem called for out-of-bounds item slot: slot=%v len=%v", ptr.Slot, len(items))) diff --git a/lib/btrfsutil/rebuilt_tree.go b/lib/btrfsutil/rebuilt_tree.go index 9ab0356..8d5921b 100644 --- a/lib/btrfsutil/rebuilt_tree.go +++ b/lib/btrfsutil/rebuilt_tree.go @@ -30,12 +30,15 @@ type RebuiltTree struct { ID btrfsprim.ObjID UUID btrfsprim.UUID + Root btrfsvol.LogicalAddr Parent *RebuiltTree ParentGen btrfsprim.Generation // offset of this tree's root item forrest *RebuiltForrest // mutable + initRootsOnce sync.Once + mu sync.RWMutex Roots containers.Set[btrfsvol.LogicalAddr] @@ -79,6 +82,14 @@ func makeRebuiltSharedCache(forrest *RebuiltForrest) rebuiltSharedCache { return ret } +func (tree *RebuiltTree) initRoots(ctx context.Context) { + tree.initRootsOnce.Do(func() { + if tree.Root != 0 { + tree.RebuiltAddRoot(ctx, tree.Root) + } + }) +} + // evictable member 1: .acquireNodeIndex() ///////////////////////////////////////////////////////////////////////////// type rebuiltRoots = map[btrfsvol.LogicalAddr]rebuiltPathInfo @@ -205,33 +216,31 @@ nextKP: } indexer.node(ctx, kp.FromNode, stack) - if len(indexer.nodeToRoots[kp.FromNode]) > 0 { - for root, rootInfo := range indexer.nodeToRoots[kp.FromNode] { - if kp.FromSlot+1 < len(indexer.tree.forrest.graph.EdgesFrom[kp.FromNode]) { - rootInfo.loMaxItem = indexer.tree.forrest.graph.EdgesFrom[kp.FromNode][kp.FromSlot+1].ToKey.Mm() - rootInfo.hiMaxItem = rootInfo.loMaxItem - } else { - // OK, now check the MaxItem expectation. - // - // We'll use the hiMaxItem, because it only needs to be - // valid in *one* of the paths to this node. - kpMaxItem := rootInfo.hiMaxItem - if kpMaxItem.Compare(nodeInfo.MaxItem(indexer.tree.forrest.graph)) < 0 { - continue nextKP - } - } - oldRootInfo, ok := roots[root] - if ok && rootInfo.loMaxItem.Compare(oldRootInfo.loMaxItem) > 0 { - rootInfo.loMaxItem = oldRootInfo.loMaxItem - } - if ok && rootInfo.hiMaxItem.Compare(oldRootInfo.hiMaxItem) < 0 { - rootInfo.hiMaxItem = oldRootInfo.hiMaxItem - } - if roots == nil { - roots = make(rebuiltRoots) + for root, rootInfo := range indexer.nodeToRoots[kp.FromNode] { + if kp.FromSlot+1 < len(indexer.tree.forrest.graph.EdgesFrom[kp.FromNode]) { + rootInfo.loMaxItem = indexer.tree.forrest.graph.EdgesFrom[kp.FromNode][kp.FromSlot+1].ToKey.Mm() + rootInfo.hiMaxItem = rootInfo.loMaxItem + } else { + // OK, now check the MaxItem expectation. + // + // We'll use the hiMaxItem, because it only needs to be + // valid in *one* of the paths to this node. + kpMaxItem := rootInfo.hiMaxItem + if kpMaxItem.Compare(nodeInfo.MaxItem(indexer.tree.forrest.graph)) < 0 { + continue nextKP } - roots[root] = rootInfo } + oldRootInfo, ok := roots[root] + if ok && rootInfo.loMaxItem.Compare(oldRootInfo.loMaxItem) > 0 { + rootInfo.loMaxItem = oldRootInfo.loMaxItem + } + if ok && rootInfo.hiMaxItem.Compare(oldRootInfo.hiMaxItem) < 0 { + rootInfo.hiMaxItem = oldRootInfo.hiMaxItem + } + if roots == nil { + roots = make(rebuiltRoots) + } + roots[root] = rootInfo } } if roots == nil { @@ -273,6 +282,10 @@ func (tree *RebuiltTree) isOwnerOK(owner btrfsprim.ObjID, gen btrfsprim.Generati // // When done with the map, call .RebuiltReleaseItems(). func (tree *RebuiltTree) RebuiltAcquireItems(ctx context.Context) *containers.SortedMap[btrfsprim.Key, ItemPtr] { + tree.initRoots(ctx) + tree.mu.RLock() + defer tree.mu.RUnlock() + return tree.forrest.incItems.Acquire(ctx, tree.ID) } @@ -290,6 +303,10 @@ func (tree *RebuiltTree) RebuiltReleaseItems() { // // When done with the map, call .RebuiltReleasePotentialItems(). func (tree *RebuiltTree) RebuiltAcquirePotentialItems(ctx context.Context) *containers.SortedMap[btrfsprim.Key, ItemPtr] { + tree.initRoots(ctx) + tree.mu.RLock() + defer tree.mu.RUnlock() + return tree.forrest.excItems.Acquire(ctx, tree.ID) } @@ -301,12 +318,12 @@ func (tree *RebuiltTree) RebuiltReleasePotentialItems() { func (tree *RebuiltTree) uncachedIncItems(ctx context.Context) containers.SortedMap[btrfsprim.Key, ItemPtr] { ctx = dlog.WithField(ctx, "btrfs.util.rebuilt-tree.index-inc-items", fmt.Sprintf("tree=%v", tree.ID)) - return tree.items(ctx, true) + return tree.uncachedItems(ctx, true) } func (tree *RebuiltTree) uncachedExcItems(ctx context.Context) containers.SortedMap[btrfsprim.Key, ItemPtr] { ctx = dlog.WithField(ctx, "btrfs.util.rebuilt-tree.index-exc-items", fmt.Sprintf("tree=%v", tree.ID)) - return tree.items(ctx, false) + return tree.uncachedItems(ctx, false) } type rebuiltItemStats struct { @@ -320,10 +337,7 @@ func (s rebuiltItemStats) String() string { s.Leafs, s.NumItems, s.NumDups) } -func (tree *RebuiltTree) items(ctx context.Context, inc bool) containers.SortedMap[btrfsprim.Key, ItemPtr] { - tree.mu.RLock() - defer tree.mu.RUnlock() - +func (tree *RebuiltTree) uncachedItems(ctx context.Context, inc bool) containers.SortedMap[btrfsprim.Key, ItemPtr] { var leafs []btrfsvol.LogicalAddr for node, roots := range tree.acquireNodeIndex(ctx).nodeToRoots { if tree.forrest.graph.Nodes[node].Level == 0 && maps.HaveAnyKeysInCommon(tree.Roots, roots) == inc { @@ -416,6 +430,7 @@ func (s rebuiltRootStats) String() string { func (tree *RebuiltTree) RebuiltAddRoot(ctx context.Context, rootNode btrfsvol.LogicalAddr) { tree.mu.Lock() defer tree.mu.Unlock() + ctx = dlog.WithField(ctx, "btrfs.util.rebuilt-tree.add-root", fmt.Sprintf("tree=%v rootNode=%v", tree.ID, rootNode)) dlog.Info(ctx, "adding root...") @@ -478,16 +493,6 @@ func (tree *RebuiltTree) RebuiltCOWDistance(parentID btrfsprim.ObjID) (dist int, } } -// ReadItem reads an item from a tree. -func (tree *RebuiltTree) ReadItem(ctx context.Context, key btrfsprim.Key) btrfsitem.Item { - ptr, ok := tree.RebuiltAcquireItems(ctx).Load(key) - tree.RebuiltReleaseItems() - if !ok { - panic(fmt.Errorf("should not happen: btrfsutil.RebuiltTree.ReadItem called for not-included key: %v", key)) - } - return tree.forrest.readItem(ctx, ptr).Body -} - // RebuiltLeafToRoots returns the list of potential roots (to pass to // .RebuiltAddRoot) that include a given leaf-node. func (tree *RebuiltTree) RebuiltLeafToRoots(ctx context.Context, leaf btrfsvol.LogicalAddr) containers.Set[btrfsvol.LogicalAddr] { @@ -495,8 +500,11 @@ func (tree *RebuiltTree) RebuiltLeafToRoots(ctx context.Context, leaf btrfsvol.L panic(fmt.Errorf("should not happen: (tree=%v).RebuiltLeafToRoots(leaf=%v): not a leaf", tree.ID, leaf)) } + + tree.initRoots(ctx) tree.mu.RLock() defer tree.mu.RUnlock() + ret := make(containers.Set[btrfsvol.LogicalAddr]) for root := range tree.acquireNodeIndex(ctx).nodeToRoots[leaf] { if tree.Roots.Has(root) { @@ -593,6 +601,7 @@ func (tree *RebuiltTree) TreeSubrange(ctx context.Context, // TreeWalk implements btrfstree.Tree. func (tree *RebuiltTree) TreeWalk(ctx context.Context, cbs btrfstree.TreeWalkHandler) { + tree.initRoots(ctx) tree.mu.RLock() defer tree.mu.RUnlock() @@ -651,7 +660,7 @@ func (walker *rebuiltWalker) walk(ctx context.Context, path btrfstree.Path) { } // 001 - nodeAddr, nodeExp, ok := path.NodeExpectations(ctx, true) + nodeAddr, nodeExp, ok := path.NodeExpectations(ctx, false) if !ok { panic(fmt.Errorf("should not happen: btrfsutil.rebuiltWalker.walk called with non-node path: %v", path)) @@ -677,6 +686,10 @@ func (walker *rebuiltWalker) walk(ctx context.Context, path btrfstree.Path) { } return } + if !maps.HaveAnyKeysInCommon(walker.tree.Roots, walker.nodeIndex.nodeToRoots[nodeAddr]) { + panic(fmt.Errorf("should not happen: node@%v is not in the tree, but did not error: path=%#v exp=%#v", + nodeAddr, path, nodeExp)) + } if walker.visited.Has(nodeAddr) { return } |