github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/interval/generic/example_interval_btree_test.go (about) 1 // Code generated by go_generics. DO NOT EDIT. 2 3 // Copyright 2020 The Cockroach Authors. 4 // 5 // Use of this software is governed by the Business Source License 6 // included in the file licenses/BSL.txt. 7 // 8 // As of the Change Date specified in that file, in accordance with 9 // the Business Source License, use of this software will be governed 10 // by the Apache License, Version 2.0, included in the file 11 // licenses/APL.txt. 12 13 package generic 14 15 import ( 16 "fmt" 17 "math/rand" 18 "reflect" 19 "sync" 20 "testing" 21 22 "github.com/cockroachdb/cockroach/pkg/roachpb" 23 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 24 "github.com/stretchr/testify/require" 25 ) 26 27 func newItem(s roachpb.Span) *example { 28 i := nilT.New() 29 i.SetKey(s.Key) 30 i.SetEndKey(s.EndKey) 31 return i 32 } 33 34 func spanFromItem(i *example) roachpb.Span { 35 return roachpb.Span{Key: i.Key(), EndKey: i.EndKey()} 36 } 37 38 ////////////////////////////////////////// 39 // Invariant verification // 40 ////////////////////////////////////////// 41 42 // Verify asserts that the tree's structural invariants all hold. 43 func (t *btree) Verify(tt *testing.T) { 44 if t.length == 0 { 45 require.Nil(tt, t.root) 46 return 47 } 48 t.verifyLeafSameDepth(tt) 49 t.verifyCountAllowed(tt) 50 t.isSorted(tt) 51 t.isUpperBoundCorrect(tt) 52 } 53 54 func (t *btree) verifyLeafSameDepth(tt *testing.T) { 55 h := t.Height() 56 t.root.verifyDepthEqualToHeight(tt, 1, h) 57 } 58 59 func (n *node) verifyDepthEqualToHeight(t *testing.T, depth, height int) { 60 if n.leaf { 61 require.Equal(t, height, depth, "all leaves should have the same depth as the tree height") 62 } 63 n.recurse(func(child *node, _ int16) { 64 child.verifyDepthEqualToHeight(t, depth+1, height) 65 }) 66 } 67 68 func (t *btree) verifyCountAllowed(tt *testing.T) { 69 t.root.verifyCountAllowed(tt, true) 70 } 71 72 func (n *node) verifyCountAllowed(t *testing.T, root bool) { 73 if !root { 74 require.GreaterOrEqual(t, n.count, int16(minItems), "latch count %d must be in range [%d,%d]", n.count, minItems, maxItems) 75 require.LessOrEqual(t, n.count, int16(maxItems), "latch count %d must be in range [%d,%d]", n.count, minItems, maxItems) 76 } 77 for i, item := range n.items { 78 if i < int(n.count) { 79 require.NotNil(t, item, "latch below count") 80 } else { 81 require.Nil(t, item, "latch above count") 82 } 83 } 84 if !n.leaf { 85 for i, child := range n.children { 86 if i <= int(n.count) { 87 require.NotNil(t, child, "node below count") 88 } else { 89 require.Nil(t, child, "node above count") 90 } 91 } 92 } 93 n.recurse(func(child *node, _ int16) { 94 child.verifyCountAllowed(t, false) 95 }) 96 } 97 98 func (t *btree) isSorted(tt *testing.T) { 99 t.root.isSorted(tt) 100 } 101 102 func (n *node) isSorted(t *testing.T) { 103 for i := int16(1); i < n.count; i++ { 104 require.LessOrEqual(t, cmp(n.items[i-1], n.items[i]), 0) 105 } 106 if !n.leaf { 107 for i := int16(0); i < n.count; i++ { 108 prev := n.children[i] 109 next := n.children[i+1] 110 111 require.LessOrEqual(t, cmp(prev.items[prev.count-1], n.items[i]), 0) 112 require.LessOrEqual(t, cmp(n.items[i], next.items[0]), 0) 113 } 114 } 115 n.recurse(func(child *node, _ int16) { 116 child.isSorted(t) 117 }) 118 } 119 120 func (t *btree) isUpperBoundCorrect(tt *testing.T) { 121 t.root.isUpperBoundCorrect(tt) 122 } 123 124 func (n *node) isUpperBoundCorrect(t *testing.T) { 125 require.Equal(t, 0, n.findUpperBound().compare(n.max)) 126 for i := int16(1); i < n.count; i++ { 127 require.LessOrEqual(t, upperBound(n.items[i]).compare(n.max), 0) 128 } 129 if !n.leaf { 130 for i := int16(0); i <= n.count; i++ { 131 child := n.children[i] 132 require.LessOrEqual(t, child.max.compare(n.max), 0) 133 } 134 } 135 n.recurse(func(child *node, _ int16) { 136 child.isUpperBoundCorrect(t) 137 }) 138 } 139 140 func (n *node) recurse(f func(child *node, pos int16)) { 141 if !n.leaf { 142 for i := int16(0); i <= n.count; i++ { 143 f(n.children[i], i) 144 } 145 } 146 } 147 148 ////////////////////////////////////////// 149 // Unit Tests // 150 ////////////////////////////////////////// 151 152 func key(i int) roachpb.Key { 153 if i < 0 || i > 99999 { 154 panic("key out of bounds") 155 } 156 return []byte(fmt.Sprintf("%05d", i)) 157 } 158 159 func span(i int) roachpb.Span { 160 switch i % 10 { 161 case 0: 162 return roachpb.Span{Key: key(i)} 163 case 1: 164 return roachpb.Span{Key: key(i), EndKey: key(i).Next()} 165 case 2: 166 return roachpb.Span{Key: key(i), EndKey: key(i + 64)} 167 default: 168 return roachpb.Span{Key: key(i), EndKey: key(i + 4)} 169 } 170 } 171 172 func spanWithEnd(start, end int) roachpb.Span { 173 if start < end { 174 return roachpb.Span{Key: key(start), EndKey: key(end)} 175 } else if start == end { 176 return roachpb.Span{Key: key(start)} 177 } else { 178 panic("illegal span") 179 } 180 } 181 182 func spanWithMemo(i int, memo map[int]roachpb.Span) roachpb.Span { 183 if s, ok := memo[i]; ok { 184 return s 185 } 186 s := span(i) 187 memo[i] = s 188 return s 189 } 190 191 func randomSpan(rng *rand.Rand, n int) roachpb.Span { 192 start := rng.Intn(n) 193 end := rng.Intn(n + 1) 194 if end < start { 195 start, end = end, start 196 } 197 return spanWithEnd(start, end) 198 } 199 200 func checkIter(t *testing.T, it iterator, start, end int, spanMemo map[int]roachpb.Span) { 201 i := start 202 for it.First(); it.Valid(); it.Next() { 203 item := it.Cur() 204 expected := spanWithMemo(i, spanMemo) 205 if !expected.Equal(spanFromItem(item)) { 206 t.Fatalf("expected %s, but found %s", expected, spanFromItem(item)) 207 } 208 i++ 209 } 210 if i != end { 211 t.Fatalf("expected %d, but at %d", end, i) 212 } 213 214 for it.Last(); it.Valid(); it.Prev() { 215 i-- 216 item := it.Cur() 217 expected := spanWithMemo(i, spanMemo) 218 if !expected.Equal(spanFromItem(item)) { 219 t.Fatalf("expected %s, but found %s", expected, spanFromItem(item)) 220 } 221 } 222 if i != start { 223 t.Fatalf("expected %d, but at %d: %+v", start, i, it) 224 } 225 226 all := newItem(spanWithEnd(start, end)) 227 for it.FirstOverlap(all); it.Valid(); it.NextOverlap(all) { 228 item := it.Cur() 229 expected := spanWithMemo(i, spanMemo) 230 if !expected.Equal(spanFromItem(item)) { 231 t.Fatalf("expected %s, but found %s", expected, spanFromItem(item)) 232 } 233 i++ 234 } 235 if i != end { 236 t.Fatalf("expected %d, but at %d", end, i) 237 } 238 } 239 240 // TestBTree tests basic btree operations. 241 func TestBTree(t *testing.T) { 242 var tr btree 243 spanMemo := make(map[int]roachpb.Span) 244 245 // With degree == 16 (max-items/node == 31) we need 513 items in order for 246 // there to be 3 levels in the tree. The count here is comfortably above 247 // that. 248 const count = 768 249 250 // Add keys in sorted order. 251 for i := 0; i < count; i++ { 252 tr.Set(newItem(span(i))) 253 tr.Verify(t) 254 if e := i + 1; e != tr.Len() { 255 t.Fatalf("expected length %d, but found %d", e, tr.Len()) 256 } 257 checkIter(t, tr.MakeIter(), 0, i+1, spanMemo) 258 } 259 260 // Delete keys in sorted order. 261 for i := 0; i < count; i++ { 262 tr.Delete(newItem(span(i))) 263 tr.Verify(t) 264 if e := count - (i + 1); e != tr.Len() { 265 t.Fatalf("expected length %d, but found %d", e, tr.Len()) 266 } 267 checkIter(t, tr.MakeIter(), i+1, count, spanMemo) 268 } 269 270 // Add keys in reverse sorted order. 271 for i := 0; i < count; i++ { 272 tr.Set(newItem(span(count - i))) 273 tr.Verify(t) 274 if e := i + 1; e != tr.Len() { 275 t.Fatalf("expected length %d, but found %d", e, tr.Len()) 276 } 277 checkIter(t, tr.MakeIter(), count-i, count+1, spanMemo) 278 } 279 280 // Delete keys in reverse sorted order. 281 for i := 0; i < count; i++ { 282 tr.Delete(newItem(span(count - i))) 283 tr.Verify(t) 284 if e := count - (i + 1); e != tr.Len() { 285 t.Fatalf("expected length %d, but found %d", e, tr.Len()) 286 } 287 checkIter(t, tr.MakeIter(), 1, count-i, spanMemo) 288 } 289 } 290 291 // TestBTreeSeek tests basic btree iterator operations. 292 func TestBTreeSeek(t *testing.T) { 293 const count = 513 294 295 var tr btree 296 for i := 0; i < count; i++ { 297 tr.Set(newItem(span(i * 2))) 298 } 299 300 it := tr.MakeIter() 301 for i := 0; i < 2*count-1; i++ { 302 it.SeekGE(newItem(span(i))) 303 if !it.Valid() { 304 t.Fatalf("%d: expected valid iterator", i) 305 } 306 item := it.Cur() 307 expected := span(2 * ((i + 1) / 2)) 308 if !expected.Equal(spanFromItem(item)) { 309 t.Fatalf("%d: expected %s, but found %s", i, expected, spanFromItem(item)) 310 } 311 } 312 it.SeekGE(newItem(span(2*count - 1))) 313 if it.Valid() { 314 t.Fatalf("expected invalid iterator") 315 } 316 317 for i := 1; i < 2*count; i++ { 318 it.SeekLT(newItem(span(i))) 319 if !it.Valid() { 320 t.Fatalf("%d: expected valid iterator", i) 321 } 322 item := it.Cur() 323 expected := span(2 * ((i - 1) / 2)) 324 if !expected.Equal(spanFromItem(item)) { 325 t.Fatalf("%d: expected %s, but found %s", i, expected, spanFromItem(item)) 326 } 327 } 328 it.SeekLT(newItem(span(0))) 329 if it.Valid() { 330 t.Fatalf("expected invalid iterator") 331 } 332 } 333 334 // TestBTreeSeekOverlap tests btree iterator overlap operations. 335 func TestBTreeSeekOverlap(t *testing.T) { 336 const count = 513 337 const size = 2 * maxItems 338 339 var tr btree 340 for i := 0; i < count; i++ { 341 tr.Set(newItem(spanWithEnd(i, i+size+1))) 342 } 343 344 // Iterate over overlaps with a point scan. 345 it := tr.MakeIter() 346 for i := 0; i < count+size; i++ { 347 scanItem := newItem(spanWithEnd(i, i)) 348 it.FirstOverlap(scanItem) 349 for j := 0; j < size+1; j++ { 350 expStart := i - size + j 351 if expStart < 0 { 352 continue 353 } 354 if expStart >= count { 355 continue 356 } 357 358 if !it.Valid() { 359 t.Fatalf("%d/%d: expected valid iterator", i, j) 360 } 361 item := it.Cur() 362 expected := spanWithEnd(expStart, expStart+size+1) 363 if !expected.Equal(spanFromItem(item)) { 364 t.Fatalf("%d: expected %s, but found %s", i, expected, spanFromItem(item)) 365 } 366 367 it.NextOverlap(scanItem) 368 } 369 if it.Valid() { 370 t.Fatalf("%d: expected invalid iterator %v", i, it.Cur()) 371 } 372 } 373 it.FirstOverlap(newItem(span(count + size + 1))) 374 if it.Valid() { 375 t.Fatalf("expected invalid iterator") 376 } 377 378 // Iterate over overlaps with a range scan. 379 it = tr.MakeIter() 380 for i := 0; i < count+size; i++ { 381 scanItem := newItem(spanWithEnd(i, i+size+1)) 382 it.FirstOverlap(scanItem) 383 for j := 0; j < 2*size+1; j++ { 384 expStart := i - size + j 385 if expStart < 0 { 386 continue 387 } 388 if expStart >= count { 389 continue 390 } 391 392 if !it.Valid() { 393 t.Fatalf("%d/%d: expected valid iterator", i, j) 394 } 395 item := it.Cur() 396 expected := spanWithEnd(expStart, expStart+size+1) 397 if !expected.Equal(spanFromItem(item)) { 398 t.Fatalf("%d: expected %s, but found %s", i, expected, spanFromItem(item)) 399 } 400 401 it.NextOverlap(scanItem) 402 } 403 if it.Valid() { 404 t.Fatalf("%d: expected invalid iterator %v", i, it.Cur()) 405 } 406 } 407 it.FirstOverlap(newItem(span(count + size + 1))) 408 if it.Valid() { 409 t.Fatalf("expected invalid iterator") 410 } 411 } 412 413 // TestBTreeSeekOverlapRandom tests btree iterator overlap operations using 414 // randomized input. 415 func TestBTreeSeekOverlapRandom(t *testing.T) { 416 rng := rand.New(rand.NewSource(timeutil.Now().UnixNano())) 417 418 const trials = 10 419 for i := 0; i < trials; i++ { 420 var tr btree 421 422 const count = 1000 423 items := make([]*example, count) 424 itemSpans := make([]int, count) 425 for j := 0; j < count; j++ { 426 var item *example 427 end := rng.Intn(count + 10) 428 if end <= j { 429 end = j 430 item = newItem(spanWithEnd(j, end)) 431 } else { 432 item = newItem(spanWithEnd(j, end+1)) 433 } 434 tr.Set(item) 435 items[j] = item 436 itemSpans[j] = end 437 } 438 439 const scanTrials = 100 440 for j := 0; j < scanTrials; j++ { 441 var scanItem *example 442 scanStart := rng.Intn(count) 443 scanEnd := rng.Intn(count + 10) 444 if scanEnd <= scanStart { 445 scanEnd = scanStart 446 scanItem = newItem(spanWithEnd(scanStart, scanEnd)) 447 } else { 448 scanItem = newItem(spanWithEnd(scanStart, scanEnd+1)) 449 } 450 451 var exp, found []*example 452 for startKey, endKey := range itemSpans { 453 if startKey <= scanEnd && endKey >= scanStart { 454 exp = append(exp, items[startKey]) 455 } 456 } 457 458 it := tr.MakeIter() 459 it.FirstOverlap(scanItem) 460 for it.Valid() { 461 found = append(found, it.Cur()) 462 it.NextOverlap(scanItem) 463 } 464 465 require.Equal(t, len(exp), len(found), "search for %v", spanFromItem(scanItem)) 466 } 467 } 468 } 469 470 // TestBTreeCloneConcurrentOperations tests that cloning a btree returns a new 471 // btree instance which is an exact logical copy of the original but that can be 472 // modified independently going forward. 473 func TestBTreeCloneConcurrentOperations(t *testing.T) { 474 const cloneTestSize = 1000 475 p := perm(cloneTestSize) 476 477 var trees []*btree 478 treeC, treeDone := make(chan *btree), make(chan struct{}) 479 go func() { 480 for b := range treeC { 481 trees = append(trees, b) 482 } 483 close(treeDone) 484 }() 485 486 var wg sync.WaitGroup 487 var populate func(tr *btree, start int) 488 populate = func(tr *btree, start int) { 489 t.Logf("Starting new clone at %v", start) 490 treeC <- tr 491 for i := start; i < cloneTestSize; i++ { 492 tr.Set(p[i]) 493 if i%(cloneTestSize/5) == 0 { 494 wg.Add(1) 495 c := tr.Clone() 496 go populate(&c, i+1) 497 } 498 } 499 wg.Done() 500 } 501 502 wg.Add(1) 503 var tr btree 504 go populate(&tr, 0) 505 wg.Wait() 506 close(treeC) 507 <-treeDone 508 509 t.Logf("Starting equality checks on %d trees", len(trees)) 510 want := rang(0, cloneTestSize-1) 511 for i, tree := range trees { 512 if !reflect.DeepEqual(want, all(tree)) { 513 t.Errorf("tree %v mismatch", i) 514 } 515 } 516 517 t.Log("Removing half of items from first half") 518 toRemove := want[cloneTestSize/2:] 519 for i := 0; i < len(trees)/2; i++ { 520 tree := trees[i] 521 wg.Add(1) 522 go func() { 523 for _, item := range toRemove { 524 tree.Delete(item) 525 } 526 wg.Done() 527 }() 528 } 529 wg.Wait() 530 531 t.Log("Checking all values again") 532 for i, tree := range trees { 533 var wantpart []*example 534 if i < len(trees)/2 { 535 wantpart = want[:cloneTestSize/2] 536 } else { 537 wantpart = want 538 } 539 if got := all(tree); !reflect.DeepEqual(wantpart, got) { 540 t.Errorf("tree %v mismatch, want %v got %v", i, len(want), len(got)) 541 } 542 } 543 } 544 545 // TestBTreeCmp tests the btree item comparison. 546 func TestBTreeCmp(t *testing.T) { 547 // NB: go_generics doesn't do well with anonymous types, so name this type. 548 // Avoid the slice literal syntax, which GofmtSimplify mandates the use of 549 // anonymous constructors with. 550 type testCase struct { 551 spanA, spanB roachpb.Span 552 idA, idB uint64 553 exp int 554 } 555 var testCases []testCase 556 testCases = append(testCases, 557 testCase{ 558 spanA: roachpb.Span{Key: roachpb.Key("a")}, 559 spanB: roachpb.Span{Key: roachpb.Key("a")}, 560 idA: 1, 561 idB: 1, 562 exp: 0, 563 }, 564 testCase{ 565 spanA: roachpb.Span{Key: roachpb.Key("a")}, 566 spanB: roachpb.Span{Key: roachpb.Key("a"), EndKey: roachpb.Key("b")}, 567 idA: 1, 568 idB: 1, 569 exp: -1, 570 }, 571 testCase{ 572 spanA: roachpb.Span{Key: roachpb.Key("a"), EndKey: roachpb.Key("c")}, 573 spanB: roachpb.Span{Key: roachpb.Key("a"), EndKey: roachpb.Key("b")}, 574 idA: 1, 575 idB: 1, 576 exp: 1, 577 }, 578 testCase{ 579 spanA: roachpb.Span{Key: roachpb.Key("a"), EndKey: roachpb.Key("c")}, 580 spanB: roachpb.Span{Key: roachpb.Key("a"), EndKey: roachpb.Key("c")}, 581 idA: 1, 582 idB: 1, 583 exp: 0, 584 }, 585 testCase{ 586 spanA: roachpb.Span{Key: roachpb.Key("a")}, 587 spanB: roachpb.Span{Key: roachpb.Key("a")}, 588 idA: 1, 589 idB: 2, 590 exp: -1, 591 }, 592 testCase{ 593 spanA: roachpb.Span{Key: roachpb.Key("a")}, 594 spanB: roachpb.Span{Key: roachpb.Key("a")}, 595 idA: 2, 596 idB: 1, 597 exp: 1, 598 }, 599 testCase{ 600 spanA: roachpb.Span{Key: roachpb.Key("b")}, 601 spanB: roachpb.Span{Key: roachpb.Key("a"), EndKey: roachpb.Key("c")}, 602 idA: 1, 603 idB: 1, 604 exp: 1, 605 }, 606 testCase{ 607 spanA: roachpb.Span{Key: roachpb.Key("b"), EndKey: roachpb.Key("e")}, 608 spanB: roachpb.Span{Key: roachpb.Key("c"), EndKey: roachpb.Key("d")}, 609 idA: 1, 610 idB: 1, 611 exp: -1, 612 }, 613 ) 614 for _, tc := range testCases { 615 name := fmt.Sprintf("cmp(%s:%d,%s:%d)", tc.spanA, tc.idA, tc.spanB, tc.idB) 616 t.Run(name, func(t *testing.T) { 617 laA := newItem(tc.spanA) 618 laA.SetID(tc.idA) 619 laB := newItem(tc.spanB) 620 laB.SetID(tc.idB) 621 require.Equal(t, tc.exp, cmp(laA, laB)) 622 }) 623 } 624 } 625 626 // TestIterStack tests the interface of the iterStack type. 627 func TestIterStack(t *testing.T) { 628 f := func(i int) iterFrame { return iterFrame{pos: int16(i)} } 629 var is iterStack 630 for i := 1; i <= 2*len(iterStackArr{}); i++ { 631 var j int 632 for j = 0; j < i; j++ { 633 is.push(f(j)) 634 } 635 require.Equal(t, j, is.len()) 636 for j--; j >= 0; j-- { 637 require.Equal(t, f(j), is.pop()) 638 } 639 is.reset() 640 } 641 } 642 643 ////////////////////////////////////////// 644 // Benchmarks // 645 ////////////////////////////////////////// 646 647 // perm returns a random permutation of items with spans in the range [0, n). 648 func perm(n int) (out []*example) { 649 for _, i := range rand.Perm(n) { 650 out = append(out, newItem(spanWithEnd(i, i+1))) 651 } 652 return out 653 } 654 655 // rang returns an ordered list of items with spans in the range [m, n]. 656 func rang(m, n int) (out []*example) { 657 for i := m; i <= n; i++ { 658 out = append(out, newItem(spanWithEnd(i, i+1))) 659 } 660 return out 661 } 662 663 // all extracts all items from a tree in order as a slice. 664 func all(tr *btree) (out []*example) { 665 it := tr.MakeIter() 666 it.First() 667 for it.Valid() { 668 out = append(out, it.Cur()) 669 it.Next() 670 } 671 return out 672 } 673 674 func forBenchmarkSizes(b *testing.B, f func(b *testing.B, count int)) { 675 for _, count := range []int{16, 128, 1024, 8192, 65536} { 676 b.Run(fmt.Sprintf("count=%d", count), func(b *testing.B) { 677 f(b, count) 678 }) 679 } 680 } 681 682 // BenchmarkBTreeInsert measures btree insertion performance. 683 func BenchmarkBTreeInsert(b *testing.B) { 684 forBenchmarkSizes(b, func(b *testing.B, count int) { 685 insertP := perm(count) 686 b.ResetTimer() 687 for i := 0; i < b.N; { 688 var tr btree 689 for _, item := range insertP { 690 tr.Set(item) 691 i++ 692 if i >= b.N { 693 return 694 } 695 } 696 } 697 }) 698 } 699 700 // BenchmarkBTreeDelete measures btree deletion performance. 701 func BenchmarkBTreeDelete(b *testing.B) { 702 forBenchmarkSizes(b, func(b *testing.B, count int) { 703 insertP, removeP := perm(count), perm(count) 704 b.ResetTimer() 705 for i := 0; i < b.N; { 706 b.StopTimer() 707 var tr btree 708 for _, item := range insertP { 709 tr.Set(item) 710 } 711 b.StartTimer() 712 for _, item := range removeP { 713 tr.Delete(item) 714 i++ 715 if i >= b.N { 716 return 717 } 718 } 719 if tr.Len() > 0 { 720 b.Fatalf("tree not empty: %s", &tr) 721 } 722 } 723 }) 724 } 725 726 // BenchmarkBTreeDeleteInsert measures btree deletion and insertion performance. 727 func BenchmarkBTreeDeleteInsert(b *testing.B) { 728 forBenchmarkSizes(b, func(b *testing.B, count int) { 729 insertP := perm(count) 730 var tr btree 731 for _, item := range insertP { 732 tr.Set(item) 733 } 734 b.ResetTimer() 735 for i := 0; i < b.N; i++ { 736 item := insertP[i%count] 737 tr.Delete(item) 738 tr.Set(item) 739 } 740 }) 741 } 742 743 // BenchmarkBTreeDeleteInsertCloneOnce measures btree deletion and insertion 744 // performance after the tree has been copy-on-write cloned once. 745 func BenchmarkBTreeDeleteInsertCloneOnce(b *testing.B) { 746 forBenchmarkSizes(b, func(b *testing.B, count int) { 747 insertP := perm(count) 748 var tr btree 749 for _, item := range insertP { 750 tr.Set(item) 751 } 752 tr = tr.Clone() 753 b.ResetTimer() 754 for i := 0; i < b.N; i++ { 755 item := insertP[i%count] 756 tr.Delete(item) 757 tr.Set(item) 758 } 759 }) 760 } 761 762 // BenchmarkBTreeDeleteInsertCloneEachTime measures btree deletion and insertion 763 // performance while the tree is repeatedly copy-on-write cloned. 764 func BenchmarkBTreeDeleteInsertCloneEachTime(b *testing.B) { 765 for _, reset := range []bool{false, true} { 766 b.Run(fmt.Sprintf("reset=%t", reset), func(b *testing.B) { 767 forBenchmarkSizes(b, func(b *testing.B, count int) { 768 insertP := perm(count) 769 var tr, trReset btree 770 for _, item := range insertP { 771 tr.Set(item) 772 } 773 b.ResetTimer() 774 for i := 0; i < b.N; i++ { 775 item := insertP[i%count] 776 if reset { 777 trReset.Reset() 778 trReset = tr 779 } 780 tr = tr.Clone() 781 tr.Delete(item) 782 tr.Set(item) 783 } 784 }) 785 }) 786 } 787 } 788 789 // BenchmarkBTreeMakeIter measures the cost of creating a btree iterator. 790 func BenchmarkBTreeMakeIter(b *testing.B) { 791 var tr btree 792 for i := 0; i < b.N; i++ { 793 it := tr.MakeIter() 794 it.First() 795 } 796 } 797 798 // BenchmarkBTreeIterSeekGE measures the cost of seeking a btree iterator 799 // forward. 800 func BenchmarkBTreeIterSeekGE(b *testing.B) { 801 rng := rand.New(rand.NewSource(timeutil.Now().UnixNano())) 802 forBenchmarkSizes(b, func(b *testing.B, count int) { 803 var spans []roachpb.Span 804 var tr btree 805 806 for i := 0; i < count; i++ { 807 s := span(i) 808 spans = append(spans, s) 809 tr.Set(newItem(s)) 810 } 811 812 b.ResetTimer() 813 for i := 0; i < b.N; i++ { 814 s := spans[rng.Intn(len(spans))] 815 it := tr.MakeIter() 816 it.SeekGE(newItem(s)) 817 if testing.Verbose() { 818 if !it.Valid() { 819 b.Fatal("expected to find key") 820 } 821 if !s.Equal(spanFromItem(it.Cur())) { 822 b.Fatalf("expected %s, but found %s", s, spanFromItem(it.Cur())) 823 } 824 } 825 } 826 }) 827 } 828 829 // BenchmarkBTreeIterSeekLT measures the cost of seeking a btree iterator 830 // backward. 831 func BenchmarkBTreeIterSeekLT(b *testing.B) { 832 rng := rand.New(rand.NewSource(timeutil.Now().UnixNano())) 833 forBenchmarkSizes(b, func(b *testing.B, count int) { 834 var spans []roachpb.Span 835 var tr btree 836 837 for i := 0; i < count; i++ { 838 s := span(i) 839 spans = append(spans, s) 840 tr.Set(newItem(s)) 841 } 842 843 b.ResetTimer() 844 for i := 0; i < b.N; i++ { 845 j := rng.Intn(len(spans)) 846 s := spans[j] 847 it := tr.MakeIter() 848 it.SeekLT(newItem(s)) 849 if testing.Verbose() { 850 if j == 0 { 851 if it.Valid() { 852 b.Fatal("unexpected key") 853 } 854 } else { 855 if !it.Valid() { 856 b.Fatal("expected to find key") 857 } 858 s := spans[j-1] 859 if !s.Equal(spanFromItem(it.Cur())) { 860 b.Fatalf("expected %s, but found %s", s, spanFromItem(it.Cur())) 861 } 862 } 863 } 864 } 865 }) 866 } 867 868 // BenchmarkBTreeIterFirstOverlap measures the cost of finding a single 869 // overlapping item using a btree iterator. 870 func BenchmarkBTreeIterFirstOverlap(b *testing.B) { 871 rng := rand.New(rand.NewSource(timeutil.Now().UnixNano())) 872 forBenchmarkSizes(b, func(b *testing.B, count int) { 873 var spans []roachpb.Span 874 var tr btree 875 876 for i := 0; i < count; i++ { 877 s := spanWithEnd(i, i+1) 878 spans = append(spans, s) 879 tr.Set(newItem(s)) 880 } 881 882 b.ResetTimer() 883 for i := 0; i < b.N; i++ { 884 j := rng.Intn(len(spans)) 885 s := spans[j] 886 it := tr.MakeIter() 887 it.FirstOverlap(newItem(s)) 888 if testing.Verbose() { 889 if !it.Valid() { 890 b.Fatal("expected to find key") 891 } 892 if !s.Equal(spanFromItem(it.Cur())) { 893 b.Fatalf("expected %s, but found %s", s, spanFromItem(it.Cur())) 894 } 895 } 896 } 897 }) 898 } 899 900 // BenchmarkBTreeIterNext measures the cost of seeking a btree iterator to the 901 // next item in the tree. 902 func BenchmarkBTreeIterNext(b *testing.B) { 903 var tr btree 904 905 const count = 8 << 10 906 const size = 2 * maxItems 907 for i := 0; i < count; i++ { 908 item := newItem(spanWithEnd(i, i+size+1)) 909 tr.Set(item) 910 } 911 912 it := tr.MakeIter() 913 b.ResetTimer() 914 for i := 0; i < b.N; i++ { 915 if !it.Valid() { 916 it.First() 917 } 918 it.Next() 919 } 920 } 921 922 // BenchmarkBTreeIterPrev measures the cost of seeking a btree iterator to the 923 // previous item in the tree. 924 func BenchmarkBTreeIterPrev(b *testing.B) { 925 var tr btree 926 927 const count = 8 << 10 928 const size = 2 * maxItems 929 for i := 0; i < count; i++ { 930 item := newItem(spanWithEnd(i, i+size+1)) 931 tr.Set(item) 932 } 933 934 it := tr.MakeIter() 935 b.ResetTimer() 936 for i := 0; i < b.N; i++ { 937 if !it.Valid() { 938 it.First() 939 } 940 it.Prev() 941 } 942 } 943 944 // BenchmarkBTreeIterNextOverlap measures the cost of seeking a btree iterator 945 // to the next overlapping item in the tree. 946 func BenchmarkBTreeIterNextOverlap(b *testing.B) { 947 var tr btree 948 949 const count = 8 << 10 950 const size = 2 * maxItems 951 for i := 0; i < count; i++ { 952 item := newItem(spanWithEnd(i, i+size+1)) 953 tr.Set(item) 954 } 955 956 allCmd := newItem(spanWithEnd(0, count+1)) 957 it := tr.MakeIter() 958 b.ResetTimer() 959 for i := 0; i < b.N; i++ { 960 if !it.Valid() { 961 it.FirstOverlap(allCmd) 962 } 963 it.NextOverlap(allCmd) 964 } 965 } 966 967 // BenchmarkBTreeIterOverlapScan measures the cost of scanning over all 968 // overlapping items using a btree iterator. 969 func BenchmarkBTreeIterOverlapScan(b *testing.B) { 970 var tr btree 971 rng := rand.New(rand.NewSource(timeutil.Now().UnixNano())) 972 973 const count = 8 << 10 974 const size = 2 * maxItems 975 for i := 0; i < count; i++ { 976 tr.Set(newItem(spanWithEnd(i, i+size+1))) 977 } 978 979 b.ResetTimer() 980 for i := 0; i < b.N; i++ { 981 item := newItem(randomSpan(rng, count)) 982 it := tr.MakeIter() 983 it.FirstOverlap(item) 984 for it.Valid() { 985 it.NextOverlap(item) 986 } 987 } 988 }