@@ -60,15 +60,63 @@ func (tx *Tx) check(cfg checkConfig, ch chan error) {
60
60
}
61
61
}
62
62
63
- // Recursively check buckets.
64
- tx .recursivelyCheckBucket (& tx .root , reachable , freed , cfg .kvStringer , ch )
65
-
66
- // Ensure all pages below high water mark are either reachable or freed.
67
- for i := common .Pgid (0 ); i < tx .meta .Pgid (); i ++ {
68
- _ , isReachable := reachable [i ]
69
- if ! isReachable && ! freed [i ] {
70
- ch <- fmt .Errorf ("page %d: unreachable unfreed" , int (i ))
63
+ if cfg .pageId == 0 {
64
+ // Check the whole db file, starting from the root bucket and
65
+ // recursively check all child buckets.
66
+ tx .recursivelyCheckBucket (& tx .root , reachable , freed , cfg .kvStringer , ch )
67
+
68
+ // Ensure all pages below high water mark are either reachable or freed.
69
+ for i := common .Pgid (0 ); i < tx .meta .Pgid (); i ++ {
70
+ _ , isReachable := reachable [i ]
71
+ if ! isReachable && ! freed [i ] {
72
+ ch <- fmt .Errorf ("page %d: unreachable unfreed" , int (i ))
73
+ }
74
+ }
75
+ } else {
76
+ // Check the db file starting from a specified pageId.
77
+ if cfg .pageId < 2 || cfg .pageId >= uint (tx .meta .Pgid ()) {
78
+ ch <- fmt .Errorf ("page ID (%d) out of range [%d, %d)" , cfg .pageId , 2 , tx .meta .Pgid ())
79
+ return
80
+ }
81
+
82
+ tx .recursivelyCheckPage (common .Pgid (cfg .pageId ), reachable , freed , cfg .kvStringer , ch )
83
+ }
84
+ }
85
+
86
+ func (tx * Tx ) recursivelyCheckPage (pageId common.Pgid , reachable map [common.Pgid ]* common.Page , freed map [common.Pgid ]bool ,
87
+ kvStringer KVStringer , ch chan error ) {
88
+ tx .checkInvariantProperties (pageId , reachable , freed , kvStringer , ch )
89
+ tx .recursivelyCheckBucketInPage (pageId , reachable , freed , kvStringer , ch )
90
+ }
91
+
92
+ func (tx * Tx ) recursivelyCheckBucketInPage (pageId common.Pgid , reachable map [common.Pgid ]* common.Page , freed map [common.Pgid ]bool ,
93
+ kvStringer KVStringer , ch chan error ) {
94
+ p := tx .page (pageId )
95
+
96
+ switch {
97
+ case p .IsBranchPage ():
98
+ for i := range p .BranchPageElements () {
99
+ elem := p .BranchPageElement (uint16 (i ))
100
+ tx .recursivelyCheckBucketInPage (elem .Pgid (), reachable , freed , kvStringer , ch )
101
+ }
102
+ case p .IsLeafPage ():
103
+ for i := range p .LeafPageElements () {
104
+ elem := p .LeafPageElement (uint16 (i ))
105
+ if elem .Flags ()& common .BucketLeafFlag != 0 {
106
+
107
+ inBkt := common .NewInBucket (pageId , 0 )
108
+ tmpBucket := Bucket {
109
+ InBucket : & inBkt ,
110
+ rootNode : & node {isLeaf : p .IsLeafPage ()},
111
+ FillPercent : DefaultFillPercent ,
112
+ }
113
+ if child := tmpBucket .Bucket (elem .Key ()); child != nil {
114
+ tx .recursivelyCheckBucket (& tmpBucket , reachable , freed , kvStringer , ch )
115
+ }
116
+ }
71
117
}
118
+ default :
119
+ ch <- fmt .Errorf ("unexpected page type (flags: %x) for pgId:%d" , p .Flags (), pageId )
72
120
}
73
121
}
74
122
@@ -167,7 +215,7 @@ func (tx *Tx) recursivelyCheckPageKeyOrderInternal(
167
215
return p .LeafPageElement (p .Count () - 1 ).Key ()
168
216
}
169
217
default :
170
- ch <- fmt .Errorf ("unexpected page type for pgId:%d" , pgId )
218
+ ch <- fmt .Errorf ("unexpected page type (flags: %x) for pgId:%d" , p . Flags () , pgId )
171
219
}
172
220
return maxKeyInSubtree
173
221
}
@@ -202,6 +250,7 @@ func verifyKeyOrder(pgId common.Pgid, pageType string, index int, key []byte, pr
202
250
203
251
type checkConfig struct {
204
252
kvStringer KVStringer
253
+ pageId uint
205
254
}
206
255
207
256
type CheckOption func (options * checkConfig )
@@ -212,6 +261,13 @@ func WithKVStringer(kvStringer KVStringer) CheckOption {
212
261
}
213
262
}
214
263
264
+ // WithPageId sets a page ID from which the check command starts to check
265
+ func WithPageId (pageId uint ) CheckOption {
266
+ return func (c * checkConfig ) {
267
+ c .pageId = pageId
268
+ }
269
+ }
270
+
215
271
// KVStringer allows to prepare human-readable diagnostic messages.
216
272
type KVStringer interface {
217
273
KeyToString ([]byte ) string
0 commit comments