From 04a0c5ef10253ae5e68eeb8271727ada23de2466 Mon Sep 17 00:00:00 2001 From: winkyao Date: Thu, 7 Dec 2017 14:45:09 +0800 Subject: [PATCH 1/5] _vendor: replace llrb library from petar/GoLLRB to google/btree. --- _vendor/src/github.com/petar/GoLLRB/LICENSE | 27 -- .../github.com/petar/GoLLRB/llrb/avgvar.go | 39 -- .../github.com/petar/GoLLRB/llrb/iterator.go | 93 ---- .../petar/GoLLRB/llrb/llrb-stats.go | 46 -- .../src/github.com/petar/GoLLRB/llrb/llrb.go | 456 ------------------ .../src/github.com/petar/GoLLRB/llrb/util.go | 17 - glide.lock | 6 +- glide.yaml | 2 + store/tikv/mocktikv/mvcc.go | 2 +- store/tikv/region_cache.go | 2 +- table/tables/memory_tables.go | 2 +- 11 files changed, 9 insertions(+), 683 deletions(-) delete mode 100644 _vendor/src/github.com/petar/GoLLRB/LICENSE delete mode 100644 _vendor/src/github.com/petar/GoLLRB/llrb/avgvar.go delete mode 100644 _vendor/src/github.com/petar/GoLLRB/llrb/iterator.go delete mode 100644 _vendor/src/github.com/petar/GoLLRB/llrb/llrb-stats.go delete mode 100644 _vendor/src/github.com/petar/GoLLRB/llrb/llrb.go delete mode 100644 _vendor/src/github.com/petar/GoLLRB/llrb/util.go diff --git a/_vendor/src/github.com/petar/GoLLRB/LICENSE b/_vendor/src/github.com/petar/GoLLRB/LICENSE deleted file mode 100644 index b75312c787d66..0000000000000 --- a/_vendor/src/github.com/petar/GoLLRB/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2010, Petar Maymounkov -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -(*) Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -(*) Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -(*) Neither the name of Petar Maymounkov nor the names of its contributors may be -used to endorse or promote products derived from this software without specific -prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/_vendor/src/github.com/petar/GoLLRB/llrb/avgvar.go b/_vendor/src/github.com/petar/GoLLRB/llrb/avgvar.go deleted file mode 100644 index 2d7e2a3262d2f..0000000000000 --- a/_vendor/src/github.com/petar/GoLLRB/llrb/avgvar.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2010 Petar Maymounkov. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package llrb - -import "math" - -// avgVar maintains the average and variance of a stream of numbers -// in a space-efficient manner. -type avgVar struct { - count int64 - sum, sumsq float64 -} - -func (av *avgVar) Init() { - av.count = 0 - av.sum = 0.0 - av.sumsq = 0.0 -} - -func (av *avgVar) Add(sample float64) { - av.count++ - av.sum += sample - av.sumsq += sample * sample -} - -func (av *avgVar) GetCount() int64 { return av.count } - -func (av *avgVar) GetAvg() float64 { return av.sum / float64(av.count) } - -func (av *avgVar) GetTotal() float64 { return av.sum } - -func (av *avgVar) GetVar() float64 { - a := av.GetAvg() - return av.sumsq/float64(av.count) - a*a -} - -func (av *avgVar) GetStdDev() float64 { return math.Sqrt(av.GetVar()) } diff --git a/_vendor/src/github.com/petar/GoLLRB/llrb/iterator.go b/_vendor/src/github.com/petar/GoLLRB/llrb/iterator.go deleted file mode 100644 index ee7b27f442b02..0000000000000 --- a/_vendor/src/github.com/petar/GoLLRB/llrb/iterator.go +++ /dev/null @@ -1,93 +0,0 @@ -package llrb - -type ItemIterator func(i Item) bool - -//func (t *Tree) Ascend(iterator ItemIterator) { -// t.AscendGreaterOrEqual(Inf(-1), iterator) -//} - -func (t *LLRB) AscendRange(greaterOrEqual, lessThan Item, iterator ItemIterator) { - t.ascendRange(t.root, greaterOrEqual, lessThan, iterator) -} - -func (t *LLRB) ascendRange(h *Node, inf, sup Item, iterator ItemIterator) bool { - if h == nil { - return true - } - if !less(h.Item, sup) { - return t.ascendRange(h.Left, inf, sup, iterator) - } - if less(h.Item, inf) { - return t.ascendRange(h.Right, inf, sup, iterator) - } - - if !t.ascendRange(h.Left, inf, sup, iterator) { - return false - } - if !iterator(h.Item) { - return false - } - return t.ascendRange(h.Right, inf, sup, iterator) -} - -// AscendGreaterOrEqual will call iterator once for each element greater or equal to -// pivot in ascending order. It will stop whenever the iterator returns false. -func (t *LLRB) AscendGreaterOrEqual(pivot Item, iterator ItemIterator) { - t.ascendGreaterOrEqual(t.root, pivot, iterator) -} - -func (t *LLRB) ascendGreaterOrEqual(h *Node, pivot Item, iterator ItemIterator) bool { - if h == nil { - return true - } - if !less(h.Item, pivot) { - if !t.ascendGreaterOrEqual(h.Left, pivot, iterator) { - return false - } - if !iterator(h.Item) { - return false - } - } - return t.ascendGreaterOrEqual(h.Right, pivot, iterator) -} - -func (t *LLRB) AscendLessThan(pivot Item, iterator ItemIterator) { - t.ascendLessThan(t.root, pivot, iterator) -} - -func (t *LLRB) ascendLessThan(h *Node, pivot Item, iterator ItemIterator) bool { - if h == nil { - return true - } - if !t.ascendLessThan(h.Left, pivot, iterator) { - return false - } - if !iterator(h.Item) { - return false - } - if less(h.Item, pivot) { - return t.ascendLessThan(h.Left, pivot, iterator) - } - return true -} - -// DescendLessOrEqual will call iterator once for each element less than the -// pivot in descending order. It will stop whenever the iterator returns false. -func (t *LLRB) DescendLessOrEqual(pivot Item, iterator ItemIterator) { - t.descendLessOrEqual(t.root, pivot, iterator) -} - -func (t *LLRB) descendLessOrEqual(h *Node, pivot Item, iterator ItemIterator) bool { - if h == nil { - return true - } - if less(h.Item, pivot) || !less(pivot, h.Item) { - if !t.descendLessOrEqual(h.Right, pivot, iterator) { - return false - } - if !iterator(h.Item) { - return false - } - } - return t.descendLessOrEqual(h.Left, pivot, iterator) -} diff --git a/_vendor/src/github.com/petar/GoLLRB/llrb/llrb-stats.go b/_vendor/src/github.com/petar/GoLLRB/llrb/llrb-stats.go deleted file mode 100644 index 47126a3be967e..0000000000000 --- a/_vendor/src/github.com/petar/GoLLRB/llrb/llrb-stats.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2010 Petar Maymounkov. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package llrb - -// GetHeight() returns an item in the tree with key @key, and it's height in the tree -func (t *LLRB) GetHeight(key Item) (result Item, depth int) { - return t.getHeight(t.root, key) -} - -func (t *LLRB) getHeight(h *Node, item Item) (Item, int) { - if h == nil { - return nil, 0 - } - if less(item, h.Item) { - result, depth := t.getHeight(h.Left, item) - return result, depth + 1 - } - if less(h.Item, item) { - result, depth := t.getHeight(h.Right, item) - return result, depth + 1 - } - return h.Item, 0 -} - -// HeightStats() returns the average and standard deviation of the height -// of elements in the tree -func (t *LLRB) HeightStats() (avg, stddev float64) { - av := &avgVar{} - heightStats(t.root, 0, av) - return av.GetAvg(), av.GetStdDev() -} - -func heightStats(h *Node, d int, av *avgVar) { - if h == nil { - return - } - av.Add(float64(d)) - if h.Left != nil { - heightStats(h.Left, d+1, av) - } - if h.Right != nil { - heightStats(h.Right, d+1, av) - } -} diff --git a/_vendor/src/github.com/petar/GoLLRB/llrb/llrb.go b/_vendor/src/github.com/petar/GoLLRB/llrb/llrb.go deleted file mode 100644 index 81373fbfdf093..0000000000000 --- a/_vendor/src/github.com/petar/GoLLRB/llrb/llrb.go +++ /dev/null @@ -1,456 +0,0 @@ -// Copyright 2010 Petar Maymounkov. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// A Left-Leaning Red-Black (LLRB) implementation of 2-3 balanced binary search trees, -// based on the following work: -// -// http://www.cs.princeton.edu/~rs/talks/LLRB/08Penn.pdf -// http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf -// http://www.cs.princeton.edu/~rs/talks/LLRB/Java/RedBlackBST.java -// -// 2-3 trees (and the run-time equivalent 2-3-4 trees) are the de facto standard BST -// algoritms found in implementations of Python, Java, and other libraries. The LLRB -// implementation of 2-3 trees is a recent improvement on the traditional implementation, -// observed and documented by Robert Sedgewick. -// -package llrb - -// Tree is a Left-Leaning Red-Black (LLRB) implementation of 2-3 trees -type LLRB struct { - count int - root *Node -} - -type Node struct { - Item - Left, Right *Node // Pointers to left and right child nodes - Black bool // If set, the color of the link (incoming from the parent) is black - // In the LLRB, new nodes are always red, hence the zero-value for node -} - -type Item interface { - Less(than Item) bool -} - -// -func less(x, y Item) bool { - if x == pinf { - return false - } - if x == ninf { - return true - } - return x.Less(y) -} - -// Inf returns an Item that is "bigger than" any other item, if sign is positive. -// Otherwise it returns an Item that is "smaller than" any other item. -func Inf(sign int) Item { - if sign == 0 { - panic("sign") - } - if sign > 0 { - return pinf - } - return ninf -} - -var ( - ninf = nInf{} - pinf = pInf{} -) - -type nInf struct{} - -func (nInf) Less(Item) bool { - return true -} - -type pInf struct{} - -func (pInf) Less(Item) bool { - return false -} - -// New() allocates a new tree -func New() *LLRB { - return &LLRB{} -} - -// SetRoot sets the root node of the tree. -// It is intended to be used by functions that deserialize the tree. -func (t *LLRB) SetRoot(r *Node) { - t.root = r -} - -// Root returns the root node of the tree. -// It is intended to be used by functions that serialize the tree. -func (t *LLRB) Root() *Node { - return t.root -} - -// Len returns the number of nodes in the tree. -func (t *LLRB) Len() int { return t.count } - -// Has returns true if the tree contains an element whose order is the same as that of key. -func (t *LLRB) Has(key Item) bool { - return t.Get(key) != nil -} - -// Get retrieves an element from the tree whose order is the same as that of key. -func (t *LLRB) Get(key Item) Item { - h := t.root - for h != nil { - switch { - case less(key, h.Item): - h = h.Left - case less(h.Item, key): - h = h.Right - default: - return h.Item - } - } - return nil -} - -// Min returns the minimum element in the tree. -func (t *LLRB) Min() Item { - h := t.root - if h == nil { - return nil - } - for h.Left != nil { - h = h.Left - } - return h.Item -} - -// Max returns the maximum element in the tree. -func (t *LLRB) Max() Item { - h := t.root - if h == nil { - return nil - } - for h.Right != nil { - h = h.Right - } - return h.Item -} - -func (t *LLRB) ReplaceOrInsertBulk(items ...Item) { - for _, i := range items { - t.ReplaceOrInsert(i) - } -} - -func (t *LLRB) InsertNoReplaceBulk(items ...Item) { - for _, i := range items { - t.InsertNoReplace(i) - } -} - -// ReplaceOrInsert inserts item into the tree. If an existing -// element has the same order, it is removed from the tree and returned. -func (t *LLRB) ReplaceOrInsert(item Item) Item { - if item == nil { - panic("inserting nil item") - } - var replaced Item - t.root, replaced = t.replaceOrInsert(t.root, item) - t.root.Black = true - if replaced == nil { - t.count++ - } - return replaced -} - -func (t *LLRB) replaceOrInsert(h *Node, item Item) (*Node, Item) { - if h == nil { - return newNode(item), nil - } - - h = walkDownRot23(h) - - var replaced Item - if less(item, h.Item) { // BUG - h.Left, replaced = t.replaceOrInsert(h.Left, item) - } else if less(h.Item, item) { - h.Right, replaced = t.replaceOrInsert(h.Right, item) - } else { - replaced, h.Item = h.Item, item - } - - h = walkUpRot23(h) - - return h, replaced -} - -// InsertNoReplace inserts item into the tree. If an existing -// element has the same order, both elements remain in the tree. -func (t *LLRB) InsertNoReplace(item Item) { - if item == nil { - panic("inserting nil item") - } - t.root = t.insertNoReplace(t.root, item) - t.root.Black = true - t.count++ -} - -func (t *LLRB) insertNoReplace(h *Node, item Item) *Node { - if h == nil { - return newNode(item) - } - - h = walkDownRot23(h) - - if less(item, h.Item) { - h.Left = t.insertNoReplace(h.Left, item) - } else { - h.Right = t.insertNoReplace(h.Right, item) - } - - return walkUpRot23(h) -} - -// Rotation driver routines for 2-3 algorithm - -func walkDownRot23(h *Node) *Node { return h } - -func walkUpRot23(h *Node) *Node { - if isRed(h.Right) && !isRed(h.Left) { - h = rotateLeft(h) - } - - if isRed(h.Left) && isRed(h.Left.Left) { - h = rotateRight(h) - } - - if isRed(h.Left) && isRed(h.Right) { - flip(h) - } - - return h -} - -// Rotation driver routines for 2-3-4 algorithm - -func walkDownRot234(h *Node) *Node { - if isRed(h.Left) && isRed(h.Right) { - flip(h) - } - - return h -} - -func walkUpRot234(h *Node) *Node { - if isRed(h.Right) && !isRed(h.Left) { - h = rotateLeft(h) - } - - if isRed(h.Left) && isRed(h.Left.Left) { - h = rotateRight(h) - } - - return h -} - -// DeleteMin deletes the minimum element in the tree and returns the -// deleted item or nil otherwise. -func (t *LLRB) DeleteMin() Item { - var deleted Item - t.root, deleted = deleteMin(t.root) - if t.root != nil { - t.root.Black = true - } - if deleted != nil { - t.count-- - } - return deleted -} - -// deleteMin code for LLRB 2-3 trees -func deleteMin(h *Node) (*Node, Item) { - if h == nil { - return nil, nil - } - if h.Left == nil { - return nil, h.Item - } - - if !isRed(h.Left) && !isRed(h.Left.Left) { - h = moveRedLeft(h) - } - - var deleted Item - h.Left, deleted = deleteMin(h.Left) - - return fixUp(h), deleted -} - -// DeleteMax deletes the maximum element in the tree and returns -// the deleted item or nil otherwise -func (t *LLRB) DeleteMax() Item { - var deleted Item - t.root, deleted = deleteMax(t.root) - if t.root != nil { - t.root.Black = true - } - if deleted != nil { - t.count-- - } - return deleted -} - -func deleteMax(h *Node) (*Node, Item) { - if h == nil { - return nil, nil - } - if isRed(h.Left) { - h = rotateRight(h) - } - if h.Right == nil { - return nil, h.Item - } - if !isRed(h.Right) && !isRed(h.Right.Left) { - h = moveRedRight(h) - } - var deleted Item - h.Right, deleted = deleteMax(h.Right) - - return fixUp(h), deleted -} - -// Delete deletes an item from the tree whose key equals key. -// The deleted item is return, otherwise nil is returned. -func (t *LLRB) Delete(key Item) Item { - var deleted Item - t.root, deleted = t.delete(t.root, key) - if t.root != nil { - t.root.Black = true - } - if deleted != nil { - t.count-- - } - return deleted -} - -func (t *LLRB) delete(h *Node, item Item) (*Node, Item) { - var deleted Item - if h == nil { - return nil, nil - } - if less(item, h.Item) { - if h.Left == nil { // item not present. Nothing to delete - return h, nil - } - if !isRed(h.Left) && !isRed(h.Left.Left) { - h = moveRedLeft(h) - } - h.Left, deleted = t.delete(h.Left, item) - } else { - if isRed(h.Left) { - h = rotateRight(h) - } - // If @item equals @h.Item and no right children at @h - if !less(h.Item, item) && h.Right == nil { - return nil, h.Item - } - // PETAR: Added 'h.Right != nil' below - if h.Right != nil && !isRed(h.Right) && !isRed(h.Right.Left) { - h = moveRedRight(h) - } - // If @item equals @h.Item, and (from above) 'h.Right != nil' - if !less(h.Item, item) { - var subDeleted Item - h.Right, subDeleted = deleteMin(h.Right) - if subDeleted == nil { - panic("logic") - } - deleted, h.Item = h.Item, subDeleted - } else { // Else, @item is bigger than @h.Item - h.Right, deleted = t.delete(h.Right, item) - } - } - - return fixUp(h), deleted -} - -// Internal node manipulation routines - -func newNode(item Item) *Node { return &Node{Item: item} } - -func isRed(h *Node) bool { - if h == nil { - return false - } - return !h.Black -} - -func rotateLeft(h *Node) *Node { - x := h.Right - if x.Black { - panic("rotating a black link") - } - h.Right = x.Left - x.Left = h - x.Black = h.Black - h.Black = false - return x -} - -func rotateRight(h *Node) *Node { - x := h.Left - if x.Black { - panic("rotating a black link") - } - h.Left = x.Right - x.Right = h - x.Black = h.Black - h.Black = false - return x -} - -// REQUIRE: Left and Right children must be present -func flip(h *Node) { - h.Black = !h.Black - h.Left.Black = !h.Left.Black - h.Right.Black = !h.Right.Black -} - -// REQUIRE: Left and Right children must be present -func moveRedLeft(h *Node) *Node { - flip(h) - if isRed(h.Right.Left) { - h.Right = rotateRight(h.Right) - h = rotateLeft(h) - flip(h) - } - return h -} - -// REQUIRE: Left and Right children must be present -func moveRedRight(h *Node) *Node { - flip(h) - if isRed(h.Left.Left) { - h = rotateRight(h) - flip(h) - } - return h -} - -func fixUp(h *Node) *Node { - if isRed(h.Right) { - h = rotateLeft(h) - } - - if isRed(h.Left) && isRed(h.Left.Left) { - h = rotateRight(h) - } - - if isRed(h.Left) && isRed(h.Right) { - flip(h) - } - - return h -} diff --git a/_vendor/src/github.com/petar/GoLLRB/llrb/util.go b/_vendor/src/github.com/petar/GoLLRB/llrb/util.go deleted file mode 100644 index 63dbdb2df0a7a..0000000000000 --- a/_vendor/src/github.com/petar/GoLLRB/llrb/util.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2010 Petar Maymounkov. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package llrb - -type Int int - -func (x Int) Less(than Item) bool { - return x < than.(Int) -} - -type String string - -func (x String) Less(than Item) bool { - return x < than.(String) -} diff --git a/glide.lock b/glide.lock index dcf035af7fef7..ec8cceb8feea9 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 706074c30615e1e0a706adef7eaeaab84e7acaeaa98132e5a1d487173ebfd5ef -updated: 2017-11-29T15:54:56.281890071+09:00 +hash: fd41f4cdbce457fae92cca9c4ceeaccc9de4e6437a200dbdc539745b2bf93b17 +updated: 2017-12-07T14:42:24.016476632+08:00 imports: - name: bitbucket.org/ww/goautoneg version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675 @@ -75,6 +75,8 @@ imports: - ptypes/any - name: github.com/golang/snappy version: 723cc1e459b8eea2dea4583200fd60757d40097a +- name: github.com/google/btree + version: 316fb6d3f031ae8f4d457c6c5186b9e3ded70435 - name: github.com/gorilla/context version: 1ea25387ff6f684839d82767c1733ff4d4d15d0a - name: github.com/gorilla/mux diff --git a/glide.yaml b/glide.yaml index 76494585bf6f6..fca145adcfcb7 100644 --- a/glide.yaml +++ b/glide.yaml @@ -43,6 +43,8 @@ import: version: 53be0d36a84c2a886ca057d34b6aa4468df9ccb4 subpackages: - llrb +- package: github.com/google/btree + version: 316fb6d3f031ae8f4d457c6c5186b9e3ded70435 - package: github.com/peterh/liner version: 3f3a91ddf7d2784892a58e27ddf48d70e3304bb7 - package: github.com/pingcap/check diff --git a/store/tikv/mocktikv/mvcc.go b/store/tikv/mocktikv/mvcc.go index ec8ce35fa5de6..7bc13e39d6710 100644 --- a/store/tikv/mocktikv/mvcc.go +++ b/store/tikv/mocktikv/mvcc.go @@ -20,8 +20,8 @@ import ( "sort" "sync" + llrb "github.com/google/btree" "github.com/juju/errors" - "github.com/petar/GoLLRB/llrb" "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/tidb/util/codec" ) diff --git a/store/tikv/region_cache.go b/store/tikv/region_cache.go index 9b8051b81abe4..768313ee8ea99 100644 --- a/store/tikv/region_cache.go +++ b/store/tikv/region_cache.go @@ -20,8 +20,8 @@ import ( "time" log "github.com/Sirupsen/logrus" + llrb "github.com/google/btree" "github.com/juju/errors" - "github.com/petar/GoLLRB/llrb" "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/kvproto/pkg/metapb" "github.com/pingcap/pd/pd-client" diff --git a/table/tables/memory_tables.go b/table/tables/memory_tables.go index 300b50b2344ce..0d896d21adbaa 100644 --- a/table/tables/memory_tables.go +++ b/table/tables/memory_tables.go @@ -17,8 +17,8 @@ import ( "sync" log "github.com/Sirupsen/logrus" + llrb "github.com/google/btree" "github.com/juju/errors" - "github.com/petar/GoLLRB/llrb" "github.com/pingcap/tidb/context" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/meta/autoid" From 2af6e5675f72f8291cfcc54288a9a39ea124419d Mon Sep 17 00:00:00 2001 From: winkyao Date: Thu, 7 Dec 2017 14:49:58 +0800 Subject: [PATCH 2/5] add vendor --- _vendor/src/github.com/google/btree/LICENSE | 202 +++++ _vendor/src/github.com/google/btree/btree.go | 821 ++++++++++++++++++ .../src/github.com/google/btree/btree_mem.go | 76 ++ store/tikv/mocktikv/mvcc.go | 2 +- 4 files changed, 1100 insertions(+), 1 deletion(-) create mode 100644 _vendor/src/github.com/google/btree/LICENSE create mode 100644 _vendor/src/github.com/google/btree/btree.go create mode 100644 _vendor/src/github.com/google/btree/btree_mem.go diff --git a/_vendor/src/github.com/google/btree/LICENSE b/_vendor/src/github.com/google/btree/LICENSE new file mode 100644 index 0000000000000..d645695673349 --- /dev/null +++ b/_vendor/src/github.com/google/btree/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/_vendor/src/github.com/google/btree/btree.go b/_vendor/src/github.com/google/btree/btree.go new file mode 100644 index 0000000000000..eb74b1d39c8ee --- /dev/null +++ b/_vendor/src/github.com/google/btree/btree.go @@ -0,0 +1,821 @@ +// Copyright 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package btree implements in-memory B-Trees of arbitrary degree. +// +// btree implements an in-memory B-Tree for use as an ordered data structure. +// It is not meant for persistent storage solutions. +// +// It has a flatter structure than an equivalent red-black or other binary tree, +// which in some cases yields better memory usage and/or performance. +// See some discussion on the matter here: +// http://google-opensource.blogspot.com/2013/01/c-containers-that-save-memory-and-time.html +// Note, though, that this project is in no way related to the C++ B-Tree +// implementation written about there. +// +// Within this tree, each node contains a slice of items and a (possibly nil) +// slice of children. For basic numeric values or raw structs, this can cause +// efficiency differences when compared to equivalent C++ template code that +// stores values in arrays within the node: +// * Due to the overhead of storing values as interfaces (each +// value needs to be stored as the value itself, then 2 words for the +// interface pointing to that value and its type), resulting in higher +// memory use. +// * Since interfaces can point to values anywhere in memory, values are +// most likely not stored in contiguous blocks, resulting in a higher +// number of cache misses. +// These issues don't tend to matter, though, when working with strings or other +// heap-allocated structures, since C++-equivalent structures also must store +// pointers and also distribute their values across the heap. +// +// This implementation is designed to be a drop-in replacement to gollrb.LLRB +// trees, (http://github.com/petar/gollrb), an excellent and probably the most +// widely used ordered tree implementation in the Go ecosystem currently. +// Its functions, therefore, exactly mirror those of +// llrb.LLRB where possible. Unlike gollrb, though, we currently don't +// support storing multiple equivalent values. +package btree + +import ( + "fmt" + "io" + "sort" + "strings" + "sync" +) + +// Item represents a single object in the tree. +type Item interface { + // Less tests whether the current item is less than the given argument. + // + // This must provide a strict weak ordering. + // If !a.Less(b) && !b.Less(a), we treat this to mean a == b (i.e. we can only + // hold one of either a or b in the tree). + Less(than Item) bool +} + +const ( + DefaultFreeListSize = 32 +) + +var ( + nilItems = make(items, 16) + nilChildren = make(children, 16) +) + +// FreeList represents a free list of btree nodes. By default each +// BTree has its own FreeList, but multiple BTrees can share the same +// FreeList. +// Two Btrees using the same freelist are safe for concurrent write access. +type FreeList struct { + mu sync.Mutex + freelist []*node +} + +// NewFreeList creates a new free list. +// size is the maximum size of the returned free list. +func NewFreeList(size int) *FreeList { + return &FreeList{freelist: make([]*node, 0, size)} +} + +func (f *FreeList) newNode() (n *node) { + f.mu.Lock() + index := len(f.freelist) - 1 + if index < 0 { + f.mu.Unlock() + return new(node) + } + n = f.freelist[index] + f.freelist[index] = nil + f.freelist = f.freelist[:index] + f.mu.Unlock() + return +} + +func (f *FreeList) freeNode(n *node) { + f.mu.Lock() + if len(f.freelist) < cap(f.freelist) { + f.freelist = append(f.freelist, n) + } + f.mu.Unlock() +} + +// ItemIterator allows callers of Ascend* to iterate in-order over portions of +// the tree. When this function returns false, iteration will stop and the +// associated Ascend* function will immediately return. +type ItemIterator func(i Item) bool + +// New creates a new B-Tree with the given degree. +// +// New(2), for example, will create a 2-3-4 tree (each node contains 1-3 items +// and 2-4 children). +func New(degree int) *BTree { + return NewWithFreeList(degree, NewFreeList(DefaultFreeListSize)) +} + +// NewWithFreeList creates a new B-Tree that uses the given node free list. +func NewWithFreeList(degree int, f *FreeList) *BTree { + if degree <= 1 { + panic("bad degree") + } + return &BTree{ + degree: degree, + cow: ©OnWriteContext{freelist: f}, + } +} + +// items stores items in a node. +type items []Item + +// insertAt inserts a value into the given index, pushing all subsequent values +// forward. +func (s *items) insertAt(index int, item Item) { + *s = append(*s, nil) + if index < len(*s) { + copy((*s)[index+1:], (*s)[index:]) + } + (*s)[index] = item +} + +// removeAt removes a value at a given index, pulling all subsequent values +// back. +func (s *items) removeAt(index int) Item { + item := (*s)[index] + copy((*s)[index:], (*s)[index+1:]) + (*s)[len(*s)-1] = nil + *s = (*s)[:len(*s)-1] + return item +} + +// pop removes and returns the last element in the list. +func (s *items) pop() (out Item) { + index := len(*s) - 1 + out = (*s)[index] + (*s)[index] = nil + *s = (*s)[:index] + return +} + +// truncate truncates this instance at index so that it contains only the +// first index items. index must be less than or equal to length. +func (s *items) truncate(index int) { + var toClear items + *s, toClear = (*s)[:index], (*s)[index:] + for len(toClear) > 0 { + toClear = toClear[copy(toClear, nilItems):] + } +} + +// find returns the index where the given item should be inserted into this +// list. 'found' is true if the item already exists in the list at the given +// index. +func (s items) find(item Item) (index int, found bool) { + i := sort.Search(len(s), func(i int) bool { + return item.Less(s[i]) + }) + if i > 0 && !s[i-1].Less(item) { + return i - 1, true + } + return i, false +} + +// children stores child nodes in a node. +type children []*node + +// insertAt inserts a value into the given index, pushing all subsequent values +// forward. +func (s *children) insertAt(index int, n *node) { + *s = append(*s, nil) + if index < len(*s) { + copy((*s)[index+1:], (*s)[index:]) + } + (*s)[index] = n +} + +// removeAt removes a value at a given index, pulling all subsequent values +// back. +func (s *children) removeAt(index int) *node { + n := (*s)[index] + copy((*s)[index:], (*s)[index+1:]) + (*s)[len(*s)-1] = nil + *s = (*s)[:len(*s)-1] + return n +} + +// pop removes and returns the last element in the list. +func (s *children) pop() (out *node) { + index := len(*s) - 1 + out = (*s)[index] + (*s)[index] = nil + *s = (*s)[:index] + return +} + +// truncate truncates this instance at index so that it contains only the +// first index children. index must be less than or equal to length. +func (s *children) truncate(index int) { + var toClear children + *s, toClear = (*s)[:index], (*s)[index:] + for len(toClear) > 0 { + toClear = toClear[copy(toClear, nilChildren):] + } +} + +// node is an internal node in a tree. +// +// It must at all times maintain the invariant that either +// * len(children) == 0, len(items) unconstrained +// * len(children) == len(items) + 1 +type node struct { + items items + children children + cow *copyOnWriteContext +} + +func (n *node) mutableFor(cow *copyOnWriteContext) *node { + if n.cow == cow { + return n + } + out := cow.newNode() + if cap(out.items) >= len(n.items) { + out.items = out.items[:len(n.items)] + } else { + out.items = make(items, len(n.items), cap(n.items)) + } + copy(out.items, n.items) + // Copy children + if cap(out.children) >= len(n.children) { + out.children = out.children[:len(n.children)] + } else { + out.children = make(children, len(n.children), cap(n.children)) + } + copy(out.children, n.children) + return out +} + +func (n *node) mutableChild(i int) *node { + c := n.children[i].mutableFor(n.cow) + n.children[i] = c + return c +} + +// split splits the given node at the given index. The current node shrinks, +// and this function returns the item that existed at that index and a new node +// containing all items/children after it. +func (n *node) split(i int) (Item, *node) { + item := n.items[i] + next := n.cow.newNode() + next.items = append(next.items, n.items[i+1:]...) + n.items.truncate(i) + if len(n.children) > 0 { + next.children = append(next.children, n.children[i+1:]...) + n.children.truncate(i + 1) + } + return item, next +} + +// maybeSplitChild checks if a child should be split, and if so splits it. +// Returns whether or not a split occurred. +func (n *node) maybeSplitChild(i, maxItems int) bool { + if len(n.children[i].items) < maxItems { + return false + } + first := n.mutableChild(i) + item, second := first.split(maxItems / 2) + n.items.insertAt(i, item) + n.children.insertAt(i+1, second) + return true +} + +// insert inserts an item into the subtree rooted at this node, making sure +// no nodes in the subtree exceed maxItems items. Should an equivalent item be +// be found/replaced by insert, it will be returned. +func (n *node) insert(item Item, maxItems int) Item { + i, found := n.items.find(item) + if found { + out := n.items[i] + n.items[i] = item + return out + } + if len(n.children) == 0 { + n.items.insertAt(i, item) + return nil + } + if n.maybeSplitChild(i, maxItems) { + inTree := n.items[i] + switch { + case item.Less(inTree): + // no change, we want first split node + case inTree.Less(item): + i++ // we want second split node + default: + out := n.items[i] + n.items[i] = item + return out + } + } + return n.mutableChild(i).insert(item, maxItems) +} + +// get finds the given key in the subtree and returns it. +func (n *node) get(key Item) Item { + i, found := n.items.find(key) + if found { + return n.items[i] + } else if len(n.children) > 0 { + return n.children[i].get(key) + } + return nil +} + +// min returns the first item in the subtree. +func min(n *node) Item { + if n == nil { + return nil + } + for len(n.children) > 0 { + n = n.children[0] + } + if len(n.items) == 0 { + return nil + } + return n.items[0] +} + +// max returns the last item in the subtree. +func max(n *node) Item { + if n == nil { + return nil + } + for len(n.children) > 0 { + n = n.children[len(n.children)-1] + } + if len(n.items) == 0 { + return nil + } + return n.items[len(n.items)-1] +} + +// toRemove details what item to remove in a node.remove call. +type toRemove int + +const ( + removeItem toRemove = iota // removes the given item + removeMin // removes smallest item in the subtree + removeMax // removes largest item in the subtree +) + +// remove removes an item from the subtree rooted at this node. +func (n *node) remove(item Item, minItems int, typ toRemove) Item { + var i int + var found bool + switch typ { + case removeMax: + if len(n.children) == 0 { + return n.items.pop() + } + i = len(n.items) + case removeMin: + if len(n.children) == 0 { + return n.items.removeAt(0) + } + i = 0 + case removeItem: + i, found = n.items.find(item) + if len(n.children) == 0 { + if found { + return n.items.removeAt(i) + } + return nil + } + default: + panic("invalid type") + } + // If we get to here, we have children. + if len(n.children[i].items) <= minItems { + return n.growChildAndRemove(i, item, minItems, typ) + } + child := n.mutableChild(i) + // Either we had enough items to begin with, or we've done some + // merging/stealing, because we've got enough now and we're ready to return + // stuff. + if found { + // The item exists at index 'i', and the child we've selected can give us a + // predecessor, since if we've gotten here it's got > minItems items in it. + out := n.items[i] + // We use our special-case 'remove' call with typ=maxItem to pull the + // predecessor of item i (the rightmost leaf of our immediate left child) + // and set it into where we pulled the item from. + n.items[i] = child.remove(nil, minItems, removeMax) + return out + } + // Final recursive call. Once we're here, we know that the item isn't in this + // node and that the child is big enough to remove from. + return child.remove(item, minItems, typ) +} + +// growChildAndRemove grows child 'i' to make sure it's possible to remove an +// item from it while keeping it at minItems, then calls remove to actually +// remove it. +// +// Most documentation says we have to do two sets of special casing: +// 1) item is in this node +// 2) item is in child +// In both cases, we need to handle the two subcases: +// A) node has enough values that it can spare one +// B) node doesn't have enough values +// For the latter, we have to check: +// a) left sibling has node to spare +// b) right sibling has node to spare +// c) we must merge +// To simplify our code here, we handle cases #1 and #2 the same: +// If a node doesn't have enough items, we make sure it does (using a,b,c). +// We then simply redo our remove call, and the second time (regardless of +// whether we're in case 1 or 2), we'll have enough items and can guarantee +// that we hit case A. +func (n *node) growChildAndRemove(i int, item Item, minItems int, typ toRemove) Item { + if i > 0 && len(n.children[i-1].items) > minItems { + // Steal from left child + child := n.mutableChild(i) + stealFrom := n.mutableChild(i - 1) + stolenItem := stealFrom.items.pop() + child.items.insertAt(0, n.items[i-1]) + n.items[i-1] = stolenItem + if len(stealFrom.children) > 0 { + child.children.insertAt(0, stealFrom.children.pop()) + } + } else if i < len(n.items) && len(n.children[i+1].items) > minItems { + // steal from right child + child := n.mutableChild(i) + stealFrom := n.mutableChild(i + 1) + stolenItem := stealFrom.items.removeAt(0) + child.items = append(child.items, n.items[i]) + n.items[i] = stolenItem + if len(stealFrom.children) > 0 { + child.children = append(child.children, stealFrom.children.removeAt(0)) + } + } else { + if i >= len(n.items) { + i-- + } + child := n.mutableChild(i) + // merge with right child + mergeItem := n.items.removeAt(i) + mergeChild := n.children.removeAt(i + 1) + child.items = append(child.items, mergeItem) + child.items = append(child.items, mergeChild.items...) + child.children = append(child.children, mergeChild.children...) + n.cow.freeNode(mergeChild) + } + return n.remove(item, minItems, typ) +} + +type direction int + +const ( + descend = direction(-1) + ascend = direction(+1) +) + +// iterate provides a simple method for iterating over elements in the tree. +// +// When ascending, the 'start' should be less than 'stop' and when descending, +// the 'start' should be greater than 'stop'. Setting 'includeStart' to true +// will force the iterator to include the first item when it equals 'start', +// thus creating a "greaterOrEqual" or "lessThanEqual" rather than just a +// "greaterThan" or "lessThan" queries. +func (n *node) iterate(dir direction, start, stop Item, includeStart bool, hit bool, iter ItemIterator) (bool, bool) { + var ok bool + switch dir { + case ascend: + for i := 0; i < len(n.items); i++ { + if start != nil && n.items[i].Less(start) { + continue + } + if len(n.children) > 0 { + if hit, ok = n.children[i].iterate(dir, start, stop, includeStart, hit, iter); !ok { + return hit, false + } + } + if !includeStart && !hit && start != nil && !start.Less(n.items[i]) { + hit = true + continue + } + hit = true + if stop != nil && !n.items[i].Less(stop) { + return hit, false + } + if !iter(n.items[i]) { + return hit, false + } + } + if len(n.children) > 0 { + if hit, ok = n.children[len(n.children)-1].iterate(dir, start, stop, includeStart, hit, iter); !ok { + return hit, false + } + } + case descend: + for i := len(n.items) - 1; i >= 0; i-- { + if start != nil && !n.items[i].Less(start) { + if !includeStart || hit || start.Less(n.items[i]) { + continue + } + } + if len(n.children) > 0 { + if hit, ok = n.children[i+1].iterate(dir, start, stop, includeStart, hit, iter); !ok { + return hit, false + } + } + if stop != nil && !stop.Less(n.items[i]) { + return hit, false // continue + } + hit = true + if !iter(n.items[i]) { + return hit, false + } + } + if len(n.children) > 0 { + if hit, ok = n.children[0].iterate(dir, start, stop, includeStart, hit, iter); !ok { + return hit, false + } + } + } + return hit, true +} + +// Used for testing/debugging purposes. +func (n *node) print(w io.Writer, level int) { + fmt.Fprintf(w, "%sNODE:%v\n", strings.Repeat(" ", level), n.items) + for _, c := range n.children { + c.print(w, level+1) + } +} + +// BTree is an implementation of a B-Tree. +// +// BTree stores Item instances in an ordered structure, allowing easy insertion, +// removal, and iteration. +// +// Write operations are not safe for concurrent mutation by multiple +// goroutines, but Read operations are. +type BTree struct { + degree int + length int + root *node + cow *copyOnWriteContext +} + +// copyOnWriteContext pointers determine node ownership... a tree with a write +// context equivalent to a node's write context is allowed to modify that node. +// A tree whose write context does not match a node's is not allowed to modify +// it, and must create a new, writable copy (IE: it's a Clone). +// +// When doing any write operation, we maintain the invariant that the current +// node's context is equal to the context of the tree that requested the write. +// We do this by, before we descend into any node, creating a copy with the +// correct context if the contexts don't match. +// +// Since the node we're currently visiting on any write has the requesting +// tree's context, that node is modifiable in place. Children of that node may +// not share context, but before we descend into them, we'll make a mutable +// copy. +type copyOnWriteContext struct { + freelist *FreeList +} + +// Clone clones the btree, lazily. Clone should not be called concurrently, +// but the original tree (t) and the new tree (t2) can be used concurrently +// once the Clone call completes. +// +// The internal tree structure of b is marked read-only and shared between t and +// t2. Writes to both t and t2 use copy-on-write logic, creating new nodes +// whenever one of b's original nodes would have been modified. Read operations +// should have no performance degredation. Write operations for both t and t2 +// will initially experience minor slow-downs caused by additional allocs and +// copies due to the aforementioned copy-on-write logic, but should converge to +// the original performance characteristics of the original tree. +func (t *BTree) Clone() (t2 *BTree) { + // Create two entirely new copy-on-write contexts. + // This operation effectively creates three trees: + // the original, shared nodes (old b.cow) + // the new b.cow nodes + // the new out.cow nodes + cow1, cow2 := *t.cow, *t.cow + out := *t + t.cow = &cow1 + out.cow = &cow2 + return &out +} + +// maxItems returns the max number of items to allow per node. +func (t *BTree) maxItems() int { + return t.degree*2 - 1 +} + +// minItems returns the min number of items to allow per node (ignored for the +// root node). +func (t *BTree) minItems() int { + return t.degree - 1 +} + +func (c *copyOnWriteContext) newNode() (n *node) { + n = c.freelist.newNode() + n.cow = c + return +} + +func (c *copyOnWriteContext) freeNode(n *node) { + if n.cow == c { + // clear to allow GC + n.items.truncate(0) + n.children.truncate(0) + n.cow = nil + c.freelist.freeNode(n) + } +} + +// ReplaceOrInsert adds the given item to the tree. If an item in the tree +// already equals the given one, it is removed from the tree and returned. +// Otherwise, nil is returned. +// +// nil cannot be added to the tree (will panic). +func (t *BTree) ReplaceOrInsert(item Item) Item { + if item == nil { + panic("nil item being added to BTree") + } + if t.root == nil { + t.root = t.cow.newNode() + t.root.items = append(t.root.items, item) + t.length++ + return nil + } else { + t.root = t.root.mutableFor(t.cow) + if len(t.root.items) >= t.maxItems() { + item2, second := t.root.split(t.maxItems() / 2) + oldroot := t.root + t.root = t.cow.newNode() + t.root.items = append(t.root.items, item2) + t.root.children = append(t.root.children, oldroot, second) + } + } + out := t.root.insert(item, t.maxItems()) + if out == nil { + t.length++ + } + return out +} + +// Delete removes an item equal to the passed in item from the tree, returning +// it. If no such item exists, returns nil. +func (t *BTree) Delete(item Item) Item { + return t.deleteItem(item, removeItem) +} + +// DeleteMin removes the smallest item in the tree and returns it. +// If no such item exists, returns nil. +func (t *BTree) DeleteMin() Item { + return t.deleteItem(nil, removeMin) +} + +// DeleteMax removes the largest item in the tree and returns it. +// If no such item exists, returns nil. +func (t *BTree) DeleteMax() Item { + return t.deleteItem(nil, removeMax) +} + +func (t *BTree) deleteItem(item Item, typ toRemove) Item { + if t.root == nil || len(t.root.items) == 0 { + return nil + } + t.root = t.root.mutableFor(t.cow) + out := t.root.remove(item, t.minItems(), typ) + if len(t.root.items) == 0 && len(t.root.children) > 0 { + oldroot := t.root + t.root = t.root.children[0] + t.cow.freeNode(oldroot) + } + if out != nil { + t.length-- + } + return out +} + +// AscendRange calls the iterator for every value in the tree within the range +// [greaterOrEqual, lessThan), until iterator returns false. +func (t *BTree) AscendRange(greaterOrEqual, lessThan Item, iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate(ascend, greaterOrEqual, lessThan, true, false, iterator) +} + +// AscendLessThan calls the iterator for every value in the tree within the range +// [first, pivot), until iterator returns false. +func (t *BTree) AscendLessThan(pivot Item, iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate(ascend, nil, pivot, false, false, iterator) +} + +// AscendGreaterOrEqual calls the iterator for every value in the tree within +// the range [pivot, last], until iterator returns false. +func (t *BTree) AscendGreaterOrEqual(pivot Item, iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate(ascend, pivot, nil, true, false, iterator) +} + +// Ascend calls the iterator for every value in the tree within the range +// [first, last], until iterator returns false. +func (t *BTree) Ascend(iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate(ascend, nil, nil, false, false, iterator) +} + +// DescendRange calls the iterator for every value in the tree within the range +// [lessOrEqual, greaterThan), until iterator returns false. +func (t *BTree) DescendRange(lessOrEqual, greaterThan Item, iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate(descend, lessOrEqual, greaterThan, true, false, iterator) +} + +// DescendLessOrEqual calls the iterator for every value in the tree within the range +// [pivot, first], until iterator returns false. +func (t *BTree) DescendLessOrEqual(pivot Item, iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate(descend, pivot, nil, true, false, iterator) +} + +// DescendGreaterThan calls the iterator for every value in the tree within +// the range (pivot, last], until iterator returns false. +func (t *BTree) DescendGreaterThan(pivot Item, iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate(descend, nil, pivot, false, false, iterator) +} + +// Descend calls the iterator for every value in the tree within the range +// [last, first], until iterator returns false. +func (t *BTree) Descend(iterator ItemIterator) { + if t.root == nil { + return + } + t.root.iterate(descend, nil, nil, false, false, iterator) +} + +// Get looks for the key item in the tree, returning it. It returns nil if +// unable to find that item. +func (t *BTree) Get(key Item) Item { + if t.root == nil { + return nil + } + return t.root.get(key) +} + +// Min returns the smallest item in the tree, or nil if the tree is empty. +func (t *BTree) Min() Item { + return min(t.root) +} + +// Max returns the largest item in the tree, or nil if the tree is empty. +func (t *BTree) Max() Item { + return max(t.root) +} + +// Has returns true if the given key is in the tree. +func (t *BTree) Has(key Item) bool { + return t.Get(key) != nil +} + +// Len returns the number of items currently in the tree. +func (t *BTree) Len() int { + return t.length +} + +// Int implements the Item interface for integers. +type Int int + +// Less returns true if int(a) < int(b). +func (a Int) Less(b Item) bool { + return a < b.(Int) +} diff --git a/_vendor/src/github.com/google/btree/btree_mem.go b/_vendor/src/github.com/google/btree/btree_mem.go new file mode 100644 index 0000000000000..cb95b7fa1bc64 --- /dev/null +++ b/_vendor/src/github.com/google/btree/btree_mem.go @@ -0,0 +1,76 @@ +// Copyright 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build ignore + +// This binary compares memory usage between btree and gollrb. +package main + +import ( + "flag" + "fmt" + "math/rand" + "runtime" + "time" + + "github.com/google/btree" + "github.com/petar/GoLLRB/llrb" +) + +var ( + size = flag.Int("size", 1000000, "size of the tree to build") + degree = flag.Int("degree", 8, "degree of btree") + gollrb = flag.Bool("llrb", false, "use llrb instead of btree") +) + +func main() { + flag.Parse() + vals := rand.Perm(*size) + var t, v interface{} + v = vals + var stats runtime.MemStats + for i := 0; i < 10; i++ { + runtime.GC() + } + fmt.Println("-------- BEFORE ----------") + runtime.ReadMemStats(&stats) + fmt.Printf("%+v\n", stats) + start := time.Now() + if *gollrb { + tr := llrb.New() + for _, v := range vals { + tr.ReplaceOrInsert(llrb.Int(v)) + } + t = tr // keep it around + } else { + tr := btree.New(*degree) + for _, v := range vals { + tr.ReplaceOrInsert(btree.Int(v)) + } + t = tr // keep it around + } + fmt.Printf("%v inserts in %v\n", *size, time.Since(start)) + fmt.Println("-------- AFTER ----------") + runtime.ReadMemStats(&stats) + fmt.Printf("%+v\n", stats) + for i := 0; i < 10; i++ { + runtime.GC() + } + fmt.Println("-------- AFTER GC ----------") + runtime.ReadMemStats(&stats) + fmt.Printf("%+v\n", stats) + if t == v { + fmt.Println("to make sure vals and tree aren't GC'd") + } +} diff --git a/store/tikv/mocktikv/mvcc.go b/store/tikv/mocktikv/mvcc.go index 7bc13e39d6710..f1fe97fc45441 100644 --- a/store/tikv/mocktikv/mvcc.go +++ b/store/tikv/mocktikv/mvcc.go @@ -471,7 +471,7 @@ func (s *MvccStore) get(key MvccKey, startTS uint64, isoLevel kvrpcpb.IsolationL return entry.(*mvccEntry).Get(startTS, isoLevel) } -// A Pair is a KV pair read from MvccStore or an error if any occurs. +// Pair is a KV pair read from MvccStore or an error if any occurs. type Pair struct { Key []byte Value []byte From 7d0a3e193d88a364f12f3e93498c92aa35c86480 Mon Sep 17 00:00:00 2001 From: winkyao Date: Thu, 7 Dec 2017 16:30:52 +0800 Subject: [PATCH 3/5] fix ci --- store/tikv/mocktikv/mvcc.go | 10 ++++++---- store/tikv/region_cache.go | 5 +++-- table/tables/memory_tables.go | 8 +++++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/store/tikv/mocktikv/mvcc.go b/store/tikv/mocktikv/mvcc.go index f1fe97fc45441..f26f27be1df5e 100644 --- a/store/tikv/mocktikv/mvcc.go +++ b/store/tikv/mocktikv/mvcc.go @@ -28,6 +28,8 @@ import ( type mvccValueType int +const btreeDegree = 32 + const ( typePut mvccValueType = iota typeDelete @@ -443,15 +445,15 @@ type MVCCDebugger interface { // MvccStore is an in-memory, multi-versioned, transaction-supported kv storage. type MvccStore struct { sync.RWMutex - tree *llrb.LLRB - rawkv *llrb.LLRB + tree *llrb.BTree + rawkv *llrb.BTree } // NewMvccStore creates a MvccStore. func NewMvccStore() *MvccStore { return &MvccStore{ - tree: llrb.New(), - rawkv: llrb.New(), + tree: llrb.New(btreeDegree), + rawkv: llrb.New(btreeDegree), } } diff --git a/store/tikv/region_cache.go b/store/tikv/region_cache.go index 768313ee8ea99..254179212ac1d 100644 --- a/store/tikv/region_cache.go +++ b/store/tikv/region_cache.go @@ -29,6 +29,7 @@ import ( ) const ( + btreeDegree = 32 rcDefaultRegionCacheTTL = time.Minute * 10 ) @@ -51,7 +52,7 @@ type RegionCache struct { mu struct { sync.RWMutex regions map[RegionVerID]*CachedRegion - sorted *llrb.LLRB + sorted *llrb.BTree } storeMu struct { sync.RWMutex @@ -65,7 +66,7 @@ func NewRegionCache(pdClient pd.Client) *RegionCache { pdClient: pdClient, } c.mu.regions = make(map[RegionVerID]*CachedRegion) - c.mu.sorted = llrb.New() + c.mu.sorted = llrb.New(btreeDegree) c.storeMu.stores = make(map[uint64]*Store) return c } diff --git a/table/tables/memory_tables.go b/table/tables/memory_tables.go index 0d896d21adbaa..6078b3748cc05 100644 --- a/table/tables/memory_tables.go +++ b/table/tables/memory_tables.go @@ -28,6 +28,8 @@ import ( "github.com/pingcap/tidb/types" ) +const btreeDegree = 32 + type itemKey int64 type itemPair struct { @@ -68,7 +70,7 @@ type MemoryTable struct { alloc autoid.Allocator meta *model.TableInfo - tree *llrb.LLRB + tree *llrb.BTree mu sync.RWMutex } @@ -98,7 +100,7 @@ func newMemoryTable(tableID int64, tableName string, cols []*table.Column, alloc alloc: alloc, Columns: cols, recordPrefix: tablecodec.GenTableRecordPrefix(tableID), - tree: llrb.New(), + tree: llrb.New(btreeDegree), } return t } @@ -169,7 +171,7 @@ func (t *MemoryTable) FirstKey() kv.Key { // Truncate drops all data in Memory Table. func (t *MemoryTable) Truncate() { - t.tree = llrb.New() + t.tree = llrb.New(btreeDegree) } // UpdateRecord implements table.Table UpdateRecord interface. From 348dbcf3e18a8a1f6dff9caed09425c5857cef81 Mon Sep 17 00:00:00 2001 From: winkyao Date: Thu, 7 Dec 2017 16:34:02 +0800 Subject: [PATCH 4/5] remove llrb in glide.yaml --- glide.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/glide.yaml b/glide.yaml index c769f6517c525..1bb9204fbb695 100644 --- a/glide.yaml +++ b/glide.yaml @@ -39,10 +39,6 @@ import: version: 6352e005618615ffaf1cb1c6622b8e91435751fe - package: github.com/ngaut/sync2 version: 7a24ed77b2efb460c1468b7dc917821c66e80e55 -- package: github.com/petar/GoLLRB - version: 53be0d36a84c2a886ca057d34b6aa4468df9ccb4 - subpackages: - - llrb - package: github.com/google/btree version: 316fb6d3f031ae8f4d457c6c5186b9e3ded70435 - package: github.com/peterh/liner From 1df30ee8e5f8765f883ed96e7c4062d7138e3d1c Mon Sep 17 00:00:00 2001 From: winkyao Date: Thu, 7 Dec 2017 16:46:11 +0800 Subject: [PATCH 5/5] rename llrb --> btree --- store/tikv/mocktikv/mvcc.go | 26 +++++++++++++------------- store/tikv/region_cache.go | 32 ++++++++++++++++---------------- table/tables/memory_tables.go | 14 +++++++------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/store/tikv/mocktikv/mvcc.go b/store/tikv/mocktikv/mvcc.go index f26f27be1df5e..834a0b54fc306 100644 --- a/store/tikv/mocktikv/mvcc.go +++ b/store/tikv/mocktikv/mvcc.go @@ -20,7 +20,7 @@ import ( "sort" "sync" - llrb "github.com/google/btree" + "github.com/google/btree" "github.com/juju/errors" "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/tidb/util/codec" @@ -222,7 +222,7 @@ func (e *mvccEntry) Clone() *mvccEntry { return &entry } -func (e *mvccEntry) Less(than llrb.Item) bool { +func (e *mvccEntry) Less(than btree.Item) bool { return bytes.Compare(e.key, than.(*mvccEntry).key) < 0 } @@ -410,7 +410,7 @@ func newRawEntry(key []byte) *rawEntry { } } -func (e *rawEntry) Less(than llrb.Item) bool { +func (e *rawEntry) Less(than btree.Item) bool { return bytes.Compare(e.key, than.(*rawEntry).key) < 0 } @@ -445,15 +445,15 @@ type MVCCDebugger interface { // MvccStore is an in-memory, multi-versioned, transaction-supported kv storage. type MvccStore struct { sync.RWMutex - tree *llrb.BTree - rawkv *llrb.BTree + tree *btree.BTree + rawkv *btree.BTree } // NewMvccStore creates a MvccStore. func NewMvccStore() *MvccStore { return &MvccStore{ - tree: llrb.New(btreeDegree), - rawkv: llrb.New(btreeDegree), + tree: btree.New(btreeDegree), + rawkv: btree.New(btreeDegree), } } @@ -514,7 +514,7 @@ func (s *MvccStore) Scan(startKey, endKey []byte, limit int, startTS uint64, iso endKey = NewMvccKey(endKey) var pairs []Pair - iterator := func(item llrb.Item) bool { + iterator := func(item btree.Item) bool { if len(pairs) >= limit { return false } @@ -546,7 +546,7 @@ func (s *MvccStore) ReverseScan(startKey, endKey []byte, limit int, startTS uint endKey = NewMvccKey(endKey) var pairs []Pair - iterator := func(item llrb.Item) bool { + iterator := func(item btree.Item) bool { if len(pairs) >= limit { return false } @@ -656,7 +656,7 @@ func (s *MvccStore) ScanLock(startKey, endKey []byte, maxTS uint64) ([]*kvrpcpb. defer s.RUnlock() var locks []*kvrpcpb.LockInfo - iterator := func(item llrb.Item) bool { + iterator := func(item btree.Item) bool { ent := item.(*mvccEntry) if !regionContains(startKey, endKey, ent.key) { return false @@ -681,7 +681,7 @@ func (s *MvccStore) ResolveLock(startKey, endKey []byte, startTS, commitTS uint6 var ents []*mvccEntry var err error - iterator := func(item llrb.Item) bool { + iterator := func(item btree.Item) bool { ent := item.(*mvccEntry) if !regionContains(startKey, endKey, ent.key) { return false @@ -750,7 +750,7 @@ func (s *MvccStore) RawScan(startKey, endKey []byte, limit int) []Pair { defer s.RUnlock() var pairs []Pair - iterator := func(item llrb.Item) bool { + iterator := func(item btree.Item) bool { if len(pairs) >= limit { return false } @@ -775,7 +775,7 @@ func (s *MvccStore) MvccGetByStartTS(startKey, endKey []byte, starTS uint64) (*k var info *kvrpcpb.MvccInfo var key []byte - iterator := func(item llrb.Item) bool { + iterator := func(item btree.Item) bool { k := item.(*mvccEntry) if !regionContains(startKey, endKey, k.key) { return false diff --git a/store/tikv/region_cache.go b/store/tikv/region_cache.go index 254179212ac1d..3444760876ab4 100644 --- a/store/tikv/region_cache.go +++ b/store/tikv/region_cache.go @@ -20,7 +20,7 @@ import ( "time" log "github.com/Sirupsen/logrus" - llrb "github.com/google/btree" + "github.com/google/btree" "github.com/juju/errors" "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/kvproto/pkg/metapb" @@ -52,7 +52,7 @@ type RegionCache struct { mu struct { sync.RWMutex regions map[RegionVerID]*CachedRegion - sorted *llrb.BTree + sorted *btree.BTree } storeMu struct { sync.RWMutex @@ -66,7 +66,7 @@ func NewRegionCache(pdClient pd.Client) *RegionCache { pdClient: pdClient, } c.mu.regions = make(map[RegionVerID]*CachedRegion) - c.mu.sorted = llrb.New(btreeDegree) + c.mu.sorted = btree.New(btreeDegree) c.storeMu.stores = make(map[uint64]*Store) return c } @@ -260,9 +260,9 @@ func (c *RegionCache) UpdateLeader(regionID RegionVerID, leaderStoreID uint64) { // insertRegionToCache tries to insert the Region to cache. func (c *RegionCache) insertRegionToCache(r *Region) { - old := c.mu.sorted.ReplaceOrInsert(newRBItem(r)) + old := c.mu.sorted.ReplaceOrInsert(newBtreeItem(r)) if old != nil { - delete(c.mu.regions, old.(*llrbItem).region.VerID()) + delete(c.mu.regions, old.(*btreeItem).region.VerID()) } c.mu.regions[r.VerID()] = &CachedRegion{ region: r, @@ -292,8 +292,8 @@ func (c *RegionCache) getCachedRegion(id RegionVerID) *Region { // used after c.mu is RUnlock(). func (c *RegionCache) searchCachedRegion(key []byte) *Region { var r *Region - c.mu.sorted.DescendLessOrEqual(newRBSearchItem(key), func(item llrb.Item) bool { - r = item.(*llrbItem).region + c.mu.sorted.DescendLessOrEqual(newBtreeSearchItem(key), func(item btree.Item) bool { + r = item.(*btreeItem).region return false }) if r != nil && r.Contains(key) { @@ -319,7 +319,7 @@ func (c *RegionCache) dropRegionFromCache(verID RegionVerID) { if !ok { return } - c.mu.sorted.Delete(newRBItem(r.region)) + c.mu.sorted.Delete(newBtreeItem(r.region)) delete(c.mu.regions, verID) } @@ -503,27 +503,27 @@ func (c *RegionCache) PDClient() pd.Client { return c.pdClient } -// llrbItem is llrbTree's Item that uses []byte to compare. -type llrbItem struct { +// btreeItem is BTree's Item that uses []byte to compare. +type btreeItem struct { key []byte region *Region } -func newRBItem(r *Region) *llrbItem { - return &llrbItem{ +func newBtreeItem(r *Region) *btreeItem { + return &btreeItem{ key: r.StartKey(), region: r, } } -func newRBSearchItem(key []byte) *llrbItem { - return &llrbItem{ +func newBtreeSearchItem(key []byte) *btreeItem { + return &btreeItem{ key: key, } } -func (item *llrbItem) Less(other llrb.Item) bool { - return bytes.Compare(item.key, other.(*llrbItem).key) < 0 +func (item *btreeItem) Less(other btree.Item) bool { + return bytes.Compare(item.key, other.(*btreeItem).key) < 0 } // Region stores region's meta and its leader peer. diff --git a/table/tables/memory_tables.go b/table/tables/memory_tables.go index 6078b3748cc05..f3170cf3ad206 100644 --- a/table/tables/memory_tables.go +++ b/table/tables/memory_tables.go @@ -17,7 +17,7 @@ import ( "sync" log "github.com/Sirupsen/logrus" - llrb "github.com/google/btree" + "github.com/google/btree" "github.com/juju/errors" "github.com/pingcap/tidb/context" "github.com/pingcap/tidb/kv" @@ -37,7 +37,7 @@ type itemPair struct { data []types.Datum } -func (r *itemPair) Less(item llrb.Item) bool { +func (r *itemPair) Less(item btree.Item) bool { switch x := item.(type) { case itemKey: return r.handle < x @@ -48,7 +48,7 @@ func (r *itemPair) Less(item llrb.Item) bool { return true } -func (k itemKey) Less(item llrb.Item) bool { +func (k itemKey) Less(item btree.Item) bool { switch x := item.(type) { case itemKey: return k < x @@ -70,7 +70,7 @@ type MemoryTable struct { alloc autoid.Allocator meta *model.TableInfo - tree *llrb.BTree + tree *btree.BTree mu sync.RWMutex } @@ -100,7 +100,7 @@ func newMemoryTable(tableID int64, tableName string, cols []*table.Column, alloc alloc: alloc, Columns: cols, recordPrefix: tablecodec.GenTableRecordPrefix(tableID), - tree: llrb.New(btreeDegree), + tree: btree.New(btreeDegree), } return t } @@ -110,7 +110,7 @@ func (t *MemoryTable) Seek(ctx context.Context, handle int64) (int64, bool, erro var found bool var result int64 t.mu.RLock() - t.tree.AscendGreaterOrEqual(itemKey(handle), func(item llrb.Item) bool { + t.tree.AscendGreaterOrEqual(itemKey(handle), func(item btree.Item) bool { found = true result = int64(item.(*itemPair).handle) return false @@ -171,7 +171,7 @@ func (t *MemoryTable) FirstKey() kv.Key { // Truncate drops all data in Memory Table. func (t *MemoryTable) Truncate() { - t.tree = llrb.New(btreeDegree) + t.tree = btree.New(btreeDegree) } // UpdateRecord implements table.Table UpdateRecord interface.