github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/iterator_test.go (about) 1 // Copyright 2013 The LevelDB-Go and Pebble and Bitalostored Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package bitalostable 6 7 import ( 8 "bytes" 9 "flag" 10 "fmt" 11 "io" 12 "runtime" 13 "sort" 14 "strconv" 15 "strings" 16 "sync/atomic" 17 "testing" 18 "time" 19 20 "github.com/cockroachdb/errors" 21 "github.com/stretchr/testify/require" 22 "github.com/zuoyebang/bitalostable/internal/base" 23 "github.com/zuoyebang/bitalostable/internal/datadriven" 24 "github.com/zuoyebang/bitalostable/internal/keyspan" 25 "github.com/zuoyebang/bitalostable/internal/manifest" 26 "github.com/zuoyebang/bitalostable/internal/testkeys" 27 "github.com/zuoyebang/bitalostable/internal/testkeys/blockprop" 28 "github.com/zuoyebang/bitalostable/sstable" 29 "github.com/zuoyebang/bitalostable/vfs" 30 "golang.org/x/exp/rand" 31 ) 32 33 var testKeyValuePairs = []string{ 34 "10:10", 35 "11:11", 36 "12:12", 37 "13:13", 38 "14:14", 39 "15:15", 40 "16:16", 41 "17:17", 42 "18:18", 43 "19:19", 44 } 45 46 type fakeIter struct { 47 lower []byte 48 upper []byte 49 keys []InternalKey 50 vals [][]byte 51 index int 52 valid bool 53 closeErr error 54 } 55 56 // fakeIter implements the base.InternalIterator interface. 57 var _ base.InternalIterator = (*fakeIter)(nil) 58 59 func fakeIkey(s string) InternalKey { 60 j := strings.Index(s, ":") 61 seqNum, err := strconv.Atoi(s[j+1:]) 62 if err != nil { 63 panic(err) 64 } 65 return base.MakeInternalKey([]byte(s[:j]), uint64(seqNum), InternalKeyKindSet) 66 } 67 68 func newFakeIterator(closeErr error, keys ...string) *fakeIter { 69 ikeys := make([]InternalKey, len(keys)) 70 for i, k := range keys { 71 ikeys[i] = fakeIkey(k) 72 } 73 return &fakeIter{ 74 keys: ikeys, 75 index: 0, 76 valid: len(ikeys) > 0, 77 closeErr: closeErr, 78 } 79 } 80 81 func (f *fakeIter) String() string { 82 return "fake" 83 } 84 85 func (f *fakeIter) SeekGE(key []byte, flags base.SeekGEFlags) (*InternalKey, []byte) { 86 f.valid = false 87 for f.index = 0; f.index < len(f.keys); f.index++ { 88 if DefaultComparer.Compare(key, f.key().UserKey) <= 0 { 89 if f.upper != nil && DefaultComparer.Compare(f.upper, f.key().UserKey) <= 0 { 90 return nil, nil 91 } 92 f.valid = true 93 return f.Key(), f.Value() 94 } 95 } 96 return nil, nil 97 } 98 99 func (f *fakeIter) SeekPrefixGE( 100 prefix, key []byte, flags base.SeekGEFlags, 101 ) (*base.InternalKey, []byte) { 102 return f.SeekGE(key, flags) 103 } 104 105 func (f *fakeIter) SeekLT(key []byte, flags base.SeekLTFlags) (*InternalKey, []byte) { 106 f.valid = false 107 for f.index = len(f.keys) - 1; f.index >= 0; f.index-- { 108 if DefaultComparer.Compare(key, f.key().UserKey) > 0 { 109 if f.lower != nil && DefaultComparer.Compare(f.lower, f.key().UserKey) > 0 { 110 return nil, nil 111 } 112 f.valid = true 113 return f.Key(), f.Value() 114 } 115 } 116 return nil, nil 117 } 118 119 func (f *fakeIter) First() (*InternalKey, []byte) { 120 f.valid = false 121 f.index = -1 122 if key, _ := f.Next(); key == nil { 123 return nil, nil 124 } 125 if f.upper != nil && DefaultComparer.Compare(f.upper, f.key().UserKey) <= 0 { 126 return nil, nil 127 } 128 f.valid = true 129 return f.Key(), f.Value() 130 } 131 132 func (f *fakeIter) Last() (*InternalKey, []byte) { 133 f.valid = false 134 f.index = len(f.keys) 135 if key, _ := f.Prev(); key == nil { 136 return nil, nil 137 } 138 if f.lower != nil && DefaultComparer.Compare(f.lower, f.key().UserKey) > 0 { 139 return nil, nil 140 } 141 f.valid = true 142 return f.Key(), f.Value() 143 } 144 145 func (f *fakeIter) Next() (*InternalKey, []byte) { 146 f.valid = false 147 if f.index == len(f.keys) { 148 return nil, nil 149 } 150 f.index++ 151 if f.index == len(f.keys) { 152 return nil, nil 153 } 154 if f.upper != nil && DefaultComparer.Compare(f.upper, f.key().UserKey) <= 0 { 155 return nil, nil 156 } 157 f.valid = true 158 return f.Key(), f.Value() 159 } 160 161 func (f *fakeIter) Prev() (*InternalKey, []byte) { 162 f.valid = false 163 if f.index < 0 { 164 return nil, nil 165 } 166 f.index-- 167 if f.index < 0 { 168 return nil, nil 169 } 170 if f.lower != nil && DefaultComparer.Compare(f.lower, f.key().UserKey) > 0 { 171 return nil, nil 172 } 173 f.valid = true 174 return f.Key(), f.Value() 175 } 176 177 // key returns the current Key the iterator is positioned at regardless of the 178 // value of f.valid. 179 func (f *fakeIter) key() *InternalKey { 180 return &f.keys[f.index] 181 } 182 183 func (f *fakeIter) Key() *InternalKey { 184 if f.valid { 185 return &f.keys[f.index] 186 } 187 // It is invalid to call Key() when Valid() returns false. Rather than 188 // returning nil here which would technically be more correct, return a 189 // non-nil key which is the behavior of some InternalIterator 190 // implementations. This provides better testing of users of 191 // InternalIterators. 192 if f.index < 0 { 193 return &f.keys[0] 194 } 195 return &f.keys[len(f.keys)-1] 196 } 197 198 func (f *fakeIter) Value() []byte { 199 if f.index >= 0 && f.index < len(f.vals) { 200 return f.vals[f.index] 201 } 202 return nil 203 } 204 205 func (f *fakeIter) Valid() bool { 206 return f.index >= 0 && f.index < len(f.keys) && f.valid 207 } 208 209 func (f *fakeIter) Error() error { 210 return f.closeErr 211 } 212 213 func (f *fakeIter) Close() error { 214 return f.closeErr 215 } 216 217 func (f *fakeIter) SetBounds(lower, upper []byte) { 218 f.lower = lower 219 f.upper = upper 220 } 221 222 // invalidatingIter tests unsafe key/value slice reuse by modifying the last 223 // returned key/value to all 1s. 224 type invalidatingIter struct { 225 iter internalIterator 226 lastKey *InternalKey 227 lastValue []byte 228 ignoreKinds [base.InternalKeyKindMax + 1]bool 229 } 230 231 func newInvalidatingIter(iter internalIterator) *invalidatingIter { 232 return &invalidatingIter{iter: iter} 233 } 234 235 func (i *invalidatingIter) ignoreKind(kind base.InternalKeyKind) { 236 i.ignoreKinds[kind] = true 237 } 238 239 func (i *invalidatingIter) update(key *InternalKey, value []byte) (*InternalKey, []byte) { 240 i.zeroLast() 241 242 if key == nil { 243 i.lastKey = nil 244 i.lastValue = nil 245 return nil, nil 246 } 247 248 i.lastKey = &InternalKey{} 249 *i.lastKey = key.Clone() 250 i.lastValue = make([]byte, len(value)) 251 copy(i.lastValue, value) 252 return i.lastKey, i.lastValue 253 } 254 255 func (i *invalidatingIter) zeroLast() { 256 if i.lastKey == nil { 257 return 258 } 259 if i.ignoreKinds[i.lastKey.Kind()] { 260 return 261 } 262 263 if i.lastKey != nil { 264 for j := range i.lastKey.UserKey { 265 i.lastKey.UserKey[j] = 0xff 266 } 267 i.lastKey.Trailer = 0 268 } 269 for j := range i.lastValue { 270 i.lastValue[j] = 0xff 271 } 272 } 273 274 func (i *invalidatingIter) SeekGE(key []byte, flags base.SeekGEFlags) (*InternalKey, []byte) { 275 return i.update(i.iter.SeekGE(key, flags)) 276 } 277 278 func (i *invalidatingIter) SeekPrefixGE( 279 prefix, key []byte, flags base.SeekGEFlags, 280 ) (*base.InternalKey, []byte) { 281 return i.update(i.iter.SeekPrefixGE(prefix, key, flags)) 282 } 283 284 func (i *invalidatingIter) SeekLT(key []byte, flags base.SeekLTFlags) (*InternalKey, []byte) { 285 return i.update(i.iter.SeekLT(key, flags)) 286 } 287 288 func (i *invalidatingIter) First() (*InternalKey, []byte) { 289 return i.update(i.iter.First()) 290 } 291 292 func (i *invalidatingIter) Last() (*InternalKey, []byte) { 293 return i.update(i.iter.Last()) 294 } 295 296 func (i *invalidatingIter) Next() (*InternalKey, []byte) { 297 return i.update(i.iter.Next()) 298 } 299 300 func (i *invalidatingIter) Prev() (*InternalKey, []byte) { 301 return i.update(i.iter.Prev()) 302 } 303 304 func (i *invalidatingIter) Error() error { 305 return i.iter.Error() 306 } 307 308 func (i *invalidatingIter) Close() error { 309 return i.iter.Close() 310 } 311 312 func (i *invalidatingIter) SetBounds(lower, upper []byte) { 313 i.iter.SetBounds(lower, upper) 314 } 315 316 func (i *invalidatingIter) String() string { 317 return i.iter.String() 318 } 319 320 // testIterator tests creating a combined iterator from a number of sub- 321 // iterators. newFunc is a constructor function. splitFunc returns a random 322 // split of the testKeyValuePairs slice such that walking a combined iterator 323 // over those splits should recover the original key/value pairs in order. 324 func testIterator( 325 t *testing.T, 326 newFunc func(...internalIterator) internalIterator, 327 splitFunc func(r *rand.Rand) [][]string, 328 ) { 329 // Test pre-determined sub-iterators. The sub-iterators are designed 330 // so that the combined key/value pair order is the same whether the 331 // combined iterator is concatenating or merging. 332 testCases := []struct { 333 desc string 334 iters []internalIterator 335 want string 336 }{ 337 { 338 "one sub-iterator", 339 []internalIterator{ 340 newFakeIterator(nil, "e:1", "w:2"), 341 }, 342 "<e:1><w:2>.", 343 }, 344 { 345 "two sub-iterators", 346 []internalIterator{ 347 newFakeIterator(nil, "a0:0"), 348 newFakeIterator(nil, "b1:1", "b2:2"), 349 }, 350 "<a0:0><b1:1><b2:2>.", 351 }, 352 { 353 "empty sub-iterators", 354 []internalIterator{ 355 newFakeIterator(nil), 356 newFakeIterator(nil), 357 newFakeIterator(nil), 358 }, 359 ".", 360 }, 361 { 362 "sub-iterator errors", 363 []internalIterator{ 364 newFakeIterator(nil, "a0:0", "a1:1"), 365 newFakeIterator(errors.New("the sky is falling"), "b2:2", "b3:3", "b4:4"), 366 newFakeIterator(errors.New("run for your lives"), "c5:5", "c6:6"), 367 }, 368 "<a0:0><a1:1><b2:2><b3:3><b4:4>err=the sky is falling", 369 }, 370 } 371 for _, tc := range testCases { 372 var b bytes.Buffer 373 iter := newInvalidatingIter(newFunc(tc.iters...)) 374 for key, _ := iter.First(); key != nil; key, _ = iter.Next() { 375 fmt.Fprintf(&b, "<%s:%d>", key.UserKey, key.SeqNum()) 376 } 377 if err := iter.Close(); err != nil { 378 fmt.Fprintf(&b, "err=%v", err) 379 } else { 380 b.WriteByte('.') 381 } 382 if got := b.String(); got != tc.want { 383 t.Errorf("%s:\ngot %q\nwant %q", tc.desc, got, tc.want) 384 } 385 } 386 387 // Test randomly generated sub-iterators. 388 r := rand.New(rand.NewSource(0)) 389 for i, nBad := 0, 0; i < 1000; i++ { 390 bad := false 391 392 splits := splitFunc(r) 393 iters := make([]internalIterator, len(splits)) 394 for i, split := range splits { 395 iters[i] = newFakeIterator(nil, split...) 396 } 397 iter := newInternalIterAdapter(newInvalidatingIter(newFunc(iters...))) 398 iter.First() 399 400 j := 0 401 for ; iter.Valid() && j < len(testKeyValuePairs); j++ { 402 got := fmt.Sprintf("%s:%d", iter.Key().UserKey, iter.Key().SeqNum()) 403 want := testKeyValuePairs[j] 404 if got != want { 405 bad = true 406 t.Errorf("random splits: i=%d, j=%d: got %q, want %q", i, j, got, want) 407 } 408 iter.Next() 409 } 410 if iter.Valid() { 411 bad = true 412 t.Errorf("random splits: i=%d, j=%d: iter was not exhausted", i, j) 413 } 414 if j != len(testKeyValuePairs) { 415 bad = true 416 t.Errorf("random splits: i=%d, j=%d: want j=%d", i, j, len(testKeyValuePairs)) 417 return 418 } 419 if err := iter.Close(); err != nil { 420 bad = true 421 t.Errorf("random splits: i=%d, j=%d: %v", i, j, err) 422 } 423 424 if bad { 425 nBad++ 426 if nBad == 10 { 427 t.Fatal("random splits: too many errors; stopping") 428 } 429 } 430 } 431 } 432 433 // deletableSumValueMerger computes the sum of its arguments, 434 // but transforms a zero sum into a non-existent entry. 435 type deletableSumValueMerger struct { 436 sum int64 437 } 438 439 func newDeletableSumValueMerger(key, value []byte) (ValueMerger, error) { 440 m := &deletableSumValueMerger{} 441 return m, m.MergeNewer(value) 442 } 443 444 func (m *deletableSumValueMerger) parseAndCalculate(value []byte) error { 445 v, err := strconv.ParseInt(string(value), 10, 64) 446 if err == nil { 447 m.sum += v 448 } 449 return err 450 } 451 452 func (m *deletableSumValueMerger) MergeNewer(value []byte) error { 453 return m.parseAndCalculate(value) 454 } 455 456 func (m *deletableSumValueMerger) MergeOlder(value []byte) error { 457 return m.parseAndCalculate(value) 458 } 459 460 func (m *deletableSumValueMerger) Finish(includesBase bool) ([]byte, io.Closer, error) { 461 if m.sum == 0 { 462 return nil, nil, nil 463 } 464 return []byte(strconv.FormatInt(m.sum, 10)), nil, nil 465 } 466 467 func (m *deletableSumValueMerger) DeletableFinish( 468 includesBase bool, 469 ) ([]byte, bool, io.Closer, error) { 470 value, closer, err := m.Finish(includesBase) 471 return value, len(value) == 0, closer, err 472 } 473 474 func TestIterator(t *testing.T) { 475 var merge Merge 476 var keys []InternalKey 477 var vals [][]byte 478 479 newIter := func(seqNum uint64, opts IterOptions) *Iterator { 480 if merge == nil { 481 merge = DefaultMerger.Merge 482 } 483 wrappedMerge := func(key, value []byte) (ValueMerger, error) { 484 if len(key) == 0 { 485 t.Fatalf("an empty key is passed into Merge") 486 } 487 return merge(key, value) 488 } 489 it := &Iterator{ 490 opts: opts, 491 comparer: *testkeys.Comparer, 492 merge: wrappedMerge, 493 } 494 // NB: Use a mergingIter to filter entries newer than seqNum. 495 iter := newMergingIter(nil /* logger */, &it.stats.InternalStats, it.cmp, it.split, &fakeIter{ 496 lower: opts.GetLowerBound(), 497 upper: opts.GetUpperBound(), 498 keys: keys, 499 vals: vals, 500 }) 501 iter.snapshot = seqNum 502 iter.elideRangeTombstones = true 503 // NB: This Iterator cannot be cloned since it is not constructed 504 // with a readState. It suffices for this test. 505 it.iter = newInvalidatingIter(iter) 506 return it 507 } 508 509 datadriven.RunTest(t, "testdata/iterator", func(d *datadriven.TestData) string { 510 switch d.Cmd { 511 case "define": 512 merge = nil 513 if len(d.CmdArgs) > 0 && d.CmdArgs[0].Key == "merger" && 514 len(d.CmdArgs[0].Vals) > 0 && d.CmdArgs[0].Vals[0] == "deletable" { 515 merge = newDeletableSumValueMerger 516 } 517 keys = keys[:0] 518 vals = vals[:0] 519 for _, key := range strings.Split(d.Input, "\n") { 520 j := strings.Index(key, ":") 521 keys = append(keys, base.ParseInternalKey(key[:j])) 522 vals = append(vals, []byte(key[j+1:])) 523 } 524 return "" 525 526 case "iter": 527 var seqNum int 528 var opts IterOptions 529 530 for _, arg := range d.CmdArgs { 531 if len(arg.Vals) != 1 { 532 return fmt.Sprintf("%s: %s=<value>", d.Cmd, arg.Key) 533 } 534 switch arg.Key { 535 case "seq": 536 var err error 537 seqNum, err = strconv.Atoi(arg.Vals[0]) 538 if err != nil { 539 return err.Error() 540 } 541 case "lower": 542 opts.LowerBound = []byte(arg.Vals[0]) 543 case "upper": 544 opts.UpperBound = []byte(arg.Vals[0]) 545 default: 546 return fmt.Sprintf("%s: unknown arg: %s", d.Cmd, arg.Key) 547 } 548 } 549 550 iter := newIter(uint64(seqNum), opts) 551 iterOutput := runIterCmd(d, iter, true) 552 stats := iter.Stats() 553 return fmt.Sprintf("%sstats: %s\n", iterOutput, stats.String()) 554 555 default: 556 return fmt.Sprintf("unknown command: %s", d.Cmd) 557 } 558 }) 559 } 560 561 type minSeqNumPropertyCollector struct { 562 minSeqNum uint64 563 } 564 565 func (c *minSeqNumPropertyCollector) Add(key InternalKey, value []byte) error { 566 if c.minSeqNum == 0 || c.minSeqNum > key.SeqNum() { 567 c.minSeqNum = key.SeqNum() 568 } 569 return nil 570 } 571 572 func (c *minSeqNumPropertyCollector) Finish(userProps map[string]string) error { 573 userProps["test.min-seq-num"] = fmt.Sprint(c.minSeqNum) 574 return nil 575 } 576 577 func (c *minSeqNumPropertyCollector) Name() string { 578 return "minSeqNumPropertyCollector" 579 } 580 581 func TestReadSampling(t *testing.T) { 582 var d *DB 583 defer func() { 584 if d != nil { 585 require.NoError(t, d.Close()) 586 } 587 }() 588 589 var iter *Iterator 590 defer func() { 591 if iter != nil { 592 require.NoError(t, iter.Close()) 593 } 594 }() 595 596 datadriven.RunTest(t, "testdata/iterator_read_sampling", func(td *datadriven.TestData) string { 597 switch td.Cmd { 598 case "define": 599 if iter != nil { 600 if err := iter.Close(); err != nil { 601 return err.Error() 602 } 603 } 604 if d != nil { 605 if err := d.Close(); err != nil { 606 return err.Error() 607 } 608 } 609 610 opts := &Options{} 611 opts.TablePropertyCollectors = append(opts.TablePropertyCollectors, 612 func() TablePropertyCollector { 613 return &minSeqNumPropertyCollector{} 614 }) 615 616 var err error 617 if d, err = runDBDefineCmd(td, opts); err != nil { 618 return err.Error() 619 } 620 621 d.mu.Lock() 622 // Disable the "dynamic base level" code for this test. 623 // d.mu.versions.picker.forceBaseLevel1() 624 s := d.mu.versions.currentVersion().String() 625 d.mu.Unlock() 626 return s 627 628 case "set": 629 if d == nil { 630 return fmt.Sprintf("%s: db is not defined", td.Cmd) 631 } 632 633 var allowedSeeks int64 634 635 for _, arg := range td.CmdArgs { 636 if len(arg.Vals) != 1 { 637 return fmt.Sprintf("%s: %s=<value>", td.Cmd, arg.Key) 638 } 639 switch arg.Key { 640 case "allowed-seeks": 641 var err error 642 allowedSeeks, err = strconv.ParseInt(arg.Vals[0], 10, 64) 643 if err != nil { 644 return err.Error() 645 } 646 } 647 } 648 649 d.mu.Lock() 650 for _, l := range d.mu.versions.currentVersion().Levels { 651 l.Slice().Each(func(f *fileMetadata) { 652 atomic.StoreInt64(&f.Atomic.AllowedSeeks, allowedSeeks) 653 }) 654 } 655 d.mu.Unlock() 656 return "" 657 658 case "show": 659 if d == nil { 660 return fmt.Sprintf("%s: db is not defined", td.Cmd) 661 } 662 663 var fileNum int64 664 for _, arg := range td.CmdArgs { 665 if len(arg.Vals) != 2 { 666 return fmt.Sprintf("%s: %s=<value>", td.Cmd, arg.Key) 667 } 668 switch arg.Key { 669 case "allowed-seeks": 670 var err error 671 fileNum, err = strconv.ParseInt(arg.Vals[0], 10, 64) 672 if err != nil { 673 return err.Error() 674 } 675 } 676 } 677 678 var foundAllowedSeeks int64 = -1 679 d.mu.Lock() 680 for _, l := range d.mu.versions.currentVersion().Levels { 681 l.Slice().Each(func(f *fileMetadata) { 682 if f.FileNum == base.FileNum(fileNum) { 683 actualAllowedSeeks := atomic.LoadInt64(&f.Atomic.AllowedSeeks) 684 foundAllowedSeeks = actualAllowedSeeks 685 } 686 }) 687 } 688 d.mu.Unlock() 689 690 if foundAllowedSeeks == -1 { 691 return fmt.Sprintf("invalid file num: %d", fileNum) 692 } 693 return fmt.Sprintf("%d", foundAllowedSeeks) 694 695 case "iter": 696 if iter == nil || iter.iter == nil { 697 // TODO(peter): runDBDefineCmd doesn't properly update the visible 698 // sequence number. So we have to use a snapshot with a very large 699 // sequence number, otherwise the DB appears empty. 700 snap := Snapshot{ 701 db: d, 702 seqNum: InternalKeySeqNumMax, 703 } 704 iter = snap.NewIter(nil) 705 iter.readSampling.forceReadSampling = true 706 } 707 return runIterCmd(td, iter, false) 708 709 case "read-compactions": 710 if d == nil { 711 return fmt.Sprintf("%s: db is not defined", td.Cmd) 712 } 713 714 d.mu.Lock() 715 var sb strings.Builder 716 if d.mu.compact.readCompactions.size == 0 { 717 sb.WriteString("(none)") 718 } 719 for i := 0; i < d.mu.compact.readCompactions.size; i++ { 720 rc := d.mu.compact.readCompactions.at(i) 721 sb.WriteString(fmt.Sprintf("(level: %d, start: %s, end: %s)\n", rc.level, string(rc.start), string(rc.end))) 722 } 723 d.mu.Unlock() 724 return sb.String() 725 726 case "iter-read-compactions": 727 if iter == nil { 728 return fmt.Sprintf("%s: iter is not defined", td.Cmd) 729 } 730 731 var sb strings.Builder 732 if iter.readSampling.pendingCompactions.size == 0 { 733 sb.WriteString("(none)") 734 } 735 for i := 0; i < iter.readSampling.pendingCompactions.size; i++ { 736 rc := iter.readSampling.pendingCompactions.at(i) 737 sb.WriteString(fmt.Sprintf("(level: %d, start: %s, end: %s)\n", rc.level, string(rc.start), string(rc.end))) 738 } 739 return sb.String() 740 741 case "close-iter": 742 if iter != nil { 743 if err := iter.Close(); err != nil { 744 return err.Error() 745 } 746 } 747 return "" 748 749 default: 750 return fmt.Sprintf("unknown command: %s", td.Cmd) 751 } 752 }) 753 } 754 755 func TestIteratorTableFilter(t *testing.T) { 756 var d *DB 757 defer func() { 758 if d != nil { 759 require.NoError(t, d.Close()) 760 } 761 }() 762 763 datadriven.RunTest(t, "testdata/iterator_table_filter", func(td *datadriven.TestData) string { 764 switch td.Cmd { 765 case "define": 766 if d != nil { 767 if err := d.Close(); err != nil { 768 return err.Error() 769 } 770 } 771 772 opts := &Options{} 773 opts.TablePropertyCollectors = append(opts.TablePropertyCollectors, 774 func() TablePropertyCollector { 775 return &minSeqNumPropertyCollector{} 776 }) 777 778 var err error 779 if d, err = runDBDefineCmd(td, opts); err != nil { 780 return err.Error() 781 } 782 783 d.mu.Lock() 784 // Disable the "dynamic base level" code for this test. 785 d.mu.versions.picker.forceBaseLevel1() 786 s := d.mu.versions.currentVersion().String() 787 d.mu.Unlock() 788 return s 789 790 case "iter": 791 // We're using an iterator table filter to approximate what is done by 792 // snapshots. 793 iterOpts := &IterOptions{} 794 for _, arg := range td.CmdArgs { 795 if len(arg.Vals) != 1 { 796 return fmt.Sprintf("%s: %s=<value>", td.Cmd, arg.Key) 797 } 798 switch arg.Key { 799 case "filter": 800 seqNum, err := strconv.ParseUint(arg.Vals[0], 10, 64) 801 if err != nil { 802 return err.Error() 803 } 804 iterOpts.TableFilter = func(userProps map[string]string) bool { 805 minSeqNum, err := strconv.ParseUint(userProps["test.min-seq-num"], 10, 64) 806 if err != nil { 807 return true 808 } 809 return minSeqNum < seqNum 810 } 811 default: 812 return fmt.Sprintf("%s: unknown arg: %s", td.Cmd, arg.Key) 813 } 814 } 815 816 // TODO(peter): runDBDefineCmd doesn't properly update the visible 817 // sequence number. So we have to use a snapshot with a very large 818 // sequence number, otherwise the DB appears empty. 819 snap := Snapshot{ 820 db: d, 821 seqNum: InternalKeySeqNumMax, 822 } 823 iter := snap.NewIter(iterOpts) 824 return runIterCmd(td, iter, true) 825 826 default: 827 return fmt.Sprintf("unknown command: %s", td.Cmd) 828 } 829 }) 830 } 831 832 func TestIteratorNextPrev(t *testing.T) { 833 var mem vfs.FS 834 var d *DB 835 defer func() { 836 require.NoError(t, d.Close()) 837 }() 838 839 reset := func() { 840 if d != nil { 841 require.NoError(t, d.Close()) 842 } 843 844 mem = vfs.NewMem() 845 require.NoError(t, mem.MkdirAll("ext", 0755)) 846 opts := &Options{FS: mem} 847 // Automatic compactions may compact away tombstones from L6, making 848 // some testcases non-deterministic. 849 opts.DisableAutomaticCompactions = true 850 var err error 851 d, err = Open("", opts) 852 require.NoError(t, err) 853 } 854 reset() 855 856 datadriven.RunTest(t, "testdata/iterator_next_prev", func(td *datadriven.TestData) string { 857 switch td.Cmd { 858 case "reset": 859 reset() 860 return "" 861 862 case "build": 863 if err := runBuildCmd(td, d, mem); err != nil { 864 return err.Error() 865 } 866 return "" 867 868 case "ingest": 869 if err := runIngestCmd(td, d, mem); err != nil { 870 return err.Error() 871 } 872 return runLSMCmd(td, d) 873 874 case "iter": 875 seqNum := InternalKeySeqNumMax 876 for _, arg := range td.CmdArgs { 877 if len(arg.Vals) != 1 { 878 return fmt.Sprintf("%s: %s=<value>", td.Cmd, arg.Key) 879 } 880 switch arg.Key { 881 case "seq": 882 var err error 883 seqNum, err = strconv.ParseUint(arg.Vals[0], 10, 64) 884 if err != nil { 885 return err.Error() 886 } 887 default: 888 return fmt.Sprintf("%s: unknown arg: %s", td.Cmd, arg.Key) 889 } 890 } 891 892 snap := Snapshot{ 893 db: d, 894 seqNum: seqNum, 895 } 896 iter := snap.NewIter(nil) 897 return runIterCmd(td, iter, true) 898 899 default: 900 return fmt.Sprintf("unknown command: %s", td.Cmd) 901 } 902 }) 903 } 904 905 func TestIteratorStats(t *testing.T) { 906 var mem vfs.FS 907 var d *DB 908 defer func() { 909 require.NoError(t, d.Close()) 910 }() 911 912 reset := func() { 913 if d != nil { 914 require.NoError(t, d.Close()) 915 } 916 917 mem = vfs.NewMem() 918 require.NoError(t, mem.MkdirAll("ext", 0755)) 919 opts := &Options{FS: mem} 920 // Automatic compactions may make some testcases non-deterministic. 921 opts.DisableAutomaticCompactions = true 922 var err error 923 d, err = Open("", opts) 924 require.NoError(t, err) 925 } 926 reset() 927 928 datadriven.RunTest(t, "testdata/iterator_stats", func(td *datadriven.TestData) string { 929 switch td.Cmd { 930 case "reset": 931 reset() 932 return "" 933 934 case "build": 935 if err := runBuildCmd(td, d, mem); err != nil { 936 return err.Error() 937 } 938 return "" 939 940 case "ingest": 941 if err := runIngestCmd(td, d, mem); err != nil { 942 return err.Error() 943 } 944 return runLSMCmd(td, d) 945 946 case "iter": 947 seqNum := InternalKeySeqNumMax 948 for _, arg := range td.CmdArgs { 949 if len(arg.Vals) != 1 { 950 return fmt.Sprintf("%s: %s=<value>", td.Cmd, arg.Key) 951 } 952 switch arg.Key { 953 case "seq": 954 var err error 955 seqNum, err = strconv.ParseUint(arg.Vals[0], 10, 64) 956 if err != nil { 957 return err.Error() 958 } 959 default: 960 return fmt.Sprintf("%s: unknown arg: %s", td.Cmd, arg.Key) 961 } 962 } 963 964 snap := Snapshot{ 965 db: d, 966 seqNum: seqNum, 967 } 968 iter := snap.NewIter(nil) 969 return runIterCmd(td, iter, true) 970 971 default: 972 return fmt.Sprintf("unknown command: %s", td.Cmd) 973 } 974 }) 975 } 976 977 type iterSeekOptWrapper struct { 978 internalIterator 979 980 seekGEUsingNext, seekPrefixGEUsingNext *int 981 } 982 983 func (i *iterSeekOptWrapper) SeekGE(key []byte, flags base.SeekGEFlags) (*InternalKey, []byte) { 984 if flags.TrySeekUsingNext() { 985 *i.seekGEUsingNext++ 986 } 987 return i.internalIterator.SeekGE(key, flags) 988 } 989 990 func (i *iterSeekOptWrapper) SeekPrefixGE( 991 prefix, key []byte, flags base.SeekGEFlags, 992 ) (*InternalKey, []byte) { 993 if flags.TrySeekUsingNext() { 994 *i.seekPrefixGEUsingNext++ 995 } 996 return i.internalIterator.SeekPrefixGE(prefix, key, flags) 997 } 998 999 func TestIteratorSeekOpt(t *testing.T) { 1000 var d *DB 1001 defer func() { 1002 require.NoError(t, d.Close()) 1003 }() 1004 var iter *Iterator 1005 defer func() { 1006 if iter != nil { 1007 require.NoError(t, iter.Close()) 1008 } 1009 }() 1010 var seekGEUsingNext, seekPrefixGEUsingNext int 1011 1012 datadriven.RunTest(t, "testdata/iterator_seek_opt", func(td *datadriven.TestData) string { 1013 switch td.Cmd { 1014 case "define": 1015 if iter != nil { 1016 if err := iter.Close(); err != nil { 1017 return err.Error() 1018 } 1019 } 1020 if d != nil { 1021 if err := d.Close(); err != nil { 1022 return err.Error() 1023 } 1024 } 1025 seekGEUsingNext = 0 1026 seekPrefixGEUsingNext = 0 1027 1028 opts := &Options{} 1029 opts.TablePropertyCollectors = append(opts.TablePropertyCollectors, 1030 func() TablePropertyCollector { 1031 return &minSeqNumPropertyCollector{} 1032 }) 1033 1034 var err error 1035 if d, err = runDBDefineCmd(td, opts); err != nil { 1036 return err.Error() 1037 } 1038 1039 d.mu.Lock() 1040 s := d.mu.versions.currentVersion().String() 1041 d.mu.Unlock() 1042 oldNewIters := d.newIters 1043 d.newIters = func(file *manifest.FileMetadata, opts *IterOptions, internalOpts internalIterOpts) (internalIterator, keyspan.FragmentIterator, error) { 1044 iter, rangeIter, err := oldNewIters(file, opts, internalOpts) 1045 iterWrapped := &iterSeekOptWrapper{ 1046 internalIterator: iter, 1047 seekGEUsingNext: &seekGEUsingNext, 1048 seekPrefixGEUsingNext: &seekPrefixGEUsingNext, 1049 } 1050 return iterWrapped, rangeIter, err 1051 } 1052 return s 1053 1054 case "iter": 1055 if iter == nil || iter.iter == nil { 1056 // TODO(peter): runDBDefineCmd doesn't properly update the visible 1057 // sequence number. So we have to use a snapshot with a very large 1058 // sequence number, otherwise the DB appears empty. 1059 snap := Snapshot{ 1060 db: d, 1061 seqNum: InternalKeySeqNumMax, 1062 } 1063 iter = snap.NewIter(nil) 1064 iter.readSampling.forceReadSampling = true 1065 iter.comparer.Split = func(a []byte) int { return len(a) } 1066 iter.forceEnableSeekOpt = true 1067 } 1068 iterOutput := runIterCmd(td, iter, false) 1069 stats := iter.Stats() 1070 // InternalStats are non-deterministic since they depend on how data is 1071 // distributed across memtables and sstables in the DB. 1072 stats.InternalStats = InternalIteratorStats{} 1073 var builder strings.Builder 1074 fmt.Fprintf(&builder, "%sstats: %s\n", iterOutput, stats.String()) 1075 fmt.Fprintf(&builder, "SeekGEs with trySeekUsingNext: %d\n", seekGEUsingNext) 1076 fmt.Fprintf(&builder, "SeekPrefixGEs with trySeekUsingNext: %d\n", seekPrefixGEUsingNext) 1077 return builder.String() 1078 1079 default: 1080 return fmt.Sprintf("unknown command: %s", td.Cmd) 1081 } 1082 }) 1083 } 1084 1085 type errorSeekIter struct { 1086 internalIterator 1087 // Fields controlling error injection for seeks. 1088 injectSeekErrorCounts []int 1089 seekCount int 1090 err error 1091 } 1092 1093 func (i *errorSeekIter) SeekGE(key []byte, flags base.SeekGEFlags) (*InternalKey, []byte) { 1094 if i.tryInjectError() { 1095 return nil, nil 1096 } 1097 i.err = nil 1098 i.seekCount++ 1099 return i.internalIterator.SeekGE(key, flags) 1100 } 1101 1102 func (i *errorSeekIter) SeekPrefixGE( 1103 prefix, key []byte, flags base.SeekGEFlags, 1104 ) (*InternalKey, []byte) { 1105 if i.tryInjectError() { 1106 return nil, nil 1107 } 1108 i.err = nil 1109 i.seekCount++ 1110 return i.internalIterator.SeekPrefixGE(prefix, key, flags) 1111 } 1112 1113 func (i *errorSeekIter) SeekLT(key []byte, flags base.SeekLTFlags) (*InternalKey, []byte) { 1114 if i.tryInjectError() { 1115 return nil, nil 1116 } 1117 i.err = nil 1118 i.seekCount++ 1119 return i.internalIterator.SeekLT(key, flags) 1120 } 1121 1122 func (i *errorSeekIter) tryInjectError() bool { 1123 if len(i.injectSeekErrorCounts) > 0 && i.injectSeekErrorCounts[0] == i.seekCount { 1124 i.seekCount++ 1125 i.err = errors.Errorf("injecting error") 1126 i.injectSeekErrorCounts = i.injectSeekErrorCounts[1:] 1127 return true 1128 } 1129 return false 1130 } 1131 1132 func (i *errorSeekIter) First() (*InternalKey, []byte) { 1133 i.err = nil 1134 return i.internalIterator.First() 1135 } 1136 1137 func (i *errorSeekIter) Last() (*InternalKey, []byte) { 1138 i.err = nil 1139 return i.internalIterator.Last() 1140 } 1141 1142 func (i *errorSeekIter) Next() (*InternalKey, []byte) { 1143 if i.err != nil { 1144 return nil, nil 1145 } 1146 return i.internalIterator.Next() 1147 } 1148 1149 func (i *errorSeekIter) Prev() (*InternalKey, []byte) { 1150 if i.err != nil { 1151 return nil, nil 1152 } 1153 return i.internalIterator.Prev() 1154 } 1155 1156 func (i *errorSeekIter) Error() error { 1157 if i.err != nil { 1158 return i.err 1159 } 1160 return i.internalIterator.Error() 1161 } 1162 1163 func TestIteratorSeekOptErrors(t *testing.T) { 1164 var keys []InternalKey 1165 var vals [][]byte 1166 1167 var errorIter errorSeekIter 1168 newIter := func(opts IterOptions) *Iterator { 1169 iter := &fakeIter{ 1170 lower: opts.GetLowerBound(), 1171 upper: opts.GetUpperBound(), 1172 keys: keys, 1173 vals: vals, 1174 } 1175 errorIter = errorSeekIter{internalIterator: newInvalidatingIter(iter)} 1176 // NB: This Iterator cannot be cloned since it is not constructed 1177 // with a readState. It suffices for this test. 1178 return &Iterator{ 1179 opts: opts, 1180 comparer: *testkeys.Comparer, 1181 merge: DefaultMerger.Merge, 1182 iter: &errorIter, 1183 } 1184 } 1185 1186 datadriven.RunTest(t, "testdata/iterator_seek_opt_errors", func(d *datadriven.TestData) string { 1187 switch d.Cmd { 1188 case "define": 1189 keys = keys[:0] 1190 vals = vals[:0] 1191 for _, key := range strings.Split(d.Input, "\n") { 1192 j := strings.Index(key, ":") 1193 keys = append(keys, base.ParseInternalKey(key[:j])) 1194 vals = append(vals, []byte(key[j+1:])) 1195 } 1196 return "" 1197 1198 case "iter": 1199 var opts IterOptions 1200 var injectSeekGEErrorCounts []int 1201 for _, arg := range d.CmdArgs { 1202 if len(arg.Vals) < 1 { 1203 return fmt.Sprintf("%s: %s=<value>", d.Cmd, arg.Key) 1204 } 1205 switch arg.Key { 1206 case "lower": 1207 opts.LowerBound = []byte(arg.Vals[0]) 1208 case "upper": 1209 opts.UpperBound = []byte(arg.Vals[0]) 1210 case "seek-error": 1211 for i := 0; i < len(arg.Vals); i++ { 1212 n, err := strconv.Atoi(arg.Vals[i]) 1213 if err != nil { 1214 return err.Error() 1215 } 1216 injectSeekGEErrorCounts = append(injectSeekGEErrorCounts, n) 1217 } 1218 default: 1219 return fmt.Sprintf("%s: unknown arg: %s", d.Cmd, arg.Key) 1220 } 1221 } 1222 1223 iter := newIter(opts) 1224 errorIter.injectSeekErrorCounts = injectSeekGEErrorCounts 1225 return runIterCmd(d, iter, true) 1226 1227 default: 1228 return fmt.Sprintf("unknown command: %s", d.Cmd) 1229 } 1230 }) 1231 } 1232 1233 type testBlockIntervalCollector struct { 1234 numLength int 1235 offsetFromEnd int 1236 initialized bool 1237 lower, upper uint64 1238 } 1239 1240 func (bi *testBlockIntervalCollector) Add(key InternalKey, value []byte) error { 1241 k := key.UserKey 1242 if len(k) < bi.numLength+bi.offsetFromEnd { 1243 return nil 1244 } 1245 n := len(k) - bi.offsetFromEnd - bi.numLength 1246 val, err := strconv.Atoi(string(k[n : n+bi.numLength])) 1247 if err != nil { 1248 return err 1249 } 1250 if val < 0 { 1251 panic("testBlockIntervalCollector expects values >= 0") 1252 } 1253 uval := uint64(val) 1254 if !bi.initialized { 1255 bi.lower, bi.upper = uval, uval+1 1256 bi.initialized = true 1257 return nil 1258 } 1259 if bi.lower > uval { 1260 bi.lower = uval 1261 } 1262 if uval >= bi.upper { 1263 bi.upper = uval + 1 1264 } 1265 return nil 1266 } 1267 1268 func (bi *testBlockIntervalCollector) FinishDataBlock() (lower uint64, upper uint64, err error) { 1269 bi.initialized = false 1270 l, u := bi.lower, bi.upper 1271 bi.lower, bi.upper = 0, 0 1272 return l, u, nil 1273 } 1274 1275 func TestIteratorBlockIntervalFilter(t *testing.T) { 1276 var mem vfs.FS 1277 var d *DB 1278 defer func() { 1279 require.NoError(t, d.Close()) 1280 }() 1281 1282 type collector struct { 1283 id uint16 1284 offset int 1285 } 1286 createDB := func(collectors []collector) { 1287 if d != nil { 1288 require.NoError(t, d.Close()) 1289 } 1290 1291 mem = vfs.NewMem() 1292 require.NoError(t, mem.MkdirAll("ext", 0755)) 1293 1294 var bpCollectors []func() BlockPropertyCollector 1295 for _, c := range collectors { 1296 coll := c 1297 bpCollectors = append(bpCollectors, func() BlockPropertyCollector { 1298 return sstable.NewBlockIntervalCollector( 1299 fmt.Sprintf("%d", coll.id), 1300 &testBlockIntervalCollector{numLength: 2, offsetFromEnd: coll.offset}, 1301 nil, /* range key collector */ 1302 ) 1303 }) 1304 } 1305 opts := &Options{ 1306 FS: mem, 1307 FormatMajorVersion: FormatNewest, 1308 BlockPropertyCollectors: bpCollectors, 1309 } 1310 lo := LevelOptions{BlockSize: 1, IndexBlockSize: 1} 1311 opts.Levels = append(opts.Levels, lo) 1312 1313 // Automatic compactions may compact away tombstones from L6, making 1314 // some testcases non-deterministic. 1315 opts.DisableAutomaticCompactions = true 1316 var err error 1317 d, err = Open("", opts) 1318 require.NoError(t, err) 1319 } 1320 1321 datadriven.RunTest( 1322 t, "testdata/iterator_block_interval_filter", func(td *datadriven.TestData) string { 1323 switch td.Cmd { 1324 case "build": 1325 var collectors []collector 1326 for _, arg := range td.CmdArgs { 1327 switch arg.Key { 1328 case "id_offset": 1329 if len(arg.Vals) != 2 { 1330 return "id and offset not provided" 1331 } 1332 var id, offset int 1333 var err error 1334 if id, err = strconv.Atoi(arg.Vals[0]); err != nil { 1335 return err.Error() 1336 } 1337 if offset, err = strconv.Atoi(arg.Vals[1]); err != nil { 1338 return err.Error() 1339 } 1340 collectors = append(collectors, collector{id: uint16(id), offset: offset}) 1341 default: 1342 return fmt.Sprintf("unknown key: %s", arg.Key) 1343 } 1344 } 1345 createDB(collectors) 1346 b := d.NewBatch() 1347 if err := runBatchDefineCmd(td, b); err != nil { 1348 return err.Error() 1349 } 1350 if err := b.Commit(nil); err != nil { 1351 return err.Error() 1352 } 1353 if err := d.Flush(); err != nil { 1354 return err.Error() 1355 } 1356 return runLSMCmd(td, d) 1357 1358 case "iter": 1359 var opts IterOptions 1360 for _, arg := range td.CmdArgs { 1361 switch arg.Key { 1362 case "id_lower_upper": 1363 if len(arg.Vals) != 3 { 1364 return "id, lower, upper not provided" 1365 } 1366 var id, lower, upper int 1367 var err error 1368 if id, err = strconv.Atoi(arg.Vals[0]); err != nil { 1369 return err.Error() 1370 } 1371 if lower, err = strconv.Atoi(arg.Vals[1]); err != nil { 1372 return err.Error() 1373 } 1374 if upper, err = strconv.Atoi(arg.Vals[2]); err != nil { 1375 return err.Error() 1376 } 1377 opts.PointKeyFilters = append(opts.PointKeyFilters, 1378 sstable.NewBlockIntervalFilter(fmt.Sprintf("%d", id), 1379 uint64(lower), uint64(upper))) 1380 default: 1381 return fmt.Sprintf("unknown key: %s", arg.Key) 1382 } 1383 } 1384 rand.Shuffle(len(opts.PointKeyFilters), func(i, j int) { 1385 opts.PointKeyFilters[i], opts.PointKeyFilters[j] = 1386 opts.PointKeyFilters[j], opts.PointKeyFilters[i] 1387 }) 1388 iter := d.NewIter(&opts) 1389 return runIterCmd(td, iter, true) 1390 1391 default: 1392 return fmt.Sprintf("unknown command: %s", td.Cmd) 1393 } 1394 }) 1395 } 1396 1397 var seed = flag.Uint64("seed", 0, "a pseudorandom number generator seed") 1398 1399 func randStr(fill []byte, rng *rand.Rand) { 1400 const letters = "abcdefghijklmnopqrstuvwxyz" 1401 const lettersLen = len(letters) 1402 for i := 0; i < len(fill); i++ { 1403 fill[i] = letters[rng.Intn(lettersLen)] 1404 } 1405 } 1406 1407 func randValue(n int, rng *rand.Rand) []byte { 1408 buf := make([]byte, n) 1409 randStr(buf, rng) 1410 return buf 1411 } 1412 1413 func randKey(n int, rng *rand.Rand) ([]byte, int) { 1414 keyPrefix := randValue(n, rng) 1415 suffix := rng.Intn(100) 1416 return append(keyPrefix, []byte(fmt.Sprintf("%02d", suffix))...), suffix 1417 } 1418 1419 func TestIteratorRandomizedBlockIntervalFilter(t *testing.T) { 1420 mem := vfs.NewMem() 1421 opts := &Options{ 1422 FS: mem, 1423 FormatMajorVersion: FormatNewest, 1424 BlockPropertyCollectors: []func() BlockPropertyCollector{ 1425 func() BlockPropertyCollector { 1426 return sstable.NewBlockIntervalCollector( 1427 "0", &testBlockIntervalCollector{numLength: 2}, nil, /* range key collector */ 1428 ) 1429 }, 1430 }, 1431 } 1432 seed := *seed 1433 if seed == 0 { 1434 seed = uint64(time.Now().UnixNano()) 1435 fmt.Printf("seed: %d\n", seed) 1436 } 1437 rng := rand.New(rand.NewSource(seed)) 1438 opts.FlushSplitBytes = 1 << rng.Intn(8) // 1B - 256B 1439 opts.L0CompactionThreshold = 1 << rng.Intn(2) // 1-2 1440 opts.L0CompactionFileThreshold = 1 << rng.Intn(11) // 1-1024 1441 opts.LBaseMaxBytes = 1 << rng.Intn(11) // 1B - 1KB 1442 opts.MemTableSize = 2 << 10 // 2KB 1443 var lopts LevelOptions 1444 lopts.BlockSize = 1 << rng.Intn(8) // 1B - 256B 1445 lopts.IndexBlockSize = 1 << rng.Intn(8) // 1B - 256B 1446 opts.Levels = []LevelOptions{lopts} 1447 1448 d, err := Open("", opts) 1449 require.NoError(t, err) 1450 defer func() { 1451 require.NoError(t, d.Close()) 1452 }() 1453 matchingKeyValues := make(map[string]string) 1454 lower := rng.Intn(100) 1455 upper := rng.Intn(100) 1456 if lower > upper { 1457 lower, upper = upper, lower 1458 } 1459 n := 2000 1460 for i := 0; i < n; i++ { 1461 key, suffix := randKey(20+rng.Intn(5), rng) 1462 value := randValue(50, rng) 1463 if lower <= suffix && suffix < upper { 1464 matchingKeyValues[string(key)] = string(value) 1465 } 1466 d.Set(key, value, nil) 1467 } 1468 1469 var iterOpts IterOptions 1470 iterOpts.PointKeyFilters = []BlockPropertyFilter{ 1471 sstable.NewBlockIntervalFilter("0", 1472 uint64(lower), uint64(upper)), 1473 } 1474 iter := d.NewIter(&iterOpts) 1475 defer func() { 1476 require.NoError(t, iter.Close()) 1477 }() 1478 iter.First() 1479 found := 0 1480 matchingCount := len(matchingKeyValues) 1481 for ; iter.Valid(); iter.Next() { 1482 found++ 1483 key := string(iter.Key()) 1484 value, ok := matchingKeyValues[key] 1485 if ok { 1486 require.Equal(t, value, string(iter.Value())) 1487 delete(matchingKeyValues, key) 1488 } 1489 } 1490 fmt.Printf("generated %d keys: %d matching, %d found\n", n, matchingCount, found) 1491 require.Equal(t, 0, len(matchingKeyValues)) 1492 } 1493 1494 func TestIteratorGuaranteedDurable(t *testing.T) { 1495 mem := vfs.NewMem() 1496 opts := &Options{FS: mem} 1497 d, err := Open("", opts) 1498 require.NoError(t, err) 1499 defer func() { 1500 require.NoError(t, d.Close()) 1501 }() 1502 iterOptions := IterOptions{OnlyReadGuaranteedDurable: true} 1503 failFunc := func(t *testing.T, reader Reader) { 1504 defer func() { 1505 if r := recover(); r == nil { 1506 require.Fail(t, "expected panic") 1507 } 1508 reader.Close() 1509 }() 1510 iter := reader.NewIter(&iterOptions) 1511 defer iter.Close() 1512 } 1513 t.Run("snapshot", func(t *testing.T) { 1514 failFunc(t, d.NewSnapshot()) 1515 }) 1516 t.Run("batch", func(t *testing.T) { 1517 failFunc(t, d.NewIndexedBatch()) 1518 }) 1519 t.Run("db", func(t *testing.T) { 1520 d.Set([]byte("k"), []byte("v"), nil) 1521 foundKV := func(o *IterOptions) bool { 1522 iter := d.NewIter(o) 1523 defer iter.Close() 1524 iter.SeekGE([]byte("k")) 1525 return iter.Valid() 1526 } 1527 require.True(t, foundKV(nil)) 1528 require.False(t, foundKV(&iterOptions)) 1529 require.NoError(t, d.Flush()) 1530 require.True(t, foundKV(nil)) 1531 require.True(t, foundKV(&iterOptions)) 1532 }) 1533 } 1534 1535 func TestIteratorBoundsLifetimes(t *testing.T) { 1536 rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano()))) 1537 d := newPointTestkeysDatabase(t, testkeys.Alpha(2)) 1538 defer func() { require.NoError(t, d.Close()) }() 1539 1540 var buf bytes.Buffer 1541 iterators := map[string]*Iterator{} 1542 var labels []string 1543 printIters := func(w io.Writer) { 1544 labels = labels[:0] 1545 for label := range iterators { 1546 labels = append(labels, label) 1547 } 1548 sort.Strings(labels) 1549 for _, label := range labels { 1550 it := iterators[label] 1551 fmt.Fprintf(&buf, "%s: (", label) 1552 if it.opts.LowerBound == nil { 1553 fmt.Fprint(&buf, "<nil>, ") 1554 } else { 1555 fmt.Fprintf(&buf, "%q, ", it.opts.LowerBound) 1556 } 1557 if it.opts.UpperBound == nil { 1558 fmt.Fprint(&buf, "<nil>)") 1559 } else { 1560 fmt.Fprintf(&buf, "%q)", it.opts.UpperBound) 1561 } 1562 fmt.Fprintf(&buf, " boundsBufIdx=%d\n", it.boundsBufIdx) 1563 } 1564 } 1565 parseBounds := func(td *datadriven.TestData) (lower, upper []byte) { 1566 for _, arg := range td.CmdArgs { 1567 if arg.Key == "lower" { 1568 lower = []byte(arg.Vals[0]) 1569 } else if arg.Key == "upper" { 1570 upper = []byte(arg.Vals[0]) 1571 } 1572 } 1573 return lower, upper 1574 } 1575 trashBounds := func(bounds ...[]byte) { 1576 for _, bound := range bounds { 1577 rng.Read(bound[:]) 1578 } 1579 } 1580 1581 datadriven.RunTest(t, "testdata/iterator_bounds_lifetimes", func(td *datadriven.TestData) string { 1582 switch td.Cmd { 1583 case "define": 1584 var err error 1585 if d, err = runDBDefineCmd(td, d.opts); err != nil { 1586 return err.Error() 1587 } 1588 d.mu.Lock() 1589 s := d.mu.versions.currentVersion().String() 1590 d.mu.Unlock() 1591 return s 1592 case "new-iter": 1593 var label string 1594 td.ScanArgs(t, "label", &label) 1595 lower, upper := parseBounds(td) 1596 iterators[label] = d.NewIter(&IterOptions{ 1597 LowerBound: lower, 1598 UpperBound: upper, 1599 }) 1600 trashBounds(lower, upper) 1601 buf.Reset() 1602 printIters(&buf) 1603 return buf.String() 1604 case "clone": 1605 var from, to string 1606 td.ScanArgs(t, "from", &from) 1607 td.ScanArgs(t, "to", &to) 1608 var err error 1609 iterators[to], err = iterators[from].Clone(CloneOptions{}) 1610 if err != nil { 1611 return err.Error() 1612 } 1613 buf.Reset() 1614 printIters(&buf) 1615 return buf.String() 1616 case "close": 1617 var label string 1618 td.ScanArgs(t, "label", &label) 1619 iterators[label].Close() 1620 delete(iterators, label) 1621 buf.Reset() 1622 printIters(&buf) 1623 return buf.String() 1624 case "iter": 1625 var label string 1626 td.ScanArgs(t, "label", &label) 1627 return runIterCmd(td, iterators[label], false /* closeIter */) 1628 case "set-bounds": 1629 var label string 1630 td.ScanArgs(t, "label", &label) 1631 lower, upper := parseBounds(td) 1632 iterators[label].SetBounds(lower, upper) 1633 trashBounds(lower, upper) 1634 buf.Reset() 1635 printIters(&buf) 1636 return buf.String() 1637 case "set-options": 1638 var label string 1639 var tableFilter bool 1640 td.ScanArgs(t, "label", &label) 1641 opts := iterators[label].opts 1642 for _, arg := range td.CmdArgs { 1643 if arg.Key == "table-filter" { 1644 tableFilter = true 1645 } 1646 if arg.Key == "key-types" { 1647 switch arg.Vals[0] { 1648 case "points-only": 1649 opts.KeyTypes = IterKeyTypePointsOnly 1650 case "ranges-only": 1651 opts.KeyTypes = IterKeyTypeRangesOnly 1652 case "both": 1653 opts.KeyTypes = IterKeyTypePointsAndRanges 1654 default: 1655 panic(fmt.Sprintf("unrecognized key type %q", arg.Vals[0])) 1656 } 1657 } 1658 } 1659 opts.LowerBound, opts.UpperBound = parseBounds(td) 1660 if tableFilter { 1661 opts.TableFilter = func(userProps map[string]string) bool { return false } 1662 } 1663 iterators[label].SetOptions(&opts) 1664 trashBounds(opts.LowerBound, opts.UpperBound) 1665 buf.Reset() 1666 printIters(&buf) 1667 return buf.String() 1668 default: 1669 return fmt.Sprintf("unrecognized command %q", td.Cmd) 1670 } 1671 }) 1672 } 1673 1674 // TestSetOptionsEquivalence tests equivalence between SetOptions to mutate an 1675 // iterator and constructing a new iterator with NewIter. The long-lived 1676 // iterator and the new iterator should surface identical iterator states. 1677 func TestSetOptionsEquivalence(t *testing.T) { 1678 seed := uint64(time.Now().UnixNano()) 1679 // Call a helper function with the seed so that the seed appears within 1680 // stack traces if there's a panic. 1681 testSetOptionsEquivalence(t, seed) 1682 } 1683 1684 func testSetOptionsEquivalence(t *testing.T, seed uint64) { 1685 rng := rand.New(rand.NewSource(seed)) 1686 ks := testkeys.Alpha(2) 1687 d := newTestkeysDatabase(t, ks, rng) 1688 d.opts.Logger = panicLogger{} 1689 defer func() { require.NoError(t, d.Close()) }() 1690 1691 var o IterOptions 1692 generateNewOptions := func() { 1693 // TODO(jackson): Include test coverage for block property filters, etc. 1694 if rng.Intn(2) == 1 { 1695 o.KeyTypes = IterKeyType(rng.Intn(3)) 1696 } 1697 if rng.Intn(2) == 1 { 1698 if rng.Intn(2) == 1 { 1699 o.LowerBound = nil 1700 if rng.Intn(2) == 1 { 1701 o.LowerBound = testkeys.KeyAt(ks, rng.Intn(ks.Count()), rng.Intn(ks.Count())) 1702 } 1703 } 1704 if rng.Intn(2) == 1 { 1705 o.UpperBound = nil 1706 if rng.Intn(2) == 1 { 1707 o.UpperBound = testkeys.KeyAt(ks, rng.Intn(ks.Count()), rng.Intn(ks.Count())) 1708 } 1709 } 1710 if testkeys.Comparer.Compare(o.LowerBound, o.UpperBound) > 0 { 1711 o.LowerBound, o.UpperBound = o.UpperBound, o.LowerBound 1712 } 1713 } 1714 o.RangeKeyMasking.Suffix = nil 1715 if o.KeyTypes == IterKeyTypePointsAndRanges && rng.Intn(2) == 1 { 1716 o.RangeKeyMasking.Suffix = testkeys.Suffix(rng.Intn(ks.Count())) 1717 } 1718 } 1719 1720 var longLivedIter, newIter *Iterator 1721 var history, longLivedBuf, newIterBuf bytes.Buffer 1722 defer func() { 1723 if r := recover(); r != nil { 1724 t.Log(history.String()) 1725 panic(r) 1726 } 1727 }() 1728 defer func() { 1729 if longLivedIter != nil { 1730 longLivedIter.Close() 1731 } 1732 if newIter != nil { 1733 newIter.Close() 1734 } 1735 }() 1736 1737 type positioningOp struct { 1738 desc string 1739 run func(*Iterator) IterValidityState 1740 } 1741 positioningOps := []func() positioningOp{ 1742 // SeekGE 1743 func() positioningOp { 1744 k := testkeys.Key(ks, rng.Intn(ks.Count())) 1745 return positioningOp{ 1746 desc: fmt.Sprintf("SeekGE(%q)", k), 1747 run: func(it *Iterator) IterValidityState { 1748 return it.SeekGEWithLimit(k, nil) 1749 }, 1750 } 1751 }, 1752 // SeekLT 1753 func() positioningOp { 1754 k := testkeys.Key(ks, rng.Intn(ks.Count())) 1755 return positioningOp{ 1756 desc: fmt.Sprintf("SeekLT(%q)", k), 1757 run: func(it *Iterator) IterValidityState { 1758 return it.SeekLTWithLimit(k, nil) 1759 }, 1760 } 1761 }, 1762 // SeekPrefixGE 1763 func() positioningOp { 1764 k := testkeys.Key(ks, rng.Intn(ks.Count())) 1765 return positioningOp{ 1766 desc: fmt.Sprintf("SeekPrefixGE(%q)", k), 1767 run: func(it *Iterator) IterValidityState { 1768 if it.SeekPrefixGE(k) { 1769 return IterValid 1770 } 1771 return IterExhausted 1772 }, 1773 } 1774 }, 1775 } 1776 1777 for i := 0; i < 10_000; i++ { 1778 // Generate new random options. The options in o will be mutated. 1779 generateNewOptions() 1780 fmt.Fprintf(&history, "new options: %s\n", iterOptionsString(&o)) 1781 1782 newIter = d.NewIter(&o) 1783 if longLivedIter == nil { 1784 longLivedIter = d.NewIter(&o) 1785 } else { 1786 longLivedIter.SetOptions(&o) 1787 } 1788 1789 // Apply the same operation to both keys. 1790 iterOp := positioningOps[rng.Intn(len(positioningOps))]() 1791 newIterValidity := iterOp.run(newIter) 1792 longLivedValidity := iterOp.run(longLivedIter) 1793 1794 newIterBuf.Reset() 1795 longLivedBuf.Reset() 1796 printIterState(&newIterBuf, newIter, newIterValidity, true /* printValidityState */) 1797 printIterState(&longLivedBuf, longLivedIter, longLivedValidity, true /* printValidityState */) 1798 fmt.Fprintf(&history, "%s = %s\n", iterOp.desc, newIterBuf.String()) 1799 1800 if newIterBuf.String() != longLivedBuf.String() { 1801 t.Logf("history:\n%s\n", history.String()) 1802 t.Logf("seed: %d\n", seed) 1803 t.Fatalf("expected %q, got %q", newIterBuf.String(), longLivedBuf.String()) 1804 } 1805 _ = newIter.Close() 1806 1807 newIter = nil 1808 } 1809 t.Logf("history:\n%s\n", history.String()) 1810 } 1811 1812 func iterOptionsString(o *IterOptions) string { 1813 var buf bytes.Buffer 1814 fmt.Fprintf(&buf, "key-types=%s, lower=%q, upper=%q", 1815 o.KeyTypes, o.LowerBound, o.UpperBound) 1816 if o.TableFilter != nil { 1817 fmt.Fprintf(&buf, ", table-filter") 1818 } 1819 if o.OnlyReadGuaranteedDurable { 1820 fmt.Fprintf(&buf, ", only-durable") 1821 } 1822 if o.UseL6Filters { 1823 fmt.Fprintf(&buf, ", use-L6-filters") 1824 } 1825 for i, pkf := range o.PointKeyFilters { 1826 fmt.Fprintf(&buf, ", point-key-filter[%d]=%q", i, pkf.Name()) 1827 } 1828 for i, rkf := range o.RangeKeyFilters { 1829 fmt.Fprintf(&buf, ", range-key-filter[%d]=%q", i, rkf.Name()) 1830 } 1831 return buf.String() 1832 } 1833 1834 func newTestkeysDatabase(t *testing.T, ks testkeys.Keyspace, rng *rand.Rand) *DB { 1835 dbOpts := &Options{ 1836 Comparer: testkeys.Comparer, 1837 FS: vfs.NewMem(), 1838 FormatMajorVersion: FormatRangeKeys, 1839 } 1840 d, err := Open("", dbOpts) 1841 require.NoError(t, err) 1842 1843 // Randomize the order in which we write keys. 1844 order := rng.Perm(ks.Count()) 1845 b := d.NewBatch() 1846 keyBuf := make([]byte, ks.MaxLen()+testkeys.MaxSuffixLen) 1847 keyBuf2 := make([]byte, ks.MaxLen()+testkeys.MaxSuffixLen) 1848 for i := 0; i < len(order); i++ { 1849 const maxVersionsPerKey = 10 1850 keyIndex := order[i] 1851 for versions := rng.Intn(maxVersionsPerKey); versions > 0; versions-- { 1852 n := testkeys.WriteKeyAt(keyBuf, ks, keyIndex, rng.Intn(maxVersionsPerKey)) 1853 b.Set(keyBuf[:n], keyBuf[:n], nil) 1854 } 1855 1856 // Sometimes add a range key too. 1857 if rng.Intn(100) == 1 { 1858 startIdx := rng.Intn(ks.Count()) 1859 endIdx := rng.Intn(ks.Count()) 1860 startLen := testkeys.WriteKey(keyBuf, ks, startIdx) 1861 endLen := testkeys.WriteKey(keyBuf2, ks, endIdx) 1862 suffixInt := rng.Intn(maxVersionsPerKey) 1863 require.NoError(t, b.RangeKeySet( 1864 keyBuf[:startLen], 1865 keyBuf2[:endLen], 1866 testkeys.Suffix(suffixInt), 1867 nil, 1868 nil)) 1869 } 1870 1871 // Randomize the flush points. 1872 if !b.Empty() && rng.Intn(10) == 1 { 1873 require.NoError(t, b.Commit(nil)) 1874 require.NoError(t, d.Flush()) 1875 b = d.NewBatch() 1876 } 1877 } 1878 if !b.Empty() { 1879 require.NoError(t, b.Commit(nil)) 1880 } 1881 return d 1882 } 1883 1884 func newPointTestkeysDatabase(t *testing.T, ks testkeys.Keyspace) *DB { 1885 dbOpts := &Options{ 1886 Comparer: testkeys.Comparer, 1887 FS: vfs.NewMem(), 1888 FormatMajorVersion: FormatRangeKeys, 1889 } 1890 d, err := Open("", dbOpts) 1891 require.NoError(t, err) 1892 1893 b := d.NewBatch() 1894 keyBuf := make([]byte, ks.MaxLen()+testkeys.MaxSuffixLen) 1895 for i := 0; i < ks.Count(); i++ { 1896 n := testkeys.WriteKeyAt(keyBuf, ks, i, i) 1897 b.Set(keyBuf[:n], keyBuf[:n], nil) 1898 } 1899 require.NoError(t, b.Commit(nil)) 1900 return d 1901 } 1902 1903 func BenchmarkIteratorSeekGE(b *testing.B) { 1904 m, keys := buildMemTable(b) 1905 iter := &Iterator{ 1906 comparer: *DefaultComparer, 1907 iter: m.newIter(nil), 1908 } 1909 rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano()))) 1910 1911 b.ResetTimer() 1912 for i := 0; i < b.N; i++ { 1913 key := keys[rng.Intn(len(keys))] 1914 iter.SeekGE(key) 1915 } 1916 } 1917 1918 func BenchmarkIteratorNext(b *testing.B) { 1919 m, _ := buildMemTable(b) 1920 iter := &Iterator{ 1921 comparer: *DefaultComparer, 1922 iter: m.newIter(nil), 1923 } 1924 1925 b.ResetTimer() 1926 for i := 0; i < b.N; i++ { 1927 if !iter.Valid() { 1928 iter.First() 1929 } 1930 iter.Next() 1931 } 1932 } 1933 1934 func BenchmarkIteratorPrev(b *testing.B) { 1935 m, _ := buildMemTable(b) 1936 iter := &Iterator{ 1937 comparer: *DefaultComparer, 1938 iter: m.newIter(nil), 1939 } 1940 1941 b.ResetTimer() 1942 for i := 0; i < b.N; i++ { 1943 if !iter.Valid() { 1944 iter.Last() 1945 } 1946 iter.Prev() 1947 } 1948 } 1949 1950 // BenchmarkIteratorSeqSeekPrefixGENotFound exercises the case of SeekPrefixGE 1951 // specifying monotonic keys all of which precede actual keys present in L6 of 1952 // the DB. Moreover, with-tombstone=true exercises the sub-case where those 1953 // actual keys are deleted using a range tombstone that has not physically 1954 // deleted those keys due to the presence of a snapshot that needs to see 1955 // those keys. This sub-case needs to be efficient in (a) avoiding iteration 1956 // over all those deleted keys, including repeated iteration, (b) using the 1957 // next optimization, since the seeks are monotonic. 1958 func BenchmarkIteratorSeqSeekPrefixGENotFound(b *testing.B) { 1959 const blockSize = 32 << 10 1960 const restartInterval = 16 1961 const levelCount = 5 1962 const keyOffset = 100000 1963 1964 var readers [4][][]*sstable.Reader 1965 var levelSlices [4][]manifest.LevelSlice 1966 indexFunc := func(bloom bool, withTombstone bool) int { 1967 index := 0 1968 if bloom { 1969 index = 2 1970 } 1971 if withTombstone { 1972 index++ 1973 } 1974 return index 1975 } 1976 for _, bloom := range []bool{false, true} { 1977 for _, withTombstone := range []bool{false, true} { 1978 index := indexFunc(bloom, withTombstone) 1979 levels := levelCount 1980 if withTombstone { 1981 levels = 1 1982 } 1983 readers[index], levelSlices[index], _ = buildLevelsForMergingIterSeqSeek( 1984 b, blockSize, restartInterval, levels, keyOffset, withTombstone, bloom) 1985 1986 } 1987 } 1988 // We will not be seeking to the keys that were written but instead to 1989 // keys before the written keys. This is to validate that the optimization 1990 // to use Next still functions when mergingIter checks for the prefix 1991 // match, and that mergingIter can avoid iterating over all the keys 1992 // deleted by a range tombstone when there is no possibility of matching 1993 // the prefix. 1994 var keys [][]byte 1995 for i := 0; i < keyOffset; i++ { 1996 keys = append(keys, []byte(fmt.Sprintf("%08d", i))) 1997 } 1998 for _, skip := range []int{1, 2, 4} { 1999 for _, bloom := range []bool{false, true} { 2000 for _, withTombstone := range []bool{false, true} { 2001 b.Run(fmt.Sprintf("skip=%d/bloom=%t/with-tombstone=%t", skip, bloom, withTombstone), 2002 func(b *testing.B) { 2003 index := indexFunc(bloom, withTombstone) 2004 readers := readers[index] 2005 levelSlices := levelSlices[index] 2006 m := buildMergingIter(readers, levelSlices) 2007 iter := Iterator{ 2008 comparer: *testkeys.Comparer, 2009 merge: DefaultMerger.Merge, 2010 iter: m, 2011 } 2012 pos := 0 2013 b.ResetTimer() 2014 for i := 0; i < b.N; i++ { 2015 // When withTombstone=true, and prior to the 2016 // optimization to stop early due to a range 2017 // tombstone, the iteration would continue into the 2018 // next file, and not be able to use Next at the lower 2019 // level in the next SeekPrefixGE call. So we would 2020 // incur the cost of iterating over all the deleted 2021 // keys for every seek. Note that it is not possible 2022 // to do a noop optimization in Iterator for the 2023 // prefix case, unlike SeekGE/SeekLT, since we don't 2024 // know if the iterators inside mergingIter are all 2025 // appropriately positioned -- some may not be due to 2026 // bloom filters not matching. 2027 valid := iter.SeekPrefixGE(keys[pos]) 2028 if valid { 2029 b.Fatalf("key should not be found") 2030 } 2031 pos += skip 2032 if pos >= keyOffset { 2033 pos = 0 2034 } 2035 } 2036 b.StopTimer() 2037 iter.Close() 2038 }) 2039 } 2040 } 2041 } 2042 for _, r := range readers { 2043 for i := range r { 2044 for j := range r[i] { 2045 r[i][j].Close() 2046 } 2047 } 2048 } 2049 } 2050 2051 // BenchmarkIteratorSeqSeekGEWithBounds is analogous to 2052 // BenchmarkMergingIterSeqSeekGEWithBounds, except for using an Iterator, 2053 // which causes it to exercise the end-to-end code path. 2054 func BenchmarkIteratorSeqSeekGEWithBounds(b *testing.B) { 2055 const blockSize = 32 << 10 2056 const restartInterval = 16 2057 const levelCount = 5 2058 readers, levelSlices, keys := buildLevelsForMergingIterSeqSeek( 2059 b, blockSize, restartInterval, levelCount, 0 /* keyOffset */, false, false) 2060 m := buildMergingIter(readers, levelSlices) 2061 iter := Iterator{ 2062 comparer: *testkeys.Comparer, 2063 merge: DefaultMerger.Merge, 2064 iter: m, 2065 } 2066 keyCount := len(keys) 2067 b.ResetTimer() 2068 for i := 0; i < b.N; i++ { 2069 pos := i % (keyCount - 1) 2070 iter.SetBounds(keys[pos], keys[pos+1]) 2071 // SeekGE will return keys[pos]. 2072 valid := iter.SeekGE(keys[pos]) 2073 for valid { 2074 valid = iter.Next() 2075 } 2076 if iter.Error() != nil { 2077 b.Fatalf(iter.Error().Error()) 2078 } 2079 } 2080 iter.Close() 2081 for i := range readers { 2082 for j := range readers[i] { 2083 readers[i][j].Close() 2084 } 2085 } 2086 } 2087 2088 func BenchmarkIteratorSeekGENoop(b *testing.B) { 2089 const blockSize = 32 << 10 2090 const restartInterval = 16 2091 const levelCount = 5 2092 const keyOffset = 10000 2093 readers, levelSlices, _ := buildLevelsForMergingIterSeqSeek( 2094 b, blockSize, restartInterval, levelCount, keyOffset, false, false) 2095 var keys [][]byte 2096 for i := 0; i < keyOffset; i++ { 2097 keys = append(keys, []byte(fmt.Sprintf("%08d", i))) 2098 } 2099 for _, withLimit := range []bool{false, true} { 2100 b.Run(fmt.Sprintf("withLimit=%t", withLimit), func(b *testing.B) { 2101 m := buildMergingIter(readers, levelSlices) 2102 iter := Iterator{ 2103 comparer: *testkeys.Comparer, 2104 merge: DefaultMerger.Merge, 2105 iter: m, 2106 } 2107 b.ResetTimer() 2108 for i := 0; i < b.N; i++ { 2109 pos := i % (len(keys) - 1) 2110 if withLimit { 2111 if iter.SeekGEWithLimit(keys[pos], keys[pos+1]) != IterAtLimit { 2112 b.Fatal("should be at limit") 2113 } 2114 } else { 2115 if !iter.SeekGE(keys[pos]) { 2116 b.Fatal("should be valid") 2117 } 2118 } 2119 } 2120 iter.Close() 2121 }) 2122 } 2123 for i := range readers { 2124 for j := range readers[i] { 2125 readers[i][j].Close() 2126 } 2127 } 2128 } 2129 2130 func BenchmarkBlockPropertyFilter(b *testing.B) { 2131 rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano()))) 2132 for _, matchInterval := range []int{1, 10, 100, 1000} { 2133 b.Run(fmt.Sprintf("match-interval=%d", matchInterval), func(b *testing.B) { 2134 mem := vfs.NewMem() 2135 opts := &Options{ 2136 FS: mem, 2137 FormatMajorVersion: FormatNewest, 2138 BlockPropertyCollectors: []func() BlockPropertyCollector{ 2139 func() BlockPropertyCollector { 2140 return sstable.NewBlockIntervalCollector( 2141 "0", &testBlockIntervalCollector{numLength: 3}, nil, /* range key collector */ 2142 ) 2143 }, 2144 }, 2145 } 2146 d, err := Open("", opts) 2147 require.NoError(b, err) 2148 defer func() { 2149 require.NoError(b, d.Close()) 2150 }() 2151 batch := d.NewBatch() 2152 const numKeys = 20 * 1000 2153 const valueSize = 1000 2154 for i := 0; i < numKeys; i++ { 2155 key := fmt.Sprintf("%06d%03d", i, i%matchInterval) 2156 value := randValue(valueSize, rng) 2157 require.NoError(b, batch.Set([]byte(key), value, nil)) 2158 } 2159 require.NoError(b, batch.Commit(nil)) 2160 require.NoError(b, d.Flush()) 2161 require.NoError(b, d.Compact(nil, []byte{0xFF}, false)) 2162 2163 for _, filter := range []bool{false, true} { 2164 b.Run(fmt.Sprintf("filter=%t", filter), func(b *testing.B) { 2165 var iterOpts IterOptions 2166 if filter { 2167 iterOpts.PointKeyFilters = []BlockPropertyFilter{ 2168 sstable.NewBlockIntervalFilter("0", 2169 uint64(0), uint64(1)), 2170 } 2171 } 2172 iter := d.NewIter(&iterOpts) 2173 b.ResetTimer() 2174 for i := 0; i < b.N; i++ { 2175 valid := iter.First() 2176 for valid { 2177 valid = iter.Next() 2178 } 2179 } 2180 b.StopTimer() 2181 require.NoError(b, iter.Close()) 2182 }) 2183 } 2184 }) 2185 } 2186 } 2187 2188 // BenchmarkIterator_RangeKeyMasking benchmarks a scan through a keyspace with 2189 // 10,000 random suffixed point keys, and three range keys covering most of the 2190 // keyspace. It varies the suffix of the range keys in subbenchmarks to exercise 2191 // varying amounts of masking. This benchmark does configure a block-property 2192 // filter, allowing for skipping blocks wholly contained within a range key and 2193 // consisting of points all with a suffix lower than the range key's. 2194 func BenchmarkIterator_RangeKeyMasking(b *testing.B) { 2195 const ( 2196 prefixLen = 20 2197 valueSize = 1024 2198 batches = 200 2199 keysPerBatch = 50 2200 ) 2201 rng := rand.New(rand.NewSource(uint64(1658872515083979000))) 2202 keyBuf := make([]byte, prefixLen+testkeys.MaxSuffixLen) 2203 valBuf := make([]byte, valueSize) 2204 2205 mem := vfs.NewStrictMem() 2206 maxProcs := runtime.GOMAXPROCS(0) 2207 opts := &Options{ 2208 FS: mem, 2209 Comparer: testkeys.Comparer, 2210 FormatMajorVersion: FormatNewest, 2211 MaxConcurrentCompactions: func() int { return maxProcs/2 + 1 }, 2212 BlockPropertyCollectors: []func() BlockPropertyCollector{ 2213 blockprop.NewBlockPropertyCollector, 2214 }, 2215 } 2216 d, err := Open("", opts) 2217 require.NoError(b, err) 2218 2219 for bi := 0; bi < batches; bi++ { 2220 batch := d.NewBatch() 2221 for k := 0; k < keysPerBatch; k++ { 2222 randStr(keyBuf[:prefixLen], rng) 2223 suffix := rng.Intn(100) 2224 suffixLen := testkeys.WriteSuffix(keyBuf[prefixLen:], suffix) 2225 randStr(valBuf[:], rng) 2226 require.NoError(b, batch.Set(keyBuf[:prefixLen+suffixLen], valBuf[:], nil)) 2227 } 2228 require.NoError(b, batch.Commit(nil)) 2229 } 2230 2231 // Wait for compactions to complete before starting benchmarks. We don't 2232 // want to benchmark while compactions are running. 2233 d.mu.Lock() 2234 for d.mu.compact.compactingCount > 0 { 2235 d.mu.compact.cond.Wait() 2236 } 2237 d.mu.Unlock() 2238 b.Log(d.Metrics().String()) 2239 require.NoError(b, d.Close()) 2240 // Set ignore syncs to true so that each subbenchmark may mutate state and 2241 // then revert back to the original state. 2242 mem.SetIgnoreSyncs(true) 2243 2244 // TODO(jackson): Benchmark lazy-combined iteration versus not. 2245 // TODO(jackson): Benchmark seeks. 2246 for _, rkSuffix := range []string{"@10", "@50", "@75", "@100"} { 2247 b.Run(fmt.Sprintf("range-keys-suffixes=%s", rkSuffix), func(b *testing.B) { 2248 d, err := Open("", opts) 2249 require.NoError(b, err) 2250 require.NoError(b, d.RangeKeySet([]byte("b"), []byte("e"), []byte(rkSuffix), nil, nil)) 2251 require.NoError(b, d.RangeKeySet([]byte("f"), []byte("p"), []byte(rkSuffix), nil, nil)) 2252 require.NoError(b, d.RangeKeySet([]byte("q"), []byte("z"), []byte(rkSuffix), nil, nil)) 2253 require.NoError(b, d.Flush()) 2254 2255 // Populate 3 range keys, covering most of the keyspace, at the 2256 // given suffix. 2257 2258 iterOpts := IterOptions{ 2259 KeyTypes: IterKeyTypePointsAndRanges, 2260 RangeKeyMasking: RangeKeyMasking{ 2261 Suffix: []byte("@100"), 2262 Filter: func() BlockPropertyFilterMask { 2263 return blockprop.NewMaskingFilter() 2264 }, 2265 }, 2266 } 2267 b.Run("forward", func(b *testing.B) { 2268 b.ResetTimer() 2269 for i := 0; i < b.N; i++ { 2270 iter := d.NewIter(&iterOpts) 2271 count := 0 2272 for valid := iter.First(); valid; valid = iter.Next() { 2273 if hasPoint, _ := iter.HasPointAndRange(); hasPoint { 2274 count++ 2275 } 2276 } 2277 if err := iter.Close(); err != nil { 2278 b.Fatal(err) 2279 } 2280 } 2281 }) 2282 b.Run("backward", func(b *testing.B) { 2283 b.ResetTimer() 2284 for i := 0; i < b.N; i++ { 2285 iter := d.NewIter(&iterOpts) 2286 count := 0 2287 for valid := iter.Last(); valid; valid = iter.Prev() { 2288 if hasPoint, _ := iter.HasPointAndRange(); hasPoint { 2289 count++ 2290 } 2291 } 2292 if err := iter.Close(); err != nil { 2293 b.Fatal(err) 2294 } 2295 } 2296 }) 2297 2298 // Reset the benchmark state at the end of each run to remove the 2299 // range keys we wrote. 2300 b.StopTimer() 2301 require.NoError(b, d.Close()) 2302 mem.ResetToSyncedState() 2303 }) 2304 } 2305 2306 } 2307 2308 func BenchmarkIteratorScan(b *testing.B) { 2309 const maxPrefixLen = 8 2310 keyBuf := make([]byte, maxPrefixLen+testkeys.MaxSuffixLen) 2311 rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano()))) 2312 2313 for _, keyCount := range []int{100, 1000, 10000} { 2314 for _, readAmp := range []int{1, 3, 7, 10} { 2315 func() { 2316 opts := &Options{ 2317 FS: vfs.NewMem(), 2318 FormatMajorVersion: FormatNewest, 2319 } 2320 opts.DisableAutomaticCompactions = true 2321 d, err := Open("", opts) 2322 require.NoError(b, err) 2323 defer func() { require.NoError(b, d.Close()) }() 2324 2325 // Take the very large keyspace consisting of alphabetic 2326 // characters of lengths up to `maxPrefixLen` and reduce it down 2327 // to `keyCount` keys by picking every 1 key every `keyCount` keys. 2328 keys := testkeys.Alpha(maxPrefixLen) 2329 keys = keys.EveryN(keys.Count() / keyCount) 2330 if keys.Count() < keyCount { 2331 b.Fatalf("expected %d keys, found %d", keyCount, keys.Count()) 2332 } 2333 2334 // Portion the keys into `readAmp` overlapping key sets. 2335 for _, ks := range testkeys.Divvy(keys, readAmp) { 2336 batch := d.NewBatch() 2337 for i := 0; i < ks.Count(); i++ { 2338 n := testkeys.WriteKeyAt(keyBuf[:], ks, i, int(rng.Uint64n(100))) 2339 batch.Set(keyBuf[:n], keyBuf[:n], nil) 2340 } 2341 require.NoError(b, batch.Commit(nil)) 2342 require.NoError(b, d.Flush()) 2343 } 2344 // Each level is a sublevel. 2345 m := d.Metrics() 2346 require.Equal(b, readAmp, m.ReadAmp()) 2347 2348 for _, keyTypes := range []IterKeyType{IterKeyTypePointsOnly, IterKeyTypePointsAndRanges} { 2349 iterOpts := IterOptions{KeyTypes: keyTypes} 2350 b.Run(fmt.Sprintf("keys=%d,r-amp=%d,key-types=%s", keyCount, readAmp, keyTypes), func(b *testing.B) { 2351 for i := 0; i < b.N; i++ { 2352 b.StartTimer() 2353 iter := d.NewIter(&iterOpts) 2354 valid := iter.First() 2355 for valid { 2356 valid = iter.Next() 2357 } 2358 b.StopTimer() 2359 require.NoError(b, iter.Close()) 2360 } 2361 }) 2362 } 2363 }() 2364 } 2365 } 2366 } 2367 2368 func BenchmarkCombinedIteratorSeek(b *testing.B) { 2369 for _, withRangeKey := range []bool{false, true} { 2370 b.Run(fmt.Sprintf("range-key=%t", withRangeKey), func(b *testing.B) { 2371 rng := rand.New(rand.NewSource(uint64(1658872515083979000))) 2372 ks := testkeys.Alpha(1) 2373 opts := &Options{ 2374 FS: vfs.NewMem(), 2375 Comparer: testkeys.Comparer, 2376 FormatMajorVersion: FormatNewest, 2377 } 2378 d, err := Open("", opts) 2379 require.NoError(b, err) 2380 defer func() { require.NoError(b, d.Close()) }() 2381 2382 keys := make([][]byte, ks.Count()) 2383 for i := 0; i < ks.Count(); i++ { 2384 keys[i] = testkeys.Key(ks, i) 2385 var val [40]byte 2386 rng.Read(val[:]) 2387 require.NoError(b, d.Set(keys[i], val[:], nil)) 2388 } 2389 if withRangeKey { 2390 require.NoError(b, d.RangeKeySet([]byte("a"), []byte{'z', 0x00}, []byte("@5"), nil, nil)) 2391 } 2392 2393 batch := d.NewIndexedBatch() 2394 defer batch.Close() 2395 2396 for _, useBatch := range []bool{false, true} { 2397 b.Run(fmt.Sprintf("batch=%t", useBatch), func(b *testing.B) { 2398 for i := 0; i < b.N; i++ { 2399 iterOpts := IterOptions{KeyTypes: IterKeyTypePointsAndRanges} 2400 var it *Iterator 2401 if useBatch { 2402 it = batch.NewIter(&iterOpts) 2403 } else { 2404 it = d.NewIter(&iterOpts) 2405 } 2406 for j := 0; j < len(keys); j++ { 2407 if !it.SeekGE(keys[j]) { 2408 b.Errorf("key %q missing", keys[j]) 2409 } 2410 } 2411 require.NoError(b, it.Close()) 2412 } 2413 }) 2414 } 2415 }) 2416 } 2417 } 2418 2419 // BenchmarkCombinedIteratorSeek_Bounded benchmarks a bounded iterator that 2420 // performs repeated seeks over 5% of the middle of a keyspace covered by a 2421 // range key that's fragmented across hundreds of files. The iterator bounds 2422 // should prevent defragmenting beyond the iterator's bounds. 2423 func BenchmarkCombinedIteratorSeek_Bounded(b *testing.B) { 2424 d, keys := buildFragmentedRangeKey(b, uint64(1658872515083979000)) 2425 2426 var lower = len(keys) / 2 2427 var upper = len(keys)/2 + len(keys)/20 // 5% 2428 iterOpts := IterOptions{ 2429 KeyTypes: IterKeyTypePointsAndRanges, 2430 LowerBound: keys[lower], 2431 UpperBound: keys[upper], 2432 } 2433 b.ResetTimer() 2434 for i := 0; i < b.N; i++ { 2435 it := d.NewIter(&iterOpts) 2436 for j := lower; j < upper; j++ { 2437 if !it.SeekGE(keys[j]) { 2438 b.Errorf("key %q missing", keys[j]) 2439 } 2440 } 2441 require.NoError(b, it.Close()) 2442 } 2443 } 2444 2445 // BenchmarkCombinedIteratorSeekPrefix benchmarks an iterator that 2446 // performs repeated prefix seeks over 5% of the middle of a keyspace covered by a 2447 // range key that's fragmented across hundreds of files. The seek prefix should 2448 // avoid defragmenting beyond the seek prefixes. 2449 func BenchmarkCombinedIteratorSeekPrefix(b *testing.B) { 2450 d, keys := buildFragmentedRangeKey(b, uint64(1658872515083979000)) 2451 2452 var lower = len(keys) / 2 2453 var upper = len(keys)/2 + len(keys)/20 // 5% 2454 iterOpts := IterOptions{ 2455 KeyTypes: IterKeyTypePointsAndRanges, 2456 } 2457 b.ResetTimer() 2458 for i := 0; i < b.N; i++ { 2459 it := d.NewIter(&iterOpts) 2460 for j := lower; j < upper; j++ { 2461 if !it.SeekPrefixGE(keys[j]) { 2462 b.Errorf("key %q missing", keys[j]) 2463 } 2464 } 2465 require.NoError(b, it.Close()) 2466 } 2467 } 2468 2469 func buildFragmentedRangeKey(b testing.TB, seed uint64) (d *DB, keys [][]byte) { 2470 rng := rand.New(rand.NewSource(seed)) 2471 ks := testkeys.Alpha(2) 2472 opts := &Options{ 2473 FS: vfs.NewMem(), 2474 Comparer: testkeys.Comparer, 2475 FormatMajorVersion: FormatNewest, 2476 L0CompactionFileThreshold: 1, 2477 } 2478 opts.EnsureDefaults() 2479 for l := 0; l < len(opts.Levels); l++ { 2480 opts.Levels[l].TargetFileSize = 1 2481 } 2482 var err error 2483 d, err = Open("", opts) 2484 require.NoError(b, err) 2485 2486 keys = make([][]byte, ks.Count()) 2487 for i := 0; i < ks.Count(); i++ { 2488 keys[i] = testkeys.Key(ks, i) 2489 } 2490 for i := 0; i < len(keys); i++ { 2491 var val [40]byte 2492 rng.Read(val[:]) 2493 require.NoError(b, d.Set(keys[i], val[:], nil)) 2494 if i < len(keys)-1 { 2495 require.NoError(b, d.RangeKeySet(keys[i], keys[i+1], []byte("@5"), nil, nil)) 2496 } 2497 require.NoError(b, d.Flush()) 2498 } 2499 2500 d.mu.Lock() 2501 for d.mu.compact.compactingCount > 0 { 2502 d.mu.compact.cond.Wait() 2503 } 2504 v := d.mu.versions.currentVersion() 2505 d.mu.Unlock() 2506 require.GreaterOrEqualf(b, v.Levels[numLevels-1].Len(), 2507 700, "expect many (≥700) L6 files but found %d", v.Levels[numLevels-1].Len()) 2508 return d, keys 2509 }