diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-11-15 20:57:04 -0700 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-12-20 19:58:11 -0700 |
commit | 580189ee3e43d5595a8700ee21b8900b0dd5389d (patch) | |
tree | 6f47b5728a9fc4cad3d87578396c30637161fbf2 /lib/btrfsprogs/btrfsinspect/rebuildnodes/visualizenodes.go | |
parent | a71e1969a1b24500ce9885c4a3f1aeee40c421a8 (diff) |
Delete 'inspect visualize-nodes'
Diffstat (limited to 'lib/btrfsprogs/btrfsinspect/rebuildnodes/visualizenodes.go')
-rw-r--r-- | lib/btrfsprogs/btrfsinspect/rebuildnodes/visualizenodes.go | 300 |
1 files changed, 0 insertions, 300 deletions
diff --git a/lib/btrfsprogs/btrfsinspect/rebuildnodes/visualizenodes.go b/lib/btrfsprogs/btrfsinspect/rebuildnodes/visualizenodes.go deleted file mode 100644 index fc9d19b..0000000 --- a/lib/btrfsprogs/btrfsinspect/rebuildnodes/visualizenodes.go +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (C) 2022 Luke Shumaker <lukeshu@lukeshu.com> -// -// SPDX-License-Identifier: GPL-2.0-or-later - -package rebuildnodes - -import ( - "archive/zip" - "context" - "fmt" - "html" - "io" - "strings" - - "github.com/datawire/dlib/derror" - "github.com/datawire/dlib/dlog" - - "git.lukeshu.com/btrfs-progs-ng/lib/btrfs" - "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsprim" - "git.lukeshu.com/btrfs-progs-ng/lib/btrfsprogs/btrfsinspect" - "git.lukeshu.com/btrfs-progs-ng/lib/containers" - "git.lukeshu.com/btrfs-progs-ng/lib/maps" -) - -func getCliques(scanData scanResult) map[btrfsprim.ObjID]*containers.Set[btrfsprim.ObjID] { - cliques := make(map[btrfsprim.ObjID]*containers.Set[btrfsprim.ObjID]) - - // UUID map - lister := newFullAncestorLister(scanData.uuidMap, map[btrfsprim.ObjID]containers.Set[btrfsprim.ObjID]{}) - for _, treeID := range maps.SortedKeys(scanData.uuidMap.SeenTrees) { - clique := ptrTo(make(containers.Set[btrfsprim.ObjID])) - clique.Insert(treeID) - clique.InsertFrom(lister.GetFullAncestors(treeID)) - for _, id := range maps.SortedKeys(*clique) { - if existingClique, ok := cliques[id]; ok { - clique.InsertFrom(*existingClique) - } - cliques[id] = clique - } - } - - // node graph - for _, laddr := range maps.SortedKeys(scanData.nodeGraph.Nodes) { - clique := ptrTo(make(containers.Set[btrfsprim.ObjID])) - clique.Insert(scanData.nodeGraph.Nodes[laddr].Owner) - for _, edge := range scanData.nodeGraph.EdgesTo[laddr] { - clique.Insert(edge.FromTree) - } - for _, id := range maps.SortedKeys(*clique) { - if existingClique, ok := cliques[id]; ok { - clique.InsertFrom(*existingClique) - } - cliques[id] = clique - } - } - return cliques -} - -func getCliqueID(cliques map[btrfsprim.ObjID]*containers.Set[btrfsprim.ObjID], treeID btrfsprim.ObjID) btrfsprim.ObjID { - clique, ok := cliques[treeID] - if !ok { - panic(fmt.Errorf("tree ID %v was not in .SeenTrees", treeID)) - } - return maps.SortedKeys(*clique)[0] -} - -func VisualizeNodes(ctx context.Context, out io.Writer, fs *btrfs.FS, nodeScanResults btrfsinspect.ScanDevicesResult) error { - scanData, err := ScanDevices(ctx, fs, nodeScanResults) - if err != nil { - return err - } - - //////////////////////////////////////////////////////////////////////////////////////////// - - dlog.Info(ctx, "Building cliques...") - cliques := getCliques(*scanData) - cliqueIDs := make(containers.Set[btrfsprim.ObjID]) - for treeID := range cliques { - cliqueIDs.Insert(getCliqueID(cliques, treeID)) - } - dlog.Infof(ctx, "... built %d cliques of %d trees", len(cliqueIDs), len(cliques)) - - //////////////////////////////////////////////////////////////////////////////////////////// - - dlog.Info(ctx, "Building graphviz graphs...") - - type graph struct { - nodes map[btrfsprim.ObjID]containers.Set[string] // keyed by treeID - badNodes containers.Set[string] - edges containers.Set[string] - } - graphs := make(map[btrfsprim.ObjID]graph, len(cliques)) // keyed by cliqueID - for cliqueID := range cliqueIDs { - graphs[cliqueID] = graph{ - nodes: make(map[btrfsprim.ObjID]containers.Set[string]), - badNodes: make(containers.Set[string]), - edges: make(containers.Set[string]), - } - } - - dlog.Infof(ctx, "... processing %d nodes...", len(scanData.Nodes)) - - for _, laddr := range maps.SortedKeys(scanData.Nodes) { - nodeData := scanData.Nodes[laddr] - cliqueID := getCliqueID(cliques, nodeData.Owner) - graph, ok := graphs[cliqueID] - if !ok { - panic(cliqueID) - } - if graph.nodes[nodeData.Owner] == nil { - graph.nodes[nodeData.Owner] = make(containers.Set[string]) - } - - var buf strings.Builder - fmt.Fprintf(&buf, `n%d [shape=record label="{laddr=%v\lgen=%v\llvl=%v\litems=%v\l|{`, - laddr, - laddr, - nodeData.Generation, - nodeData.Level, - nodeData.NumItems) - if nodeData.Level == 0 { - buf.WriteString("leaf") - } else { - for i := uint32(0); i < nodeData.NumItems; i++ { - if i == 0 { - fmt.Fprintf(&buf, "<p%[1]d>%[1]d", i) - } else { - fmt.Fprintf(&buf, "|<p%[1]d>%[1]d", i) - } - } - } - buf.WriteString(`}}"]`) - graph.nodes[nodeData.Owner].Insert(buf.String()) - - if len(scanData.EdgesTo[laddr]) == 0 { - graph.edges.Insert(fmt.Sprintf("orphanRoot -> n%d", laddr)) - } - - graphs[cliqueID] = graph - } - - dlog.Infof(ctx, "... processing %d bad nodes...", len(scanData.BadNodes)) - - for _, laddr := range maps.SortedKeys(scanData.BadNodes) { - cliqueIDs := make(containers.Set[btrfsprim.ObjID]) - for _, edge := range scanData.EdgesTo[laddr] { - cliqueIDs.Insert(getCliqueID(cliques, edge.FromTree)) - } - if len(cliqueIDs) != 1 { - dlog.Errorf(ctx, "couldn't assign bad node@%v to a clique: %v", laddr, maps.SortedKeys(cliqueIDs)) - continue - } - - cliqueID := cliqueIDs.TakeOne() - graph, ok := graphs[cliqueID] - if !ok { - panic(cliqueID) - } - graph.badNodes.Insert(fmt.Sprintf(`n%d [shape=star color=red label="%v\l\lerr=%s"]`, - laddr, laddr, gvEscape(scanData.BadNodes[laddr].Error()+"\n"))) - graphs[cliqueID] = graph - } - - numEdges := 0 - for _, kps := range scanData.EdgesFrom { - numEdges += (len(kps)) - } - dlog.Infof(ctx, "... processing %d keypointers...", numEdges) - - for _, laddr := range maps.SortedKeys(scanData.EdgesFrom) { - for _, kp := range scanData.EdgesFrom[laddr] { - cliqueID := getCliqueID(cliques, kp.FromTree) - graph, ok := graphs[cliqueID] - if !ok { - panic(cliqueID) - } - - var buf strings.Builder - if kp.FromNode == 0 { - if graph.nodes[kp.FromTree] == nil { - graph.nodes[kp.FromTree] = make(containers.Set[string]) - } - graph.nodes[kp.FromTree].Insert(fmt.Sprintf(`t%d [label="root of %s"]`, kp.FromTree, gvEscape(kp.FromTree.String()))) - fmt.Fprintf(&buf, "t%d", kp.FromTree) - } else { - fmt.Fprintf(&buf, "n%d:p%d", kp.FromNode, kp.FromItem) - } - fmt.Fprintf(&buf, ` -> n%d`, kp.ToNode) - - var err error - toNode, ok := scanData.Nodes[kp.ToNode] - if !ok { - err = scanData.BadNodes[kp.ToNode] - } else { - err = checkNodeExpectations(*kp, toNode) - } - if err != nil { - fmt.Fprintf(&buf, ` [label="key=(%d,%v,%d) gen=%v\l\lerr=%s" color=red]`, - kp.ToKey.ObjectID, - kp.ToKey.ItemType, - kp.ToKey.Offset, - kp.ToGeneration, - gvEscape(err.Error()+"\n")) - } - - graph.edges.Insert(buf.String()) - graphs[cliqueID] = graph - } - } - - //////////////////////////////////////////////////////////////////////////////////////////// - - dlog.Info(ctx, "Writing graphviz output...") - - zw := zip.NewWriter(out) - for _, cliqueID := range maps.SortedKeys(graphs) { - if err := func() (err error) { - graph := graphs[cliqueID] - - buf, err := zw.Create(fmt.Sprintf("%d.dot", cliqueID)) - if err != nil { - return err - } - if _, err := fmt.Fprintf(buf, "strict digraph clique%d {\n", cliqueID); err != nil { - return err - } - if _, err := fmt.Fprintf(buf, "rankdir=LR;\n nodesep=0.1;\n ranksep=25;\n splines=line;\n"); err != nil { - return err - } - for _, treeID := range maps.SortedKeys(graph.nodes) { - nodes := graph.nodes[treeID] - - if _, err := fmt.Fprintf(buf, " subgraph cluster_tree%d {\n", treeID); err != nil { - return err - } - for _, node := range maps.SortedKeys(nodes) { - if _, err := fmt.Fprintf(buf, " %s;\n", node); err != nil { - return err - } - } - if _, err := fmt.Fprintln(buf, " }"); err != nil { - return err - } - } - for _, node := range maps.SortedKeys(graph.badNodes) { - if _, err := fmt.Fprintf(buf, " %s;\n", node); err != nil { - return err - } - } - for _, edge := range maps.SortedKeys(graph.edges) { - if _, err := fmt.Fprintf(buf, " %s;\n", edge); err != nil { - return err - } - } - - if _, err := fmt.Fprintln(buf, "}"); err != nil { - return err - } - return nil - }(); err != nil { - return err - } - } - if err := zw.Close(); err != nil { - return err - } - - dlog.Info(ctx, "... done writing") - - return nil -} - -func gvEscape(str string) string { - str = html.EscapeString(str) - str = strings.ReplaceAll(str, "\n", `\l`) - str = strings.ReplaceAll(str, `\n`, `\l`) - return str -} - -func checkNodeExpectations(kp kpData, toNode nodeData) error { - var errs derror.MultiError - if toNode.Level != kp.ToLevel { - errs = append(errs, fmt.Errorf("kp.level=%v != node.level=%v", - kp.ToLevel, toNode.Level)) - } - if toNode.Generation != kp.ToGeneration { - errs = append(errs, fmt.Errorf("kp.generation=%v != node.generation=%v", - kp.ToGeneration, toNode.Generation)) - } - if toNode.NumItems == 0 { - errs = append(errs, fmt.Errorf("node.num_items=0")) - } else if 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)) - } - if len(errs) > 0 { - return errs - } - return nil -} |