1 // Copyright 2014 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package btree 16 17 import ( 18 "flag" 19 "fmt" 20 "math/rand" 21 "reflect" 22 "sort" 23 "sync" 24 "testing" 25 "time" 26 ) 27 28 func init() { 29 seed := time.Now().Unix() 30 fmt.Println(seed) 31 rand.Seed(seed) 32 } 33 34 // perm returns a random permutation of n Int items in the range [0, n). 35 func perm(n int) (out []Item) { 36 for _, v := range rand.Perm(n) { 37 out = append(out, Int(v)) 38 } 39 return 40 } 41 42 // rang returns an ordered list of Int items in the range [0, n). 43 func rang(n int) (out []Item) { 44 for i := 0; i < n; i++ { 45 out = append(out, Int(i)) 46 } 47 return 48 } 49 50 // all extracts all items from a tree in order as a slice. 51 func all(t *BTree) (out []Item) { 52 t.Ascend(func(a Item) bool { 53 out = append(out, a) 54 return true 55 }) 56 return 57 } 58 59 // rangerev returns a reversed ordered list of Int items in the range [0, n). 60 func rangrev(n int) (out []Item) { 61 for i := n - 1; i >= 0; i-- { 62 out = append(out, Int(i)) 63 } 64 return 65 } 66 67 // allrev extracts all items from a tree in reverse order as a slice. 68 func allrev(t *BTree) (out []Item) { 69 t.Descend(func(a Item) bool { 70 out = append(out, a) 71 return true 72 }) 73 return 74 } 75 76 var btreeDegree = flag.Int("degree", 32, "B-Tree degree") 77 78 func TestBTree(t *testing.T) { 79 tr := New(*btreeDegree) 80 const treeSize = 10000 81 for i := 0; i < 10; i++ { 82 if min := tr.Min(); min != nil { 83 t.Fatalf("empty min, got %+v", min) 84 } 85 if max := tr.Max(); max != nil { 86 t.Fatalf("empty max, got %+v", max) 87 } 88 for _, item := range perm(treeSize) { 89 if x := tr.ReplaceOrInsert(item); x != nil { 90 t.Fatal("insert found item", item) 91 } 92 } 93 for _, item := range perm(treeSize) { 94 if x := tr.ReplaceOrInsert(item); x == nil { 95 t.Fatal("insert didn't find item", item) 96 } 97 } 98 if min, want := tr.Min(), Item(Int(0)); min != want { 99 t.Fatalf("min: want %+v, got %+v", want, min) 100 } 101 if max, want := tr.Max(), Item(Int(treeSize-1)); max != want { 102 t.Fatalf("max: want %+v, got %+v", want, max) 103 } 104 got := all(tr) 105 want := rang(treeSize) 106 if !reflect.DeepEqual(got, want) { 107 t.Fatalf("mismatch:\n got: %v\nwant: %v", got, want) 108 } 109 110 gotrev := allrev(tr) 111 wantrev := rangrev(treeSize) 112 if !reflect.DeepEqual(gotrev, wantrev) { 113 t.Fatalf("mismatch:\n got: %v\nwant: %v", got, want) 114 } 115 116 for _, item := range perm(treeSize) { 117 if x := tr.Delete(item); x == nil { 118 t.Fatalf("didn't find %v", item) 119 } 120 } 121 if got = all(tr); len(got) > 0 { 122 t.Fatalf("some left!: %v", got) 123 } 124 } 125 } 126 127 func ExampleBTree() { 128 tr := New(*btreeDegree) 129 for i := Int(0); i < 10; i++ { 130 tr.ReplaceOrInsert(i) 131 } 132 fmt.Println("len: ", tr.Len()) 133 fmt.Println("get3: ", tr.Get(Int(3))) 134 fmt.Println("get100: ", tr.Get(Int(100))) 135 fmt.Println("del4: ", tr.Delete(Int(4))) 136 fmt.Println("del100: ", tr.Delete(Int(100))) 137 fmt.Println("replace5: ", tr.ReplaceOrInsert(Int(5))) 138 fmt.Println("replace100:", tr.ReplaceOrInsert(Int(100))) 139 fmt.Println("min: ", tr.Min()) 140 fmt.Println("delmin: ", tr.DeleteMin()) 141 fmt.Println("max: ", tr.Max()) 142 fmt.Println("delmax: ", tr.DeleteMax()) 143 fmt.Println("len: ", tr.Len()) 144 // Output: 145 // len: 10 146 // get3: 3 147 // get100: <nil> 148 // del4: 4 149 // del100: <nil> 150 // replace5: 5 151 // replace100: <nil> 152 // min: 0 153 // delmin: 0 154 // max: 100 155 // delmax: 100 156 // len: 8 157 } 158 159 func TestDeleteMin(t *testing.T) { 160 tr := New(3) 161 for _, v := range perm(100) { 162 tr.ReplaceOrInsert(v) 163 } 164 var got []Item 165 for v := tr.DeleteMin(); v != nil; v = tr.DeleteMin() { 166 got = append(got, v) 167 } 168 if want := rang(100); !reflect.DeepEqual(got, want) { 169 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) 170 } 171 } 172 173 func TestDeleteMax(t *testing.T) { 174 tr := New(3) 175 for _, v := range perm(100) { 176 tr.ReplaceOrInsert(v) 177 } 178 var got []Item 179 for v := tr.DeleteMax(); v != nil; v = tr.DeleteMax() { 180 got = append(got, v) 181 } 182 // Reverse our list. 183 for i := 0; i < len(got)/2; i++ { 184 got[i], got[len(got)-i-1] = got[len(got)-i-1], got[i] 185 } 186 if want := rang(100); !reflect.DeepEqual(got, want) { 187 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) 188 } 189 } 190 191 func TestAscendRange(t *testing.T) { 192 tr := New(2) 193 for _, v := range perm(100) { 194 tr.ReplaceOrInsert(v) 195 } 196 var got []Item 197 tr.AscendRange(Int(40), Int(60), func(a Item) bool { 198 got = append(got, a) 199 return true 200 }) 201 if want := rang(100)[40:60]; !reflect.DeepEqual(got, want) { 202 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) 203 } 204 got = got[:0] 205 tr.AscendRange(Int(40), Int(60), func(a Item) bool { 206 if a.(Int) > 50 { 207 return false 208 } 209 got = append(got, a) 210 return true 211 }) 212 if want := rang(100)[40:51]; !reflect.DeepEqual(got, want) { 213 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) 214 } 215 } 216 217 func TestDescendRange(t *testing.T) { 218 tr := New(2) 219 for _, v := range perm(100) { 220 tr.ReplaceOrInsert(v) 221 } 222 var got []Item 223 tr.DescendRange(Int(60), Int(40), func(a Item) bool { 224 got = append(got, a) 225 return true 226 }) 227 if want := rangrev(100)[39:59]; !reflect.DeepEqual(got, want) { 228 t.Fatalf("descendrange:\n got: %v\nwant: %v", got, want) 229 } 230 got = got[:0] 231 tr.DescendRange(Int(60), Int(40), func(a Item) bool { 232 if a.(Int) < 50 { 233 return false 234 } 235 got = append(got, a) 236 return true 237 }) 238 if want := rangrev(100)[39:50]; !reflect.DeepEqual(got, want) { 239 t.Fatalf("descendrange:\n got: %v\nwant: %v", got, want) 240 } 241 } 242 func TestAscendLessThan(t *testing.T) { 243 tr := New(*btreeDegree) 244 for _, v := range perm(100) { 245 tr.ReplaceOrInsert(v) 246 } 247 var got []Item 248 tr.AscendLessThan(Int(60), func(a Item) bool { 249 got = append(got, a) 250 return true 251 }) 252 if want := rang(100)[:60]; !reflect.DeepEqual(got, want) { 253 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) 254 } 255 got = got[:0] 256 tr.AscendLessThan(Int(60), func(a Item) bool { 257 if a.(Int) > 50 { 258 return false 259 } 260 got = append(got, a) 261 return true 262 }) 263 if want := rang(100)[:51]; !reflect.DeepEqual(got, want) { 264 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) 265 } 266 } 267 268 func TestDescendLessOrEqual(t *testing.T) { 269 tr := New(*btreeDegree) 270 for _, v := range perm(100) { 271 tr.ReplaceOrInsert(v) 272 } 273 var got []Item 274 tr.DescendLessOrEqual(Int(40), func(a Item) bool { 275 got = append(got, a) 276 return true 277 }) 278 if want := rangrev(100)[59:]; !reflect.DeepEqual(got, want) { 279 t.Fatalf("descendlessorequal:\n got: %v\nwant: %v", got, want) 280 } 281 got = got[:0] 282 tr.DescendLessOrEqual(Int(60), func(a Item) bool { 283 if a.(Int) < 50 { 284 return false 285 } 286 got = append(got, a) 287 return true 288 }) 289 if want := rangrev(100)[39:50]; !reflect.DeepEqual(got, want) { 290 t.Fatalf("descendlessorequal:\n got: %v\nwant: %v", got, want) 291 } 292 } 293 func TestAscendGreaterOrEqual(t *testing.T) { 294 tr := New(*btreeDegree) 295 for _, v := range perm(100) { 296 tr.ReplaceOrInsert(v) 297 } 298 var got []Item 299 tr.AscendGreaterOrEqual(Int(40), func(a Item) bool { 300 got = append(got, a) 301 return true 302 }) 303 if want := rang(100)[40:]; !reflect.DeepEqual(got, want) { 304 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) 305 } 306 got = got[:0] 307 tr.AscendGreaterOrEqual(Int(40), func(a Item) bool { 308 if a.(Int) > 50 { 309 return false 310 } 311 got = append(got, a) 312 return true 313 }) 314 if want := rang(100)[40:51]; !reflect.DeepEqual(got, want) { 315 t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) 316 } 317 } 318 319 func TestDescendGreaterThan(t *testing.T) { 320 tr := New(*btreeDegree) 321 for _, v := range perm(100) { 322 tr.ReplaceOrInsert(v) 323 } 324 var got []Item 325 tr.DescendGreaterThan(Int(40), func(a Item) bool { 326 got = append(got, a) 327 return true 328 }) 329 if want := rangrev(100)[:59]; !reflect.DeepEqual(got, want) { 330 t.Fatalf("descendgreaterthan:\n got: %v\nwant: %v", got, want) 331 } 332 got = got[:0] 333 tr.DescendGreaterThan(Int(40), func(a Item) bool { 334 if a.(Int) < 50 { 335 return false 336 } 337 got = append(got, a) 338 return true 339 }) 340 if want := rangrev(100)[:50]; !reflect.DeepEqual(got, want) { 341 t.Fatalf("descendgreaterthan:\n got: %v\nwant: %v", got, want) 342 } 343 } 344 345 const benchmarkTreeSize = 10000 346 347 func BenchmarkInsert(b *testing.B) { 348 b.StopTimer() 349 insertP := perm(benchmarkTreeSize) 350 b.StartTimer() 351 i := 0 352 for i < b.N { 353 tr := New(*btreeDegree) 354 for _, item := range insertP { 355 tr.ReplaceOrInsert(item) 356 i++ 357 if i >= b.N { 358 return 359 } 360 } 361 } 362 } 363 364 func BenchmarkSeek(b *testing.B) { 365 b.StopTimer() 366 size := 100000 367 insertP := perm(size) 368 tr := New(*btreeDegree) 369 for _, item := range insertP { 370 tr.ReplaceOrInsert(item) 371 } 372 b.StartTimer() 373 374 for i := 0; i < b.N; i++ { 375 tr.AscendGreaterOrEqual(Int(i%size), func(i Item) bool { return false }) 376 } 377 } 378 379 func BenchmarkDeleteInsert(b *testing.B) { 380 b.StopTimer() 381 insertP := perm(benchmarkTreeSize) 382 tr := New(*btreeDegree) 383 for _, item := range insertP { 384 tr.ReplaceOrInsert(item) 385 } 386 b.StartTimer() 387 for i := 0; i < b.N; i++ { 388 tr.Delete(insertP[i%benchmarkTreeSize]) 389 tr.ReplaceOrInsert(insertP[i%benchmarkTreeSize]) 390 } 391 } 392 393 func BenchmarkDeleteInsertCloneOnce(b *testing.B) { 394 b.StopTimer() 395 insertP := perm(benchmarkTreeSize) 396 tr := New(*btreeDegree) 397 for _, item := range insertP { 398 tr.ReplaceOrInsert(item) 399 } 400 tr = tr.Clone() 401 b.StartTimer() 402 for i := 0; i < b.N; i++ { 403 tr.Delete(insertP[i%benchmarkTreeSize]) 404 tr.ReplaceOrInsert(insertP[i%benchmarkTreeSize]) 405 } 406 } 407 408 func BenchmarkDeleteInsertCloneEachTime(b *testing.B) { 409 b.StopTimer() 410 insertP := perm(benchmarkTreeSize) 411 tr := New(*btreeDegree) 412 for _, item := range insertP { 413 tr.ReplaceOrInsert(item) 414 } 415 b.StartTimer() 416 for i := 0; i < b.N; i++ { 417 tr = tr.Clone() 418 tr.Delete(insertP[i%benchmarkTreeSize]) 419 tr.ReplaceOrInsert(insertP[i%benchmarkTreeSize]) 420 } 421 } 422 423 func BenchmarkDelete(b *testing.B) { 424 b.StopTimer() 425 insertP := perm(benchmarkTreeSize) 426 removeP := perm(benchmarkTreeSize) 427 b.StartTimer() 428 i := 0 429 for i < b.N { 430 b.StopTimer() 431 tr := New(*btreeDegree) 432 for _, v := range insertP { 433 tr.ReplaceOrInsert(v) 434 } 435 b.StartTimer() 436 for _, item := range removeP { 437 tr.Delete(item) 438 i++ 439 if i >= b.N { 440 return 441 } 442 } 443 if tr.Len() > 0 { 444 panic(tr.Len()) 445 } 446 } 447 } 448 449 func BenchmarkGet(b *testing.B) { 450 b.StopTimer() 451 insertP := perm(benchmarkTreeSize) 452 removeP := perm(benchmarkTreeSize) 453 b.StartTimer() 454 i := 0 455 for i < b.N { 456 b.StopTimer() 457 tr := New(*btreeDegree) 458 for _, v := range insertP { 459 tr.ReplaceOrInsert(v) 460 } 461 b.StartTimer() 462 for _, item := range removeP { 463 tr.Get(item) 464 i++ 465 if i >= b.N { 466 return 467 } 468 } 469 } 470 } 471 472 func BenchmarkGetCloneEachTime(b *testing.B) { 473 b.StopTimer() 474 insertP := perm(benchmarkTreeSize) 475 removeP := perm(benchmarkTreeSize) 476 b.StartTimer() 477 i := 0 478 for i < b.N { 479 b.StopTimer() 480 tr := New(*btreeDegree) 481 for _, v := range insertP { 482 tr.ReplaceOrInsert(v) 483 } 484 b.StartTimer() 485 for _, item := range removeP { 486 tr = tr.Clone() 487 tr.Get(item) 488 i++ 489 if i >= b.N { 490 return 491 } 492 } 493 } 494 } 495 496 type byInts []Item 497 498 func (a byInts) Len() int { 499 return len(a) 500 } 501 502 func (a byInts) Less(i, j int) bool { 503 return a[i].(Int) < a[j].(Int) 504 } 505 506 func (a byInts) Swap(i, j int) { 507 a[i], a[j] = a[j], a[i] 508 } 509 510 func BenchmarkAscend(b *testing.B) { 511 arr := perm(benchmarkTreeSize) 512 tr := New(*btreeDegree) 513 for _, v := range arr { 514 tr.ReplaceOrInsert(v) 515 } 516 sort.Sort(byInts(arr)) 517 b.ResetTimer() 518 for i := 0; i < b.N; i++ { 519 j := 0 520 tr.Ascend(func(item Item) bool { 521 if item.(Int) != arr[j].(Int) { 522 b.Fatalf("mismatch: expected: %v, got %v", arr[j].(Int), item.(Int)) 523 } 524 j++ 525 return true 526 }) 527 } 528 } 529 530 func BenchmarkDescend(b *testing.B) { 531 arr := perm(benchmarkTreeSize) 532 tr := New(*btreeDegree) 533 for _, v := range arr { 534 tr.ReplaceOrInsert(v) 535 } 536 sort.Sort(byInts(arr)) 537 b.ResetTimer() 538 for i := 0; i < b.N; i++ { 539 j := len(arr) - 1 540 tr.Descend(func(item Item) bool { 541 if item.(Int) != arr[j].(Int) { 542 b.Fatalf("mismatch: expected: %v, got %v", arr[j].(Int), item.(Int)) 543 } 544 j-- 545 return true 546 }) 547 } 548 } 549 func BenchmarkAscendRange(b *testing.B) { 550 arr := perm(benchmarkTreeSize) 551 tr := New(*btreeDegree) 552 for _, v := range arr { 553 tr.ReplaceOrInsert(v) 554 } 555 sort.Sort(byInts(arr)) 556 b.ResetTimer() 557 for i := 0; i < b.N; i++ { 558 j := 100 559 tr.AscendRange(Int(100), arr[len(arr)-100], func(item Item) bool { 560 if item.(Int) != arr[j].(Int) { 561 b.Fatalf("mismatch: expected: %v, got %v", arr[j].(Int), item.(Int)) 562 } 563 j++ 564 return true 565 }) 566 if j != len(arr)-100 { 567 b.Fatalf("expected: %v, got %v", len(arr)-100, j) 568 } 569 } 570 } 571 572 func BenchmarkDescendRange(b *testing.B) { 573 arr := perm(benchmarkTreeSize) 574 tr := New(*btreeDegree) 575 for _, v := range arr { 576 tr.ReplaceOrInsert(v) 577 } 578 sort.Sort(byInts(arr)) 579 b.ResetTimer() 580 for i := 0; i < b.N; i++ { 581 j := len(arr) - 100 582 tr.DescendRange(arr[len(arr)-100], Int(100), func(item Item) bool { 583 if item.(Int) != arr[j].(Int) { 584 b.Fatalf("mismatch: expected: %v, got %v", arr[j].(Int), item.(Int)) 585 } 586 j-- 587 return true 588 }) 589 if j != 100 { 590 b.Fatalf("expected: %v, got %v", len(arr)-100, j) 591 } 592 } 593 } 594 func BenchmarkAscendGreaterOrEqual(b *testing.B) { 595 arr := perm(benchmarkTreeSize) 596 tr := New(*btreeDegree) 597 for _, v := range arr { 598 tr.ReplaceOrInsert(v) 599 } 600 sort.Sort(byInts(arr)) 601 b.ResetTimer() 602 for i := 0; i < b.N; i++ { 603 j := 100 604 k := 0 605 tr.AscendGreaterOrEqual(Int(100), func(item Item) bool { 606 if item.(Int) != arr[j].(Int) { 607 b.Fatalf("mismatch: expected: %v, got %v", arr[j].(Int), item.(Int)) 608 } 609 j++ 610 k++ 611 return true 612 }) 613 if j != len(arr) { 614 b.Fatalf("expected: %v, got %v", len(arr), j) 615 } 616 if k != len(arr)-100 { 617 b.Fatalf("expected: %v, got %v", len(arr)-100, k) 618 } 619 } 620 } 621 func BenchmarkDescendLessOrEqual(b *testing.B) { 622 arr := perm(benchmarkTreeSize) 623 tr := New(*btreeDegree) 624 for _, v := range arr { 625 tr.ReplaceOrInsert(v) 626 } 627 sort.Sort(byInts(arr)) 628 b.ResetTimer() 629 for i := 0; i < b.N; i++ { 630 j := len(arr) - 100 631 k := len(arr) 632 tr.DescendLessOrEqual(arr[len(arr)-100], func(item Item) bool { 633 if item.(Int) != arr[j].(Int) { 634 b.Fatalf("mismatch: expected: %v, got %v", arr[j].(Int), item.(Int)) 635 } 636 j-- 637 k-- 638 return true 639 }) 640 if j != -1 { 641 b.Fatalf("expected: %v, got %v", -1, j) 642 } 643 if k != 99 { 644 b.Fatalf("expected: %v, got %v", 99, k) 645 } 646 } 647 } 648 649 const cloneTestSize = 10000 650 651 func cloneTest(t *testing.T, b *BTree, start int, p []Item, wg *sync.WaitGroup, trees *[]*BTree) { 652 t.Logf("Starting new clone at %v", start) 653 *trees = append(*trees, b) 654 for i := start; i < cloneTestSize; i++ { 655 b.ReplaceOrInsert(p[i]) 656 if i%(cloneTestSize/5) == 0 { 657 wg.Add(1) 658 go cloneTest(t, b.Clone(), i+1, p, wg, trees) 659 } 660 } 661 wg.Done() 662 } 663 664 func TestCloneConcurrentOperations(t *testing.T) { 665 b := New(*btreeDegree) 666 trees := []*BTree{} 667 p := perm(cloneTestSize) 668 var wg sync.WaitGroup 669 wg.Add(1) 670 go cloneTest(t, b, 0, p, &wg, &trees) 671 wg.Wait() 672 want := rang(cloneTestSize) 673 t.Logf("Starting equality checks on %d trees", len(trees)) 674 for i, tree := range trees { 675 if !reflect.DeepEqual(want, all(tree)) { 676 t.Errorf("tree %v mismatch", i) 677 } 678 } 679 t.Log("Removing half from first half") 680 toRemove := rang(cloneTestSize)[cloneTestSize/2:] 681 for i := 0; i < len(trees)/2; i++ { 682 tree := trees[i] 683 wg.Add(1) 684 go func() { 685 for _, item := range toRemove { 686 tree.Delete(item) 687 } 688 wg.Done() 689 }() 690 } 691 wg.Wait() 692 t.Log("Checking all values again") 693 for i, tree := range trees { 694 var wantpart []Item 695 if i < len(trees)/2 { 696 wantpart = want[:cloneTestSize/2] 697 } else { 698 wantpart = want 699 } 700 if got := all(tree); !reflect.DeepEqual(wantpart, got) { 701 t.Errorf("tree %v mismatch, want %v got %v", i, len(want), len(got)) 702 } 703 } 704 } 705 706 func BenchmarkDeleteAndRestore(b *testing.B) { 707 items := perm(16392) 708 b.ResetTimer() 709 b.Run(`CopyBigFreeList`, func(b *testing.B) { 710 fl := NewFreeList(16392) 711 tr := NewWithFreeList(*btreeDegree, fl) 712 for _, v := range items { 713 tr.ReplaceOrInsert(v) 714 } 715 b.ReportAllocs() 716 b.ResetTimer() 717 for i := 0; i < b.N; i++ { 718 dels := make([]Item, 0, tr.Len()) 719 tr.Ascend(ItemIterator(func(b Item) bool { 720 dels = append(dels, b) 721 return true 722 })) 723 for _, del := range dels { 724 tr.Delete(del) 725 } 726 // tr is now empty, we make a new empty copy of it. 727 tr = NewWithFreeList(*btreeDegree, fl) 728 for _, v := range items { 729 tr.ReplaceOrInsert(v) 730 } 731 } 732 }) 733 b.Run(`Copy`, func(b *testing.B) { 734 tr := New(*btreeDegree) 735 for _, v := range items { 736 tr.ReplaceOrInsert(v) 737 } 738 b.ReportAllocs() 739 b.ResetTimer() 740 for i := 0; i < b.N; i++ { 741 dels := make([]Item, 0, tr.Len()) 742 tr.Ascend(ItemIterator(func(b Item) bool { 743 dels = append(dels, b) 744 return true 745 })) 746 for _, del := range dels { 747 tr.Delete(del) 748 } 749 // tr is now empty, we make a new empty copy of it. 750 tr = New(*btreeDegree) 751 for _, v := range items { 752 tr.ReplaceOrInsert(v) 753 } 754 } 755 }) 756 b.Run(`ClearBigFreelist`, func(b *testing.B) { 757 fl := NewFreeList(16392) 758 tr := NewWithFreeList(*btreeDegree, fl) 759 for _, v := range items { 760 tr.ReplaceOrInsert(v) 761 } 762 b.ReportAllocs() 763 b.ResetTimer() 764 for i := 0; i < b.N; i++ { 765 tr.Clear(true) 766 for _, v := range items { 767 tr.ReplaceOrInsert(v) 768 } 769 } 770 }) 771 b.Run(`Clear`, func(b *testing.B) { 772 tr := New(*btreeDegree) 773 for _, v := range items { 774 tr.ReplaceOrInsert(v) 775 } 776 b.ReportAllocs() 777 b.ResetTimer() 778 for i := 0; i < b.N; i++ { 779 tr.Clear(true) 780 for _, v := range items { 781 tr.ReplaceOrInsert(v) 782 } 783 } 784 }) 785 }
1 // Copyright 2014 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build ignore 16 17 // This binary compares memory usage between btree and gollrb. 18 package main 19 20 import ( 21 "flag" 22 "fmt" 23 "math/rand" 24 "runtime" 25 "time" 26 27 "github.com/google/btree" 28 "github.com/petar/GoLLRB/llrb" 29 ) 30 31 var ( 32 size = flag.Int("size", 1000000, "size of the tree to build") 33 degree = flag.Int("degree", 8, "degree of btree") 34 gollrb = flag.Bool("llrb", false, "use llrb instead of btree") 35 ) 36 37 func main() { 38 flag.Parse() 39 vals := rand.Perm(*size) 40 var t, v interface{} 41 v = vals 42 var stats runtime.MemStats 43 for i := 0; i < 10; i++ { 44 runtime.GC() 45 } 46 fmt.Println("-------- BEFORE ----------") 47 runtime.ReadMemStats(&stats) 48 fmt.Printf("%+v\n", stats) 49 start := time.Now() 50 if *gollrb { 51 tr := llrb.New() 52 for _, v := range vals { 53 tr.ReplaceOrInsert(llrb.Int(v)) 54 } 55 t = tr // keep it around 56 } else { 57 tr := btree.New(*degree) 58 for _, v := range vals { 59 tr.ReplaceOrInsert(btree.Int(v)) 60 } 61 t = tr // keep it around 62 } 63 fmt.Printf("%v inserts in %v\n", *size, time.Since(start)) 64 fmt.Println("-------- AFTER ----------") 65 runtime.ReadMemStats(&stats) 66 fmt.Printf("%+v\n", stats) 67 for i := 0; i < 10; i++ { 68 runtime.GC() 69 } 70 fmt.Println("-------- AFTER GC ----------") 71 runtime.ReadMemStats(&stats) 72 fmt.Printf("%+v\n", stats) 73 if t == v { 74 fmt.Println("to make sure vals and tree aren't GC'd") 75 } 76 }
1 // Copyright 2014 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package btree implements in-memory B-Trees of arbitrary degree. 16 // 17 // btree implements an in-memory B-Tree for use as an ordered data structure. 18 // It is not meant for persistent storage solutions. 19 // 20 // It has a flatter structure than an equivalent red-black or other binary tree, 21 // which in some cases yields better memory usage and/or performance. 22 // See some discussion on the matter here: 23 // http://google-opensource.blogspot.com/2013/01/c-containers-that-save-memory-and-time.html 24 // Note, though, that this project is in no way related to the C++ B-Tree 25 // implementation written about there. 26 // 27 // Within this tree, each node contains a slice of items and a (possibly nil) 28 // slice of children. For basic numeric values or raw structs, this can cause 29 // efficiency differences when compared to equivalent C++ template code that 30 // stores values in arrays within the node: 31 // * Due to the overhead of storing values as interfaces (each 32 // value needs to be stored as the value itself, then 2 words for the 33 // interface pointing to that value and its type), resulting in higher 34 // memory use. 35 // * Since interfaces can point to values anywhere in memory, values are 36 // most likely not stored in contiguous blocks, resulting in a higher 37 // number of cache misses. 38 // These issues don't tend to matter, though, when working with strings or other 39 // heap-allocated structures, since C++-equivalent structures also must store 40 // pointers and also distribute their values across the heap. 41 // 42 // This implementation is designed to be a drop-in replacement to gollrb.LLRB 43 // trees, (http://github.com/petar/gollrb), an excellent and probably the most 44 // widely used ordered tree implementation in the Go ecosystem currently. 45 // Its functions, therefore, exactly mirror those of 46 // llrb.LLRB where possible. Unlike gollrb, though, we currently don't 47 // support storing multiple equivalent values. 48 package btree 49 50 import ( 51 "fmt" 52 "io" 53 "sort" 54 "strings" 55 "sync" 56 ) 57 58 // Item represents a single object in the tree. 59 type Item interface { 60 // Less tests whether the current item is less than the given argument. 61 // 62 // This must provide a strict weak ordering. 63 // If !a.Less(b) && !b.Less(a), we treat this to mean a == b (i.e. we can only 64 // hold one of either a or b in the tree). 65 Less(than Item) bool 66 } 67 68 const ( 69 DefaultFreeListSize = 32 70 ) 71 72 var ( 73 nilItems = make(items, 16) 74 nilChildren = make(children, 16) 75 ) 76 77 // FreeList represents a free list of btree nodes. By default each 78 // BTree has its own FreeList, but multiple BTrees can share the same 79 // FreeList. 80 // Two Btrees using the same freelist are safe for concurrent write access. 81 type FreeList struct { 82 mu sync.Mutex 83 freelist []*node 84 } 85 86 // NewFreeList creates a new free list. 87 // size is the maximum size of the returned free list. 88 func NewFreeList(size int) *FreeList { 89 return &FreeList{freelist: make([]*node, 0, size)} 90 } 91 92 func (f *FreeList) newNode() (n *node) { 93 f.mu.Lock() 94 index := len(f.freelist) - 1 95 if index < 0 { 96 f.mu.Unlock() 97 return new(node) 98 } 99 n = f.freelist[index] 100 f.freelist[index] = nil 101 f.freelist = f.freelist[:index] 102 f.mu.Unlock() 103 return 104 } 105 106 // freeNode adds the given node to the list, returning true if it was added 107 // and false if it was discarded. 108 func (f *FreeList) freeNode(n *node) (out bool) { 109 f.mu.Lock() 110 if len(f.freelist) < cap(f.freelist) { 111 f.freelist = append(f.freelist, n) 112 out = true 113 } 114 f.mu.Unlock() 115 return 116 } 117 118 // ItemIterator allows callers of Ascend* to iterate in-order over portions of 119 // the tree. When this function returns false, iteration will stop and the 120 // associated Ascend* function will immediately return. 121 type ItemIterator func(i Item) bool 122 123 // New creates a new B-Tree with the given degree. 124 // 125 // New(2), for example, will create a 2-3-4 tree (each node contains 1-3 items 126 // and 2-4 children). 127 func New(degree int) *BTree { 128 return NewWithFreeList(degree, NewFreeList(DefaultFreeListSize)) 129 } 130 131 // NewWithFreeList creates a new B-Tree that uses the given node free list. 132 func NewWithFreeList(degree int, f *FreeList) *BTree { 133 if degree <= 1 { 134 panic("bad degree") 135 } 136 return &BTree{ 137 degree: degree, 138 cow: ©OnWriteContext{freelist: f}, 139 } 140 } 141 142 // items stores items in a node. 143 type items []Item 144 145 // insertAt inserts a value into the given index, pushing all subsequent values 146 // forward. 147 func (s *items) insertAt(index int, item Item) { 148 *s = append(*s, nil) 149 if index < len(*s) { 150 copy((*s)[index+1:], (*s)[index:]) 151 } 152 (*s)[index] = item 153 } 154 155 // removeAt removes a value at a given index, pulling all subsequent values 156 // back. 157 func (s *items) removeAt(index int) Item { 158 item := (*s)[index] 159 copy((*s)[index:], (*s)[index+1:]) 160 (*s)[len(*s)-1] = nil 161 *s = (*s)[:len(*s)-1] 162 return item 163 } 164 165 // pop removes and returns the last element in the list. 166 func (s *items) pop() (out Item) { 167 index := len(*s) - 1 168 out = (*s)[index] 169 (*s)[index] = nil 170 *s = (*s)[:index] 171 return 172 } 173 174 // truncate truncates this instance at index so that it contains only the 175 // first index items. index must be less than or equal to length. 176 func (s *items) truncate(index int) { 177 var toClear items 178 *s, toClear = (*s)[:index], (*s)[index:] 179 for len(toClear) > 0 { 180 toClear = toClear[copy(toClear, nilItems):] 181 } 182 } 183 184 // find returns the index where the given item should be inserted into this 185 // list. 'found' is true if the item already exists in the list at the given 186 // index. 187 func (s items) find(item Item) (index int, found bool) { 188 i := sort.Search(len(s), func(i int) bool { 189 return item.Less(s[i]) 190 }) 191 if i > 0 && !s[i-1].Less(item) { 192 return i - 1, true 193 } 194 return i, false 195 } 196 197 // children stores child nodes in a node. 198 type children []*node 199 200 // insertAt inserts a value into the given index, pushing all subsequent values 201 // forward. 202 func (s *children) insertAt(index int, n *node) { 203 *s = append(*s, nil) 204 if index < len(*s) { 205 copy((*s)[index+1:], (*s)[index:]) 206 } 207 (*s)[index] = n 208 } 209 210 // removeAt removes a value at a given index, pulling all subsequent values 211 // back. 212 func (s *children) removeAt(index int) *node { 213 n := (*s)[index] 214 copy((*s)[index:], (*s)[index+1:]) 215 (*s)[len(*s)-1] = nil 216 *s = (*s)[:len(*s)-1] 217 return n 218 } 219 220 // pop removes and returns the last element in the list. 221 func (s *children) pop() (out *node) { 222 index := len(*s) - 1 223 out = (*s)[index] 224 (*s)[index] = nil 225 *s = (*s)[:index] 226 return 227 } 228 229 // truncate truncates this instance at index so that it contains only the 230 // first index children. index must be less than or equal to length. 231 func (s *children) truncate(index int) { 232 var toClear children 233 *s, toClear = (*s)[:index], (*s)[index:] 234 for len(toClear) > 0 { 235 toClear = toClear[copy(toClear, nilChildren):] 236 } 237 } 238 239 // node is an internal node in a tree. 240 // 241 // It must at all times maintain the invariant that either 242 // * len(children) == 0, len(items) unconstrained 243 // * len(children) == len(items) + 1 244 type node struct { 245 items items 246 children children 247 cow *copyOnWriteContext 248 } 249 250 func (n *node) mutableFor(cow *copyOnWriteContext) *node { 251 if n.cow == cow { 252 return n 253 } 254 out := cow.newNode() 255 if cap(out.items) >= len(n.items) { 256 out.items = out.items[:len(n.items)] 257 } else { 258 out.items = make(items, len(n.items), cap(n.items)) 259 } 260 copy(out.items, n.items) 261 // Copy children 262 if cap(out.children) >= len(n.children) { 263 out.children = out.children[:len(n.children)] 264 } else { 265 out.children = make(children, len(n.children), cap(n.children)) 266 } 267 copy(out.children, n.children) 268 return out 269 } 270 271 func (n *node) mutableChild(i int) *node { 272 c := n.children[i].mutableFor(n.cow) 273 n.children[i] = c 274 return c 275 } 276 277 // split splits the given node at the given index. The current node shrinks, 278 // and this function returns the item that existed at that index and a new node 279 // containing all items/children after it. 280 func (n *node) split(i int) (Item, *node) { 281 item := n.items[i] 282 next := n.cow.newNode() 283 next.items = append(next.items, n.items[i+1:]...) 284 n.items.truncate(i) 285 if len(n.children) > 0 { 286 next.children = append(next.children, n.children[i+1:]...) 287 n.children.truncate(i + 1) 288 } 289 return item, next 290 } 291 292 // maybeSplitChild checks if a child should be split, and if so splits it. 293 // Returns whether or not a split occurred. 294 func (n *node) maybeSplitChild(i, maxItems int) bool { 295 if len(n.children[i].items) < maxItems { 296 return false 297 } 298 first := n.mutableChild(i) 299 item, second := first.split(maxItems / 2) 300 n.items.insertAt(i, item) 301 n.children.insertAt(i+1, second) 302 return true 303 } 304 305 // insert inserts an item into the subtree rooted at this node, making sure 306 // no nodes in the subtree exceed maxItems items. Should an equivalent item be 307 // be found/replaced by insert, it will be returned. 308 func (n *node) insert(item Item, maxItems int) Item { 309 i, found := n.items.find(item) 310 if found { 311 out := n.items[i] 312 n.items[i] = item 313 return out 314 } 315 if len(n.children) == 0 { 316 n.items.insertAt(i, item) 317 return nil 318 } 319 if n.maybeSplitChild(i, maxItems) { 320 inTree := n.items[i] 321 switch { 322 case item.Less(inTree): 323 // no change, we want first split node 324 case inTree.Less(item): 325 i++ // we want second split node 326 default: 327 out := n.items[i] 328 n.items[i] = item 329 return out 330 } 331 } 332 return n.mutableChild(i).insert(item, maxItems) 333 } 334 335 // get finds the given key in the subtree and returns it. 336 func (n *node) get(key Item) Item { 337 i, found := n.items.find(key) 338 if found { 339 return n.items[i] 340 } else if len(n.children) > 0 { 341 return n.children[i].get(key) 342 } 343 return nil 344 } 345 346 // min returns the first item in the subtree. 347 func min(n *node) Item { 348 if n == nil { 349 return nil 350 } 351 for len(n.children) > 0 { 352 n = n.children[0] 353 } 354 if len(n.items) == 0 { 355 return nil 356 } 357 return n.items[0] 358 } 359 360 // max returns the last item in the subtree. 361 func max(n *node) Item { 362 if n == nil { 363 return nil 364 } 365 for len(n.children) > 0 { 366 n = n.children[len(n.children)-1] 367 } 368 if len(n.items) == 0 { 369 return nil 370 } 371 return n.items[len(n.items)-1] 372 } 373 374 // toRemove details what item to remove in a node.remove call. 375 type toRemove int 376 377 const ( 378 removeItem toRemove = iota // removes the given item 379 removeMin // removes smallest item in the subtree 380 removeMax // removes largest item in the subtree 381 ) 382 383 // remove removes an item from the subtree rooted at this node. 384 func (n *node) remove(item Item, minItems int, typ toRemove) Item { 385 var i int 386 var found bool 387 switch typ { 388 case removeMax: 389 if len(n.children) == 0 { 390 return n.items.pop() 391 } 392 i = len(n.items) 393 case removeMin: 394 if len(n.children) == 0 { 395 return n.items.removeAt(0) 396 } 397 i = 0 398 case removeItem: 399 i, found = n.items.find(item) 400 if len(n.children) == 0 { 401 if found { 402 return n.items.removeAt(i) 403 } 404 return nil 405 } 406 default: 407 panic("invalid type") 408 } 409 // If we get to here, we have children. 410 if len(n.children[i].items) <= minItems { 411 return n.growChildAndRemove(i, item, minItems, typ) 412 } 413 child := n.mutableChild(i) 414 // Either we had enough items to begin with, or we've done some 415 // merging/stealing, because we've got enough now and we're ready to return 416 // stuff. 417 if found { 418 // The item exists at index 'i', and the child we've selected can give us a 419 // predecessor, since if we've gotten here it's got > minItems items in it. 420 out := n.items[i] 421 // We use our special-case 'remove' call with typ=maxItem to pull the 422 // predecessor of item i (the rightmost leaf of our immediate left child) 423 // and set it into where we pulled the item from. 424 n.items[i] = child.remove(nil, minItems, removeMax) 425 return out 426 } 427 // Final recursive call. Once we're here, we know that the item isn't in this 428 // node and that the child is big enough to remove from. 429 return child.remove(item, minItems, typ) 430 } 431 432 // growChildAndRemove grows child 'i' to make sure it's possible to remove an 433 // item from it while keeping it at minItems, then calls remove to actually 434 // remove it. 435 // 436 // Most documentation says we have to do two sets of special casing: 437 // 1) item is in this node 438 // 2) item is in child 439 // In both cases, we need to handle the two subcases: 440 // A) node has enough values that it can spare one 441 // B) node doesn't have enough values 442 // For the latter, we have to check: 443 // a) left sibling has node to spare 444 // b) right sibling has node to spare 445 // c) we must merge 446 // To simplify our code here, we handle cases #1 and #2 the same: 447 // If a node doesn't have enough items, we make sure it does (using a,b,c). 448 // We then simply redo our remove call, and the second time (regardless of 449 // whether we're in case 1 or 2), we'll have enough items and can guarantee 450 // that we hit case A. 451 func (n *node) growChildAndRemove(i int, item Item, minItems int, typ toRemove) Item { 452 if i > 0 && len(n.children[i-1].items) > minItems { 453 // Steal from left child 454 child := n.mutableChild(i) 455 stealFrom := n.mutableChild(i - 1) 456 stolenItem := stealFrom.items.pop() 457 child.items.insertAt(0, n.items[i-1]) 458 n.items[i-1] = stolenItem 459 if len(stealFrom.children) > 0 { 460 child.children.insertAt(0, stealFrom.children.pop()) 461 } 462 } else if i < len(n.items) && len(n.children[i+1].items) > minItems { 463 // steal from right child 464 child := n.mutableChild(i) 465 stealFrom := n.mutableChild(i + 1) 466 stolenItem := stealFrom.items.removeAt(0) 467 child.items = append(child.items, n.items[i]) 468 n.items[i] = stolenItem 469 if len(stealFrom.children) > 0 { 470 child.children = append(child.children, stealFrom.children.removeAt(0)) 471 } 472 } else { 473 if i >= len(n.items) { 474 i-- 475 } 476 child := n.mutableChild(i) 477 // merge with right child 478 mergeItem := n.items.removeAt(i) 479 mergeChild := n.children.removeAt(i + 1) 480 child.items = append(child.items, mergeItem) 481 child.items = append(child.items, mergeChild.items...) 482 child.children = append(child.children, mergeChild.children...) 483 n.cow.freeNode(mergeChild) 484 } 485 return n.remove(item, minItems, typ) 486 } 487 488 type direction int 489 490 const ( 491 descend = direction(-1) 492 ascend = direction(+1) 493 ) 494 495 // iterate provides a simple method for iterating over elements in the tree. 496 // 497 // When ascending, the 'start' should be less than 'stop' and when descending, 498 // the 'start' should be greater than 'stop'. Setting 'includeStart' to true 499 // will force the iterator to include the first item when it equals 'start', 500 // thus creating a "greaterOrEqual" or "lessThanEqual" rather than just a 501 // "greaterThan" or "lessThan" queries. 502 func (n *node) iterate(dir direction, start, stop Item, includeStart bool, hit bool, iter ItemIterator) (bool, bool) { 503 var ok, found bool 504 var index int 505 switch dir { 506 case ascend: 507 if start != nil { 508 index, _ = n.items.find(start) 509 } 510 for i := index; i < len(n.items); i++ { 511 if len(n.children) > 0 { 512 if hit, ok = n.children[i].iterate(dir, start, stop, includeStart, hit, iter); !ok { 513 return hit, false 514 } 515 } 516 if !includeStart && !hit && start != nil && !start.Less(n.items[i]) { 517 hit = true 518 continue 519 } 520 hit = true 521 if stop != nil && !n.items[i].Less(stop) { 522 return hit, false 523 } 524 if !iter(n.items[i]) { 525 return hit, false 526 } 527 } 528 if len(n.children) > 0 { 529 if hit, ok = n.children[len(n.children)-1].iterate(dir, start, stop, includeStart, hit, iter); !ok { 530 return hit, false 531 } 532 } 533 case descend: 534 if start != nil { 535 index, found = n.items.find(start) 536 if !found { 537 index = index - 1 538 } 539 } else { 540 index = len(n.items) - 1 541 } 542 for i := index; i >= 0; i-- { 543 if start != nil && !n.items[i].Less(start) { 544 if !includeStart || hit || start.Less(n.items[i]) { 545 continue 546 } 547 } 548 if len(n.children) > 0 { 549 if hit, ok = n.children[i+1].iterate(dir, start, stop, includeStart, hit, iter); !ok { 550 return hit, false 551 } 552 } 553 if stop != nil && !stop.Less(n.items[i]) { 554 return hit, false // continue 555 } 556 hit = true 557 if !iter(n.items[i]) { 558 return hit, false 559 } 560 } 561 if len(n.children) > 0 { 562 if hit, ok = n.children[0].iterate(dir, start, stop, includeStart, hit, iter); !ok { 563 return hit, false 564 } 565 } 566 } 567 return hit, true 568 } 569 570 // Used for testing/debugging purposes. 571 func (n *node) print(w io.Writer, level int) { 572 fmt.Fprintf(w, "%sNODE:%v\n", strings.Repeat(" ", level), n.items) 573 for _, c := range n.children { 574 c.print(w, level+1) 575 } 576 } 577 578 // BTree is an implementation of a B-Tree. 579 // 580 // BTree stores Item instances in an ordered structure, allowing easy insertion, 581 // removal, and iteration. 582 // 583 // Write operations are not safe for concurrent mutation by multiple 584 // goroutines, but Read operations are. 585 type BTree struct { 586 degree int 587 length int 588 root *node 589 cow *copyOnWriteContext 590 } 591 592 // copyOnWriteContext pointers determine node ownership... a tree with a write 593 // context equivalent to a node's write context is allowed to modify that node. 594 // A tree whose write context does not match a node's is not allowed to modify 595 // it, and must create a new, writable copy (IE: it's a Clone). 596 // 597 // When doing any write operation, we maintain the invariant that the current 598 // node's context is equal to the context of the tree that requested the write. 599 // We do this by, before we descend into any node, creating a copy with the 600 // correct context if the contexts don't match. 601 // 602 // Since the node we're currently visiting on any write has the requesting 603 // tree's context, that node is modifiable in place. Children of that node may 604 // not share context, but before we descend into them, we'll make a mutable 605 // copy. 606 type copyOnWriteContext struct { 607 freelist *FreeList 608 } 609 610 // Clone clones the btree, lazily. Clone should not be called concurrently, 611 // but the original tree (t) and the new tree (t2) can be used concurrently 612 // once the Clone call completes. 613 // 614 // The internal tree structure of b is marked read-only and shared between t and 615 // t2. Writes to both t and t2 use copy-on-write logic, creating new nodes 616 // whenever one of b's original nodes would have been modified. Read operations 617 // should have no performance degredation. Write operations for both t and t2 618 // will initially experience minor slow-downs caused by additional allocs and 619 // copies due to the aforementioned copy-on-write logic, but should converge to 620 // the original performance characteristics of the original tree. 621 func (t *BTree) Clone() (t2 *BTree) { 622 // Create two entirely new copy-on-write contexts. 623 // This operation effectively creates three trees: 624 // the original, shared nodes (old b.cow) 625 // the new b.cow nodes 626 // the new out.cow nodes 627 cow1, cow2 := *t.cow, *t.cow 628 out := *t 629 t.cow = &cow1 630 out.cow = &cow2 631 return &out 632 } 633 634 // maxItems returns the max number of items to allow per node. 635 func (t *BTree) maxItems() int { 636 return t.degree*2 - 1 637 } 638 639 // minItems returns the min number of items to allow per node (ignored for the 640 // root node). 641 func (t *BTree) minItems() int { 642 return t.degree - 1 643 } 644 645 func (c *copyOnWriteContext) newNode() (n *node) { 646 n = c.freelist.newNode() 647 n.cow = c 648 return 649 } 650 651 type freeType int 652 653 const ( 654 ftFreelistFull freeType = iota // node was freed (available for GC, not stored in freelist) 655 ftStored // node was stored in the freelist for later use 656 ftNotOwned // node was ignored by COW, since it's owned by another one 657 ) 658 659 // freeNode frees a node within a given COW context, if it's owned by that 660 // context. It returns what happened to the node (see freeType const 661 // documentation). 662 func (c *copyOnWriteContext) freeNode(n *node) freeType { 663 if n.cow == c { 664 // clear to allow GC 665 n.items.truncate(0) 666 n.children.truncate(0) 667 n.cow = nil 668 if c.freelist.freeNode(n) { 669 return ftStored 670 } else { 671 return ftFreelistFull 672 } 673 } else { 674 return ftNotOwned 675 } 676 } 677 678 // ReplaceOrInsert adds the given item to the tree. If an item in the tree 679 // already equals the given one, it is removed from the tree and returned. 680 // Otherwise, nil is returned. 681 // 682 // nil cannot be added to the tree (will panic). 683 func (t *BTree) ReplaceOrInsert(item Item) Item { 684 if item == nil { 685 panic("nil item being added to BTree") 686 } 687 if t.root == nil { 688 t.root = t.cow.newNode() 689 t.root.items = append(t.root.items, item) 690 t.length++ 691 return nil 692 } else { 693 t.root = t.root.mutableFor(t.cow) 694 if len(t.root.items) >= t.maxItems() { 695 item2, second := t.root.split(t.maxItems() / 2) 696 oldroot := t.root 697 t.root = t.cow.newNode() 698 t.root.items = append(t.root.items, item2) 699 t.root.children = append(t.root.children, oldroot, second) 700 } 701 } 702 out := t.root.insert(item, t.maxItems()) 703 if out == nil { 704 t.length++ 705 } 706 return out 707 } 708 709 // Delete removes an item equal to the passed in item from the tree, returning 710 // it. If no such item exists, returns nil. 711 func (t *BTree) Delete(item Item) Item { 712 return t.deleteItem(item, removeItem) 713 } 714 715 // DeleteMin removes the smallest item in the tree and returns it. 716 // If no such item exists, returns nil. 717 func (t *BTree) DeleteMin() Item { 718 return t.deleteItem(nil, removeMin) 719 } 720 721 // DeleteMax removes the largest item in the tree and returns it. 722 // If no such item exists, returns nil. 723 func (t *BTree) DeleteMax() Item { 724 return t.deleteItem(nil, removeMax) 725 } 726 727 func (t *BTree) deleteItem(item Item, typ toRemove) Item { 728 if t.root == nil || len(t.root.items) == 0 { 729 return nil 730 } 731 t.root = t.root.mutableFor(t.cow) 732 out := t.root.remove(item, t.minItems(), typ) 733 if len(t.root.items) == 0 && len(t.root.children) > 0 { 734 oldroot := t.root 735 t.root = t.root.children[0] 736 t.cow.freeNode(oldroot) 737 } 738 if out != nil { 739 t.length-- 740 } 741 return out 742 } 743 744 // AscendRange calls the iterator for every value in the tree within the range 745 // [greaterOrEqual, lessThan), until iterator returns false. 746 func (t *BTree) AscendRange(greaterOrEqual, lessThan Item, iterator ItemIterator) { 747 if t.root == nil { 748 return 749 } 750 t.root.iterate(ascend, greaterOrEqual, lessThan, true, false, iterator) 751 } 752 753 // AscendLessThan calls the iterator for every value in the tree within the range 754 // [first, pivot), until iterator returns false. 755 func (t *BTree) AscendLessThan(pivot Item, iterator ItemIterator) { 756 if t.root == nil { 757 return 758 } 759 t.root.iterate(ascend, nil, pivot, false, false, iterator) 760 } 761 762 // AscendGreaterOrEqual calls the iterator for every value in the tree within 763 // the range [pivot, last], until iterator returns false. 764 func (t *BTree) AscendGreaterOrEqual(pivot Item, iterator ItemIterator) { 765 if t.root == nil { 766 return 767 } 768 t.root.iterate(ascend, pivot, nil, true, false, iterator) 769 } 770 771 // Ascend calls the iterator for every value in the tree within the range 772 // [first, last], until iterator returns false. 773 func (t *BTree) Ascend(iterator ItemIterator) { 774 if t.root == nil { 775 return 776 } 777 t.root.iterate(ascend, nil, nil, false, false, iterator) 778 } 779 780 // DescendRange calls the iterator for every value in the tree within the range 781 // [lessOrEqual, greaterThan), until iterator returns false. 782 func (t *BTree) DescendRange(lessOrEqual, greaterThan Item, iterator ItemIterator) { 783 if t.root == nil { 784 return 785 } 786 t.root.iterate(descend, lessOrEqual, greaterThan, true, false, iterator) 787 } 788 789 // DescendLessOrEqual calls the iterator for every value in the tree within the range 790 // [pivot, first], until iterator returns false. 791 func (t *BTree) DescendLessOrEqual(pivot Item, iterator ItemIterator) { 792 if t.root == nil { 793 return 794 } 795 t.root.iterate(descend, pivot, nil, true, false, iterator) 796 } 797 798 // DescendGreaterThan calls the iterator for every value in the tree within 799 // the range (pivot, last], until iterator returns false. 800 func (t *BTree) DescendGreaterThan(pivot Item, iterator ItemIterator) { 801 if t.root == nil { 802 return 803 } 804 t.root.iterate(descend, nil, pivot, false, false, iterator) 805 } 806 807 // Descend calls the iterator for every value in the tree within the range 808 // [last, first], until iterator returns false. 809 func (t *BTree) Descend(iterator ItemIterator) { 810 if t.root == nil { 811 return 812 } 813 t.root.iterate(descend, nil, nil, false, false, iterator) 814 } 815 816 // Get looks for the key item in the tree, returning it. It returns nil if 817 // unable to find that item. 818 func (t *BTree) Get(key Item) Item { 819 if t.root == nil { 820 return nil 821 } 822 return t.root.get(key) 823 } 824 825 // Min returns the smallest item in the tree, or nil if the tree is empty. 826 func (t *BTree) Min() Item { 827 return min(t.root) 828 } 829 830 // Max returns the largest item in the tree, or nil if the tree is empty. 831 func (t *BTree) Max() Item { 832 return max(t.root) 833 } 834 835 // Has returns true if the given key is in the tree. 836 func (t *BTree) Has(key Item) bool { 837 return t.Get(key) != nil 838 } 839 840 // Len returns the number of items currently in the tree. 841 func (t *BTree) Len() int { 842 return t.length 843 } 844 845 // Clear removes all items from the btree. If addNodesToFreelist is true, 846 // t's nodes are added to its freelist as part of this call, until the freelist 847 // is full. Otherwise, the root node is simply dereferenced and the subtree 848 // left to Go's normal GC processes. 849 // 850 // This can be much faster 851 // than calling Delete on all elements, because that requires finding/removing 852 // each element in the tree and updating the tree accordingly. It also is 853 // somewhat faster than creating a new tree to replace the old one, because 854 // nodes from the old tree are reclaimed into the freelist for use by the new 855 // one, instead of being lost to the garbage collector. 856 // 857 // This call takes: 858 // O(1): when addNodesToFreelist is false, this is a single operation. 859 // O(1): when the freelist is already full, it breaks out immediately 860 // O(freelist size): when the freelist is empty and the nodes are all owned 861 // by this tree, nodes are added to the freelist until full. 862 // O(tree size): when all nodes are owned by another tree, all nodes are 863 // iterated over looking for nodes to add to the freelist, and due to 864 // ownership, none are. 865 func (t *BTree) Clear(addNodesToFreelist bool) { 866 if t.root != nil && addNodesToFreelist { 867 t.root.reset(t.cow) 868 } 869 t.root, t.length = nil, 0 870 } 871 872 // reset returns a subtree to the freelist. It breaks out immediately if the 873 // freelist is full, since the only benefit of iterating is to fill that 874 // freelist up. Returns true if parent reset call should continue. 875 func (n *node) reset(c *copyOnWriteContext) bool { 876 for _, child := range n.children { 877 if !child.reset(c) { 878 return false 879 } 880 } 881 return c.freeNode(n) != ftFreelistFull 882 } 883 884 // Int implements the Item interface for integers. 885 type Int int 886 887 // Less returns true if int(a) < int(b). 888 func (a Int) Less(b Item) bool { 889 return a < b.(Int) 890 }