github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/bitree_test.go (about) 1 // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bitree 16 17 import ( 18 "bytes" 19 "fmt" 20 "os" 21 "sync" 22 "testing" 23 "time" 24 25 "github.com/stretchr/testify/require" 26 "github.com/zuoyebang/bitalosdb/bitable" 27 "github.com/zuoyebang/bitalosdb/bitpage" 28 "github.com/zuoyebang/bitalosdb/bitree/bdb" 29 "github.com/zuoyebang/bitalosdb/internal/base" 30 "github.com/zuoyebang/bitalosdb/internal/bitask" 31 "github.com/zuoyebang/bitalosdb/internal/consts" 32 "github.com/zuoyebang/bitalosdb/internal/hash" 33 "github.com/zuoyebang/bitalosdb/internal/options" 34 "github.com/zuoyebang/bitalosdb/internal/sortedkv" 35 "github.com/zuoyebang/bitalosdb/internal/utils" 36 ) 37 38 const testDir = "test" 39 const testBitreeIndex = 1 40 41 var testBtree *Bitree 42 43 type testBitpageTask struct { 44 task *bitask.BitpageTask 45 taskWg sync.WaitGroup 46 } 47 48 var bpageTask *testBitpageTask 49 50 var ( 51 testBithashSize = 128 << 20 52 testIsUseBitable = false 53 ) 54 55 func makeTestKey(i int) []byte { 56 return []byte(fmt.Sprintf("bitree_key_%d", i)) 57 } 58 59 func testMakeSortedKV(num int, seqNum uint64, vsize int) sortedkv.SortedKVList { 60 return sortedkv.MakeSlotSortedKVList(0, num, seqNum, vsize, uint16(testBitreeIndex)) 61 } 62 63 func testMakeSortedSlotKey(n int) []byte { 64 return sortedkv.MakeSortedSlotKey(n, uint16(testBitreeIndex)) 65 } 66 67 func testNewBitreePages(t *Bitree) error { 68 err := t.bdb.Update(func(tx *bdb.Tx) error { 69 bkt := tx.Bucket(consts.BdbBucketName) 70 if bkt == nil { 71 return bdb.ErrBucketNotFound 72 } 73 for j := 1; j < 10; j++ { 74 key := makeTestKey(j) 75 pn, err := t.bpage.NewPage() 76 if err != nil { 77 return err 78 } 79 if err = bkt.Put(key, pn.ToByte()); err != nil { 80 return err 81 } 82 } 83 return nil 84 }) 85 return err 86 } 87 88 func resetTestOptsVal() { 89 testBithashSize = 128 << 20 90 testIsUseBitable = false 91 } 92 93 func testOpenBitree() (*Bitree, *options.BitreeOptions) { 94 defer func() { 95 resetTestOptsVal() 96 }() 97 optsPool := options.InitTestDefaultsOptionsPool() 98 return testOpenBitree1(optsPool) 99 } 100 101 func testOpenBitree1(optsPool *options.OptionsPool) (*Bitree, *options.BitreeOptions) { 102 bpageTask = &testBitpageTask{} 103 bpageTask.task = bitask.NewBitpageTask(&bitask.BitpageTaskOptions{ 104 Size: 100, 105 DbState: optsPool.DbState, 106 Logger: optsPool.BaseOptions.Logger, 107 DoFunc: testDoBitpageTask, 108 TaskWg: &bpageTask.taskWg, 109 }) 110 optsPool.BaseOptions.BitpageTaskPushFunc = bpageTask.task.PushTask 111 optsPool.BaseOptions.UseBitable = testIsUseBitable 112 optsPool.BithashOptions.TableMaxSize = testBithashSize 113 optsPool.BaseOptions.KeyPrefixDeleteFunc = options.TestKeyPrefixDeleteFunc 114 bitreeOpts := optsPool.CloneBitreeOptions() 115 bitreeOpts.Index = testBitreeIndex 116 117 var err error 118 testBtree, err = NewBitree(testDir, bitreeOpts) 119 if err != nil { 120 panic(err) 121 } 122 return testBtree, bitreeOpts 123 } 124 125 func testDoBitpageTask(task *bitask.BitpageTaskData) { 126 testBtree.DoBitpageTask(task) 127 } 128 129 func testBitreeClose(bt *Bitree) error { 130 bpageTask.task.Close() 131 bpageTask.taskWg.Wait() 132 err := bt.Close() 133 bt.opts.DeleteFilePacer.Close() 134 return err 135 } 136 137 func TestBitree_CompactToBitable(t *testing.T) { 138 defer os.RemoveAll(testDir) 139 os.RemoveAll(testDir) 140 testBithashSize = 10 << 20 141 testIsUseBitable = true 142 btree, _ := testOpenBitree() 143 defer func() { 144 require.NoError(t, testBitreeClose(btree)) 145 }() 146 147 require.NotEqual(t, (*bitable.Bitable)(nil), btree.btable) 148 149 err := btree.bdb.Update(func(tx *bdb.Tx) error { 150 bkt := tx.Bucket(consts.BdbBucketName) 151 if bkt == nil { 152 return bdb.ErrBucketNotFound 153 } 154 for i := 1; i < 10; i++ { 155 key := makeTestKey(i) 156 pn, err := btree.bpage.NewPage() 157 require.NoError(t, err) 158 require.NoError(t, bkt.Put(key, pn.ToByte())) 159 } 160 return nil 161 }) 162 btree.txPool.Update() 163 require.NoError(t, err) 164 165 bw, err := btree.NewBitreeWriter() 166 require.NoError(t, err) 167 largeValue := utils.FuncRandBytes(520) 168 smallValue := utils.FuncRandBytes(500) 169 keyCount := 1000 170 seqNum := uint64(0) 171 kvList := testMakeSortedKV(keyCount, seqNum, 10) 172 seqNum += uint64(keyCount) 173 174 for i := 0; i < keyCount; i++ { 175 if i%2 == 0 { 176 kvList[i].Value = smallValue 177 } else { 178 kvList[i].Value = largeValue 179 } 180 require.NoError(t, bw.Apply(*kvList[i].Key, kvList[i].Value)) 181 } 182 require.NoError(t, bw.Finish()) 183 184 time.Sleep(2 * time.Second) 185 186 readIter := func(it base.InternalIterator) { 187 i := 0 188 for k, v := it.First(); k != nil; k, v = it.Next() { 189 if base.InternalCompare(bytes.Compare, *kvList[i].Key, *k) != 0 { 190 t.Fatal("InternalCompare", i, k.String(), kvList[i].Key.String()) 191 } 192 require.Equal(t, kvList[i].Value, v) 193 i++ 194 } 195 require.Equal(t, keyCount, i) 196 } 197 198 btreeIter := btree.newBitreeIter(nil) 199 readIter(btreeIter) 200 require.NoError(t, btreeIter.Close()) 201 202 require.Equal(t, 10, btree.bpage.GetPageCount()) 203 pn := btree.CompactBitreeToBitable() 204 205 bdbIter := btree.NewBdbIter() 206 bdbKey, bdbValue := bdbIter.First() 207 require.Equal(t, consts.BdbMaxKey, bdbKey.UserKey) 208 require.Equal(t, uint32(pn), utils.BytesToUint32(bdbValue)) 209 bdbKey, _ = bdbIter.Next() 210 require.Equal(t, (*base.InternalKey)(nil), bdbKey) 211 require.NoError(t, bdbIter.Close()) 212 213 isFree := btree.bpage.CheckFreePages(pn) 214 require.Equal(t, true, isFree) 215 216 _ = btree.bdb.Update(func(tx *bdb.Tx) error { return nil }) 217 btree.txPool.Update() 218 _ = btree.bdb.Update(func(tx *bdb.Tx) error { return nil }) 219 220 time.Sleep(2 * time.Second) 221 require.Equal(t, 1, btree.bpage.GetPageCount()) 222 223 btableIter := btree.newBitableIter(nil) 224 readIter(btableIter) 225 require.NoError(t, btableIter.Close()) 226 227 btreeIter = btree.newBitreeIter(nil) 228 ik, _ := btreeIter.First() 229 require.Equal(t, (*base.InternalKey)(nil), ik) 230 require.NoError(t, btreeIter.Close()) 231 } 232 233 func TestBitree_Checkpoint_Flush(t *testing.T) { 234 ckDir := testDir + "_ck" 235 os.RemoveAll(testDir) 236 os.RemoveAll(ckDir) 237 238 require.NoError(t, os.MkdirAll(ckDir, 0755)) 239 btree, _ := testOpenBitree() 240 defer func() { 241 require.NoError(t, testBitreeClose(btree)) 242 require.NoError(t, os.RemoveAll(testDir)) 243 require.NoError(t, os.RemoveAll(ckDir)) 244 }() 245 246 require.NoError(t, testNewBitreePages(btree)) 247 248 keyCount := 200 249 seqNum := uint64(0) 250 kvList := testMakeSortedKV(keyCount, seqNum, 200) 251 seqNum += uint64(keyCount) 252 253 writeData := func(start int) { 254 bw, err := btree.NewBitreeWriter() 255 require.NoError(t, err) 256 for i := start; i < start+100; i++ { 257 require.NoError(t, bw.Apply(*kvList[i].Key, kvList[i].Value)) 258 } 259 require.NoError(t, bw.Finish()) 260 } 261 262 writeData(0) 263 time.Sleep(1 * time.Second) 264 require.Equal(t, uint64(0), btree.dbState.GetBitpageFlushCount()) 265 require.NoError(t, btree.Checkpoint(btree.opts.FS, ckDir, testDir)) 266 267 writeData(100) 268 time.Sleep(1 * time.Second) 269 require.Equal(t, uint64(1), btree.dbState.GetBitpageFlushCount()) 270 271 for i := 0; i < keyCount; i++ { 272 k := kvList[i].Key.UserKey 273 v, exist, vcloser := btree.Get(k, hash.Crc32(k)) 274 require.Equal(t, true, exist) 275 require.Equal(t, kvList[i].Value, v) 276 vcloser() 277 } 278 } 279 280 func TestBitree_BitpageFlushState(t *testing.T) { 281 defer os.RemoveAll(testDir) 282 os.RemoveAll(testDir) 283 284 btree, _ := testOpenBitree() 285 require.NoError(t, testNewBitreePages(btree)) 286 287 keyCount := 100 288 seqNum := uint64(0) 289 kvList := testMakeSortedKV(keyCount, seqNum, 200) 290 seqNum += uint64(keyCount) 291 292 var pageNum bitpage.PageNum 293 bw, err := btree.NewBitreeWriter() 294 require.NoError(t, err) 295 for i := 0; i < keyCount; i++ { 296 pn, sentinel, closer := btree.FindKeyPageNum(kvList[i].Key.UserKey) 297 closer() 298 require.NotEqual(t, nilPageNum, pn) 299 require.NoError(t, bw.set(*kvList[i].Key, kvList[i].Value, pn, sentinel)) 300 pageNum = pn 301 } 302 require.NoError(t, bw.Finish()) 303 304 task := &bitask.BitpageTaskData{ 305 Event: bitask.BitpageEventFlush, 306 Pn: uint32(pageNum), 307 Sentinel: nil, 308 } 309 err = btree.bpage.PageFlush(bitpage.PageNum(task.Pn), task.Sentinel, "") 310 require.Equal(t, bitpage.ErrPageFlushState, err) 311 312 require.NoError(t, testBitreeClose(btree)) 313 } 314 315 func TestBitree_BitpageFlushDelPercent(t *testing.T) { 316 defer os.RemoveAll(testDir) 317 os.RemoveAll(testDir) 318 319 optsPool := options.InitTestDefaultsOptionsPool() 320 optsPool.BaseOptions.BitpageFlushSize = 40 << 10 321 btree, _ := testOpenBitree1(optsPool) 322 require.NoError(t, testNewBitreePages(btree)) 323 324 keyCount := 1000 325 seqNum := uint64(0) 326 kvList := testMakeSortedKV(keyCount, seqNum, 500) 327 seqNum += uint64(keyCount) 328 329 var pageNum bitpage.PageNum 330 bw, err := btree.NewBitreeWriter() 331 require.NoError(t, err) 332 for i := 0; i < keyCount; i++ { 333 k := makeTestKey(i) 334 pn, sentinel, closer := btree.FindKeyPageNum(k) 335 closer() 336 require.NotEqual(t, nilPageNum, pn) 337 if i%2 == 0 || i > 700 { 338 kvList[i].Key.SetKind(base.InternalKeyKindDelete) 339 } 340 require.NoError(t, bw.set(*kvList[i].Key, kvList[i].Value, pn, sentinel)) 341 pageNum = pn 342 } 343 344 delPercent := btree.bpage.GetPageDelPercent(pageNum) 345 if delPercent < 0.5 { 346 t.Fatal("delpercent err", delPercent) 347 } 348 require.NoError(t, bw.Finish()) 349 time.Sleep(2 * time.Second) 350 require.Equal(t, uint64(1), btree.dbState.GetBitpageFlushCount()) 351 352 for i := 0; i < keyCount; i++ { 353 k := kvList[i].Key.UserKey 354 v, exist, vcloser := btree.Get(k, hash.Crc32(k)) 355 if i%2 == 0 || i > 700 { 356 require.Equal(t, false, exist) 357 } else { 358 require.Equal(t, true, exist) 359 require.Equal(t, kvList[i].Value, v) 360 vcloser() 361 } 362 } 363 364 require.NoError(t, testBitreeClose(btree)) 365 } 366 367 func TestBitree_BitableFlushBatch(t *testing.T) { 368 defer os.RemoveAll(testDir) 369 os.RemoveAll(testDir) 370 371 testBithashSize = 10 << 20 372 testIsUseBitable = true 373 btree, _ := testOpenBitree() 374 defer func() { 375 require.NoError(t, testBitreeClose(btree)) 376 require.NoError(t, os.RemoveAll(testDir)) 377 }() 378 379 batch := btree.btable.NewFlushBatch(1 << 20) 380 require.Equal(t, true, batch.Empty()) 381 batch.Set([]byte("123"), []byte("123")) 382 require.Equal(t, false, batch.Empty()) 383 batch.Delete([]byte("123")) 384 require.Equal(t, false, batch.Empty()) 385 batch.AllocFree() 386 require.NoError(t, batch.Close()) 387 } 388 389 func TestBitree_IterRange(t *testing.T) { 390 defer os.RemoveAll(testDir) 391 os.RemoveAll(testDir) 392 393 btree, _ := testOpenBitree() 394 require.NoError(t, testNewBitreePages(btree)) 395 396 largeValue := utils.FuncRandBytes(consts.KvSeparateSize + 200) 397 smallValue := utils.FuncRandBytes(consts.KvSeparateSize - 10) 398 keyCount := 100 399 seqNum := uint64(0) 400 kvList := testMakeSortedKV(keyCount, seqNum, 1) 401 seqNum += uint64(keyCount) 402 403 bw, err := btree.NewBitreeWriter() 404 require.NoError(t, err) 405 for i := 0; i < keyCount; i++ { 406 if i%3 == 0 { 407 kvList[i].Value = smallValue 408 } else if i%3 == 1 { 409 kvList[i].Value = largeValue 410 } else { 411 kvList[i].Key.SetKind(base.InternalKeyKindDelete) 412 } 413 kvList[i].Key.SetSeqNum(seqNum) 414 seqNum++ 415 require.NoError(t, bw.Apply(*kvList[i].Key, kvList[i].Value)) 416 } 417 require.NoError(t, bw.Finish()) 418 time.Sleep(2 * time.Second) 419 420 rangeLoop := func(o *options.IterOptions, start int) int { 421 iter := btree.newBitreeIter(o) 422 i := start 423 count := 0 424 for ik, val := iter.First(); ik != nil; ik, val = iter.Next() { 425 require.Equal(t, 0, base.InternalCompare(bytes.Compare, *kvList[i].Key, *ik)) 426 kind := ik.Kind() 427 if i%3 == 0 || i%3 == 1 { 428 require.Equal(t, base.InternalKeyKindSet, kind) 429 require.Equal(t, kvList[i].Value, val) 430 } else { 431 require.Equal(t, base.InternalKeyKindDelete, kind) 432 require.Equal(t, 0, len(val)) 433 } 434 i++ 435 count++ 436 } 437 require.NoError(t, iter.Close()) 438 return count 439 } 440 441 rangeReverseLoop := func(o *options.IterOptions, start int) int { 442 iter := btree.newBitreeIter(o) 443 i := start 444 count := 0 445 for ik, val := iter.Last(); ik != nil; ik, val = iter.Prev() { 446 require.Equal(t, 0, base.InternalCompare(bytes.Compare, *kvList[i].Key, *ik)) 447 kind := ik.Kind() 448 if i%3 == 0 || i%3 == 1 { 449 require.Equal(t, base.InternalKeyKindSet, kind) 450 require.Equal(t, kvList[i].Value, val) 451 } else { 452 require.Equal(t, base.InternalKeyKindDelete, kind) 453 require.Equal(t, 0, len(val)) 454 } 455 i-- 456 count++ 457 } 458 require.NoError(t, iter.Close()) 459 return count 460 } 461 462 require.Equal(t, keyCount, rangeLoop(nil, 0)) 463 require.Equal(t, keyCount, rangeReverseLoop(nil, keyCount-1)) 464 ops := &options.IterOptions{ 465 LowerBound: kvList[20].Key.UserKey, 466 UpperBound: kvList[50].Key.UserKey, 467 } 468 require.Equal(t, 30, rangeLoop(ops, 20)) 469 require.Equal(t, 30, rangeReverseLoop(ops, 49)) 470 ops = &options.IterOptions{ 471 LowerBound: kvList[30].Key.UserKey, 472 } 473 require.Equal(t, 70, rangeLoop(ops, 30)) 474 ops = &options.IterOptions{ 475 UpperBound: kvList[50].Key.UserKey, 476 } 477 require.Equal(t, 50, rangeReverseLoop(ops, 49)) 478 479 require.NoError(t, testBitreeClose(btree)) 480 } 481 482 func TestBitree_IterSeek(t *testing.T) { 483 defer os.RemoveAll(testDir) 484 os.RemoveAll(testDir) 485 486 btree, _ := testOpenBitree() 487 require.NoError(t, testNewBitreePages(btree)) 488 489 keyCount := 100 490 seqNum := uint64(0) 491 kvList := testMakeSortedKV(keyCount, seqNum, 520) 492 seqNum += uint64(keyCount) 493 494 bw, err := btree.NewBitreeWriter() 495 require.NoError(t, err) 496 for i := 0; i < keyCount; i++ { 497 if i >= 1 && i < 13 { 498 continue 499 } 500 require.NoError(t, bw.Apply(*kvList[i].Key, kvList[i].Value)) 501 } 502 require.NoError(t, bw.Finish()) 503 time.Sleep(2 * time.Second) 504 505 makeByte := func(pos, extra int) []byte { 506 return []byte(fmt.Sprintf("%s%d", string(kvList[pos].Key.UserKey), extra)) 507 } 508 509 iterOp := func(it *BitreeIterator, op string, seek []byte, want int) { 510 var ik *base.InternalKey 511 var v []byte 512 switch op { 513 case "SeekGE": 514 ik, v = it.SeekGE(seek) 515 case "SeekLT": 516 ik, v = it.SeekLT(seek) 517 case "First": 518 ik, v = it.First() 519 case "Next": 520 ik, v = it.Next() 521 case "Last": 522 ik, v = it.Last() 523 case "Prev": 524 ik, v = it.Prev() 525 } 526 if want == -1 { 527 require.Equal(t, (*base.InternalKey)(nil), ik) 528 } else { 529 require.Equal(t, kvList[want].Key, ik) 530 require.Equal(t, kvList[want].Value, v) 531 } 532 } 533 534 iter := btree.newBitreeIter(nil) 535 iterOp(iter, "SeekGE", kvList[14].Key.UserKey, 14) 536 iterOp(iter, "SeekGE", makeByte(14, 1), 15) 537 iterOp(iter, "SeekGE", kvList[29].Key.UserKey, 29) 538 iterOp(iter, "SeekGE", makeByte(29, 0), 30) 539 iterOp(iter, "SeekGE", makeByte(49, 1), 50) 540 iterOp(iter, "SeekGE", kvList[99].Key.UserKey, 99) 541 iterOp(iter, "SeekGE", testMakeSortedSlotKey(990), -1) 542 require.NoError(t, iter.Close()) 543 544 iter = btree.newBitreeIter(nil) 545 iterOp(iter, "SeekLT", kvList[14].Key.UserKey, 13) 546 iterOp(iter, "SeekLT", makeByte(14, 1), 14) 547 iterOp(iter, "SeekLT", kvList[30].Key.UserKey, 29) 548 iterOp(iter, "SeekLT", kvList[31].Key.UserKey, 30) 549 iterOp(iter, "SeekLT", testMakeSortedSlotKey(990), 99) 550 iterOp(iter, "SeekLT", kvList[0].Key.UserKey, -1) 551 require.NoError(t, iter.Close()) 552 553 bw, err = btree.NewBitreeWriter() 554 require.NoError(t, err) 555 for i := 0; i < keyCount; i++ { 556 if i > 0 && i < 90 { 557 continue 558 } 559 kvList[i].Key.SetKind(base.InternalKeyKindDelete) 560 kvList[i].Key.SetSeqNum(seqNum) 561 kvList[i].Value = []byte(nil) 562 seqNum++ 563 require.NoError(t, bw.Apply(*kvList[i].Key, kvList[i].Value)) 564 } 565 require.NoError(t, bw.Finish()) 566 time.Sleep(1 * time.Second) 567 568 iter = btree.newBitreeIter(nil) 569 iterOp(iter, "First", nil, 0) 570 iterOp(iter, "Next", nil, 13) 571 iterOp(iter, "SeekGE", testMakeSortedSlotKey(2), 13) 572 iterOp(iter, "Prev", nil, 0) 573 iterOp(iter, "Next", nil, 13) 574 iterOp(iter, "Last", nil, 99) 575 iterOp(iter, "Prev", nil, 98) 576 iterOp(iter, "SeekGE", kvList[89].Key.UserKey, 89) 577 iterOp(iter, "Prev", nil, 88) 578 iterOp(iter, "SeekLT", kvList[60].Key.UserKey, 59) 579 iterOp(iter, "Next", nil, 60) 580 iterOp(iter, "Prev", nil, 59) 581 require.NoError(t, iter.Close()) 582 583 require.NoError(t, testBitreeClose(btree)) 584 } 585 586 func TestBitree_IterCache(t *testing.T) { 587 defer os.RemoveAll(testDir) 588 os.RemoveAll(testDir) 589 590 optspool := options.InitDefaultsOptionsPool() 591 optspool.BaseOptions.BitpageFlushSize = 1 << 20 592 optspool.BaseOptions.UseBlockCompress = true 593 btree, _ := testOpenBitree1(optspool) 594 require.NoError(t, testNewBitreePages(btree)) 595 596 keyCount := 10000 597 seqNum := uint64(0) 598 kvList := testMakeSortedKV(keyCount, seqNum, 100) 599 seqNum += uint64(keyCount) 600 601 bw, err := btree.NewBitreeWriter() 602 require.NoError(t, err) 603 for i := 0; i < keyCount; i++ { 604 kvList[i].Key.SetSeqNum(seqNum) 605 seqNum++ 606 require.NoError(t, bw.Apply(*kvList[i].Key, kvList[i].Value)) 607 } 608 require.NoError(t, bw.Finish()) 609 time.Sleep(1 * time.Second) 610 611 rangeLoop := func(o *options.IterOptions) int { 612 iter := btree.newBitreeIter(o) 613 i := 0 614 for ik, val := iter.First(); ik != nil; ik, val = iter.Next() { 615 require.Equal(t, *kvList[i].Key, *ik) 616 require.Equal(t, kvList[i].Value, val) 617 i++ 618 } 619 require.NoError(t, iter.Close()) 620 return i 621 } 622 623 iterOpts := &options.IterOptions{DisableCache: true} 624 require.Equal(t, keyCount, rangeLoop(iterOpts)) 625 fmt.Println("start range disable cache", btree.bpage.GetCacheMetrics()) 626 627 require.Equal(t, keyCount, rangeLoop(nil)) 628 fmt.Println("start range use cache", btree.bpage.GetCacheMetrics()) 629 630 require.NoError(t, testBitreeClose(btree)) 631 }