From 1faafcd3809fe5b452a1a742137ca2cb7336aad6 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sun, 1 Jan 2023 17:39:11 -0700 Subject: lint: Turn on dupword --- lib/containers/rbtree.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib/containers') diff --git a/lib/containers/rbtree.go b/lib/containers/rbtree.go index e2d8f8a..17bb3e3 100644 --- a/lib/containers/rbtree.go +++ b/lib/containers/rbtree.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -65,9 +65,9 @@ func (node *RBNode[V]) walk(fn func(*RBNode[V]) error) error { } // Search the tree for a value that satisfied the given callbackk -// function. A return value of 0 means to to return this value; <0 -// means to go left on the tree (the value is too high), >0 means to -// go right on th etree (the value is too low). +// function. A return value of 0 means to return this value; <0 means +// to go left on the tree (the value is too high), >0 means to go +// right on th etree (the value is too low). // // +-----+ // | v=8 | == 0 : this is it @@ -287,6 +287,8 @@ func (t *RBTree[K, V]) leftRotate(x *RBNode[V]) { } func (t *RBTree[K, V]) rightRotate(y *RBNode[V]) { + //nolint:dupword + // // | | // +---+ +---+ // | y | | x | -- cgit v1.2.3-54-g00ecf From 493ec396fab32d9e8859e34ad497fdb0a910a33c Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sun, 1 Jan 2023 17:49:11 -0700 Subject: lint: Turn on forcetypeassert --- .golangci.yml | 1 - lib/binstruct/size.go | 3 +- lib/btrfs/btrfsitem/items.go | 3 +- lib/btrfs/io2_lv.go | 18 ++++-- lib/btrfs/io4_fs.go | 129 ++++++++++++++++++++++++++++--------------- lib/containers/lru.go | 5 +- lib/containers/set.go | 7 ++- lib/containers/syncmap.go | 6 +- lib/textui/progress.go | 1 + 9 files changed, 116 insertions(+), 57 deletions(-) (limited to 'lib/containers') diff --git a/.golangci.yml b/.golangci.yml index 7dd7f00..d5c6e53 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -27,7 +27,6 @@ linters: - cyclop - exhaustive - exhaustruct - - forcetypeassert - funlen - gci - gochecknoglobals diff --git a/lib/binstruct/size.go b/lib/binstruct/size.go index 365da85..52fa380 100644 --- a/lib/binstruct/size.go +++ b/lib/binstruct/size.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -30,6 +30,7 @@ var ( func staticSize(typ reflect.Type) (int, error) { if typ.Implements(staticSizerType) { + //nolint:forcetypeassert // Already did a type check via reflection. return reflect.New(typ).Elem().Interface().(StaticSizer).BinaryStaticSize(), nil } if typ.Implements(marshalerType) || typ.Implements(unmarshalerType) { diff --git a/lib/btrfs/btrfsitem/items.go b/lib/btrfs/btrfsitem/items.go index 29b3cb0..d300179 100644 --- a/lib/btrfs/btrfsitem/items.go +++ b/lib/btrfs/btrfsitem/items.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -79,5 +79,6 @@ func UnmarshalItem(key btrfsprim.Key, csumType btrfssum.CSumType, dat []byte) It key.ItemType, len(dat), n), } } + //nolint:forcetypeassert // items_gen.go has all types in keytype2gotype implement the Item interface. return retPtr.Elem().Interface().(Item) } diff --git a/lib/btrfs/io2_lv.go b/lib/btrfs/io2_lv.go index 5580285..3f82cd0 100644 --- a/lib/btrfs/io2_lv.go +++ b/lib/btrfs/io2_lv.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -171,10 +171,20 @@ func (fs *FS) initDev(ctx context.Context, sb btrfstree.Superblock) error { if item.Key.ItemType != btrfsitem.CHUNK_ITEM_KEY { return nil } - for _, mapping := range item.Body.(btrfsitem.Chunk).Mappings(item.Key) { - if err := fs.LV.AddMapping(mapping); err != nil { - return err + switch itemBody := item.Body.(type) { + case btrfsitem.Chunk: + for _, mapping := range itemBody.Mappings(item.Key) { + if err := fs.LV.AddMapping(mapping); err != nil { + return err + } } + case btrfsitem.Error: + // do nothing + default: + // This is a panic because the item decoder should not emit CHUNK_ITEM items as + // anything but btrfsitem.Chunk or btrfsitem.Error without this code also being + // updated. + panic(fmt.Errorf("should not happen: CHUNK_ITEM has unexpected item type: %T", itemBody)) } return nil }, diff --git a/lib/btrfs/io4_fs.go b/lib/btrfs/io4_fs.go index ea81bc2..d7c2770 100644 --- a/lib/btrfs/io4_fs.go +++ b/lib/btrfs/io4_fs.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -152,17 +152,29 @@ func (sv *Subvolume) LoadFullInode(inode btrfsprim.ObjID) (*FullInode, error) { for _, item := range items { switch item.Key.ItemType { case btrfsitem.INODE_ITEM_KEY: - itemBody := item.Body.(btrfsitem.Inode) - if val.InodeItem != nil { - if !reflect.DeepEqual(itemBody, *val.InodeItem) { - val.Errs = append(val.Errs, fmt.Errorf("multiple inodes")) + switch itemBody := item.Body.(type) { + case btrfsitem.Inode: + if val.InodeItem != nil { + if !reflect.DeepEqual(itemBody, *val.InodeItem) { + val.Errs = append(val.Errs, fmt.Errorf("multiple inodes")) + } + continue } - continue + val.InodeItem = &itemBody + case btrfsitem.Error: + val.Errs = append(val.Errs, fmt.Errorf("malformed INODE_ITEM: %w", itemBody.Err)) + default: + panic(fmt.Errorf("should not happen: INODE_ITEM has unexpected item type: %T", itemBody)) } - val.InodeItem = &itemBody case btrfsitem.XATTR_ITEM_KEY: - itemBody := item.Body.(btrfsitem.DirEntry) - val.XAttrs[string(itemBody.Name)] = string(itemBody.Data) + switch itemBody := item.Body.(type) { + case btrfsitem.DirEntry: + val.XAttrs[string(itemBody.Name)] = string(itemBody.Data) + case btrfsitem.Error: + val.Errs = append(val.Errs, fmt.Errorf("malformed XATTR_ITEM: %w", itemBody.Err)) + default: + panic(fmt.Errorf("should not happen: XATTR_ITEM has unexpected item type: %T", itemBody)) + } default: val.OtherItems = append(val.OtherItems, item) } @@ -200,48 +212,66 @@ func (ret *Dir) populate() { for _, item := range ret.OtherItems { switch item.Key.ItemType { case btrfsitem.INODE_REF_KEY: - body := item.Body.(btrfsitem.InodeRefs) - if len(body) != 1 { - ret.Errs = append(ret.Errs, fmt.Errorf("INODE_REF item with %d entries on a directory", - len(body))) - continue - } - ref := InodeRef{ - Inode: btrfsprim.ObjID(item.Key.Offset), - InodeRef: body[0], - } - if ret.DotDot != nil { - if !reflect.DeepEqual(ref, *ret.DotDot) { - ret.Errs = append(ret.Errs, fmt.Errorf("multiple INODE_REF items on a directory")) + switch body := item.Body.(type) { + case btrfsitem.InodeRefs: + if len(body) != 1 { + ret.Errs = append(ret.Errs, fmt.Errorf("INODE_REF item with %d entries on a directory", + len(body))) + continue + } + ref := InodeRef{ + Inode: btrfsprim.ObjID(item.Key.Offset), + InodeRef: body[0], } - continue + if ret.DotDot != nil { + if !reflect.DeepEqual(ref, *ret.DotDot) { + ret.Errs = append(ret.Errs, fmt.Errorf("multiple INODE_REF items on a directory")) + } + continue + } + ret.DotDot = &ref + case btrfsitem.Error: + ret.Errs = append(ret.Errs, fmt.Errorf("malformed INODE_REF: %w", body.Err)) + default: + panic(fmt.Errorf("should not happen: INODE_REF has unexpected item type: %T", body)) } - ret.DotDot = &ref case btrfsitem.DIR_ITEM_KEY: - entry := item.Body.(btrfsitem.DirEntry) - namehash := btrfsitem.NameHash(entry.Name) - if namehash != item.Key.Offset { - ret.Errs = append(ret.Errs, fmt.Errorf("direntry crc32c mismatch: key=%#x crc32c(%q)=%#x", - item.Key.Offset, entry.Name, namehash)) - continue - } - if other, exists := ret.ChildrenByName[string(entry.Name)]; exists { - if !reflect.DeepEqual(entry, other) { - ret.Errs = append(ret.Errs, fmt.Errorf("multiple instances of direntry name %q", entry.Name)) + switch entry := item.Body.(type) { + case btrfsitem.DirEntry: + namehash := btrfsitem.NameHash(entry.Name) + if namehash != item.Key.Offset { + ret.Errs = append(ret.Errs, fmt.Errorf("direntry crc32c mismatch: key=%#x crc32c(%q)=%#x", + item.Key.Offset, entry.Name, namehash)) + continue + } + if other, exists := ret.ChildrenByName[string(entry.Name)]; exists { + if !reflect.DeepEqual(entry, other) { + ret.Errs = append(ret.Errs, fmt.Errorf("multiple instances of direntry name %q", entry.Name)) + } + continue } - continue + ret.ChildrenByName[string(entry.Name)] = entry + case btrfsitem.Error: + ret.Errs = append(ret.Errs, fmt.Errorf("malformed DIR_ITEM: %w", entry.Err)) + default: + panic(fmt.Errorf("should not happen: DIR_ITEM has unexpected item type: %T", entry)) } - ret.ChildrenByName[string(entry.Name)] = entry case btrfsitem.DIR_INDEX_KEY: index := item.Key.Offset - entry := item.Body.(btrfsitem.DirEntry) - if other, exists := ret.ChildrenByIndex[index]; exists { - if !reflect.DeepEqual(entry, other) { - ret.Errs = append(ret.Errs, fmt.Errorf("multiple instances of direntry index %v", index)) + switch entry := item.Body.(type) { + case btrfsitem.DirEntry: + if other, exists := ret.ChildrenByIndex[index]; exists { + if !reflect.DeepEqual(entry, other) { + ret.Errs = append(ret.Errs, fmt.Errorf("multiple instances of direntry index %v", index)) + } + continue } - continue + ret.ChildrenByIndex[index] = entry + case btrfsitem.Error: + ret.Errs = append(ret.Errs, fmt.Errorf("malformed DIR_INDEX: %w", entry.Err)) + default: + panic(fmt.Errorf("should not happen: DIR_INDEX has unexpected item type: %T", entry)) } - ret.ChildrenByIndex[index] = entry default: panic(fmt.Errorf("TODO: handle item type %v", item.Key.ItemType)) } @@ -317,10 +347,17 @@ func (ret *File) populate() { case btrfsitem.INODE_REF_KEY: // TODO case btrfsitem.EXTENT_DATA_KEY: - ret.Extents = append(ret.Extents, FileExtent{ - OffsetWithinFile: int64(item.Key.Offset), - FileExtent: item.Body.(btrfsitem.FileExtent), - }) + switch itemBody := item.Body.(type) { + case btrfsitem.FileExtent: + ret.Extents = append(ret.Extents, FileExtent{ + OffsetWithinFile: int64(item.Key.Offset), + FileExtent: itemBody, + }) + case btrfsitem.Error: + ret.Errs = append(ret.Errs, fmt.Errorf("malformed EXTENT_DATA: %w", itemBody.Err)) + default: + panic(fmt.Errorf("should not happen: EXTENT_DATA has unexpected item type: %T", itemBody)) + } default: panic(fmt.Errorf("TODO: handle item type %v", item.Key.ItemType)) } diff --git a/lib/containers/lru.go b/lib/containers/lru.go index a235a12..12446b0 100644 --- a/lib/containers/lru.go +++ b/lib/containers/lru.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -44,6 +44,7 @@ func (c *LRUCache[K, V]) Get(key K) (value V, ok bool) { c.init() _value, ok := c.inner.Get(key) if ok { + //nolint:forcetypeassert // Typed wrapper around untyped lib. value = _value.(V) } return value, ok @@ -53,6 +54,7 @@ func (c *LRUCache[K, V]) Keys() []K { untyped := c.inner.Keys() typed := make([]K, len(untyped)) for i := range untyped { + //nolint:forcetypeassert // Typed wrapper around untyped lib. typed[i] = untyped[i].(K) } return typed @@ -65,6 +67,7 @@ func (c *LRUCache[K, V]) Peek(key K) (value V, ok bool) { c.init() _value, ok := c.inner.Peek(key) if ok { + //nolint:forcetypeassert // Typed wrapper around untyped lib. value = _value.(V) } return value, ok diff --git a/lib/containers/set.go b/lib/containers/set.go index 67ba7ac..4fc8aad 100644 --- a/lib/containers/set.go +++ b/lib/containers/set.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -22,7 +22,10 @@ var ( _ lowmemjson.Decodable = (*Set[int])(nil) ) -func cast[T any](x any) T { return x.(T) } +func cast[T any](x any) T { + //nolint:forcetypeassert // Only called within a type switch. + return x.(T) +} func (o Set[T]) EncodeJSON(w io.Writer) error { var less func(a, b T) bool diff --git a/lib/containers/syncmap.go b/lib/containers/syncmap.go index fb7f59b..4af678f 100644 --- a/lib/containers/syncmap.go +++ b/lib/containers/syncmap.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -18,6 +18,7 @@ func (m *SyncMap[K, V]) Delete(key K) { func (m *SyncMap[K, V]) Load(key K) (value V, ok bool) { _value, ok := m.inner.Load(key) if ok { + //nolint:forcetypeassert // Typed wrapper around untyped lib. value = _value.(V) } return value, ok @@ -25,17 +26,20 @@ func (m *SyncMap[K, V]) Load(key K) (value V, ok bool) { func (m *SyncMap[K, V]) LoadAndDelete(key K) (value V, loaded bool) { _value, ok := m.inner.LoadAndDelete(key) if ok { + //nolint:forcetypeassert // Typed wrapper around untyped lib. value = _value.(V) } return value, ok } func (m *SyncMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) { _actual, loaded := m.inner.LoadOrStore(key, value) + //nolint:forcetypeassert // Typed wrapper around untyped lib. actual = _actual.(V) return actual, loaded } func (m *SyncMap[K, V]) Range(f func(key K, value V) bool) { m.inner.Range(func(key, value any) bool { + //nolint:forcetypeassert // Typed wrapper around untyped lib. return f(key.(K), value.(V)) }) } diff --git a/lib/textui/progress.go b/lib/textui/progress.go index 56fda96..68d986f 100644 --- a/lib/textui/progress.go +++ b/lib/textui/progress.go @@ -56,6 +56,7 @@ func (p *Progress[T]) Done() { } func (p *Progress[T]) flush(force bool) { + //nolint:forcetypeassert // It wasn't worth it to me (yet?) to make a typed wrapper around atomic.Value. cur := p.cur.Load().(T) if !force && cur == p.oldStat { return -- cgit v1.2.3-54-g00ecf From c307e7048da3c02e1e540eab227def7fec7340cc Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sun, 1 Jan 2023 19:27:49 -0700 Subject: lint: Turn on gocritic --- .golangci.yml | 4 +- cmd/btrfs-rec/inspect_lstrees.go | 8 ++-- lib/btrfs/btrfstree/ops.go | 14 +++---- lib/btrfs/btrfstree/types_node.go | 9 ++-- lib/btrfs/btrfstree/types_node_test.go | 5 +-- lib/btrfs/btrfsvol/lvm.go | 8 ++-- lib/btrfsprogs/btrfsinspect/mount.go | 4 +- lib/btrfsprogs/btrfsinspect/print_tree.go | 48 +++++++++++----------- .../btrfsinspect/rebuildmappings/fuzzymatchsums.go | 11 ++--- .../btrfsinspect/rebuildnodes/rebuild.go | 4 +- .../btrfsinspect/rebuildnodes/rebuild_graph.go | 14 +++---- lib/containers/intervaltree.go | 4 +- lib/containers/rbtree.go | 7 ++-- lib/containers/rbtree_test.go | 10 +---- 14 files changed, 72 insertions(+), 78 deletions(-) (limited to 'lib/containers') diff --git a/.golangci.yml b/.golangci.yml index ad53616..953b512 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -31,7 +31,6 @@ linters: - gochecknoglobals - gochecknoinits - gocognit - - gocritic - gocyclo - godot - godox @@ -67,6 +66,9 @@ linters-settings: - standard - default - prefix(git.lukeshu.com/btrfs-progs-ng) + gocritic: + disabled-checks: + - appendAssign gofmt: simplify: true nolintlint: diff --git a/cmd/btrfs-rec/inspect_lstrees.go b/cmd/btrfs-rec/inspect_lstrees.go index e92c544..a6d86eb 100644 --- a/cmd/btrfs-rec/inspect_lstrees.go +++ b/cmd/btrfs-rec/inspect_lstrees.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -79,12 +79,12 @@ func init() { }, Item: func(_ btrfstree.TreePath, item btrfstree.Item) error { typ := item.Key.ItemType - treeItemCnt[typ] = treeItemCnt[typ] + 1 + treeItemCnt[typ]++ return nil }, BadItem: func(_ btrfstree.TreePath, item btrfstree.Item) error { typ := item.Key.ItemType - treeItemCnt[typ] = treeItemCnt[typ] + 1 + treeItemCnt[typ]++ return nil }, }, @@ -113,7 +113,7 @@ func init() { } for _, item := range node.Data.BodyLeaf { typ := item.Key.ItemType - treeItemCnt[typ] = treeItemCnt[typ] + 1 + treeItemCnt[typ]++ } } } diff --git a/lib/btrfs/btrfstree/ops.go b/lib/btrfs/btrfstree/ops.go index f2eb6f0..ddab630 100644 --- a/lib/btrfs/btrfstree/ops.go +++ b/lib/btrfs/btrfstree/ops.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -156,14 +156,12 @@ func (fs TreeOperatorImpl) treeWalk(ctx context.Context, path TreePath, errHandl } if err != nil { errHandle(&TreeError{Path: path, Err: err}) - } else { - if cbs.Node != nil { - if err := cbs.Node(path, node); err != nil { - if errors.Is(err, iofs.SkipDir) { - return - } - errHandle(&TreeError{Path: path, Err: err}) + } else if cbs.Node != nil { + if err := cbs.Node(path, node); err != nil { + if errors.Is(err, iofs.SkipDir) { + return } + errHandle(&TreeError{Path: path, Err: err}) } } if ctx.Err() != nil { diff --git a/lib/btrfs/btrfstree/types_node.go b/lib/btrfs/btrfstree/types_node.go index 299c433..d2e91de 100644 --- a/lib/btrfs/btrfstree/types_node.go +++ b/lib/btrfs/btrfstree/types_node.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -212,10 +212,11 @@ func (node Node) MarshalBinary() ([]byte, error) { if bs, err := binstruct.Marshal(node.Head); err != nil { return buf, err - } else if len(bs) != binstruct.StaticSize(NodeHeader{}) { - return nil, fmt.Errorf("header is %v bytes but expected %v", - len(bs), binstruct.StaticSize(NodeHeader{})) } else { + if len(bs) != binstruct.StaticSize(NodeHeader{}) { + return nil, fmt.Errorf("header is %v bytes but expected %v", + len(bs), binstruct.StaticSize(NodeHeader{})) + } copy(buf, bs) } diff --git a/lib/btrfs/btrfstree/types_node_test.go b/lib/btrfs/btrfstree/types_node_test.go index 040b90c..80855d8 100644 --- a/lib/btrfs/btrfstree/types_node_test.go +++ b/lib/btrfs/btrfstree/types_node_test.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -23,13 +23,12 @@ func FuzzRoundTripNode(f *testing.F) { n, err := binstruct.Unmarshal(inDat, &node) if err != nil { t.Logf("err=%v", err) - //require.Equal(t, 0, n) } else { require.Equal(t, len(inDat), n) outDat, err := binstruct.Marshal(node) require.NoError(t, err) - require.Equal(t, inDat[:], outDat) + require.Equal(t, inDat, outDat) } }) } diff --git a/lib/btrfs/btrfsvol/lvm.go b/lib/btrfs/btrfsvol/lvm.go index c7551fc..605524b 100644 --- a/lib/btrfs/btrfsvol/lvm.go +++ b/lib/btrfs/btrfsvol/lvm.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -335,10 +335,8 @@ func (lv *LogicalVolume[PhysicalVolume]) maybeShortReadAt(dat []byte, laddr Logi } if first { copy(dat, buf) - } else { - if !bytes.Equal(dat, buf) { - return 0, fmt.Errorf("inconsistent stripes at laddr=%v len=%v", laddr, len(dat)) - } + } else if !bytes.Equal(dat, buf) { + return 0, fmt.Errorf("inconsistent stripes at laddr=%v len=%v", laddr, len(dat)) } } return len(dat), nil diff --git a/lib/btrfsprogs/btrfsinspect/mount.go b/lib/btrfsprogs/btrfsinspect/mount.go index 2a0b232..29193cb 100644 --- a/lib/btrfsprogs/btrfsinspect/mount.go +++ b/lib/btrfsprogs/btrfsinspect/mount.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -213,7 +213,7 @@ func (sv *subvolume) StatFS(_ context.Context, op *fuseops.StatFSOp) error { op.IoSize = sb.SectorSize op.BlockSize = sb.SectorSize op.Blocks = sb.TotalBytes / uint64(sb.SectorSize) // TODO: adjust for RAID type - //op.BlocksFree = TODO + // op.BlocksFree = TODO // btrfs doesn't have a fixed number of inodes op.Inodes = 0 diff --git a/lib/btrfsprogs/btrfsinspect/print_tree.go b/lib/btrfsprogs/btrfsinspect/print_tree.go index 6c31350..62d1d7b 100644 --- a/lib/btrfsprogs/btrfsinspect/print_tree.go +++ b/lib/btrfsprogs/btrfsinspect/print_tree.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -142,8 +142,8 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri textui.Fprintf(out, "\t\tindex %v namelen %v name: %s\n", ref.Index, ref.NameLen, ref.Name) } - //case btrfsitem.INODE_EXTREF_KEY: - // // TODO + // case btrfsitem.INODE_EXTREF_KEY: + // // TODO case btrfsitem.DirEntry: textui.Fprintf(out, "\t\tlocation %v type %v\n", fmtKey(body.Location), body.Type) @@ -153,8 +153,8 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri if len(body.Data) > 0 { textui.Fprintf(out, "\t\tdata %v\n", body.Data) } - //case btrfsitem.DIR_LOG_INDEX_KEY, btrfsitem.DIR_LOG_ITEM_KEY: - // // TODO + // case btrfsitem.DIR_LOG_INDEX_KEY, btrfsitem.DIR_LOG_ITEM_KEY: + // // TODO case btrfsitem.Root: textui.Fprintf(out, "\t\tgeneration %v root_dirid %v bytenr %d byte_limit %v bytes_used %v\n", body.Generation, body.RootDirID, body.ByteNr, body.ByteLimit, body.BytesUsed) @@ -200,10 +200,10 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri body.Head.Refs, body.Head.Generation, body.Head.Flags) textui.Fprintf(out, "\t\ttree block skinny level %v\n", item.Key.Offset) printExtentInlineRefs(out, body.Refs) - //case btrfsitem.EXTENT_DATA_REF_KEY: - // // TODO - //case btrfsitem.SHARED_DATA_REF_KEY: - // // TODO + // case btrfsitem.EXTENT_DATA_REF_KEY: + // // TODO + // case btrfsitem.SHARED_DATA_REF_KEY: + // // TODO case btrfsitem.ExtentCSum: start := btrfsvol.LogicalAddr(item.Key.Offset) textui.Fprintf(out, "\t\trange start %d end %d length %d", @@ -291,16 +291,16 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri "\t\tchunk_tree_uuid %v\n", body.ChunkTree, body.ChunkObjectID, body.ChunkOffset, body.Length, body.ChunkTreeUUID) - //case btrfsitem.QGROUP_STATUS_KEY: - // // TODO - //case btrfsitem.QGROUP_INFO_KEY: - // // TODO - //case btrfsitem.QGROUP_LIMIT_KEY: - // // TODO + // case btrfsitem.QGROUP_STATUS_KEY: + // // TODO + // case btrfsitem.QGROUP_INFO_KEY: + // // TODO + // case btrfsitem.QGROUP_LIMIT_KEY: + // // TODO case btrfsitem.UUIDMap: textui.Fprintf(out, "\t\tsubvol_id %d\n", body.ObjID) - //case btrfsitem.STRING_ITEM_KEY: - // // TODO + // case btrfsitem.STRING_ITEM_KEY: + // // TODO case btrfsitem.DevStats: textui.Fprintf(out, "\t\tpersistent item objectid %v offset %v\n", item.Key.ObjectID.Format(item.Key.ItemType), item.Key.Offset) @@ -316,8 +316,8 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri default: textui.Fprintf(out, "\t\tunknown persistent item objectid %v\n", item.Key.ObjectID) } - //case btrfsitem.TEMPORARY_ITEM_KEY: - // // TODO + // case btrfsitem.TEMPORARY_ITEM_KEY: + // // TODO case btrfsitem.Empty: switch item.Key.ItemType { case btrfsitem.ORPHAN_ITEM_KEY: // 48 @@ -330,10 +330,10 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfspri textui.Fprintf(out, "\t\tfree space extent\n") case btrfsitem.QGROUP_RELATION_KEY: // 246 // do nothing - //case btrfsitem.EXTENT_REF_V0_KEY: - // textui.Fprintf(out, "\t\textent ref v0 (deprecated)\n") - //case btrfsitem.CSUM_ITEM_KEY: - // textui.Fprintf(out, "\t\tcsum item\n") + // case btrfsitem.EXTENT_REF_V0_KEY: + // textui.Fprintf(out, "\t\textent ref v0 (deprecated)\n") + // case btrfsitem.CSUM_ITEM_KEY: + // textui.Fprintf(out, "\t\tcsum item\n") default: textui.Fprintf(out, "\t\t(error) unhandled empty item type: %v\n", item.Key.ItemType) } @@ -426,7 +426,7 @@ func fmtKey(key btrfsprim.Key) string { var out strings.Builder textui.Fprintf(&out, "key (%v %v", key.ObjectID.Format(key.ItemType), key.ItemType) switch key.ItemType { - case btrfsitem.QGROUP_RELATION_KEY: //TODO, btrfsitem.QGROUP_INFO_KEY, btrfsitem.QGROUP_LIMIT_KEY: + case btrfsitem.QGROUP_RELATION_KEY: // TODO, btrfsitem.QGROUP_INFO_KEY, btrfsitem.QGROUP_LIMIT_KEY: panic("TODO: printing qgroup items not yet implemented") case btrfsitem.UUID_SUBVOL_KEY, btrfsitem.UUID_RECEIVED_SUBVOL_KEY: textui.Fprintf(&out, " %#08x)", key.Offset) diff --git a/lib/btrfsprogs/btrfsinspect/rebuildmappings/fuzzymatchsums.go b/lib/btrfsprogs/btrfsinspect/rebuildmappings/fuzzymatchsums.go index ae83513..b1be7ba 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildmappings/fuzzymatchsums.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildmappings/fuzzymatchsums.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -78,7 +78,7 @@ func fuzzyMatchBlockGroupSums(ctx context.Context, Dev: paddr.Dev, Addr: paddr.Addr.Add(-off), } - matches[key] = matches[key] + 1 + matches[key]++ } return nil }); err != nil { @@ -145,11 +145,12 @@ type lowestN[T containers.Ordered[T]] struct { } func (l *lowestN[T]) Insert(v T) { - if len(l.Dat) < l.N { + switch { + case len(l.Dat) < l.N: l.Dat = append(l.Dat, v) - } else if v.Cmp(l.Dat[0]) < 0 { + case v.Cmp(l.Dat[0]) < 0: l.Dat[0] = v - } else { + default: return } sort.Slice(l.Dat, func(i, j int) bool { diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go index a7fe5c7..3057e75 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -317,7 +317,7 @@ func (o *rebuilder) resolveTreeAugments(ctx context.Context, listsWithDistances counts := make(map[btrfsvol.LogicalAddr]int) for _, list := range lists { for item := range list { - counts[item] = counts[item] + 1 + counts[item]++ } } diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go index df5ae71..bf4c95d 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild_graph.go @@ -112,13 +112,13 @@ func handleItem(o rebuildCallbacks, ctx context.Context, treeID btrfsprim.ObjID, case btrfsitem.Empty: // nothing case btrfsitem.Extent: - //if body.Head.Flags.Has(btrfsitem.EXTENT_FLAG_TREE_BLOCK) { - // // Supposedly this flag indicates that - // // body.Info.Key identifies a node by the - // // first key in the node. But nothing in the - // // kernel ever reads this, so who knows if it - // // always gets updated correctly? - //} + // if body.Head.Flags.Has(btrfsitem.EXTENT_FLAG_TREE_BLOCK) { + // // Supposedly this flag indicates that + // // body.Info.Key identifies a node by the + // // first key in the node. But nothing in the + // // kernel ever reads this, so who knows if it + // // always gets updated correctly? + // } for i, ref := range body.Refs { switch refBody := ref.Body.(type) { case nil: diff --git a/lib/containers/intervaltree.go b/lib/containers/intervaltree.go index 424b297..16bc916 100644 --- a/lib/containers/intervaltree.go +++ b/lib/containers/intervaltree.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -139,4 +139,4 @@ func (t *IntervalTree[K, V]) SearchAll(fn func(K) int) []V { return ret } -//func (t *IntervalTree[K, V]) Walk(fn func(*RBNode[V]) error) error +// TODO: func (t *IntervalTree[K, V]) Walk(fn func(*RBNode[V]) error) error diff --git a/lib/containers/rbtree.go b/lib/containers/rbtree.go index 17bb3e3..f922a7b 100644 --- a/lib/containers/rbtree.go +++ b/lib/containers/rbtree.go @@ -338,11 +338,12 @@ func (t *RBTree[K, V]) Insert(val V) { Parent: parent, Value: val, } - if parent == nil { + switch { + case parent == nil: t.root = node - } else if key.Cmp(t.KeyFn(parent.Value)) < 0 { + case key.Cmp(t.KeyFn(parent.Value)) < 0: parent.Left = node - } else { + default: parent.Right = node } t.updateAttr(node) diff --git a/lib/containers/rbtree_test.go b/lib/containers/rbtree_test.go index a487c52..e42410e 100644 --- a/lib/containers/rbtree_test.go +++ b/lib/containers/rbtree_test.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -39,13 +39,7 @@ func (node *RBNode[V]) asciiArt(w io.Writer, u, m, l string) { } node.Right.asciiArt(w, u+" ", u+" ,--", u+" | ") - - if node.Color == Red { - fmt.Fprintf(w, "%s%v\n", m, node) - } else { - fmt.Fprintf(w, "%s%v\n", m, node) - } - + fmt.Fprintf(w, "%s%v\n", m, node) node.Left.asciiArt(w, l+" | ", l+" `--", l+" ") } -- cgit v1.2.3-54-g00ecf From a06a7fb2d5bbf1ca5659de06fc9e975666bdcf9f Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sun, 1 Jan 2023 19:33:03 -0700 Subject: lint: Turn on gofumpt All edits to .go files are made by `tools/bin/golangci-lint run --fix ./...`, not by me as a human. --- .golangci.yml | 1 - lib/binstruct/binint/builtins.go | 12 ++++++++++++ lib/btrfs/btrfsitem/items.go | 1 - lib/btrfs/btrfssum/csum_test.go | 1 - lib/btrfs/btrfstree/ops.go | 2 +- lib/btrfs/btrfstree/types_node.go | 14 ++++++++++---- lib/btrfs/btrfsvol/lvm.go | 3 +++ lib/btrfs/io2_lv.go | 1 + lib/btrfs/io3_btree.go | 3 +++ lib/btrfs/io4_fs.go | 1 - lib/btrfsprogs/btrfsinspect/mount.go | 10 +++++++--- lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go | 2 ++ lib/containers/lru.go | 7 +++++++ lib/containers/syncmap.go | 5 +++++ lib/fmtutil/fmt.go | 3 ++- lib/textui/text.go | 4 +--- 16 files changed, 54 insertions(+), 16 deletions(-) (limited to 'lib/containers') diff --git a/.golangci.yml b/.golangci.yml index 953b512..edb8499 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -35,7 +35,6 @@ linters: - godot - godox - goerr113 - - gofumpt - gomnd - gomoddirectives - ireturn diff --git a/lib/binstruct/binint/builtins.go b/lib/binstruct/binint/builtins.go index 01186bc..e4be2a6 100644 --- a/lib/binstruct/binint/builtins.go +++ b/lib/binstruct/binint/builtins.go @@ -34,6 +34,7 @@ func (x U16le) MarshalBinary() ([]byte, error) { binary.LittleEndian.PutUint16(buf[:], uint16(x)) return buf[:], nil } + func (x *U16le) UnmarshalBinary(dat []byte) (int, error) { if err := binutil.NeedNBytes(dat, 2); err != nil { return 0, err @@ -50,6 +51,7 @@ func (x U32le) MarshalBinary() ([]byte, error) { binary.LittleEndian.PutUint32(buf[:], uint32(x)) return buf[:], nil } + func (x *U32le) UnmarshalBinary(dat []byte) (int, error) { if err := binutil.NeedNBytes(dat, 4); err != nil { return 0, err @@ -66,6 +68,7 @@ func (x U64le) MarshalBinary() ([]byte, error) { binary.LittleEndian.PutUint64(buf[:], uint64(x)) return buf[:], nil } + func (x *U64le) UnmarshalBinary(dat []byte) (int, error) { if err := binutil.NeedNBytes(dat, 8); err != nil { return 0, err @@ -84,6 +87,7 @@ func (x U16be) MarshalBinary() ([]byte, error) { binary.BigEndian.PutUint16(buf[:], uint16(x)) return buf[:], nil } + func (x *U16be) UnmarshalBinary(dat []byte) (int, error) { if err := binutil.NeedNBytes(dat, 2); err != nil { return 0, err @@ -100,6 +104,7 @@ func (x U32be) MarshalBinary() ([]byte, error) { binary.BigEndian.PutUint32(buf[:], uint32(x)) return buf[:], nil } + func (x *U32be) UnmarshalBinary(dat []byte) (int, error) { if err := binutil.NeedNBytes(dat, 4); err != nil { return 0, err @@ -116,6 +121,7 @@ func (x U64be) MarshalBinary() ([]byte, error) { binary.BigEndian.PutUint64(buf[:], uint64(x)) return buf[:], nil } + func (x *U64be) UnmarshalBinary(dat []byte) (int, error) { if err := binutil.NeedNBytes(dat, 8); err != nil { return 0, err @@ -148,6 +154,7 @@ func (x I16le) MarshalBinary() ([]byte, error) { binary.LittleEndian.PutUint16(buf[:], uint16(x)) return buf[:], nil } + func (x *I16le) UnmarshalBinary(dat []byte) (int, error) { if err := binutil.NeedNBytes(dat, 2); err != nil { return 0, err @@ -164,6 +171,7 @@ func (x I32le) MarshalBinary() ([]byte, error) { binary.LittleEndian.PutUint32(buf[:], uint32(x)) return buf[:], nil } + func (x *I32le) UnmarshalBinary(dat []byte) (int, error) { if err := binutil.NeedNBytes(dat, 4); err != nil { return 0, err @@ -180,6 +188,7 @@ func (x I64le) MarshalBinary() ([]byte, error) { binary.LittleEndian.PutUint64(buf[:], uint64(x)) return buf[:], nil } + func (x *I64le) UnmarshalBinary(dat []byte) (int, error) { if err := binutil.NeedNBytes(dat, 8); err != nil { return 0, err @@ -198,6 +207,7 @@ func (x I16be) MarshalBinary() ([]byte, error) { binary.BigEndian.PutUint16(buf[:], uint16(x)) return buf[:], nil } + func (x *I16be) UnmarshalBinary(dat []byte) (int, error) { if err := binutil.NeedNBytes(dat, 2); err != nil { return 0, err @@ -214,6 +224,7 @@ func (x I32be) MarshalBinary() ([]byte, error) { binary.BigEndian.PutUint32(buf[:], uint32(x)) return buf[:], nil } + func (x *I32be) UnmarshalBinary(dat []byte) (int, error) { if err := binutil.NeedNBytes(dat, 4); err != nil { return 0, err @@ -230,6 +241,7 @@ func (x I64be) MarshalBinary() ([]byte, error) { binary.BigEndian.PutUint64(buf[:], uint64(x)) return buf[:], nil } + func (x *I64be) UnmarshalBinary(dat []byte) (int, error) { if err := binutil.NeedNBytes(dat, 8); err != nil { return 0, err diff --git a/lib/btrfs/btrfsitem/items.go b/lib/btrfs/btrfsitem/items.go index d300179..67f96fa 100644 --- a/lib/btrfs/btrfsitem/items.go +++ b/lib/btrfs/btrfsitem/items.go @@ -70,7 +70,6 @@ func UnmarshalItem(key btrfsprim.Key, csumType btrfssum.CSumType, dat []byte) It Dat: dat, Err: fmt.Errorf("btrfsitem.UnmarshalItem({ItemType:%v}, dat): %w", key.ItemType, err), } - } if n < len(dat) { return Error{ diff --git a/lib/btrfs/btrfssum/csum_test.go b/lib/btrfs/btrfssum/csum_test.go index 5c17779..0a4aef6 100644 --- a/lib/btrfs/btrfssum/csum_test.go +++ b/lib/btrfs/btrfssum/csum_test.go @@ -22,7 +22,6 @@ func TestCSumFormat(t *testing.T) { } csum := btrfssum.CSum{0xbd, 0x7b, 0x41, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} testcases := map[string]TestCase{ - "s": {InputSum: csum, InputFmt: "%s", Output: "bd7b41f400000000000000000000000000000000000000000000000000000000"}, "x": {InputSum: csum, InputFmt: "%x", Output: "bd7b41f400000000000000000000000000000000000000000000000000000000"}, "v": {InputSum: csum, InputFmt: "%v", Output: "bd7b41f400000000000000000000000000000000000000000000000000000000"}, diff --git a/lib/btrfs/btrfstree/ops.go b/lib/btrfs/btrfstree/ops.go index ddab630..537773a 100644 --- a/lib/btrfs/btrfstree/ops.go +++ b/lib/btrfs/btrfstree/ops.go @@ -504,7 +504,7 @@ func (fs TreeOperatorImpl) TreeSearchAll(treeID btrfsprim.ObjID, fn func(btrfspr } middleItem := middleNode.Data.BodyLeaf[middlePath.Node(-1).FromItemIdx] - var ret = []Item{middleItem} + ret := []Item{middleItem} var errs derror.MultiError for prevPath, prevNode := middlePath, middleNode; true; { prevPath, prevNode, err = fs.prev(prevPath, prevNode) diff --git a/lib/btrfs/btrfstree/types_node.go b/lib/btrfs/btrfstree/types_node.go index d2e91de..b709d34 100644 --- a/lib/btrfs/btrfstree/types_node.go +++ b/lib/btrfs/btrfstree/types_node.go @@ -26,11 +26,13 @@ type NodeFlags uint64 func (NodeFlags) BinaryStaticSize() int { return 7 } + func (f NodeFlags) MarshalBinary() ([]byte, error) { var bs [8]byte binary.LittleEndian.PutUint64(bs[:], uint64(f)) return bs[:7], nil } + func (f *NodeFlags) UnmarshalBinary(dat []byte) (int, error) { var bs [8]byte copy(bs[:7], dat[:7]) @@ -418,9 +420,11 @@ func (e *IOError) Unwrap() error { return e.Err } // NodeError are ErrNotANode and *IOError. func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp NodeExpectations) (*diskio.Ref[Addr, Node], error) { if int(sb.NodeSize) < binstruct.StaticSize(NodeHeader{}) { - return nil, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, + return nil, &NodeError[Addr]{ + Op: "btrfstree.ReadNode", NodeAddr: addr, Err: fmt.Errorf("superblock.NodeSize=%v is too small to contain even a node header (%v bytes)", - sb.NodeSize, binstruct.StaticSize(NodeHeader{}))} + sb.NodeSize, binstruct.StaticSize(NodeHeader{})), + } } nodeBuf := make([]byte, sb.NodeSize) if _, err := fs.ReadAt(nodeBuf, addr); err != nil { @@ -456,9 +460,11 @@ func ReadNode[Addr ~int64](fs diskio.File[Addr], sb Superblock, addr Addr, exp N return nodeRef, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, Err: err} } if stored != calced { - return nodeRef, &NodeError[Addr]{Op: "btrfstree.ReadNode", NodeAddr: addr, + return nodeRef, &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)} + stored, calced), + } } // parse (main) diff --git a/lib/btrfs/btrfsvol/lvm.go b/lib/btrfs/btrfsvol/lvm.go index 605524b..1cb1ded 100644 --- a/lib/btrfs/btrfsvol/lvm.go +++ b/lib/btrfs/btrfsvol/lvm.go @@ -82,6 +82,7 @@ func (lv *LogicalVolume[PhysicalVolume]) Close() error { } return nil } + func (lv *LogicalVolume[PhysicalVolume]) AddPhysicalVolume(id DeviceID, dev PhysicalVolume) error { lv.init() if other, exists := lv.id2pv[id]; exists { @@ -121,9 +122,11 @@ type Mapping struct { func (lv *LogicalVolume[PhysicalVolume]) CouldAddMapping(m Mapping) bool { return lv.addMapping(m, true) == nil } + func (lv *LogicalVolume[PhysicalVolume]) AddMapping(m Mapping) error { return lv.addMapping(m, false) } + func (lv *LogicalVolume[PhysicalVolume]) addMapping(m Mapping, dryRun bool) error { lv.init() // sanity check diff --git a/lib/btrfs/io2_lv.go b/lib/btrfs/io2_lv.go index 3f82cd0..ac7ea70 100644 --- a/lib/btrfs/io2_lv.go +++ b/lib/btrfs/io2_lv.go @@ -70,6 +70,7 @@ func (fs *FS) Size() btrfsvol.LogicalAddr { func (fs *FS) ReadAt(p []byte, off btrfsvol.LogicalAddr) (int, error) { return fs.LV.ReadAt(p, off) } + func (fs *FS) WriteAt(p []byte, off btrfsvol.LogicalAddr) (int, error) { return fs.LV.WriteAt(p, off) } diff --git a/lib/btrfs/io3_btree.go b/lib/btrfs/io3_btree.go index b8c1a6d..8ec4b41 100644 --- a/lib/btrfs/io3_btree.go +++ b/lib/btrfs/io3_btree.go @@ -17,12 +17,15 @@ import ( func (fs *FS) TreeWalk(ctx context.Context, treeID btrfsprim.ObjID, errHandle func(*btrfstree.TreeError), cbs btrfstree.TreeWalkHandler) { btrfstree.TreeOperatorImpl{NodeSource: fs}.TreeWalk(ctx, treeID, errHandle, cbs) } + func (fs *FS) TreeLookup(treeID btrfsprim.ObjID, key btrfsprim.Key) (btrfstree.Item, error) { return btrfstree.TreeOperatorImpl{NodeSource: fs}.TreeLookup(treeID, key) } + func (fs *FS) TreeSearch(treeID btrfsprim.ObjID, fn func(key btrfsprim.Key, size uint32) int) (btrfstree.Item, error) { return btrfstree.TreeOperatorImpl{NodeSource: fs}.TreeSearch(treeID, fn) } + func (fs *FS) TreeSearchAll(treeID btrfsprim.ObjID, fn func(key btrfsprim.Key, size uint32) int) ([]btrfstree.Item, error) { return btrfstree.TreeOperatorImpl{NodeSource: fs}.TreeSearchAll(treeID, fn) } diff --git a/lib/btrfs/io4_fs.go b/lib/btrfs/io4_fs.go index d9c7cdb..3848ef1 100644 --- a/lib/btrfs/io4_fs.go +++ b/lib/btrfs/io4_fs.go @@ -95,7 +95,6 @@ func (sv *Subvolume) init() { default: panic(fmt.Errorf("should not happen: ROOT_ITEM has unexpected item type: %T", rootBody)) } - }) } diff --git a/lib/btrfsprogs/btrfsinspect/mount.go b/lib/btrfsprogs/btrfsinspect/mount.go index 29193cb..f061526 100644 --- a/lib/btrfsprogs/btrfsinspect/mount.go +++ b/lib/btrfsprogs/btrfsinspect/mount.go @@ -144,11 +144,11 @@ func inodeItemToFUSE(itemBody btrfsitem.Inode) fuseops.InodeAttributes { Size: uint64(itemBody.Size), Nlink: uint32(itemBody.NLink), Mode: uint32(itemBody.Mode), - //RDev: itemBody.Rdev, // jacobsa/fuse doesn't expose rdev + // RDev: itemBody.Rdev, // jacobsa/fuse doesn't expose rdev Atime: itemBody.ATime.ToStd(), Mtime: itemBody.MTime.ToStd(), Ctime: itemBody.CTime.ToStd(), - //Crtime: itemBody.OTime, + // Crtime: itemBody.OTime, Uid: uint32(itemBody.UID), Gid: uint32(itemBody.GID), } @@ -260,7 +260,7 @@ func (sv *subvolume) LookUpInode(_ context.Context, op *fuseops.LookUpInodeOp) e Child: 2, // an inode number that a real file will never have Attributes: fuseops.InodeAttributes{ Nlink: 1, - Mode: uint32(btrfsitem.ModeFmtDir | 0700), + Mode: uint32(btrfsitem.ModeFmtDir | 0o700), }, } return nil @@ -315,6 +315,7 @@ func (sv *subvolume) OpenDir(_ context.Context, op *fuseops.OpenDirOp) error { op.Handle = handle return nil } + func (sv *subvolume) ReadDir(_ context.Context, op *fuseops.ReadDirOp) error { state, ok := sv.dirHandles.Load(op.Handle) if !ok { @@ -348,6 +349,7 @@ func (sv *subvolume) ReadDir(_ context.Context, op *fuseops.ReadDirOp) error { } return nil } + func (sv *subvolume) ReleaseDirHandle(_ context.Context, op *fuseops.ReleaseDirHandleOp) error { _, ok := sv.dirHandles.LoadAndDelete(op.Handle) if !ok { @@ -369,6 +371,7 @@ func (sv *subvolume) OpenFile(_ context.Context, op *fuseops.OpenFileOp) error { op.KeepPageCache = true return nil } + func (sv *subvolume) ReadFile(_ context.Context, op *fuseops.ReadFileOp) error { state, ok := sv.fileHandles.Load(op.Handle) if !ok { @@ -392,6 +395,7 @@ func (sv *subvolume) ReadFile(_ context.Context, op *fuseops.ReadFileOp) error { return err } + func (sv *subvolume) ReleaseFileHandle(_ context.Context, op *fuseops.ReleaseFileHandleOp) error { _, ok := sv.fileHandles.LoadAndDelete(op.Handle) if !ok { diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go index 3057e75..5d0804c 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go @@ -386,6 +386,7 @@ func (o *rebuilder) want(ctx context.Context, reason string, treeID btrfsprim.Ob fmt.Sprintf("tree=%v key={%v %v ?}", treeID, objID, typ)) o._want(ctx, treeID, objID, typ) } + func (o *rebuilder) _want(ctx context.Context, treeID btrfsprim.ObjID, objID btrfsprim.ObjID, typ btrfsprim.ItemType) (key btrfsprim.Key, ok bool) { if !o.rebuilt.AddTree(ctx, treeID) { o.itemQueue = append(o.itemQueue, o.curKey) @@ -429,6 +430,7 @@ func (o *rebuilder) wantOff(ctx context.Context, reason string, treeID btrfsprim ctx = dlog.WithField(ctx, "btrfsinspect.rebuild-nodes.rebuild.want.key", keyAndTree{TreeID: treeID, Key: key}) o._wantOff(ctx, treeID, key) } + func (o *rebuilder) _wantOff(ctx context.Context, treeID btrfsprim.ObjID, tgt btrfsprim.Key) (ok bool) { if !o.rebuilt.AddTree(ctx, treeID) { o.itemQueue = append(o.itemQueue, o.curKey) diff --git a/lib/containers/lru.go b/lib/containers/lru.go index 12446b0..bfda361 100644 --- a/lib/containers/lru.go +++ b/lib/containers/lru.go @@ -36,10 +36,12 @@ func (c *LRUCache[K, V]) Add(key K, value V) { c.init() c.inner.Add(key, value) } + func (c *LRUCache[K, V]) Contains(key K) bool { c.init() return c.inner.Contains(key) } + func (c *LRUCache[K, V]) Get(key K) (value V, ok bool) { c.init() _value, ok := c.inner.Get(key) @@ -49,6 +51,7 @@ func (c *LRUCache[K, V]) Get(key K) (value V, ok bool) { } return value, ok } + func (c *LRUCache[K, V]) Keys() []K { c.init() untyped := c.inner.Keys() @@ -59,10 +62,12 @@ func (c *LRUCache[K, V]) Keys() []K { } return typed } + func (c *LRUCache[K, V]) Len() int { c.init() return c.inner.Len() } + func (c *LRUCache[K, V]) Peek(key K) (value V, ok bool) { c.init() _value, ok := c.inner.Peek(key) @@ -72,10 +77,12 @@ func (c *LRUCache[K, V]) Peek(key K) (value V, ok bool) { } return value, ok } + func (c *LRUCache[K, V]) Purge() { c.init() c.inner.Purge() } + func (c *LRUCache[K, V]) Remove(key K) { c.init() c.inner.Remove(key) diff --git a/lib/containers/syncmap.go b/lib/containers/syncmap.go index 4af678f..74da4b3 100644 --- a/lib/containers/syncmap.go +++ b/lib/containers/syncmap.go @@ -15,6 +15,7 @@ type SyncMap[K comparable, V any] struct { func (m *SyncMap[K, V]) Delete(key K) { m.inner.Delete(key) } + func (m *SyncMap[K, V]) Load(key K) (value V, ok bool) { _value, ok := m.inner.Load(key) if ok { @@ -23,6 +24,7 @@ func (m *SyncMap[K, V]) Load(key K) (value V, ok bool) { } return value, ok } + func (m *SyncMap[K, V]) LoadAndDelete(key K) (value V, loaded bool) { _value, ok := m.inner.LoadAndDelete(key) if ok { @@ -31,18 +33,21 @@ func (m *SyncMap[K, V]) LoadAndDelete(key K) (value V, loaded bool) { } return value, ok } + func (m *SyncMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) { _actual, loaded := m.inner.LoadOrStore(key, value) //nolint:forcetypeassert // Typed wrapper around untyped lib. actual = _actual.(V) return actual, loaded } + func (m *SyncMap[K, V]) Range(f func(key K, value V) bool) { m.inner.Range(func(key, value any) bool { //nolint:forcetypeassert // Typed wrapper around untyped lib. return f(key.(K), value.(V)) }) } + func (m *SyncMap[K, V]) Store(key K, value V) { m.inner.Store(key, value) } diff --git a/lib/fmtutil/fmt.go b/lib/fmtutil/fmt.go index 3898046..b310eb6 100644 --- a/lib/fmtutil/fmt.go +++ b/lib/fmtutil/fmt.go @@ -52,7 +52,8 @@ func FormatByteArrayStringer( fmt.Formatter }, objBytes []byte, - f fmt.State, verb rune) { + f fmt.State, verb rune, +) { switch verb { case 'v': if !f.Flag('#') { diff --git a/lib/textui/text.go b/lib/textui/text.go index d6a80b3..615516d 100644 --- a/lib/textui/text.go +++ b/lib/textui/text.go @@ -72,9 +72,7 @@ type Portion[T constraints.Integer] struct { N, D T } -var ( - _ fmt.Stringer = Portion[int]{} -) +var _ fmt.Stringer = Portion[int]{} // String implements fmt.Stringer. func (p Portion[T]) String() string { -- cgit v1.2.3-54-g00ecf From b261c2a4f5f028c9d83cef208ccc7d829f841bad Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sat, 31 Dec 2022 11:59:09 -0700 Subject: tree-wide: Annotate values that I might want to be tuning --- cmd/btrfs-rec/util.go | 2 +- lib/btrfs/io4_fs.go | 44 +++++++++++++--------- .../btrfsinspect/rebuildmappings/fuzzymatchsums.go | 2 +- .../rebuildnodes/btrees/rebuilt_btrees.go | 6 +-- .../btrfsinspect/rebuildnodes/graph/graph.go | 4 +- .../btrfsinspect/rebuildnodes/keyio/keyio.go | 3 +- .../btrfsinspect/rebuildnodes/rebuild.go | 4 +- lib/btrfsprogs/btrfsinspect/rebuildnodes/scan.go | 2 +- lib/btrfsprogs/btrfsinspect/scandevices.go | 2 +- lib/btrfsprogs/btrfsutil/open.go | 5 ++- lib/btrfsprogs/btrfsutil/skinny_paths.go | 3 +- lib/containers/lru.go | 26 ++----------- lib/textui/log_memstats.go | 2 +- lib/textui/tunable.go | 13 +++++++ 14 files changed, 62 insertions(+), 56 deletions(-) create mode 100644 lib/textui/tunable.go (limited to 'lib/containers') diff --git a/cmd/btrfs-rec/util.go b/cmd/btrfs-rec/util.go index ed1b75d..ffc03cc 100644 --- a/cmd/btrfs-rec/util.go +++ b/cmd/btrfs-rec/util.go @@ -34,7 +34,7 @@ func newRuneScanner(ctx context.Context, fh *os.File) (*runeScanner, error) { progress: textui.Portion[int64]{ D: fi.Size(), }, - progressWriter: textui.NewProgress[textui.Portion[int64]](ctx, dlog.LogLevelInfo, 1*time.Second), + progressWriter: textui.NewProgress[textui.Portion[int64]](ctx, dlog.LogLevelInfo, textui.Tunable(1*time.Second)), reader: bufio.NewReader(fh), closer: fh, } diff --git a/lib/btrfs/io4_fs.go b/lib/btrfs/io4_fs.go index 3848ef1..41df3a8 100644 --- a/lib/btrfs/io4_fs.go +++ b/lib/btrfs/io4_fs.go @@ -22,6 +22,7 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/containers" "git.lukeshu.com/btrfs-progs-ng/lib/maps" "git.lukeshu.com/btrfs-progs-ng/lib/slices" + "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) type BareInode struct { @@ -69,32 +70,37 @@ type Subvolume struct { TreeID btrfsprim.ObjID NoChecksums bool - rootOnce sync.Once - rootVal btrfsitem.Root - rootErr error + initOnce sync.Once - bareInodeCache containers.LRUCache[btrfsprim.ObjID, *BareInode] - fullInodeCache containers.LRUCache[btrfsprim.ObjID, *FullInode] - dirCache containers.LRUCache[btrfsprim.ObjID, *Dir] - fileCache containers.LRUCache[btrfsprim.ObjID, *File] + rootVal btrfsitem.Root + rootErr error + + bareInodeCache *containers.LRUCache[btrfsprim.ObjID, *BareInode] + fullInodeCache *containers.LRUCache[btrfsprim.ObjID, *FullInode] + dirCache *containers.LRUCache[btrfsprim.ObjID, *Dir] + fileCache *containers.LRUCache[btrfsprim.ObjID, *File] } func (sv *Subvolume) init() { - sv.rootOnce.Do(func() { + sv.initOnce.Do(func() { root, err := sv.FS.TreeSearch(btrfsprim.ROOT_TREE_OBJECTID, btrfstree.RootItemSearchFn(sv.TreeID)) if err != nil { sv.rootErr = err - return + } else { + switch rootBody := root.Body.(type) { + case btrfsitem.Root: + sv.rootVal = rootBody + case btrfsitem.Error: + sv.rootErr = fmt.Errorf("FS_TREE ROOT_ITEM has malformed body: %w", rootBody.Err) + default: + panic(fmt.Errorf("should not happen: ROOT_ITEM has unexpected item type: %T", rootBody)) + } } - switch rootBody := root.Body.(type) { - case btrfsitem.Root: - sv.rootVal = rootBody - case btrfsitem.Error: - sv.rootErr = fmt.Errorf("FS_TREE ROOT_ITEM has malformed body: %w", rootBody.Err) - default: - panic(fmt.Errorf("should not happen: ROOT_ITEM has unexpected item type: %T", rootBody)) - } + sv.bareInodeCache = containers.NewLRUCache[btrfsprim.ObjID, *BareInode](textui.Tunable(128)) + sv.fullInodeCache = containers.NewLRUCache[btrfsprim.ObjID, *FullInode](textui.Tunable(128)) + sv.dirCache = containers.NewLRUCache[btrfsprim.ObjID, *Dir](textui.Tunable(128)) + sv.fileCache = containers.NewLRUCache[btrfsprim.ObjID, *File](textui.Tunable(128)) }) } @@ -104,6 +110,7 @@ func (sv *Subvolume) GetRootInode() (btrfsprim.ObjID, error) { } func (sv *Subvolume) LoadBareInode(inode btrfsprim.ObjID) (*BareInode, error) { + sv.init() val := sv.bareInodeCache.GetOrElse(inode, func() (val *BareInode) { val = &BareInode{ Inode: inode, @@ -136,6 +143,7 @@ func (sv *Subvolume) LoadBareInode(inode btrfsprim.ObjID) (*BareInode, error) { } func (sv *Subvolume) LoadFullInode(inode btrfsprim.ObjID) (*FullInode, error) { + sv.init() val := sv.fullInodeCache.GetOrElse(inode, func() (val *FullInode) { val = &FullInode{ BareInode: BareInode{ @@ -191,6 +199,7 @@ func (sv *Subvolume) LoadFullInode(inode btrfsprim.ObjID) (*FullInode, error) { } func (sv *Subvolume) LoadDir(inode btrfsprim.ObjID) (*Dir, error) { + sv.init() val := sv.dirCache.GetOrElse(inode, func() (val *Dir) { val = new(Dir) fullInode, err := sv.LoadFullInode(inode) @@ -326,6 +335,7 @@ func (dir *Dir) AbsPath() (string, error) { } func (sv *Subvolume) LoadFile(inode btrfsprim.ObjID) (*File, error) { + sv.init() val := sv.fileCache.GetOrElse(inode, func() (val *File) { val = new(File) fullInode, err := sv.LoadFullInode(inode) diff --git a/lib/btrfsprogs/btrfsinspect/rebuildmappings/fuzzymatchsums.go b/lib/btrfsprogs/btrfsinspect/rebuildmappings/fuzzymatchsums.go index b1be7ba..a8d05eb 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildmappings/fuzzymatchsums.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildmappings/fuzzymatchsums.go @@ -19,7 +19,7 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) -const minFuzzyPct = 0.5 +var minFuzzyPct = textui.Tunable(0.5) type fuzzyRecord struct { PAddr btrfsvol.QualifiedPhysicalAddr diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/btrees/rebuilt_btrees.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/btrees/rebuilt_btrees.go index 33eb352..5e8883a 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/btrees/rebuilt_btrees.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/btrees/rebuilt_btrees.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -191,7 +191,7 @@ func (ts *RebuiltTrees) AddRoot(ctx context.Context, treeID btrfsprim.ObjID, roo var stats rootStats stats.Leafs.D = len(tree.leafToRoots) - progressWriter := textui.NewProgress[rootStats](ctx, dlog.LogLevelInfo, 1*time.Second) + progressWriter := textui.NewProgress[rootStats](ctx, dlog.LogLevelInfo, textui.Tunable(1*time.Second)) for i, leaf := range maps.SortedKeys(tree.leafToRoots) { stats.Leafs.N = i progressWriter.Set(stats) @@ -297,7 +297,7 @@ func (tree *rebuiltTree) indexLeafs(ctx context.Context, graph pkggraph.Graph) { var stats textui.Portion[int] stats.D = len(graph.Nodes) - progressWriter := textui.NewProgress[textui.Portion[int]](ctx, dlog.LogLevelInfo, 1*time.Second) + progressWriter := textui.NewProgress[textui.Portion[int]](ctx, dlog.LogLevelInfo, textui.Tunable(1*time.Second)) progress := func() { stats.N = len(nodeToRoots) progressWriter.Set(stats) diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/graph/graph.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/graph/graph.go index c4ed675..cf86d74 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/graph/graph.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/graph/graph.go @@ -197,7 +197,7 @@ func (g Graph) FinalCheck(ctx context.Context, fs diskio.File[btrfsvol.LogicalAd ctx = dlog.WithField(_ctx, "btrfsinspect.rebuild-nodes.read.substep", "check-keypointers") dlog.Info(_ctx, "Checking keypointers for dead-ends...") - progressWriter := textui.NewProgress[textui.Portion[int]](ctx, dlog.LogLevelInfo, 1*time.Second) + progressWriter := textui.NewProgress[textui.Portion[int]](ctx, dlog.LogLevelInfo, textui.Tunable(1*time.Second)) stats.D = len(g.EdgesTo) progressWriter.Set(stats) for laddr := range g.EdgesTo { @@ -221,7 +221,7 @@ func (g Graph) FinalCheck(ctx context.Context, fs diskio.File[btrfsvol.LogicalAd dlog.Info(_ctx, "Checking for btree loops...") stats.D = len(g.Nodes) stats.N = 0 - progressWriter = textui.NewProgress[textui.Portion[int]](ctx, dlog.LogLevelInfo, 1*time.Second) + progressWriter = textui.NewProgress[textui.Portion[int]](ctx, dlog.LogLevelInfo, textui.Tunable(1*time.Second)) progressWriter.Set(stats) visited := make(containers.Set[btrfsvol.LogicalAddr], len(g.Nodes)) numLoops := 0 diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go index b1e68f9..24c3dcf 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/keyio/keyio.go @@ -17,6 +17,7 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsinspect/rebuildnodes/graph" "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 { @@ -50,7 +51,7 @@ func NewHandle(file diskio.File[btrfsvol.LogicalAddr], sb btrfstree.Superblock) Sizes: make(map[ItemPtr]SizeAndErr), - cache: containers.NewLRUCache[btrfsvol.LogicalAddr, *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]](8), + cache: containers.NewLRUCache[btrfsvol.LogicalAddr, *diskio.Ref[btrfsvol.LogicalAddr, btrfstree.Node]](textui.Tunable(8)), } } diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go index 5d0804c..0a3ccdf 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/rebuild.go @@ -126,7 +126,7 @@ func (o *rebuilder) rebuild(_ctx context.Context) error { o.itemQueue = nil var progress textui.Portion[int] progress.D = len(itemQueue) - progressWriter := textui.NewProgress[textui.Portion[int]](stepCtx, dlog.LogLevelInfo, 1*time.Second) + progressWriter := textui.NewProgress[textui.Portion[int]](stepCtx, dlog.LogLevelInfo, textui.Tunable(1*time.Second)) stepCtx = dlog.WithField(stepCtx, "btrfsinspect.rebuild-nodes.rebuild.substep.progress", &progress) for i, key := range itemQueue { itemCtx := dlog.WithField(stepCtx, "btrfsinspect.rebuild-nodes.rebuild.process.item", key) @@ -160,7 +160,7 @@ func (o *rebuilder) rebuild(_ctx context.Context) error { progress.D += len(resolvedAugments[treeID]) } o.augmentQueue = make(map[btrfsprim.ObjID][]map[btrfsvol.LogicalAddr]int) - progressWriter = textui.NewProgress[textui.Portion[int]](stepCtx, dlog.LogLevelInfo, 1*time.Second) + progressWriter = textui.NewProgress[textui.Portion[int]](stepCtx, dlog.LogLevelInfo, textui.Tunable(1*time.Second)) stepCtx = dlog.WithField(stepCtx, "btrfsinspect.rebuild-nodes.rebuild.substep.progress", &progress) for _, treeID := range maps.SortedKeys(resolvedAugments) { treeCtx := dlog.WithField(stepCtx, "btrfsinspect.rebuild-nodes.rebuild.augment.tree", treeID) diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/scan.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/scan.go index 7a112b4..7e96e29 100644 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/scan.go +++ b/lib/btrfsprogs/btrfsinspect/rebuildnodes/scan.go @@ -32,7 +32,7 @@ func ScanDevices(ctx context.Context, fs *btrfs.FS, scanResults btrfsinspect.Sca stats.D = countNodes(scanResults) progressWriter := textui.NewProgress[textui.Portion[int]]( dlog.WithField(ctx, "btrfsinspect.rebuild-nodes.read.substep", "read-nodes"), - dlog.LogLevelInfo, 1*time.Second) + dlog.LogLevelInfo, textui.Tunable(1*time.Second)) nodeGraph := graph.New(*sb) keyIO := keyio.NewHandle(fs, *sb) diff --git a/lib/btrfsprogs/btrfsinspect/scandevices.go b/lib/btrfsprogs/btrfsinspect/scandevices.go index 4058663..7668a83 100644 --- a/lib/btrfsprogs/btrfsinspect/scandevices.go +++ b/lib/btrfsprogs/btrfsinspect/scandevices.go @@ -126,7 +126,7 @@ func ScanOneDevice(ctx context.Context, dev *btrfs.Device, sb btrfstree.Superblo var sums strings.Builder sums.Grow(numSums * csumSize) - progressWriter := textui.NewProgress[scanStats](ctx, dlog.LogLevelInfo, 1*time.Second) + progressWriter := textui.NewProgress[scanStats](ctx, dlog.LogLevelInfo, textui.Tunable(1*time.Second)) progress := func(pos btrfsvol.PhysicalAddr) { progressWriter.Set(scanStats{ Portion: textui.Portion[btrfsvol.PhysicalAddr]{ diff --git a/lib/btrfsprogs/btrfsutil/open.go b/lib/btrfsprogs/btrfsutil/open.go index 9491a20..441d4e2 100644 --- a/lib/btrfsprogs/btrfsutil/open.go +++ b/lib/btrfsprogs/btrfsutil/open.go @@ -14,6 +14,7 @@ import ( "git.lukeshu.com/btrfs-progs-ng/lib/btrfs" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" "git.lukeshu.com/btrfs-progs-ng/lib/diskio" + "git.lukeshu.com/btrfs-progs-ng/lib/textui" ) func Open(ctx context.Context, flag int, filenames ...string) (*btrfs.FS, error) { @@ -30,8 +31,8 @@ func Open(ctx context.Context, flag int, filenames ...string) (*btrfs.FS, error) } bufFile := diskio.NewBufferedFile[btrfsvol.PhysicalAddr]( typedFile, - 16384, // block size: 16KiB - 1024, // number of blocks to buffer; total of 16MiB + textui.Tunable[btrfsvol.PhysicalAddr](16384), // block size: 16KiB + textui.Tunable(1024), // number of blocks to buffer; total of 16MiB ) devFile := &btrfs.Device{ File: bufFile, diff --git a/lib/btrfsprogs/btrfsutil/skinny_paths.go b/lib/btrfsprogs/btrfsutil/skinny_paths.go index 2f71968..6a51739 100644 --- a/lib/btrfsprogs/btrfsutil/skinny_paths.go +++ b/lib/btrfsprogs/btrfsutil/skinny_paths.go @@ -11,6 +11,7 @@ import ( "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 skinnyItem struct { @@ -42,7 +43,7 @@ func (a *SkinnyPathArena) init() { // which is a good number for me. Then I tought it to do a // better job of recovering trees, and so the memory grew, and I // cut it to 64K. Then to 8K. Then grew it to 128K. - a.fatItems = containers.NewLRUCache[skinnyItem, btrfstree.TreePathElem](128 * 1024) + a.fatItems = containers.NewLRUCache[skinnyItem, btrfstree.TreePathElem](textui.Tunable(128 * 1024)) } } diff --git a/lib/containers/lru.go b/lib/containers/lru.go index bfda361..aa372ed 100644 --- a/lib/containers/lru.go +++ b/lib/containers/lru.go @@ -5,45 +5,30 @@ package containers import ( - "sync" - lru "github.com/hashicorp/golang-lru" ) // LRUCache is a least-recently-used(ish) cache. A zero LRUCache is -// usable and has a cache size of 128 items; use NewLRUCache to set a -// different size. +// not usable; it must be initialized with NewLRUCache. type LRUCache[K comparable, V any] struct { - initOnce sync.Once - inner *lru.ARCCache + inner *lru.ARCCache } func NewLRUCache[K comparable, V any](size int) *LRUCache[K, V] { c := new(LRUCache[K, V]) - c.initOnce.Do(func() { - c.inner, _ = lru.NewARC(size) - }) + c.inner, _ = lru.NewARC(size) return c } -func (c *LRUCache[K, V]) init() { - c.initOnce.Do(func() { - c.inner, _ = lru.NewARC(128) - }) -} - func (c *LRUCache[K, V]) Add(key K, value V) { - c.init() c.inner.Add(key, value) } func (c *LRUCache[K, V]) Contains(key K) bool { - c.init() return c.inner.Contains(key) } func (c *LRUCache[K, V]) Get(key K) (value V, ok bool) { - c.init() _value, ok := c.inner.Get(key) if ok { //nolint:forcetypeassert // Typed wrapper around untyped lib. @@ -53,7 +38,6 @@ func (c *LRUCache[K, V]) Get(key K) (value V, ok bool) { } func (c *LRUCache[K, V]) Keys() []K { - c.init() untyped := c.inner.Keys() typed := make([]K, len(untyped)) for i := range untyped { @@ -64,12 +48,10 @@ func (c *LRUCache[K, V]) Keys() []K { } func (c *LRUCache[K, V]) Len() int { - c.init() return c.inner.Len() } func (c *LRUCache[K, V]) Peek(key K) (value V, ok bool) { - c.init() _value, ok := c.inner.Peek(key) if ok { //nolint:forcetypeassert // Typed wrapper around untyped lib. @@ -79,12 +61,10 @@ func (c *LRUCache[K, V]) Peek(key K) (value V, ok bool) { } func (c *LRUCache[K, V]) Purge() { - c.init() c.inner.Purge() } func (c *LRUCache[K, V]) Remove(key K) { - c.init() c.inner.Remove(key) } diff --git a/lib/textui/log_memstats.go b/lib/textui/log_memstats.go index 39733c6..6e3c3a1 100644 --- a/lib/textui/log_memstats.go +++ b/lib/textui/log_memstats.go @@ -19,7 +19,7 @@ type LiveMemUse struct { var _ fmt.Stringer = (*LiveMemUse)(nil) -const liveMemUseUpdateInterval = 1 * time.Second +var liveMemUseUpdateInterval = Tunable(1 * time.Second) func (o *LiveMemUse) String() string { o.mu.Lock() diff --git a/lib/textui/tunable.go b/lib/textui/tunable.go new file mode 100644 index 0000000..7e5f311 --- /dev/null +++ b/lib/textui/tunable.go @@ -0,0 +1,13 @@ +// Copyright (C) 2022 Luke Shumaker +// +// SPDX-License-Identifier: GPL-2.0-or-later + +package textui + +// Tunable annotates a value as something that might want to be tuned +// as the program gets optimized. +// +// TODO(lukeshu): Have Tunable be runtime-configurable. +func Tunable[T any](x T) T { + return x +} -- cgit v1.2.3-54-g00ecf From 5edd0d7be38595c4777d5130ca20f907d8a74963 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sun, 1 Jan 2023 21:12:41 -0700 Subject: lint: Turn on paralleltest --- .golangci.yml | 1 - lib/binstruct/binstruct_test.go | 3 ++- lib/containers/intervaltree_test.go | 3 ++- lib/diskio/kmp_test.go | 5 ++++- lib/textui/log_test.go | 5 ++++- lib/textui/text_test.go | 5 ++++- 6 files changed, 16 insertions(+), 6 deletions(-) (limited to 'lib/containers') diff --git a/.golangci.yml b/.golangci.yml index 5e31143..afaf507 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -41,7 +41,6 @@ linters: - nestif - nlreturn - nonamedreturns - - paralleltest - predeclared - revive - stylecheck diff --git a/lib/binstruct/binstruct_test.go b/lib/binstruct/binstruct_test.go index 105e790..8780acc 100644 --- a/lib/binstruct/binstruct_test.go +++ b/lib/binstruct/binstruct_test.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -13,6 +13,7 @@ import ( ) func TestSmoke(t *testing.T) { + t.Parallel() type UUID [16]byte type PhysicalAddr int64 type DevItem struct { diff --git a/lib/containers/intervaltree_test.go b/lib/containers/intervaltree_test.go index 88c3003..45743a2 100644 --- a/lib/containers/intervaltree_test.go +++ b/lib/containers/intervaltree_test.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -35,6 +35,7 @@ func (ival SimpleInterval) String() string { } func TestIntervalTree(t *testing.T) { + t.Parallel() tree := IntervalTree[NativeOrdered[int], SimpleInterval]{ MinFn: func(ival SimpleInterval) NativeOrdered[int] { return NativeOrdered[int]{ival.Min} }, MaxFn: func(ival SimpleInterval) NativeOrdered[int] { return NativeOrdered[int]{ival.Max} }, diff --git a/lib/diskio/kmp_test.go b/lib/diskio/kmp_test.go index 59b6224..4d4b3be 100644 --- a/lib/diskio/kmp_test.go +++ b/lib/diskio/kmp_test.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -14,6 +14,7 @@ import ( ) func TestBuildKMPTable(t *testing.T) { + t.Parallel() substr := SliceSequence[int64, byte]([]byte("ababaa")) table, err := buildKMPTable[int64, byte](substr) require.NoError(t, err) @@ -81,6 +82,7 @@ func (re RESeq) Get(i int64) (byte, error) { } func TestKMPWildcard(t *testing.T) { + t.Parallel() type testcase struct { InStr string InSubstr string @@ -111,6 +113,7 @@ func TestKMPWildcard(t *testing.T) { for tcName, tc := range testcases { tc := tc t.Run(tcName, func(t *testing.T) { + t.Parallel() matches, err := IndexAll[int64, byte]( StringSequence[int64](tc.InStr), RESeq(tc.InSubstr)) diff --git a/lib/textui/log_test.go b/lib/textui/log_test.go index 08eb38c..514d96e 100644 --- a/lib/textui/log_test.go +++ b/lib/textui/log_test.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -20,6 +20,7 @@ func logLineRegexp(inner string) string { } func TestLogFormat(t *testing.T) { + t.Parallel() var out strings.Builder ctx := dlog.WithLogger(context.Background(), textui.NewLogger(&out, dlog.LogLevelTrace)) dlog.Debugf(ctx, "foo %d", 12345) @@ -29,6 +30,7 @@ func TestLogFormat(t *testing.T) { } func TestLogLevel(t *testing.T) { + t.Parallel() var out strings.Builder ctx := dlog.WithLogger(context.Background(), textui.NewLogger(&out, dlog.LogLevelInfo)) dlog.Error(ctx, "Error") @@ -54,6 +56,7 @@ func TestLogLevel(t *testing.T) { } func TestLogField(t *testing.T) { + t.Parallel() var out strings.Builder ctx := dlog.WithLogger(context.Background(), textui.NewLogger(&out, dlog.LogLevelInfo)) ctx = dlog.WithField(ctx, "foo", 12345) diff --git a/lib/textui/text_test.go b/lib/textui/text_test.go index c4b42f6..4b93683 100644 --- a/lib/textui/text_test.go +++ b/lib/textui/text_test.go @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Luke Shumaker +// Copyright (C) 2022-2023 Luke Shumaker // // SPDX-License-Identifier: GPL-2.0-or-later @@ -16,12 +16,14 @@ import ( ) func TestFprintf(t *testing.T) { + t.Parallel() var out strings.Builder textui.Fprintf(&out, "%d", 12345) assert.Equal(t, "12,345", out.String()) } func TestHumanized(t *testing.T) { + t.Parallel() assert.Equal(t, "12,345", fmt.Sprint(textui.Humanized(12345))) assert.Equal(t, "12,345 ", fmt.Sprintf("%-8d", textui.Humanized(12345))) @@ -32,6 +34,7 @@ func TestHumanized(t *testing.T) { } func TestPortion(t *testing.T) { + t.Parallel() assert.Equal(t, "100% (0/0)", fmt.Sprint(textui.Portion[int]{})) assert.Equal(t, "0% (1/12,345)", fmt.Sprint(textui.Portion[int]{N: 1, D: 12345})) assert.Equal(t, "100% (0/0)", fmt.Sprint(textui.Portion[btrfsvol.PhysicalAddr]{})) -- cgit v1.2.3-54-g00ecf From 0c706b6ad52776430ac15cf0e286dd473091d93e Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sun, 1 Jan 2023 21:14:26 -0700 Subject: lint: Turn on predeclared --- .golangci.yml | 1 - lib/containers/rbtree.go | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'lib/containers') diff --git a/.golangci.yml b/.golangci.yml index afaf507..e8b7678 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -41,7 +41,6 @@ linters: - nestif - nlreturn - nonamedreturns - - predeclared - revive - stylecheck - tagliatelle diff --git a/lib/containers/rbtree.go b/lib/containers/rbtree.go index f922a7b..0430123 100644 --- a/lib/containers/rbtree.go +++ b/lib/containers/rbtree.go @@ -391,10 +391,10 @@ func (t *RBTree[K, V]) Insert(val V) { t.root.Color = Black } -func (t *RBTree[K, V]) transplant(old, new *RBNode[V]) { - *t.parentChild(old) = new - if new != nil { - new.Parent = old.Parent +func (t *RBTree[K, V]) transplant(oldNode, newNode *RBNode[V]) { + *t.parentChild(oldNode) = newNode + if newNode != nil { + newNode.Parent = oldNode.Parent } } -- cgit v1.2.3-54-g00ecf