github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/interval/btree_based_interval_test.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package interval 12 13 import ( 14 "bytes" 15 "encoding/binary" 16 "flag" 17 "fmt" 18 "math/rand" 19 "reflect" 20 "sort" 21 "testing" 22 23 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 24 "golang.org/x/sync/errgroup" 25 ) 26 27 var btreeMinDegree = flag.Int("btree_min_degree", DefaultBTreeMinimumDegree, "B-Tree minimum degree") 28 29 func init() { 30 seed := timeutil.Now().Unix() 31 rand.Seed(seed) 32 } 33 34 // perm returns a random permutation of intervals whose range start is in the 35 // range [0, n). 36 func perm(n uint32) (out items) { 37 for _, i := range rand.Perm(int(n)) { 38 u := uint32(i) 39 iv := makeMultiByteInterval(u, u+1, u) 40 out = append(out, iv) 41 } 42 return 43 } 44 45 // rang returns an ordered list of intervals in the range [m, n]. 46 func rang(m, n uint32) (out items) { 47 for u := m; u <= n; u++ { 48 iv := makeMultiByteInterval(u, u+1, u) 49 out = append(out, iv) 50 } 51 return 52 } 53 54 // all extracts all items from a tree in order as a slice. 55 func all(t *btree) (out items) { 56 t.Do(func(a Interface) bool { 57 out = append(out, a) 58 return false 59 }) 60 return 61 } 62 63 func makeMultiByteInterval(start, end, id uint32) *Interval { 64 return &Interval{Range{toBytes(start), toBytes(end)}, uintptr(id)} 65 } 66 67 func toBytes(n uint32) Comparable { 68 buf := new(bytes.Buffer) 69 if err := binary.Write(buf, binary.BigEndian, n); err != nil { 70 panic(fmt.Sprintf("binary.Write error: %s", err)) 71 } 72 return Comparable(buf.Bytes()) 73 } 74 75 type Interval struct { 76 r Range 77 id uintptr 78 } 79 80 func (iv *Interval) Range() Range { 81 return iv.r 82 } 83 84 func (iv *Interval) ID() uintptr { 85 return iv.id 86 } 87 88 func (iv *Interval) String() string { 89 return fmt.Sprintf("%v-%d", iv.Range(), iv.ID()) 90 } 91 92 func (items items) Len() int { 93 return len(items) 94 } 95 96 func (items items) Less(i, j int) bool { 97 return Compare(items[i], items[j]) <= 0 98 } 99 100 func (items items) Swap(i, j int) { 101 items[i], items[j] = items[j], items[i] 102 } 103 104 func (children children) Len() int { 105 return len(children) 106 } 107 108 func (children children) Less(i, j int) bool { 109 return children[i].Range.Start.Compare(children[j].Range.Start) <= 0 110 } 111 112 func (children children) Swap(i, j int) { 113 children[i], children[j] = children[j], children[i] 114 } 115 116 // describe returns a string description of the tree. The format is similar to 117 // https://en.wikipedia.org/wiki/Newick_format 118 func (tree *btree) describe() string { 119 if tree.isEmpty() { 120 return ";" 121 } 122 return tree.root.String() 123 } 124 125 var _ = (*btree).describe 126 127 func (n node) String() string { 128 var buf bytes.Buffer 129 n.describe(&buf) 130 return buf.String() 131 } 132 133 func (n *node) describe(buf *bytes.Buffer) { 134 if len(n.children) == 0 { 135 for idx, i := range n.items { 136 if idx != 0 { 137 buf.WriteString(",") 138 } 139 buf.WriteString(i.(*Interval).String()) 140 } 141 } 142 for i, c := range n.children { 143 buf.WriteString("(") 144 c.describe(buf) 145 buf.WriteString(fmt.Sprintf(":%s", c.Range)) 146 buf.WriteString(")") 147 if i < len(n.children)-1 { 148 buf.WriteString(n.items[i].(*Interval).String()) 149 } 150 } 151 } 152 153 func (n *node) isKeyInRange(t *testing.T, min, max Comparable) bool { 154 for _, i := range n.items { 155 start := i.Range().Start 156 if min != nil && start.Compare(min) < 0 { 157 return false 158 } 159 if max != nil && start.Compare(max) > 0 { 160 return false 161 } 162 } 163 oldMin, oldMax := min, max 164 for i, c := range n.children { 165 min, max := oldMin, oldMax 166 if i != 0 { 167 min = n.items[i-1].Range().Start 168 } 169 if i != len(n.children)-1 { 170 max = n.items[i].Range().Start 171 } 172 if !c.isKeyInRange(t, min, max) { 173 return false 174 } 175 } 176 return true 177 } 178 179 func (n *node) isSorted(t *testing.T) bool { 180 for _, c := range n.children { 181 if !c.isSorted(t) { 182 return false 183 } 184 } 185 if !sort.IsSorted(n.items) { 186 return false 187 } 188 if !sort.IsSorted(n.children) { 189 return false 190 } 191 return true 192 } 193 194 func (tree *btree) computeHeight() (h int) { 195 h = -1 196 for node := tree.root; ; { 197 h++ 198 if len(node.children) == 0 { 199 break 200 } 201 node = node.children[0] 202 } 203 return 204 } 205 206 func (n *node) isDepthEqualToHeight(t *testing.T, depth, height int) bool { 207 if len(n.children) == 0 { 208 return depth == height 209 } 210 for _, c := range n.children { 211 if !c.isDepthEqualToHeight(t, depth+1, height) { 212 return false 213 } 214 } 215 return true 216 } 217 218 func (n *node) isCountAllowed(t *testing.T, minItems, maxItems int, root bool) bool { 219 iLen := len(n.items) 220 cLen := len(n.children) 221 if !root { 222 iAllowed := minItems <= iLen && iLen <= maxItems 223 if !iAllowed { 224 return false 225 } 226 } 227 if cLen > 0 { 228 cAllowed := cLen == iLen+1 229 if !cAllowed { 230 return false 231 } 232 for _, c := range n.children { 233 allowed := c.isCountAllowed(t, minItems, maxItems, false) 234 if !allowed { 235 return false 236 } 237 } 238 } 239 return true 240 } 241 242 func (n *node) isIntervalInRange(t *testing.T) bool { 243 for _, c := range n.children { 244 if !c.isIntervalInRange(t) { 245 return false 246 } 247 } 248 r := n.bound() 249 if !n.Range.Equal(r) { 250 t.Errorf("%v expected range %v, got %v", n, r, n.Range) 251 return false 252 } 253 return true 254 } 255 256 func (r *Range) combine(other Range) { 257 if r.Start.Compare(other.Start) > 0 { 258 r.Start = other.Start 259 } 260 if r.End.Compare(other.End) < 0 { 261 r.End = other.End 262 } 263 } 264 265 func (n *node) bound() Range { 266 r := n.items[0].Range() 267 ptr := &r 268 for _, e := range n.items[1:] { 269 ptr.combine(e.Range()) 270 } 271 for _, c := range n.children { 272 ptr.combine(c.Range) 273 } 274 return r 275 } 276 277 func checkWithLen(t *testing.T, tree *btree, l int) { 278 if tree.Len() != l { 279 t.Errorf("expected tree length %d, got %d", l, tree.Len()) 280 } 281 check(t, tree) 282 } 283 284 func check(t *testing.T, tree *btree) { 285 if !tree.isLeafSameDepth(t) { 286 t.Error("Not all the leaves have the same depth as the tree height") 287 } 288 if !tree.isCountAllowed(t) { 289 t.Error("Not all the nodes have allowed key count and child node count") 290 } 291 if !tree.isIntervalInRange(t) { 292 t.Error("Not all the nodes bound all the intervals in its subtree with its Range field") 293 } 294 if !tree.isSorted(t) { 295 t.Error("Not all the nodes have its items and children fields sorted") 296 } 297 if !tree.isKeyInRange(t) { 298 t.Error("not all the nodes keep node keys (range.start) in range") 299 } 300 } 301 302 func (tree *btree) isLeafSameDepth(t *testing.T) bool { 303 if tree.isEmpty() { 304 return true 305 } 306 h := tree.computeHeight() 307 t.Logf("tree height: %d", h) 308 return tree.root.isDepthEqualToHeight(t, 0, h) 309 } 310 311 func (tree *btree) isCountAllowed(t *testing.T) bool { 312 if tree.isEmpty() { 313 return true 314 } 315 return tree.root.isCountAllowed(t, tree.minItems(), tree.maxItems(), true) 316 } 317 318 // Does every node correctly annotate the range of its children. 319 func (tree *btree) isIntervalInRange(t *testing.T) bool { 320 if tree.isEmpty() { 321 return true 322 } 323 return tree.root.isIntervalInRange(t) 324 } 325 326 func (tree *btree) isSorted(t *testing.T) bool { 327 if tree.isEmpty() { 328 return true 329 } 330 return tree.root.isSorted(t) 331 } 332 333 func (tree *btree) isKeyInRange(t *testing.T) bool { 334 if tree.isEmpty() { 335 return true 336 } 337 return tree.root.isKeyInRange(t, nil, nil) 338 } 339 340 func checkEqualIntervals(t *testing.T, actual, expected items) { 341 for i := 0; i < len(actual)-1; i++ { 342 if actual[i].Range().Start.Compare(actual[i+1].Range().Start) > 0 { 343 t.Fatalf("interval slice is not sorted: %v", actual) 344 break 345 } 346 } 347 itemsLen := len(expected) 348 sortedExpected := make(items, itemsLen) 349 copy(sortedExpected, expected) 350 sort.Sort(sortedExpected) 351 if !reflect.DeepEqual(actual, sortedExpected) { 352 t.Errorf("expected intervals %v, got %v", expected, actual) 353 } 354 } 355 356 func checkTraversal(t *testing.T, tree *btree, ivs items) { 357 // Get, GetWithOverlapper 358 r := Range{Comparable{0x0}, Comparable{0x1}} 359 expectedIntervals := items{ivs[0], ivs[2], ivs[4]} 360 checkEqualIntervals(t, tree.Get(r), expectedIntervals) 361 checkEqualIntervals(t, tree.GetWithOverlapper(r, ExclusiveOverlapper), items{ivs[0]}) 362 363 // DoMatching 364 var overlapped items 365 tree.DoMatching(func(e Interface) bool { 366 overlapped = append(overlapped, e) 367 return false 368 }, r) 369 checkEqualIntervals(t, overlapped, expectedIntervals) 370 371 // Do 372 var all items 373 tree.Do(func(e Interface) bool { 374 all = append(all, e) 375 return false 376 }) 377 checkEqualIntervals(t, all, ivs) 378 } 379 380 func checkIterator(t *testing.T, tree *btree, ivs items) { 381 var actual items 382 it := tree.Iterator() 383 for r, ok := it.Next(); ok; r, ok = it.Next() { 384 actual = append(actual, r) 385 } 386 checkEqualIntervals(t, actual, ivs) 387 } 388 389 func checkFastDelete(t *testing.T, tree *btree, ivs items, deleteCount int) { 390 for i, iv := range ivs[:deleteCount] { 391 if err := tree.Delete(iv, true); err != nil { 392 t.Fatalf("delete error: %s", err) 393 } 394 // Unlike fast insert, AdjustRanges must be called after each fast delete. 395 // Otherwise, the following fast deletes may go wrong. 396 tree.AdjustRanges() 397 checkWithLen(t, tree, len(ivs)-i-1) 398 } 399 } 400 401 func makeIntervals() items { 402 ivs := items{ 403 &Interval{Range{Comparable{0}, Comparable{2}}, 0}, 404 &Interval{Range{Comparable{2}, Comparable{4}}, 0}, 405 &Interval{Range{Comparable{1}, Comparable{6}}, 0}, 406 &Interval{Range{Comparable{3}, Comparable{4}}, 0}, 407 &Interval{Range{Comparable{1}, Comparable{3}}, 0}, 408 &Interval{Range{Comparable{4}, Comparable{6}}, 0}, 409 &Interval{Range{Comparable{5}, Comparable{8}}, 0}, 410 &Interval{Range{Comparable{6}, Comparable{8}}, 0}, 411 &Interval{Range{Comparable{5}, Comparable{9}}, 0}, 412 &Interval{Range{Comparable{0x11}, Comparable{0x13}}, 0}, 413 &Interval{Range{Comparable{0x14}, Comparable{0x16}}, 0}, 414 &Interval{Range{Comparable{0x15}, Comparable{0x18}}, 0}, 415 &Interval{Range{Comparable{0x10}, Comparable{0x12}}, 0}, 416 &Interval{Range{Comparable{0x20}, Comparable{0x62}}, 0}, 417 &Interval{Range{Comparable{0x24}, Comparable{0xA0}}, 0}, 418 &Interval{Range{Comparable{0x31}, Comparable{0x63}}, 0}, 419 &Interval{Range{Comparable{0x44}, Comparable{0x56}}, 0}, 420 &Interval{Range{Comparable{0x45}, Comparable{0x68}}, 0}, 421 &Interval{Range{Comparable{0x30}, Comparable{0x72}}, 0}, 422 &Interval{Range{Comparable{0x30}, Comparable{0x52}}, 0}, 423 &Interval{Range{Comparable{0x44}, Comparable{0xB0}}, 0}, 424 } 425 for i, iv := range ivs { 426 iv.(*Interval).id = uintptr(i) 427 } 428 return ivs 429 } 430 431 // TestBTree is based on https://github.com/google/btree/blob/master/btree_test.go. 432 func TestBTree(t *testing.T) { 433 tree := newBTreeWithDegree(InclusiveOverlapper, *btreeMinDegree) 434 const treeSize = 10000 435 for i := 0; i < 10; i++ { 436 for _, iv := range perm(treeSize) { 437 if x := tree.Insert(iv, false); x != nil { 438 t.Fatalf("insert found interval %v", x) 439 } 440 } 441 442 for _, iv := range perm(treeSize) { 443 if x := tree.Insert(iv, false); x != nil { 444 t.Fatalf("insert didn't find interval %v", x) 445 } 446 } 447 448 var all items 449 tree.DoMatching(func(e Interface) bool { 450 all = append(all, e) 451 return false 452 }, Range{toBytes(0), toBytes(treeSize)}) 453 if expected := rang(0, treeSize-1); !reflect.DeepEqual(all, expected) { 454 t.Fatalf("expected intervals %v, got %v", expected, all) 455 } 456 457 var slice items 458 min := uint32(10) 459 max := uint32(20) 460 tree.DoMatching(func(e Interface) bool { 461 slice = append(slice, e) 462 return false 463 }, Range{toBytes(min + 1), toBytes(max)}) 464 if expected := rang(min, max); !reflect.DeepEqual(slice, expected) { 465 t.Fatalf("expected intervals %v, got %v", expected, slice) 466 } 467 468 var halfSlice items 469 half := uint32(15) 470 tree.DoMatching(func(e Interface) bool { 471 if e.Range().Start.Compare(toBytes(half)) > 0 { 472 return true 473 } 474 halfSlice = append(halfSlice, e) 475 return false 476 }, Range{toBytes(min + 1), toBytes(max)}) 477 if expected := rang(min, half); !reflect.DeepEqual(halfSlice, expected) { 478 t.Fatalf("expected intervals %v, got %v", expected, halfSlice) 479 } 480 481 for _, item := range perm(treeSize) { 482 if err := tree.Delete(item, false); err != nil { 483 t.Fatalf("delete error: %s", err) 484 } 485 } 486 487 if len := tree.Len(); len > 0 { 488 t.Fatalf("expected 0 item, got %d items", len) 489 } 490 } 491 } 492 493 // TestDeleteAfterRootNodeMerge verifies that delete from a leaf node works 494 // correctly after a merge which involves the root node. During the delete of a 495 // Interface from a leaf node, if the root node has only one Interface and takes 496 // part of a merge, the root does have any Interface after the merge. The 497 // subsequent adjustment of node range should take this into account. 498 func TestDeleteAfterRootNodeMerge(t *testing.T) { 499 tree := newBTreeWithDegree(InclusiveOverlapper, 2) 500 ivs := items{ 501 &Interval{Range{Comparable{1}, Comparable{8}}, 0}, 502 &Interval{Range{Comparable{2}, Comparable{3}}, 1}, 503 &Interval{Range{Comparable{3}, Comparable{4}}, 2}, 504 &Interval{Range{Comparable{4}, Comparable{5}}, 3}, 505 } 506 507 // 508 // +------+ 509 // | id-1 | 510 // +------+ 511 // / \ 512 // v v 513 // +------+ +-----------+ 514 // | id-0 | | id-2 id-3 | 515 // +------+ +-----------+ 516 // 517 for i := 0; i < len(ivs); i++ { 518 if err := tree.Insert(ivs[i], false); err != nil { 519 t.Fatalf("insert error: %s", err) 520 } 521 } 522 523 // 524 // +------+ 525 // | id-1 | 526 // +------+ 527 // / \ 528 // v v 529 // +------+ +------+ 530 // | id-0 | | id-3 | 531 // +------+ +------+ 532 // 533 if err := tree.Delete(ivs[2], false); err != nil { 534 t.Fatalf("delete error: %s", err) 535 } 536 537 // Delete id-0 538 if err := tree.Delete(ivs[0], false); err != nil { 539 t.Fatalf("delete error: %s", err) 540 } 541 } 542 543 func TestSmallTree(t *testing.T) { 544 tree := newBTreeWithDegree(InclusiveOverlapper, 2) 545 ivs := makeIntervals() 546 547 // Insert 548 for i, iv := range ivs { 549 if err := tree.Insert(iv, false); err != nil { 550 t.Fatalf("insert error: %s", err) 551 } 552 checkWithLen(t, tree, i+1) 553 } 554 555 checkTraversal(t, tree, ivs) 556 checkIterator(t, tree, ivs) 557 558 // Delete 559 l := tree.Len() 560 for i, iv := range ivs { 561 if err := tree.Delete(iv, false); err != nil { 562 t.Fatalf("delete error: %s", err) 563 } 564 checkWithLen(t, tree, l-i-1) 565 } 566 } 567 568 func TestSmallTreeWithFastOperations(t *testing.T) { 569 tree := newBTreeWithDegree(InclusiveOverlapper, 2) 570 ivs := makeIntervals() 571 572 // Fast insert 573 for _, iv := range ivs { 574 if err := tree.Insert(iv, true); err != nil { 575 t.Fatalf("insert error: %s", err) 576 } 577 } 578 tree.AdjustRanges() 579 checkWithLen(t, tree, len(ivs)) 580 581 checkTraversal(t, tree, ivs) 582 checkIterator(t, tree, ivs) 583 checkFastDelete(t, tree, ivs, tree.Len()) 584 } 585 586 func TestLargeTree(t *testing.T) { 587 var ivs items 588 589 const treeSize = 40000 590 for i := uint32(0); i < treeSize; i++ { 591 iv := makeMultiByteInterval(i, i+1, i) 592 ivs = append(ivs, iv) 593 } 594 595 tree := newBTreeWithDegree(ExclusiveOverlapper, *btreeMinDegree) 596 for _, iv := range ivs { 597 if err := tree.Insert(iv, true); err != nil { 598 t.Fatalf("fast insert error: %s", err) 599 } 600 } 601 tree.AdjustRanges() 602 checkWithLen(t, tree, treeSize) 603 checkFastDelete(t, tree, ivs, 10) 604 } 605 606 const cloneTestSize = 10000 607 608 func cloneTest( 609 t *testing.T, b *btree, start int, p items, g *errgroup.Group, treeC chan *btree, 610 ) error { 611 t.Logf("Starting new clone at %v", start) 612 treeC <- b 613 for i := start; i < cloneTestSize; i++ { 614 if err := b.Insert(p[i], false); err != nil { 615 return err 616 } 617 if i%(cloneTestSize/5) == 0 { 618 i := i 619 c := b.cloneInternal() 620 g.Go(func() error { 621 return cloneTest(t, c, i+1, p, g, treeC) 622 }) 623 } 624 } 625 return nil 626 } 627 628 func TestCloneConcurrentOperations(t *testing.T) { 629 var trees []*btree 630 treeC, treeDone := make(chan *btree), make(chan struct{}) 631 go func() { 632 for b := range treeC { 633 trees = append(trees, b) 634 } 635 close(treeDone) 636 }() 637 638 var g errgroup.Group 639 b := newBTree(InclusiveOverlapper) 640 p := perm(cloneTestSize) 641 g.Go(func() error { 642 return cloneTest(t, b, 0, p, &g, treeC) 643 }) 644 if err := g.Wait(); err != nil { 645 t.Fatal(err) 646 } 647 close(treeC) 648 <-treeDone 649 650 want := rang(0, cloneTestSize-1) 651 t.Logf("Starting equality checks on %d trees", len(trees)) 652 for i, tree := range trees { 653 if !reflect.DeepEqual(want, all(tree)) { 654 t.Errorf("tree %v mismatch", i) 655 } 656 } 657 658 t.Log("Removing half from first half") 659 toRemove := want[cloneTestSize/2:] 660 for i := 0; i < len(trees)/2; i++ { 661 tree := trees[i] 662 g.Go(func() error { 663 for _, item := range toRemove { 664 if err := tree.Delete(item, false); err != nil { 665 return err 666 } 667 } 668 return nil 669 }) 670 } 671 if err := g.Wait(); err != nil { 672 t.Fatal(err) 673 } 674 675 t.Log("Checking all values again") 676 for i, tree := range trees { 677 var wantpart items 678 if i < len(trees)/2 { 679 wantpart = want[:cloneTestSize/2] 680 } else { 681 wantpart = want 682 } 683 if got := all(tree); !reflect.DeepEqual(wantpart, got) { 684 t.Errorf("tree %v mismatch, want %v got %v", i, len(want), len(got)) 685 } 686 } 687 } 688 689 func TestIterator(t *testing.T) { 690 var ivs items 691 const treeSize = 400 692 for i := uint32(0); i < treeSize; i++ { 693 iv := makeMultiByteInterval(i, i+1, i) 694 ivs = append(ivs, iv) 695 } 696 tree := newBTreeWithDegree(InclusiveOverlapper, 4) 697 for _, iv := range ivs { 698 if err := tree.Insert(iv, true); err != nil { 699 t.Fatalf("fast insert error: %s", err) 700 } 701 } 702 tree.AdjustRanges() 703 checkIterator(t, tree, ivs) 704 } 705 706 func forBenchmarkSizes(b *testing.B, f func(b *testing.B, count int)) { 707 for _, count := range []int{16, 128, 1024, 8192, 65536} { 708 b.Run(fmt.Sprintf("count=%d", count), func(b *testing.B) { 709 f(b, count) 710 }) 711 } 712 } 713 714 func BenchmarkBTreeInsert(b *testing.B) { 715 forBenchmarkSizes(b, func(b *testing.B, count int) { 716 insertP := perm(uint32(count)) 717 b.ResetTimer() 718 i := 0 719 for i < b.N { 720 tr := newBTree(InclusiveOverlapper) 721 for _, item := range insertP { 722 if err := tr.Insert(item, false); err != nil { 723 b.Fatal(err) 724 } 725 i++ 726 if i >= b.N { 727 return 728 } 729 } 730 } 731 }) 732 } 733 734 func BenchmarkBTreeDelete(b *testing.B) { 735 forBenchmarkSizes(b, func(b *testing.B, count int) { 736 insertP, removeP := perm(uint32(count)), perm(uint32(count)) 737 b.ResetTimer() 738 i := 0 739 for i < b.N { 740 b.StopTimer() 741 tr := newBTree(InclusiveOverlapper) 742 for _, item := range insertP { 743 if err := tr.Insert(item, false); err != nil { 744 b.Fatal(err) 745 } 746 } 747 b.StartTimer() 748 for _, item := range removeP { 749 if err := tr.Delete(item, false); err != nil { 750 b.Fatal(err) 751 } 752 i++ 753 if i >= b.N { 754 return 755 } 756 } 757 if tr.Len() > 0 { 758 panic(tr.Len()) 759 } 760 } 761 }) 762 } 763 764 func BenchmarkBTreeDeleteInsert(b *testing.B) { 765 forBenchmarkSizes(b, func(b *testing.B, count int) { 766 insertP := perm(uint32(count)) 767 tr := newBTree(InclusiveOverlapper) 768 for _, item := range insertP { 769 if err := tr.Insert(item, false); err != nil { 770 b.Fatal(err) 771 } 772 } 773 b.ResetTimer() 774 for i := 0; i < b.N; i++ { 775 if err := tr.Delete(insertP[i%count], false); err != nil { 776 b.Fatal(err) 777 } 778 if err := tr.Insert(insertP[i%count], false); err != nil { 779 b.Fatal(err) 780 } 781 } 782 }) 783 } 784 785 func BenchmarkBTreeDeleteInsertCloneOnce(b *testing.B) { 786 forBenchmarkSizes(b, func(b *testing.B, count int) { 787 insertP := perm(uint32(count)) 788 tr := newBTree(InclusiveOverlapper) 789 for _, item := range insertP { 790 if err := tr.Insert(item, false); err != nil { 791 b.Fatal(err) 792 } 793 } 794 tr = tr.cloneInternal() 795 b.ResetTimer() 796 for i := 0; i < b.N; i++ { 797 if err := tr.Delete(insertP[i%count], false); err != nil { 798 b.Fatal(err) 799 } 800 if err := tr.Insert(insertP[i%count], false); err != nil { 801 b.Fatal(err) 802 } 803 } 804 }) 805 } 806 807 func BenchmarkBTreeDeleteInsertCloneEachTime(b *testing.B) { 808 forBenchmarkSizes(b, func(b *testing.B, count int) { 809 insertP := perm(uint32(count)) 810 tr := newBTree(InclusiveOverlapper) 811 for _, item := range insertP { 812 if err := tr.Insert(item, false); err != nil { 813 b.Fatal(err) 814 } 815 } 816 b.ResetTimer() 817 for i := 0; i < b.N; i++ { 818 tr = tr.cloneInternal() 819 if err := tr.Delete(insertP[i%count], false); err != nil { 820 b.Fatal(err) 821 } 822 if err := tr.Insert(insertP[i%count], false); err != nil { 823 b.Fatal(err) 824 } 825 } 826 }) 827 } 828 829 func BenchmarkBTreeGet(b *testing.B) { 830 forBenchmarkSizes(b, func(b *testing.B, count int) { 831 insertP := perm(uint32(count)) 832 removeP := perm(uint32(count)) 833 b.ResetTimer() 834 i := 0 835 for i < b.N { 836 b.StopTimer() 837 tr := newBTree(InclusiveOverlapper) 838 for _, item := range insertP { 839 if err := tr.Insert(item, false); err != nil { 840 b.Fatal(err) 841 } 842 } 843 b.StartTimer() 844 for _, item := range removeP { 845 tr.Get(item.Range()) 846 i++ 847 if i >= b.N { 848 return 849 } 850 } 851 } 852 }) 853 } 854 855 func BenchmarkBTreeGetCloneEachTime(b *testing.B) { 856 forBenchmarkSizes(b, func(b *testing.B, count int) { 857 insertP := perm(uint32(count)) 858 removeP := perm(uint32(count)) 859 b.ResetTimer() 860 i := 0 861 for i < b.N { 862 b.StopTimer() 863 tr := newBTree(InclusiveOverlapper) 864 for _, v := range insertP { 865 if err := tr.Insert(v, false); err != nil { 866 b.Fatal(err) 867 } 868 } 869 b.StartTimer() 870 for _, item := range removeP { 871 tr = tr.cloneInternal() 872 tr.Get(item.Range()) 873 i++ 874 if i >= b.N { 875 return 876 } 877 } 878 } 879 }) 880 } 881 882 func key(i int) Comparable { 883 return []byte(fmt.Sprintf("%04d", i)) 884 } 885 886 func rangeWithEnd(start, end int) Range { 887 return Range{Start: key(start), End: key(end)} 888 } 889 890 func randomRange(rng *rand.Rand, n int) Range { 891 start := rng.Intn(n) 892 end := rng.Intn(n + 1) 893 if end < start { 894 start, end = end, start 895 } 896 return rangeWithEnd(start, end) 897 } 898 899 func BenchmarkBTreeOverlapScan(b *testing.B) { 900 tr := newBTree(InclusiveOverlapper) 901 rng := rand.New(rand.NewSource(timeutil.Now().UnixNano())) 902 903 const count = 8 << 10 904 const size = 2 * 31 905 for i := 0; i < count; i++ { 906 iv := &Interval{rangeWithEnd(i, i+size+1), uintptr(i)} 907 if err := tr.Insert(iv, false); err != nil { 908 b.Fatal(err) 909 } 910 } 911 912 b.ResetTimer() 913 for i := 0; i < b.N; i++ { 914 cmd := randomRange(rng, count) 915 tr.DoMatching(func(e Interface) bool { 916 return false 917 }, cmd) 918 } 919 }