diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2023-03-15 11:09:35 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2023-03-15 11:09:35 -0600 |
commit | c2925f0f8a5d69369b43de0d2d201291fe5ed9d1 (patch) | |
tree | 996f557b23618650983146ff0e93e8204a8ff5d3 /lib/btrfsutil | |
parent | 9ff81649f425370bf3c1aee32542a784119947f8 (diff) | |
parent | bb9dafebfbf3bfd6ea111c88371844f3402f3f3f (diff) |
Merge branch 'lukeshu/misc'
Diffstat (limited to 'lib/btrfsutil')
-rw-r--r-- | lib/btrfsutil/graph.go | 34 | ||||
-rw-r--r-- | lib/btrfsutil/graph_loops.go | 21 | ||||
-rw-r--r-- | lib/btrfsutil/old_rebuilt_forrest.go | 92 | ||||
-rw-r--r-- | lib/btrfsutil/rebuilt_readitem.go | 22 | ||||
-rw-r--r-- | lib/btrfsutil/rebuilt_tree.go | 8 | ||||
-rw-r--r-- | lib/btrfsutil/skinny_paths.go | 38 |
6 files changed, 110 insertions, 105 deletions
diff --git a/lib/btrfsutil/graph.go b/lib/btrfsutil/graph.go index 8debe9d..09a17b4 100644 --- a/lib/btrfsutil/graph.go +++ b/lib/btrfsutil/graph.go @@ -27,20 +27,31 @@ type GraphNode struct { Level uint8 Generation btrfsprim.Generation Owner btrfsprim.ObjID - NumItems uint32 - MinItem btrfsprim.Key - MaxItem btrfsprim.Key Items []btrfsprim.Key } +func (n GraphNode) MinItem() btrfsprim.Key { + if len(n.Items) == 0 { + return btrfsprim.Key{} + } + return n.Items[0] +} + +func (n GraphNode) MaxItem() btrfsprim.Key { + if len(n.Items) == 0 { + return btrfsprim.Key{} + } + return n.Items[len(n.Items)-1] +} + func (n GraphNode) String() string { if reflect.ValueOf(n).IsZero() { return "{}" } return fmt.Sprintf(`{lvl:%v, gen:%v, tree:%v, cnt:%v, min:(%v,%v,%v), max:(%v,%v,%v)}`, - n.Level, n.Generation, n.Owner, n.NumItems, - n.MinItem.ObjectID, n.MinItem.ItemType, n.MinItem.Offset, - n.MaxItem.ObjectID, n.MaxItem.ItemType, n.MaxItem.Offset) + n.Level, n.Generation, n.Owner, len(n.Items), + n.MinItem().ObjectID, n.MinItem().ItemType, n.MinItem().Offset, + n.MaxItem().ObjectID, n.MaxItem().ItemType, n.MaxItem().Offset) } type GraphEdge struct { @@ -143,9 +154,6 @@ func (g Graph) InsertNode(nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.No Level: nodeRef.Data.Head.Level, Generation: nodeRef.Data.Head.Generation, Owner: nodeRef.Data.Head.Owner, - NumItems: nodeRef.Data.Head.NumItems, - MinItem: discardOK(nodeRef.Data.MinItem()), - MaxItem: discardOK(nodeRef.Data.MaxItem()), } if nodeRef.Data.Head.Level == 0 { @@ -175,8 +183,8 @@ func (g Graph) InsertNode(nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.No } } else { g.Nodes[nodeRef.Addr] = nodeData - kps := make([]GraphEdge, len(nodeRef.Data.BodyInternal)) - for i, kp := range nodeRef.Data.BodyInternal { + kps := make([]GraphEdge, len(nodeRef.Data.BodyInterior)) + for i, kp := range nodeRef.Data.BodyInterior { kps[i] = GraphEdge{ FromNode: nodeRef.Addr, FromItem: i, @@ -256,7 +264,3 @@ func (g Graph) FinalCheck(ctx context.Context, fs diskio.File[btrfsvol.LogicalAd return nil } - -func discardOK[T any](val T, _ bool) T { - return val -} diff --git a/lib/btrfsutil/graph_loops.go b/lib/btrfsutil/graph_loops.go index 3382705..b5690af 100644 --- a/lib/btrfsutil/graph_loops.go +++ b/lib/btrfsutil/graph_loops.go @@ -22,15 +22,15 @@ func (g Graph) renderNode(node btrfsvol.LogicalAddr) []string { fmt.Sprintf("{addr: %v,", node), fmt.Sprintf(" level: %v,", nodeData.Level), fmt.Sprintf(" gen: %v,", nodeData.Generation), - fmt.Sprintf(" num_items: %v,", nodeData.NumItems), + fmt.Sprintf(" num_items: %v,", len(nodeData.Items)), fmt.Sprintf(" min_item: {%d,%v,%d},", - nodeData.MinItem.ObjectID, - nodeData.MinItem.ItemType, - nodeData.MinItem.Offset), + nodeData.MinItem().ObjectID, + nodeData.MinItem().ItemType, + nodeData.MinItem().Offset), fmt.Sprintf(" max_item: {%d,%v,%d}}", - nodeData.MaxItem.ObjectID, - nodeData.MaxItem.ItemType, - nodeData.MaxItem.Offset), + nodeData.MaxItem().ObjectID, + nodeData.MaxItem().ItemType, + nodeData.MaxItem().Offset), } } else if nodeErr, ok := g.BadNodes[node]; ok { return []string{ @@ -120,11 +120,12 @@ func checkNodeExpectations(kp GraphEdge, toNode GraphNode) error { errs = append(errs, fmt.Errorf("kp.generation=%v != node.generation=%v", kp.ToGeneration, toNode.Generation)) } - if toNode.NumItems == 0 { + switch { + case len(toNode.Items) == 0: errs = append(errs, fmt.Errorf("node.num_items=0")) - } else if kp.ToKey != (btrfsprim.Key{}) && toNode.MinItem != kp.ToKey { + case kp.ToKey != (btrfsprim.Key{}) && toNode.MinItem() != kp.ToKey: errs = append(errs, fmt.Errorf("kp.key=%v != node.items[0].key=%v", - kp.ToKey, toNode.MinItem)) + kp.ToKey, toNode.MinItem())) } if len(errs) > 0 { return errs diff --git a/lib/btrfsutil/old_rebuilt_forrest.go b/lib/btrfsutil/old_rebuilt_forrest.go index 2386803..af2643a 100644 --- a/lib/btrfsutil/old_rebuilt_forrest.go +++ b/lib/btrfsutil/old_rebuilt_forrest.go @@ -153,40 +153,39 @@ func (bt *OldRebuiltForrest) RebuiltTree(treeID btrfsprim.ObjID) oldRebuiltTree } func (bt *OldRebuiltForrest) rawTreeWalk(root btrfstree.TreeRoot, cacheEntry oldRebuiltTree, walked *[]btrfsprim.Key) { - btrfstree.TreeOperatorImpl{NodeSource: bt.inner}.RawTreeWalk( - bt.ctx, - root, - func(err *btrfstree.TreeError) { - if len(err.Path) > 0 && err.Path.Node(-1).ToNodeAddr == 0 { - // This is a panic because on the filesystems I'm working with it more likely - // indicates a bug in my item parser than a problem with the filesystem. - panic(fmt.Errorf("TODO: error parsing item: %w", err)) + errHandle := func(err *btrfstree.TreeError) { + if len(err.Path) > 0 && err.Path.Node(-1).ToNodeAddr == 0 { + // This is a panic because on the filesystems I'm working with it more likely + // indicates a bug in my item parser than a problem with the filesystem. + panic(fmt.Errorf("TODO: error parsing item: %w", err)) + } + cacheEntry.Errors.Insert(oldRebuiltTreeError{ + Path: bt.arena.Deflate(err.Path), + Err: err.Err, + }) + } + + cbs := btrfstree.TreeWalkHandler{ + Item: func(path btrfstree.TreePath, item btrfstree.Item) error { + if cacheEntry.Items.Search(func(v oldRebuiltTreeValue) int { return item.Key.Compare(v.Key) }) != nil { + // This is a panic because I'm not really sure what the best way to + // handle this is, and so if this happens I want the program to crash + // and force me to figure out how to handle it. + panic(fmt.Errorf("dup key=%v in tree=%v", item.Key, root.TreeID)) } - cacheEntry.Errors.Insert(oldRebuiltTreeError{ - Path: bt.arena.Deflate(err.Path), - Err: err.Err, + cacheEntry.Items.Insert(oldRebuiltTreeValue{ + Path: bt.arena.Deflate(path), + Key: item.Key, + ItemSize: item.BodySize, }) + if walked != nil { + *walked = append(*walked, item.Key) + } + return nil }, - btrfstree.TreeWalkHandler{ - Item: func(path btrfstree.TreePath, item btrfstree.Item) error { - if cacheEntry.Items.Search(func(v oldRebuiltTreeValue) int { return item.Key.Compare(v.Key) }) != nil { - // This is a panic because I'm not really sure what the best way to - // handle this is, and so if this happens I want the program to crash - // and force me to figure out how to handle it. - panic(fmt.Errorf("dup key=%v in tree=%v", item.Key, root.TreeID)) - } - cacheEntry.Items.Insert(oldRebuiltTreeValue{ - Path: bt.arena.Deflate(path), - Key: item.Key, - ItemSize: item.BodySize, - }) - if walked != nil { - *walked = append(*walked, item.Key) - } - return nil - }, - }, - ) + } + + btrfstree.TreeOperatorImpl{NodeSource: bt.inner}.RawTreeWalk(bt.ctx, root, errHandle, cbs) } func (bt *OldRebuiltForrest) TreeLookup(treeID btrfsprim.ObjID, key btrfsprim.Key) (btrfstree.Item, error) { @@ -237,7 +236,7 @@ func (bt *OldRebuiltForrest) TreeSearch(treeID btrfsprim.ObjID, fn func(btrfspri return btrfstree.Item{}, bt.addErrs(tree, fn, err) } - item := node.Data.BodyLeaf[itemPath.Node(-1).FromItemIdx] + item := node.Data.BodyLeaf[itemPath.Node(-1).FromItemSlot] item.Body = item.Body.CloneItem() // Since we were only asked to return 1 item, it isn't @@ -275,7 +274,7 @@ func (bt *OldRebuiltForrest) TreeSearchAll(treeID btrfsprim.ObjID, fn func(btrfs return nil, bt.addErrs(tree, fn, err) } } - ret[i] = node.Data.BodyLeaf[itemPath.Node(-1).FromItemIdx] + ret[i] = node.Data.BodyLeaf[itemPath.Node(-1).FromItemSlot] ret[i].Body = ret[i].Body.CloneItem() } btrfstree.FreeNodeRef(node) @@ -295,6 +294,9 @@ func (bt *OldRebuiltForrest) TreeWalk(ctx context.Context, treeID btrfsprim.ObjI }) return } + if cbs.Item == nil { + return + } var node *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node] tree.Items.Range(func(indexItem *containers.RBNode[oldRebuiltTreeValue]) bool { if ctx.Err() != nil { @@ -303,23 +305,21 @@ func (bt *OldRebuiltForrest) TreeWalk(ctx context.Context, treeID btrfsprim.ObjI if bt.ctx.Err() != nil { return false } - if cbs.Item != nil { - itemPath := bt.arena.Inflate(indexItem.Value.Path) - if node == nil || node.Addr != itemPath.Node(-2).ToNodeAddr { - var err error + itemPath := bt.arena.Inflate(indexItem.Value.Path) + if node == nil || node.Addr != itemPath.Node(-2).ToNodeAddr { + var err error + btrfstree.FreeNodeRef(node) + node, err = bt.inner.ReadNode(itemPath.Parent()) + if err != nil { btrfstree.FreeNodeRef(node) - node, err = bt.inner.ReadNode(itemPath.Parent()) - if err != nil { - btrfstree.FreeNodeRef(node) - errHandle(&btrfstree.TreeError{Path: itemPath, Err: err}) - return true - } - } - item := node.Data.BodyLeaf[itemPath.Node(-1).FromItemIdx] - if err := cbs.Item(itemPath, item); err != nil { errHandle(&btrfstree.TreeError{Path: itemPath, Err: err}) + return true } } + item := node.Data.BodyLeaf[itemPath.Node(-1).FromItemSlot] + if err := cbs.Item(itemPath, item); err != nil { + errHandle(&btrfstree.TreeError{Path: itemPath, Err: err}) + } return true }) btrfstree.FreeNodeRef(node) diff --git a/lib/btrfsutil/rebuilt_readitem.go b/lib/btrfsutil/rebuilt_readitem.go index 57440cf..016299c 100644 --- a/lib/btrfsutil/rebuilt_readitem.go +++ b/lib/btrfsutil/rebuilt_readitem.go @@ -22,11 +22,11 @@ import ( type ItemPtr struct { Node btrfsvol.LogicalAddr - Idx int + Slot int } func (ptr ItemPtr) String() string { - return fmt.Sprintf("node@%v[%v]", ptr.Node, ptr.Idx) + return fmt.Sprintf("node@%v[%v]", ptr.Node, ptr.Slot) } type SizeAndErr struct { @@ -74,7 +74,7 @@ func (o *KeyIO) InsertNode(nodeRef *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.N for i, item := range nodeRef.Data.BodyLeaf { ptr := ItemPtr{ Node: nodeRef.Addr, - Idx: i, + Slot: i, } switch itemBody := item.Body.(type) { case *btrfsitem.Inode: @@ -141,8 +141,8 @@ func (o *KeyIO) readNode(ctx context.Context, laddr btrfsvol.LogicalAddr) *diski } return nil }, - MinItem: containers.Optional[btrfsprim.Key]{OK: true, Val: graphInfo.MinItem}, - MaxItem: containers.Optional[btrfsprim.Key]{OK: true, Val: graphInfo.MaxItem}, + MinItem: containers.Optional[btrfsprim.Key]{OK: true, Val: graphInfo.MinItem()}, + MaxItem: containers.Optional[btrfsprim.Key]{OK: true, Val: graphInfo.MaxItem()}, }) if err != nil { panic(fmt.Errorf("should not happen: i/o error: %w", err)) @@ -159,13 +159,13 @@ func (o *KeyIO) ReadItem(ctx context.Context, ptr ItemPtr) btrfsitem.Item { 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)) } - if ptr.Idx < 0 { - panic(fmt.Errorf("should not happen: btrfsutil.KeyIO.ReadItem called for negative item index: %v", ptr.Idx)) + if ptr.Slot < 0 { + panic(fmt.Errorf("should not happen: btrfsutil.KeyIO.ReadItem called for negative item slot: %v", ptr.Slot)) } items := o.readNode(ctx, ptr.Node).Data.BodyLeaf - if ptr.Idx >= len(items) { - panic(fmt.Errorf("should not happen: btrfsutil.KeyIO.ReadItem called for out-of-bounds item index: index=%v len=%v", - ptr.Idx, len(items))) + 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", + ptr.Slot, len(items))) } - return items[ptr.Idx].Body.CloneItem() + return items[ptr.Slot].Body.CloneItem() } diff --git a/lib/btrfsutil/rebuilt_tree.go b/lib/btrfsutil/rebuilt_tree.go index 1009204..3133a9e 100644 --- a/lib/btrfsutil/rebuilt_tree.go +++ b/lib/btrfsutil/rebuilt_tree.go @@ -33,7 +33,7 @@ type RebuiltTree struct { mu sync.RWMutex Roots containers.Set[btrfsvol.LogicalAddr] // There are 3 more mutable "members" that are protected by - // `mu`; but they live in a shared LRUcache. They are all + // `mu`; but they live in a shared ARCache. They are all // derived from tree.Roots, which is why it's OK if they get // evicted. // @@ -42,7 +42,7 @@ type RebuiltTree struct { // 3. tree.PotentialItems() = tree.forrest.excItems.Load(tree.ID) } -// LRU member 1: .leafToRoots() //////////////////////////////////////////////////////////////////////////////////////// +// evictable member 1: .leafToRoots() ////////////////////////////////////////////////////////////////////////////////// // leafToRoots returns all leafs (lvl=0) in the filesystem that pass // .isOwnerOK, whether or not they're in the tree. @@ -129,7 +129,7 @@ func (tree *RebuiltTree) isOwnerOK(owner btrfsprim.ObjID, gen btrfsprim.Generati } } -// LRU members 2 and 3: .Items() and .PotentialItems() ///////////////////////////////////////////////////////////////// +// evictable members 2 and 3: .Items() and .PotentialItems() /////////////////////////////////////////////////////////// // Items returns a map of the items contained in this tree. // @@ -192,7 +192,7 @@ func (tree *RebuiltTree) items(ctx context.Context, cache containers.Map[btrfspr for j, itemKey := range tree.forrest.graph.Nodes[leaf].Items { newPtr := ItemPtr{ Node: leaf, - Idx: j, + Slot: j, } if oldPtr, exists := index.Load(itemKey); !exists { index.Store(itemKey, newPtr) diff --git a/lib/btrfsutil/skinny_paths.go b/lib/btrfsutil/skinny_paths.go index 1695990..adf539b 100644 --- a/lib/btrfsutil/skinny_paths.go +++ b/lib/btrfsutil/skinny_paths.go @@ -39,8 +39,8 @@ func (a *SkinnyPathArena) init() { } } -func (a *SkinnyPathArena) getItem(parent btrfstree.TreePath, itemIdx int) (btrfstree.TreePathElem, error) { - if itemIdx < 0 { +func (a *SkinnyPathArena) getItem(parent btrfstree.TreePath, itemSlot int) (btrfstree.TreePathElem, error) { + if itemSlot < 0 { panic("should not happen") } @@ -48,7 +48,7 @@ func (a *SkinnyPathArena) getItem(parent btrfstree.TreePath, itemIdx int) (btrfs ret, ok := a.fatItems.Load(skinnyItem{ Node: parent.Node(-1).ToNodeAddr, - Item: itemIdx, + Item: itemSlot, }) if ok { return ret, nil @@ -60,17 +60,17 @@ func (a *SkinnyPathArena) getItem(parent btrfstree.TreePath, itemIdx int) (btrfs return btrfstree.TreePathElem{}, err } if node.Data.Head.Level > 0 { - if itemIdx >= len(node.Data.BodyInternal) { + if itemSlot >= len(node.Data.BodyInterior) { panic("should not happen") } - for i, item := range node.Data.BodyInternal { + for i, item := range node.Data.BodyInterior { toMaxKey := parent.Node(-1).ToMaxKey - if i+1 < len(node.Data.BodyInternal) { - toMaxKey = node.Data.BodyInternal[i+1].Key.Mm() + if i+1 < len(node.Data.BodyInterior) { + toMaxKey = node.Data.BodyInterior[i+1].Key.Mm() } elem := btrfstree.TreePathElem{ FromTree: node.Data.Head.Owner, - FromItemIdx: i, + FromItemSlot: i, ToNodeAddr: item.BlockPtr, ToNodeGeneration: item.Generation, ToNodeLevel: node.Data.Head.Level - 1, @@ -78,23 +78,23 @@ func (a *SkinnyPathArena) getItem(parent btrfstree.TreePath, itemIdx int) (btrfs ToMaxKey: toMaxKey, } a.fatItems.Store(skinnyItem{Node: parent.Node(-1).ToNodeAddr, Item: i}, elem) - if i == itemIdx { + if i == itemSlot { ret = elem } } } else { - if itemIdx >= len(node.Data.BodyLeaf) { + if itemSlot >= len(node.Data.BodyLeaf) { panic("should not happen") } for i, item := range node.Data.BodyLeaf { elem := btrfstree.TreePathElem{ - FromTree: node.Data.Head.Owner, - FromItemIdx: i, - ToKey: item.Key, - ToMaxKey: item.Key, + FromTree: node.Data.Head.Owner, + FromItemSlot: i, + ToKey: item.Key, + ToMaxKey: item.Key, } a.fatItems.Store(skinnyItem{Node: parent.Node(-1).ToNodeAddr, Item: i}, elem) - if i == itemIdx { + if i == itemSlot { ret = elem } } @@ -114,8 +114,8 @@ func (a *SkinnyPathArena) Deflate(fat btrfstree.TreePath) SkinnyPath { a.fatRoots[elem.ToNodeAddr] = elem ret.Root = elem.ToNodeAddr } else { - a.fatItems.Store(skinnyItem{Node: prevNode, Item: elem.FromItemIdx}, elem) - ret.Items = append(ret.Items, elem.FromItemIdx) + a.fatItems.Store(skinnyItem{Node: prevNode, Item: elem.FromItemSlot}, elem) + ret.Items = append(ret.Items, elem.FromItemSlot) } prevNode = elem.ToNodeAddr } @@ -134,8 +134,8 @@ func (a *SkinnyPathArena) Inflate(skinny SkinnyPath) btrfstree.TreePath { } ret = append(ret, root) - for _, itemIdx := range skinny.Items { - elem, err := a.getItem(ret, itemIdx) + for _, itemSlot := range skinny.Items { + elem, err := a.getItem(ret, itemSlot) if err != nil { panic(err) } |