@@ -57,7 +57,7 @@ func (tx *Tx) check(kvStringer KVStringer, ch chan error) {
57
57
}
58
58
59
59
// Recursively check buckets.
60
- tx .checkBucket (& tx .root , reachable , freed , kvStringer , ch )
60
+ tx .recursivelyCheckBucket (& tx .root , reachable , freed , kvStringer , ch )
61
61
62
62
// Ensure all pages below high water mark are either reachable or freed.
63
63
for i := common .Pgid (0 ); i < tx .meta .Pgid (); i ++ {
@@ -71,7 +71,7 @@ func (tx *Tx) check(kvStringer KVStringer, ch chan error) {
71
71
close (ch )
72
72
}
73
73
74
- func (tx * Tx ) checkBucket (b * Bucket , reachable map [common.Pgid ]* common.Page , freed map [common.Pgid ]bool ,
74
+ func (tx * Tx ) recursivelyCheckBucket (b * Bucket , reachable map [common.Pgid ]* common.Page , freed map [common.Pgid ]bool ,
75
75
kvStringer KVStringer , ch chan error ) {
76
76
// Ignore inline buckets.
77
77
if b .RootPage () == 0 {
@@ -80,52 +80,56 @@ func (tx *Tx) checkBucket(b *Bucket, reachable map[common.Pgid]*common.Page, fre
80
80
81
81
// Check every page used by this bucket.
82
82
b .tx .forEachPage (b .RootPage (), func (p * common.Page , _ int , stack []common.Pgid ) {
83
- if p .Id () > tx .meta .Pgid () {
84
- ch <- fmt .Errorf ("page %d: out of bounds: %d (stack: %v)" , int (p .Id ()), int (b .tx .meta .Pgid ()), stack )
85
- }
86
-
87
- // Ensure each page is only referenced once.
88
- for i := common .Pgid (0 ); i <= common .Pgid (p .Overflow ()); i ++ {
89
- var id = p .Id () + i
90
- if _ , ok := reachable [id ]; ok {
91
- ch <- fmt .Errorf ("page %d: multiple references (stack: %v)" , int (id ), stack )
92
- }
93
- reachable [id ] = p
94
- }
95
-
96
- // We should only encounter un-freed leaf and branch pages.
97
- if freed [p .Id ()] {
98
- ch <- fmt .Errorf ("page %d: reachable freed" , int (p .Id ()))
99
- } else if ! p .IsBranchPage () && ! p .IsLeafPage () {
100
- ch <- fmt .Errorf ("page %d: invalid type: %s (stack: %v)" , int (p .Id ()), p .Typ (), stack )
101
- }
83
+ verifyPageReachable (p , tx .meta .Pgid (), stack , reachable , freed , ch )
102
84
})
103
85
104
- tx .recursivelyCheckPages (b .RootPage (), kvStringer .KeyToString , ch )
86
+ tx .recursivelyCheckPageKeyOrder (b .RootPage (), kvStringer .KeyToString , ch )
105
87
106
88
// Check each bucket within this bucket.
107
89
_ = b .ForEachBucket (func (k []byte ) error {
108
90
if child := b .Bucket (k ); child != nil {
109
- tx .checkBucket (child , reachable , freed , kvStringer , ch )
91
+ tx .recursivelyCheckBucket (child , reachable , freed , kvStringer , ch )
110
92
}
111
93
return nil
112
94
})
113
95
}
114
96
115
- // recursivelyCheckPages confirms database consistency with respect to b-tree
97
+ func verifyPageReachable (p * common.Page , hwm common.Pgid , stack []common.Pgid , reachable map [common.Pgid ]* common.Page , freed map [common.Pgid ]bool , ch chan error ) {
98
+ if p .Id () > hwm {
99
+ ch <- fmt .Errorf ("page %d: out of bounds: %d (stack: %v)" , int (p .Id ()), int (hwm ), stack )
100
+ }
101
+
102
+ // Ensure each page is only referenced once.
103
+ for i := common .Pgid (0 ); i <= common .Pgid (p .Overflow ()); i ++ {
104
+ var id = p .Id () + i
105
+ if _ , ok := reachable [id ]; ok {
106
+ ch <- fmt .Errorf ("page %d: multiple references (stack: %v)" , int (id ), stack )
107
+ }
108
+ reachable [id ] = p
109
+ }
110
+
111
+ // We should only encounter un-freed leaf and branch pages.
112
+ if freed [p .Id ()] {
113
+ ch <- fmt .Errorf ("page %d: reachable freed" , int (p .Id ()))
114
+ } else if ! p .IsBranchPage () && ! p .IsLeafPage () {
115
+ ch <- fmt .Errorf ("page %d: invalid type: %s (stack: %v)" , int (p .Id ()), p .Typ (), stack )
116
+ }
117
+ }
118
+
119
+ // recursivelyCheckPageKeyOrder verifies database consistency with respect to b-tree
116
120
// key order constraints:
117
121
// - keys on pages must be sorted
118
122
// - keys on children pages are between 2 consecutive keys on the parent's branch page).
119
- func (tx * Tx ) recursivelyCheckPages (pgId common.Pgid , keyToString func ([]byte ) string , ch chan error ) {
120
- tx .recursivelyCheckPagesInternal (pgId , nil , nil , nil , keyToString , ch )
123
+ func (tx * Tx ) recursivelyCheckPageKeyOrder (pgId common.Pgid , keyToString func ([]byte ) string , ch chan error ) {
124
+ tx .recursivelyCheckPageKeyOrderInternal (pgId , nil , nil , nil , keyToString , ch )
121
125
}
122
126
123
- // recursivelyCheckPagesInternal verifies that all keys in the subtree rooted at `pgid` are:
127
+ // recursivelyCheckPageKeyOrderInternal verifies that all keys in the subtree rooted at `pgid` are:
124
128
// - >=`minKeyClosed` (can be nil)
125
129
// - <`maxKeyOpen` (can be nil)
126
130
// - Are in right ordering relationship to their parents.
127
131
// `pagesStack` is expected to contain IDs of pages from the tree root to `pgid` for the clean debugging message.
128
- func (tx * Tx ) recursivelyCheckPagesInternal (
132
+ func (tx * Tx ) recursivelyCheckPageKeyOrderInternal (
129
133
pgId common.Pgid , minKeyClosed , maxKeyOpen []byte , pagesStack []common.Pgid ,
130
134
keyToString func ([]byte ) string , ch chan error ) (maxKeyInSubtree []byte ) {
131
135
@@ -143,7 +147,7 @@ func (tx *Tx) recursivelyCheckPagesInternal(
143
147
if i < len (p .BranchPageElements ())- 1 {
144
148
maxKey = p .BranchPageElement (uint16 (i + 1 )).Key ()
145
149
}
146
- maxKeyInSubtree = tx .recursivelyCheckPagesInternal (elem .Pgid (), elem .Key (), maxKey , pagesStack , keyToString , ch )
150
+ maxKeyInSubtree = tx .recursivelyCheckPageKeyOrderInternal (elem .Pgid (), elem .Key (), maxKey , pagesStack , keyToString , ch )
147
151
runningMin = maxKeyInSubtree
148
152
}
149
153
return maxKeyInSubtree
0 commit comments