diff --git a/.gitignore b/.gitignore index 32cf78e898d..e697be8125c 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ vendor/**/* vendor/**/*_test.go *.bak +.vscode/ \ No newline at end of file diff --git a/auth/range_perm_cache.go b/auth/range_perm_cache.go index 8de2d175c25..e799e18e335 100644 --- a/auth/range_perm_cache.go +++ b/auth/range_perm_cache.go @@ -28,8 +28,8 @@ func getMergedPerms(lg *zap.Logger, tx backend.BatchTx, userName string) *unifie return nil } - readPerms := &adt.IntervalTree{} - writePerms := &adt.IntervalTree{} + readPerms := adt.NewIntervalTree() + writePerms := adt.NewIntervalTree() for _, roleName := range user.Roles { role := getRole(tx, roleName) diff --git a/auth/range_perm_cache_test.go b/auth/range_perm_cache_test.go index e5baa86b40c..fae488b6c5b 100644 --- a/auth/range_perm_cache_test.go +++ b/auth/range_perm_cache_test.go @@ -48,7 +48,7 @@ func TestRangePermission(t *testing.T) { } for i, tt := range tests { - readPerms := &adt.IntervalTree{} + readPerms := adt.NewIntervalTree() for _, p := range tt.perms { readPerms.Insert(p, struct{}{}) } @@ -89,7 +89,7 @@ func TestKeyPermission(t *testing.T) { } for i, tt := range tests { - readPerms := &adt.IntervalTree{} + readPerms := adt.NewIntervalTree() for _, p := range tt.perms { readPerms.Insert(p, struct{}{}) } diff --git a/etcdserver/api/v3rpc/key.go b/etcdserver/api/v3rpc/key.go index fdb002e0dd8..583668db8c3 100644 --- a/etcdserver/api/v3rpc/key.go +++ b/etcdserver/api/v3rpc/key.go @@ -178,8 +178,8 @@ func checkTxnRequest(r *pb.TxnRequest, maxTxnOps int) error { // checkIntervals tests whether puts and deletes overlap for a list of ops. If // there is an overlap, returns an error. If no overlap, return put and delete // sets for recursive evaluation. -func checkIntervals(reqs []*pb.RequestOp) (map[string]struct{}, adt.IntervalTree, error) { - var dels adt.IntervalTree +func checkIntervals(reqs []*pb.RequestOp) (map[string]struct{}, *adt.IntervalTree, error) { + dels := adt.NewIntervalTree() // collect deletes from this level; build first to check lower level overlapped puts for _, req := range reqs { diff --git a/mvcc/watcher_group.go b/mvcc/watcher_group.go index 07029335a85..3d480606e4d 100644 --- a/mvcc/watcher_group.go +++ b/mvcc/watcher_group.go @@ -148,7 +148,7 @@ type watcherGroup struct { // keyWatchers has the watchers that watch on a single key keyWatchers watcherSetByKey // ranges has the watchers that watch a range; it is sorted by interval - ranges adt.IntervalTree + ranges *adt.IntervalTree // watchers is the set of all watchers watchers watcherSet } @@ -156,6 +156,7 @@ type watcherGroup struct { func newWatcherGroup() watcherGroup { return watcherGroup{ keyWatchers: make(watcherSetByKey), + ranges: adt.NewIntervalTree(), watchers: make(watcherSet), } } diff --git a/pkg/adt/example_test.go b/pkg/adt/example_test.go index e3edf225c46..07109384854 100644 --- a/pkg/adt/example_test.go +++ b/pkg/adt/example_test.go @@ -21,7 +21,7 @@ import ( ) func Example() { - ivt := &adt.IntervalTree{} + ivt := adt.NewIntervalTree() ivt.Insert(adt.NewInt64Interval(1, 3), 123) ivt.Insert(adt.NewInt64Interval(9, 13), 456) diff --git a/pkg/adt/interval_tree.go b/pkg/adt/interval_tree.go index 342eab75bdc..7263604633f 100644 --- a/pkg/adt/interval_tree.go +++ b/pkg/adt/interval_tree.go @@ -74,39 +74,39 @@ type intervalNode struct { c rbcolor } -func (x *intervalNode) color() rbcolor { - if x == nil { +func (x *intervalNode) color(nilNode *intervalNode) rbcolor { + if x == nilNode { return black } return x.c } -func (x *intervalNode) height() int { - if x == nil { +func (x *intervalNode) height(nilNode *intervalNode) int { + if x == nilNode { return 0 } - ld := x.left.height() - rd := x.right.height() + ld := x.left.height(nilNode) + rd := x.right.height(nilNode) if ld < rd { return rd + 1 } return ld + 1 } -func (x *intervalNode) min() *intervalNode { - for x.left != nil { +func (x *intervalNode) min(nilNode *intervalNode) *intervalNode { + for x.left != nilNode { x = x.left } return x } // successor is the next in-order node in the tree -func (x *intervalNode) successor() *intervalNode { - if x.right != nil { - return x.right.min() +func (x *intervalNode) successor(nilNode *intervalNode) *intervalNode { + if x.right != nilNode { + return x.right.min(nilNode) } y := x.parent - for y != nil && x == y.right { + for y != nilNode && x == y.right { x = y y = y.parent } @@ -114,14 +114,14 @@ func (x *intervalNode) successor() *intervalNode { } // updateMax updates the maximum values for a node and its ancestors -func (x *intervalNode) updateMax() { - for x != nil { +func (x *intervalNode) updateMax(nilNode *intervalNode) { + for x != nilNode { oldmax := x.max max := x.iv.Ivl.End - if x.left != nil && x.left.max.Compare(max) > 0 { + if x.left != nilNode && x.left.max.Compare(max) > 0 { max = x.left.max } - if x.right != nil && x.right.max.Compare(max) > 0 { + if x.right != nilNode && x.right.max.Compare(max) > 0 { max = x.right.max } if oldmax.Compare(max) == 0 { @@ -135,25 +135,25 @@ func (x *intervalNode) updateMax() { type nodeVisitor func(n *intervalNode) bool // visit will call a node visitor on each node that overlaps the given interval -func (x *intervalNode) visit(iv *Interval, nv nodeVisitor) bool { - if x == nil { +func (x *intervalNode) visit(iv *Interval, nilNode *intervalNode, nv nodeVisitor) bool { + if x == nilNode { return true } v := iv.Compare(&x.iv.Ivl) switch { case v < 0: - if !x.left.visit(iv, nv) { + if !x.left.visit(iv, nilNode, nv) { return false } case v > 0: maxiv := Interval{x.iv.Ivl.Begin, x.max} if maxiv.Compare(iv) == 0 { - if !x.left.visit(iv, nv) || !x.right.visit(iv, nv) { + if !x.left.visit(iv, nilNode, nv) || !x.right.visit(iv, nilNode, nv) { return false } } default: - if !x.left.visit(iv, nv) || !nv(x) || !x.right.visit(iv, nv) { + if !x.left.visit(iv, nilNode, nv) || !nv(x) || !x.right.visit(iv, nilNode, nv) { return false } } @@ -171,30 +171,45 @@ type IntervalValue struct { type IntervalTree struct { root *intervalNode count int + + // red-black NIL node, can not use golang nil instead + nilNode *intervalNode +} + +func NewIntervalTree() *IntervalTree { + tree := &IntervalTree{} + + tree.nilNode = &intervalNode{} + + tree.root = tree.nilNode + tree.nilNode.c = black + + return tree } // Delete removes the node with the given interval from the tree, returning // true if a node is in fact removed. func (ivt *IntervalTree) Delete(ivl Interval) bool { z := ivt.find(ivl) - if z == nil { + if z == ivt.nilNode { return false } y := z - if z.left != nil && z.right != nil { - y = z.successor() + if z.left != ivt.nilNode && z.right != ivt.nilNode { + y = z.successor(ivt.nilNode) } - x := y.left - if x == nil { + x := ivt.nilNode + if y.left != ivt.nilNode { + x = y.left + } else if y.right != ivt.nilNode { x = y.right } - if x != nil { - x.parent = y.parent - } - if y.parent == nil { + x.parent = y.parent + + if y.parent == ivt.nilNode { ivt.root = x } else { if y == y.parent.left { @@ -202,14 +217,14 @@ func (ivt *IntervalTree) Delete(ivl Interval) bool { } else { y.parent.right = x } - y.parent.updateMax() + y.parent.updateMax(ivt.nilNode) } if y != z { z.iv = y.iv - z.updateMax() + z.updateMax(ivt.nilNode) } - if y.color() == black && x != nil { + if y.color(ivt.nilNode) == black { ivt.deleteFixup(x) } @@ -218,29 +233,26 @@ func (ivt *IntervalTree) Delete(ivl Interval) bool { } func (ivt *IntervalTree) deleteFixup(x *intervalNode) { - for x != ivt.root && x.color() == black && x.parent != nil { + for x != ivt.root && x.color(ivt.nilNode) == black { if x == x.parent.left { w := x.parent.right - if w.color() == red { + if w.color(ivt.nilNode) == red { w.c = black x.parent.c = red ivt.rotateLeft(x.parent) w = x.parent.right } - if w == nil { - break - } - if w.left.color() == black && w.right.color() == black { + if w.left.color(ivt.nilNode) == black && w.right.color(ivt.nilNode) == black { w.c = red x = x.parent } else { - if w.right.color() == black { + if w.right.color(ivt.nilNode) == black { w.left.c = black w.c = red ivt.rotateRight(w) w = x.parent.right } - w.c = x.parent.color() + w.c = x.parent.color(ivt.nilNode) x.parent.c = black w.right.c = black ivt.rotateLeft(x.parent) @@ -249,26 +261,23 @@ func (ivt *IntervalTree) deleteFixup(x *intervalNode) { } else { // same as above but with left and right exchanged w := x.parent.left - if w.color() == red { + if w.color(ivt.nilNode) == red { w.c = black x.parent.c = red ivt.rotateRight(x.parent) w = x.parent.left } - if w == nil { - break - } - if w.left.color() == black && w.right.color() == black { + if w.left.color(ivt.nilNode) == black && w.right.color(ivt.nilNode) == black { w.c = red x = x.parent } else { - if w.left.color() == black { + if w.left.color(ivt.nilNode) == black { w.right.c = black w.c = red ivt.rotateLeft(w) w = x.parent.left } - w.c = x.parent.color() + w.c = x.parent.color(ivt.nilNode) x.parent.c = black w.left.c = black ivt.rotateRight(x.parent) @@ -276,17 +285,22 @@ func (ivt *IntervalTree) deleteFixup(x *intervalNode) { } } } - if x != nil { - x.c = black - } + x.c = black } // Insert adds a node with the given interval into the tree. func (ivt *IntervalTree) Insert(ivl Interval, val interface{}) { - var y *intervalNode - z := &intervalNode{iv: IntervalValue{ivl, val}, max: ivl.End, c: red} + y := ivt.nilNode + z := &intervalNode{ + iv: IntervalValue{ivl, val}, + max: ivl.End, + c: red, + left: ivt.nilNode, + right: ivt.nilNode, + parent: ivt.nilNode, + } x := ivt.root - for x != nil { + for x != ivt.nilNode { y = x if z.iv.Ivl.Begin.Compare(x.iv.Ivl.Begin) < 0 { x = x.left @@ -296,7 +310,7 @@ func (ivt *IntervalTree) Insert(ivl Interval, val interface{}) { } z.parent = y - if y == nil { + if y == ivt.nilNode { ivt.root = z } else { if z.iv.Ivl.Begin.Compare(y.iv.Ivl.Begin) < 0 { @@ -304,7 +318,7 @@ func (ivt *IntervalTree) Insert(ivl Interval, val interface{}) { } else { y.right = z } - y.updateMax() + y.updateMax(ivt.nilNode) } z.c = red ivt.insertFixup(z) @@ -312,10 +326,10 @@ func (ivt *IntervalTree) Insert(ivl Interval, val interface{}) { } func (ivt *IntervalTree) insertFixup(z *intervalNode) { - for z.parent != nil && z.parent.parent != nil && z.parent.color() == red { + for z.parent.color(ivt.nilNode) == red { if z.parent == z.parent.parent.left { y := z.parent.parent.right - if y.color() == red { + if y.color(ivt.nilNode) == red { y.c = black z.parent.c = black z.parent.parent.c = red @@ -332,7 +346,7 @@ func (ivt *IntervalTree) insertFixup(z *intervalNode) { } else { // same as then with left/right exchanged y := z.parent.parent.left - if y.color() == red { + if y.color(ivt.nilNode) == red { y.c = black z.parent.c = black z.parent.parent.c = red @@ -353,37 +367,44 @@ func (ivt *IntervalTree) insertFixup(z *intervalNode) { // rotateLeft moves x so it is left of its right child func (ivt *IntervalTree) rotateLeft(x *intervalNode) { + // rotateLeft x must have right child + if x.right == ivt.nilNode { + return + } + y := x.right x.right = y.left - if y.left != nil { + if y.left != ivt.nilNode { y.left.parent = x } - x.updateMax() + x.updateMax(ivt.nilNode) ivt.replaceParent(x, y) y.left = x - y.updateMax() + y.updateMax(ivt.nilNode) } -// rotateLeft moves x so it is right of its left child +// rotateRight moves x so it is right of its left child func (ivt *IntervalTree) rotateRight(x *intervalNode) { - if x == nil { + // rotateRight x must have left child + if x.left == ivt.nilNode { return } + y := x.left x.left = y.right - if y.right != nil { + if y.right != ivt.nilNode { y.right.parent = x } - x.updateMax() + x.updateMax(ivt.nilNode) ivt.replaceParent(x, y) y.right = x - y.updateMax() + y.updateMax(ivt.nilNode) } // replaceParent replaces x's parent with y func (ivt *IntervalTree) replaceParent(x *intervalNode, y *intervalNode) { y.parent = x.parent - if x.parent == nil { + if x.parent == ivt.nilNode { ivt.root = y } else { if x == x.parent.left { @@ -391,7 +412,7 @@ func (ivt *IntervalTree) replaceParent(x *intervalNode, y *intervalNode) { } else { x.parent.right = y } - x.parent.updateMax() + x.parent.updateMax(ivt.nilNode) } x.parent = y } @@ -400,7 +421,7 @@ func (ivt *IntervalTree) replaceParent(x *intervalNode, y *intervalNode) { func (ivt *IntervalTree) Len() int { return ivt.count } // Height is the number of levels in the tree; one node has height 1. -func (ivt *IntervalTree) Height() int { return ivt.root.height() } +func (ivt *IntervalTree) Height() int { return ivt.root.height(ivt.nilNode) } // MaxHeight is the expected maximum tree height given the number of nodes func (ivt *IntervalTree) MaxHeight() int { @@ -413,11 +434,12 @@ type IntervalVisitor func(n *IntervalValue) bool // Visit calls a visitor function on every tree node intersecting the given interval. // It will visit each interval [x, y) in ascending order sorted on x. func (ivt *IntervalTree) Visit(ivl Interval, ivv IntervalVisitor) { - ivt.root.visit(&ivl, func(n *intervalNode) bool { return ivv(&n.iv) }) + ivt.root.visit(&ivl, ivt.nilNode, func(n *intervalNode) bool { return ivv(&n.iv) }) } // find the exact node for a given interval -func (ivt *IntervalTree) find(ivl Interval) (ret *intervalNode) { +func (ivt *IntervalTree) find(ivl Interval) *intervalNode { + ret := ivt.nilNode f := func(n *intervalNode) bool { if n.iv.Ivl != ivl { return true @@ -425,14 +447,16 @@ func (ivt *IntervalTree) find(ivl Interval) (ret *intervalNode) { ret = n return false } - ivt.root.visit(&ivl, f) + + ivt.root.visit(&ivl, ivt.nilNode, f) + return ret } // Find gets the IntervalValue for the node matching the given interval func (ivt *IntervalTree) Find(ivl Interval) (ret *IntervalValue) { n := ivt.find(ivl) - if n == nil { + if n == ivt.nilNode { return nil } return &n.iv @@ -441,14 +465,14 @@ func (ivt *IntervalTree) Find(ivl Interval) (ret *IntervalValue) { // Intersects returns true if there is some tree node intersecting the given interval. func (ivt *IntervalTree) Intersects(iv Interval) bool { x := ivt.root - for x != nil && iv.Compare(&x.iv.Ivl) != 0 { - if x.left != nil && x.left.max.Compare(iv.Begin) > 0 { + for x != ivt.nilNode && iv.Compare(&x.iv.Ivl) != 0 { + if x.left != ivt.nilNode && x.left.max.Compare(iv.Begin) > 0 { x = x.left } else { x = x.right } } - return x != nil + return x != ivt.nilNode } // Contains returns true if the interval tree's keys cover the entire given interval. @@ -486,7 +510,7 @@ func (ivt *IntervalTree) Stab(iv Interval) (ivs []*IntervalValue) { } // Union merges a given interval tree into the receiver. -func (ivt *IntervalTree) Union(inIvt IntervalTree, ivl Interval) { +func (ivt *IntervalTree) Union(inIvt *IntervalTree, ivl Interval) { f := func(n *IntervalValue) bool { ivt.Insert(n.Ivl, n.Val) return true diff --git a/pkg/adt/interval_tree_test.go b/pkg/adt/interval_tree_test.go index 493c11fa0b3..2b3fcd92217 100644 --- a/pkg/adt/interval_tree_test.go +++ b/pkg/adt/interval_tree_test.go @@ -21,7 +21,7 @@ import ( ) func TestIntervalTreeIntersects(t *testing.T) { - ivt := &IntervalTree{} + ivt := NewIntervalTree() ivt.Insert(NewStringInterval("1", "3"), 123) if ivt.Intersects(NewStringPoint("0")) { @@ -42,7 +42,7 @@ func TestIntervalTreeIntersects(t *testing.T) { } func TestIntervalTreeStringAffine(t *testing.T) { - ivt := &IntervalTree{} + ivt := NewIntervalTree() ivt.Insert(NewStringAffineInterval("8", ""), 123) if !ivt.Intersects(NewStringAffinePoint("9")) { t.Errorf("missing 9") @@ -53,7 +53,7 @@ func TestIntervalTreeStringAffine(t *testing.T) { } func TestIntervalTreeStab(t *testing.T) { - ivt := &IntervalTree{} + ivt := NewIntervalTree() ivt.Insert(NewStringInterval("0", "1"), 123) ivt.Insert(NewStringInterval("0", "2"), 456) ivt.Insert(NewStringInterval("5", "6"), 789) @@ -94,7 +94,7 @@ type xy struct { func TestIntervalTreeRandom(t *testing.T) { // generate unique intervals ivs := make(map[xy]struct{}) - ivt := &IntervalTree{} + ivt := NewIntervalTree() maxv := 128 rand.Seed(time.Now().UnixNano()) @@ -168,7 +168,7 @@ func TestIntervalTreeSortedVisit(t *testing.T) { }, } for i, tt := range tests { - ivt := &IntervalTree{} + ivt := NewIntervalTree() for _, ivl := range tt.ivls { ivt.Insert(ivl, struct{}{}) } @@ -217,7 +217,7 @@ func TestIntervalTreeVisitExit(t *testing.T) { } for i, tt := range tests { - ivt := &IntervalTree{} + ivt := NewIntervalTree() for _, ivl := range ivls { ivt.Insert(ivl, struct{}{}) } @@ -284,7 +284,7 @@ func TestIntervalTreeContains(t *testing.T) { }, } for i, tt := range tests { - ivt := &IntervalTree{} + ivt := NewIntervalTree() for _, ivl := range tt.ivls { ivt.Insert(ivl, struct{}{}) } @@ -293,3 +293,172 @@ func TestIntervalTreeContains(t *testing.T) { } } } + +func (ivt *IntervalTree) levelOrder() [][]*intervalNode { + levels := make([][]*intervalNode, ivt.Height()) + + queue := []*intervalNode{ivt.root} + cur, last := 0, 1 + level := 0 + for cur < len(queue) { + last = len(queue) + levels[level] = []*intervalNode{} + for cur < last { + levels[level] = append(levels[level], queue[cur]) + if queue[cur].left != ivt.nilNode { + queue = append(queue, queue[cur].left) + } + if queue[cur].right != ivt.nilNode { + queue = append(queue, queue[cur].right) + } + cur++ + } + + level++ + } + + return levels +} + +// TestIntervalTreeDeleteFixUp tests that delete some interval the tree is red-black tree +func TestIntervalTreeDeleteFixUp(t *testing.T) { + ivt := NewIntervalTree() + ivt.Insert(NewInt64Interval(510, 511), 123) + ivt.Insert(NewInt64Interval(82, 83), 456) + ivt.Insert(NewInt64Interval(830, 831), 789) + ivt.Insert(NewInt64Interval(11, 12), 999) + ivt.Insert(NewInt64Interval(383, 384), 1) + ivt.Insert(NewInt64Interval(647, 648), 2) + ivt.Insert(NewInt64Interval(899, 900), 3) + ivt.Insert(NewInt64Interval(261, 262), 4) + ivt.Insert(NewInt64Interval(410, 411), 5) + ivt.Insert(NewInt64Interval(514, 515), 6) + ivt.Insert(NewInt64Interval(815, 816), 7) + ivt.Insert(NewInt64Interval(888, 889), 8) + ivt.Insert(NewInt64Interval(972, 973), 9) + ivt.Insert(NewInt64Interval(238, 239), 10) + ivt.Insert(NewInt64Interval(292, 293), 11) + ivt.Insert(NewInt64Interval(953, 954), 12) + + type intervalNodeValue struct { + node *intervalNode + c rbcolor + } + + rawTreeLevels := make([][]*intervalNodeValue, ivt.Height()) + + rawTreeLevels[0] = []*intervalNodeValue{ + {&intervalNode{iv: IntervalValue{NewInt64Interval(510, 511), 123}}, black}, + } + + rawTreeLevels[1] = []*intervalNodeValue{ + {&intervalNode{iv: IntervalValue{NewInt64Interval(82, 83), 456}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(830, 831), 789}}, black}, + } + + rawTreeLevels[2] = []*intervalNodeValue{ + {&intervalNode{iv: IntervalValue{NewInt64Interval(11, 12), 999}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(383, 384), 1}}, red}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(647, 648), 2}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(899, 900), 3}}, red}, + } + + rawTreeLevels[3] = []*intervalNodeValue{ + {&intervalNode{iv: IntervalValue{NewInt64Interval(261, 262), 4}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(410, 411), 5}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(514, 515), 6}}, red}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(815, 816), 7}}, red}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(888, 889), 8}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(972, 973), 9}}, black}, + } + + rawTreeLevels[4] = []*intervalNodeValue{ + {&intervalNode{iv: IntervalValue{NewInt64Interval(238, 239), 10}}, red}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(292, 293), 11}}, red}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(953, 954), 12}}, red}, + } + + // {Ivl:{Begin:510 End:511} Val:123} + // {Ivl:{Begin:82 End:83} Val:456}{Ivl:{Begin:830 End:831} Val:789} + // {Ivl:{Begin:11 End:12} Val:999}{Ivl:{Begin:383 End:384} Val:1}{Ivl:{Begin:647 End:648} Val:2}{Ivl:{Begin:899 End:900} Val:3} + // {Ivl:{Begin:261 End:262} Val:4}{Ivl:{Begin:410 End:411} Val:5}{Ivl:{Begin:514 End:515} Val:6}{Ivl:{Begin:815 End:816} Val:7}{Ivl:{Begin:888 End:889} Val:8}{Ivl:{Begin:972 End:973} Val:9} + // {Ivl:{Begin:238 End:239} Val:10}{Ivl:{Begin:292 End:293} Val:11}{Ivl:{Begin:953 End:954} Val:12} + + levels := ivt.levelOrder() + for i, curLevels := range levels { + if len(curLevels) != len(rawTreeLevels[i]) { + t.Errorf("#%d: interval tree level, expected %d=%d", i, len(curLevels), len(rawTreeLevels[i])) + } + for j, node := range curLevels { + if node.iv.Ivl.Begin.Compare(rawTreeLevels[i][j].node.iv.Ivl.Begin) != 0 || + node.iv.Ivl.End.Compare(rawTreeLevels[i][j].node.iv.Ivl.End) != 0 || + node.c != rawTreeLevels[i][j].c { + t.Errorf("interval node expected same, but %+v != %+v", node, rawTreeLevels[i][j].node) + } + } + } + + ivt.Delete(NewInt64Interval(514, 515)) + + // After Delete (514, 515) node: + // {Ivl:{Begin:510 End:511} Val:123} + // {Ivl:{Begin:82 End:83} Val:456}{Ivl:{Begin:830 End:831} Val:789} + // {Ivl:{Begin:11 End:12} Val:999}{Ivl:{Begin:383 End:384} Val:1}{Ivl:{Begin:647 End:648} Val:2}{Ivl:{Begin:899 End:900} Val:3} + // {Ivl:{Begin:261 End:262} Val:4}{Ivl:{Begin:410 End:411} Val:5}{Ivl:{Begin:815 End:816} Val:7}{Ivl:{Begin:888 End:889} Val:8}{Ivl:{Begin:972 End:973} Val:9} + // {Ivl:{Begin:238 End:239} Val:10}{Ivl:{Begin:292 End:293} Val:11}{Ivl:{Begin:953 End:954} Val:12} + + ivt.Delete(NewInt64Interval(11, 12)) + + // After Delete (11, 12) node: + // {Ivl:{Begin:510 End:511} Val:123} + // {Ivl:{Begin:383 End:384} Val:1}{Ivl:{Begin:830 End:831} Val:789} + // {Ivl:{Begin:261 End:262} Val:4}{Ivl:{Begin:410 End:411} Val:5}{Ivl:{Begin:647 End:648} Val:2}{Ivl:{Begin:899 End:900} Val:3} + // {Ivl:{Begin:82 End:83} Val:456}{Ivl:{Begin:292 End:293} Val:11}{Ivl:{Begin:815 End:816} Val:7}{Ivl:{Begin:888 End:889} Val:8}{Ivl:{Begin:972 End:973} Val:9} + // {Ivl:{Begin:238 End:239} Val:10}{Ivl:{Begin:953 End:954} Val:12} + + delTreeLevels := make([][]*intervalNodeValue, ivt.Height()) + + delTreeLevels[0] = []*intervalNodeValue{ + {&intervalNode{iv: IntervalValue{NewInt64Interval(510, 511), 123}}, black}, + } + + delTreeLevels[1] = []*intervalNodeValue{ + {&intervalNode{iv: IntervalValue{NewInt64Interval(383, 384), 1}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(830, 831), 789}}, black}, + } + + delTreeLevels[2] = []*intervalNodeValue{ + {&intervalNode{iv: IntervalValue{NewInt64Interval(261, 262), 4}}, red}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(410, 411), 5}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(647, 648), 2}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(899, 900), 3}}, red}, + } + + delTreeLevels[3] = []*intervalNodeValue{ + {&intervalNode{iv: IntervalValue{NewInt64Interval(82, 83), 456}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(292, 293), 11}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(815, 816), 7}}, red}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(888, 889), 8}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(972, 973), 9}}, black}, + } + + delTreeLevels[4] = []*intervalNodeValue{ + {&intervalNode{iv: IntervalValue{NewInt64Interval(238, 239), 10}}, red}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(953, 954), 12}}, red}, + } + + levels = ivt.levelOrder() + + for i, curLevels := range levels { + if len(curLevels) != len(delTreeLevels[i]) { + t.Errorf("#%d: interval tree level, expected %d=%d", i, len(curLevels), len(delTreeLevels[i])) + } + for j, node := range curLevels { + if node.iv.Ivl.Begin.Compare(delTreeLevels[i][j].node.iv.Ivl.Begin) != 0 || + node.iv.Ivl.End.Compare(delTreeLevels[i][j].node.iv.Ivl.End) != 0 || + node.c != delTreeLevels[i][j].c { + t.Errorf("interval node expected same, but %+v != %+v", node, delTreeLevels[i][j].node) + } + } + } +} diff --git a/proxy/grpcproxy/cache/store.go b/proxy/grpcproxy/cache/store.go index 1f9688b895f..b0039ca2fb4 100644 --- a/proxy/grpcproxy/cache/store.go +++ b/proxy/grpcproxy/cache/store.go @@ -53,6 +53,7 @@ func keyFunc(req *pb.RangeRequest) string { func NewCache(maxCacheEntries int) Cache { return &cache{ lru: lru.New(maxCacheEntries), + cachedRanges: adt.NewIntervalTree(), compactedRev: -1, } } @@ -65,7 +66,7 @@ type cache struct { lru *lru.Cache // a reverse index for cache invalidation - cachedRanges adt.IntervalTree + cachedRanges *adt.IntervalTree compactedRev int64 }