MCPcopy
hub / github.com/etcd-io/bbolt / TestFindPathsToKey_CycleDetected

Function TestFindPathsToKey_CycleDetected

internal/surgeon/xray_test.go:42–84  ·  view source on GitHub ↗

TestFindPathsToKey_CycleDetected corrupts the db so that a branch page points at its own ancestor, then verifies that FindPathsToKey returns an error instead of recursing until stack overflow. See issue #701 for the real-world corruption pattern (power-off creating a page cycle).

(t *testing.T)

Source from the content-addressed store, hash-verified

40// error instead of recursing until stack overflow. See issue #701 for the
41// real-world corruption pattern (power-off creating a page cycle).
42func TestFindPathsToKey_CycleDetected(t *testing.T) {
43 db := btesting.MustCreateDB(t)
44 require.NoError(t,
45 db.Fill([]byte("data"), 1, 500,
46 func(tx int, k int) []byte { return []byte(fmt.Sprintf("%04d", k)) },
47 func(tx int, k int) []byte { return make([]byte, 100) },
48 ))
49 require.NoError(t, db.Close())
50
51 // Find the path to an arbitrary key so we can pick a branch ancestor
52 // and one of its leaf descendants to corrupt.
53 navigator := surgeon.NewXRay(db.Path())
54 paths, err := navigator.FindPathsToKey([]byte("0001"))
55 require.NoError(t, err)
56 require.NotEmpty(t, paths)
57 path := paths[0]
58 require.GreaterOrEqual(t, len(path), 2, "need at least one branch above the leaf")
59
60 // Overwrite the leaf page with a copy of its branch ancestor. The
61 // rewritten page is still a branch and now references its own pgid
62 // through the ancestor's element list, forming a cycle.
63 ancestor := path[len(path)-2]
64 leaf := path[len(path)-1]
65 require.NoError(t, surgeon.CopyPage(db.Path(), ancestor, leaf))
66
67 // Confirm the ancestor actually lists the leaf as one of its children,
68 // so copying creates a real cycle rather than two disjoint branches.
69 ancestorPage, _, err := guts_cli.ReadPage(db.Path(), uint64(ancestor))
70 require.NoError(t, err)
71 require.True(t, ancestorPage.IsBranchPage())
72 var hasLeafAsChild bool
73 for i := uint16(0); i < ancestorPage.Count(); i++ {
74 if ancestorPage.BranchPageElement(i).Pgid() == common.Pgid(leaf) {
75 hasLeafAsChild = true
76 break
77 }
78 }
79 require.True(t, hasLeafAsChild, "expected ancestor to reference the leaf directly")
80
81 _, err = surgeon.NewXRay(db.Path()).FindPathsToKey([]byte("0001"))
82 require.Error(t, err)
83 require.Contains(t, err.Error(), "cycle detected")
84}
85
86// TestFindPathsToKey_MultipleBuckets ensures the shared visited map in
87// traverse does not suppress legitimate paths when the same key appears

Callers

nothing calls this directly

Calls 14

FindPathsToKeyMethod · 0.95
MustCreateDBFunction · 0.92
NewXRayFunction · 0.92
CopyPageFunction · 0.92
ReadPageFunction · 0.92
PgidTypeAlias · 0.92
FillMethod · 0.80
IsBranchPageMethod · 0.80
BranchPageElementMethod · 0.80
CountMethod · 0.65
ErrorMethod · 0.65
CloseMethod · 0.45

Tested by

no test coverage detected