From e9d204dc140fac711208ea1fce8f426b4dd32ac8 Mon Sep 17 00:00:00 2001 From: xkey Date: Tue, 9 Jul 2019 15:28:01 +0800 Subject: [PATCH 1/8] fix: interval tree complete implemention based on red-black tree --- .gitignore | 2 + auth/range_perm_cache.go | 4 +- auth/range_perm_cache_test.go | 4 +- etcdserver/api/v3rpc/key.go | 4 +- mvcc/watcher_group.go | 2 +- pkg/adt/example_test.go | 2 +- pkg/adt/interval_tree.go | 213 ++++++++++++++++++++++----------- pkg/adt/interval_tree_test.go | 164 +++++++++++++++++++++++-- proxy/grpcproxy/cache/store.go | 2 +- 9 files changed, 309 insertions(+), 88 deletions(-) diff --git a/.gitignore b/.gitignore index 32cf78e898d..8dcacdee4b4 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ 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..49afd3b8696 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 } 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..a6aff9bb891 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,45 +171,65 @@ 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.left = tree.root + tree.nilNode.right = tree.root + tree.nilNode.parent = tree.root + 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 { + if x == 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 + ivt.nilNode.left = ivt.root + ivt.nilNode.right = ivt.root + ivt.nilNode.parent = ivt.root } else { if y == y.parent.left { y.parent.left = x } 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() == black && x != nil { + if y.color(ivt.nilNode) == black && !(x == ivt.nilNode && x.parent == ivt.nilNode) { ivt.deleteFixup(x) } @@ -218,29 +238,29 @@ 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 { + if w == ivt.nilNode { 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 +269,26 @@ 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 { + if w == ivt.nilNode { 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 +296,23 @@ func (ivt *IntervalTree) deleteFixup(x *intervalNode) { } } } - if x != nil { - x.c = black - } + //if x != nil { + 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, + } 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,15 +322,19 @@ func (ivt *IntervalTree) Insert(ivl Interval, val interface{}) { } z.parent = y - if y == nil { + if y == ivt.nilNode { ivt.root = z + ivt.root.parent = ivt.nilNode + ivt.nilNode.parent = ivt.root + ivt.nilNode.left = ivt.root + ivt.nilNode.right = ivt.root } else { if z.iv.Ivl.Begin.Compare(y.iv.Ivl.Begin) < 0 { y.left = z } else { y.right = z } - y.updateMax() + y.updateMax(ivt.nilNode) } z.c = red ivt.insertFixup(z) @@ -312,10 +342,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 +362,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,45 +383,57 @@ 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 == ivt.nilNode || 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 == ivt.nilNode || 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 + ivt.nilNode.left = ivt.root + ivt.nilNode.right = ivt.root + ivt.nilNode.parent = ivt.root } else { if x == x.parent.left { x.parent.left = y } else { x.parent.right = y } - x.parent.updateMax() + x.parent.updateMax(ivt.nilNode) } x.parent = y } @@ -400,7 +442,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,7 +455,7 @@ 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 @@ -425,14 +467,14 @@ 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 +483,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 +528,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 @@ -494,6 +536,33 @@ func (ivt *IntervalTree) Union(inIvt IntervalTree, ivl Interval) { inIvt.Visit(ivl, f) } +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 +} + type StringComparable string func (s StringComparable) Compare(c Comparable) int { diff --git a/pkg/adt/interval_tree_test.go b/pkg/adt/interval_tree_test.go index 493c11fa0b3..6ba25d0793b 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,153 @@ func TestIntervalTreeContains(t *testing.T) { } } } + +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{ + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(510, 511), 123}}, black}, + } + + rawTreeLevels[1] = []*intervalNodeValue{ + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(82, 83), 456}}, black}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(830, 831), 789}}, black}, + } + + rawTreeLevels[2] = []*intervalNodeValue{ + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(11, 12), 999}}, black}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(383, 384), 1}}, red}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(647, 648), 2}}, black}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(899, 900), 3}}, red}, + } + + rawTreeLevels[3] = []*intervalNodeValue{ + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(261, 262), 4}}, black}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(410, 411), 5}}, black}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(514, 515), 6}}, red}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(815, 816), 7}}, red}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(888, 889), 8}}, black}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(972, 973), 9}}, black}, + } + + rawTreeLevels[4] = []*intervalNodeValue{ + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(238, 239), 10}}, red}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(292, 293), 11}}, red}, + &intervalNodeValue{&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{ + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(510, 511), 123}}, black}, + } + + delTreeLevels[1] = []*intervalNodeValue{ + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(383, 384), 1}}, black}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(830, 831), 789}}, black}, + } + + delTreeLevels[2] = []*intervalNodeValue{ + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(261, 262), 4}}, red}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(410, 411), 5}}, black}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(647, 648), 2}}, black}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(899, 900), 3}}, red}, + } + + delTreeLevels[3] = []*intervalNodeValue{ + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(82, 83), 456}}, black}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(292, 293), 11}}, black}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(815, 816), 7}}, red}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(888, 889), 8}}, black}, + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(972, 973), 9}}, black}, + } + + delTreeLevels[4] = []*intervalNodeValue{ + &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(238, 239), 10}}, red}, + &intervalNodeValue{&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..73e90ec667b 100644 --- a/proxy/grpcproxy/cache/store.go +++ b/proxy/grpcproxy/cache/store.go @@ -65,7 +65,7 @@ type cache struct { lru *lru.Cache // a reverse index for cache invalidation - cachedRanges adt.IntervalTree + cachedRanges *adt.IntervalTree compactedRev int64 } From dd7a62d3388f6a713f0f1deb02a812128d15e8ab Mon Sep 17 00:00:00 2001 From: xkey Date: Tue, 9 Jul 2019 22:40:04 +0800 Subject: [PATCH 2/8] fix: interval tree --- mvcc/watcher_group.go | 1 + pkg/adt/interval_tree.go | 66 +++++++++++++++++++--------------- proxy/grpcproxy/cache/store.go | 1 + 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/mvcc/watcher_group.go b/mvcc/watcher_group.go index 49afd3b8696..3d480606e4d 100644 --- a/mvcc/watcher_group.go +++ b/mvcc/watcher_group.go @@ -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/interval_tree.go b/pkg/adt/interval_tree.go index a6aff9bb891..5dafd8908bd 100644 --- a/pkg/adt/interval_tree.go +++ b/pkg/adt/interval_tree.go @@ -182,9 +182,9 @@ func NewIntervalTree() *IntervalTree { tree.nilNode = &intervalNode{} tree.root = tree.nilNode - tree.nilNode.left = tree.root - tree.nilNode.right = tree.root - tree.nilNode.parent = tree.root + //tree.nilNode.left = tree.root + //tree.nilNode.right = tree.root + //tree.nilNode.parent = tree.root tree.nilNode.c = black return tree @@ -203,8 +203,14 @@ func (ivt *IntervalTree) Delete(ivl Interval) bool { y = z.successor(ivt.nilNode) } - x := y.left - if x == ivt.nilNode { + // x := y.left + // if x == ivt.nilNode { + // x = y.right + // } + x := ivt.nilNode + if y.left != ivt.nilNode { + x = y.left + } else if y.right != ivt.nilNode { x = y.right } @@ -212,9 +218,9 @@ func (ivt *IntervalTree) Delete(ivl Interval) bool { if y.parent == ivt.nilNode { ivt.root = x - ivt.nilNode.left = ivt.root - ivt.nilNode.right = ivt.root - ivt.nilNode.parent = ivt.root + //ivt.nilNode.left = ivt.root + //ivt.nilNode.right = ivt.root + //ivt.nilNode.parent = ivt.root } else { if y == y.parent.left { y.parent.left = x @@ -229,7 +235,7 @@ func (ivt *IntervalTree) Delete(ivl Interval) bool { } //if y.color() == black && x != nil { - if y.color(ivt.nilNode) == black && !(x == ivt.nilNode && x.parent == ivt.nilNode) { + if y.color(ivt.nilNode) == black { //&& !(x == ivt.nilNode && x.parent == ivt.nilNode) { ivt.deleteFixup(x) } @@ -247,9 +253,9 @@ func (ivt *IntervalTree) deleteFixup(x *intervalNode) { ivt.rotateLeft(x.parent) w = x.parent.right } - if w == ivt.nilNode { - break - } + // if w == ivt.nilNode { + // break + // } if w.left.color(ivt.nilNode) == black && w.right.color(ivt.nilNode) == black { w.c = red x = x.parent @@ -275,9 +281,9 @@ func (ivt *IntervalTree) deleteFixup(x *intervalNode) { ivt.rotateRight(x.parent) w = x.parent.left } - if w == ivt.nilNode { - break - } + // if w == ivt.nilNode { + // break + // } if w.left.color(ivt.nilNode) == black && w.right.color(ivt.nilNode) == black { w.c = red x = x.parent @@ -297,6 +303,7 @@ func (ivt *IntervalTree) deleteFixup(x *intervalNode) { } } //if x != nil { + //ivt.nilNode.parent = ivt.root x.c = black //} } @@ -305,11 +312,12 @@ func (ivt *IntervalTree) deleteFixup(x *intervalNode) { func (ivt *IntervalTree) Insert(ivl Interval, val interface{}) { y := ivt.nilNode z := &intervalNode{ - iv: IntervalValue{ivl, val}, - max: ivl.End, - c: red, - left: ivt.nilNode, - right: ivt.nilNode, + iv: IntervalValue{ivl, val}, + max: ivl.End, + c: red, + left: ivt.nilNode, + right: ivt.nilNode, + parent: ivt.nilNode, } x := ivt.root for x != ivt.nilNode { @@ -324,10 +332,10 @@ func (ivt *IntervalTree) Insert(ivl Interval, val interface{}) { z.parent = y if y == ivt.nilNode { ivt.root = z - ivt.root.parent = ivt.nilNode - ivt.nilNode.parent = ivt.root - ivt.nilNode.left = ivt.root - ivt.nilNode.right = ivt.root + //ivt.root.parent = ivt.nilNode + //ivt.nilNode.parent = ivt.root + //ivt.nilNode.left = ivt.root + //ivt.nilNode.right = ivt.root } else { if z.iv.Ivl.Begin.Compare(y.iv.Ivl.Begin) < 0 { y.left = z @@ -385,7 +393,7 @@ func (ivt *IntervalTree) insertFixup(z *intervalNode) { func (ivt *IntervalTree) rotateLeft(x *intervalNode) { // rotateLeft x must have right child - if x == ivt.nilNode || x.right == ivt.nilNode { + if x.right == ivt.nilNode { return } @@ -404,7 +412,7 @@ func (ivt *IntervalTree) rotateLeft(x *intervalNode) { func (ivt *IntervalTree) rotateRight(x *intervalNode) { // rotateRight x must have left child - if x == ivt.nilNode || x.left == ivt.nilNode { + if x.left == ivt.nilNode { return } @@ -424,9 +432,9 @@ func (ivt *IntervalTree) replaceParent(x *intervalNode, y *intervalNode) { y.parent = x.parent if x.parent == ivt.nilNode { ivt.root = y - ivt.nilNode.left = ivt.root - ivt.nilNode.right = ivt.root - ivt.nilNode.parent = ivt.root + //ivt.nilNode.left = ivt.root + //ivt.nilNode.right = ivt.root + //ivt.nilNode.parent = ivt.root } else { if x == x.parent.left { x.parent.left = y diff --git a/proxy/grpcproxy/cache/store.go b/proxy/grpcproxy/cache/store.go index 73e90ec667b..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, } } From c62f5b7c3e971dea892771d72154fc2f05ca0890 Mon Sep 17 00:00:00 2001 From: xkey Date: Thu, 11 Jul 2019 16:31:56 +0800 Subject: [PATCH 3/8] fix: interval tree --- pkg/adt/interval_tree.go | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/pkg/adt/interval_tree.go b/pkg/adt/interval_tree.go index 5dafd8908bd..e656fc698d6 100644 --- a/pkg/adt/interval_tree.go +++ b/pkg/adt/interval_tree.go @@ -468,15 +468,32 @@ func (ivt *IntervalTree) Visit(ivl Interval, ivv IntervalVisitor) { // find the exact node for a given interval func (ivt *IntervalTree) find(ivl Interval) (ret *intervalNode) { - f := func(n *intervalNode) bool { - if n.iv.Ivl != ivl { - return true + // f := func(n *intervalNode) bool { + // if n.iv.Ivl != ivl { + // return true + // } + // ret = n + // return false + // } + // ivt.root.visit(&ivl, ivt.nilNode, f) + + x := ivt.root + + for x != ivt.nilNode { + if ivl.Begin.Compare(x.iv.Ivl.Begin) == 0 && ivl.End.Compare(x.iv.Ivl.End) == 0 { + break + } + + if ivl.End.Compare(x.max) > 0 { + x = ivt.nilNode + } else if ivl.Begin.Compare(x.iv.Ivl.Begin) < 0 { + x = x.left + } else { + x = x.right } - ret = n - return false } - ivt.root.visit(&ivl, ivt.nilNode, f) - return ret + + return x } // Find gets the IntervalValue for the node matching the given interval From a2d04751f2e86141264e399cd3c3dbb15ebef58d Mon Sep 17 00:00:00 2001 From: xkey Date: Thu, 11 Jul 2019 18:06:49 +0800 Subject: [PATCH 4/8] fix: interval tree find the exact node same Begin not found bugs --- pkg/adt/interval_tree.go | 68 ++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/pkg/adt/interval_tree.go b/pkg/adt/interval_tree.go index e656fc698d6..3f60948e44b 100644 --- a/pkg/adt/interval_tree.go +++ b/pkg/adt/interval_tree.go @@ -182,9 +182,6 @@ func NewIntervalTree() *IntervalTree { tree.nilNode = &intervalNode{} tree.root = tree.nilNode - //tree.nilNode.left = tree.root - //tree.nilNode.right = tree.root - //tree.nilNode.parent = tree.root tree.nilNode.c = black return tree @@ -203,10 +200,6 @@ func (ivt *IntervalTree) Delete(ivl Interval) bool { y = z.successor(ivt.nilNode) } - // x := y.left - // if x == ivt.nilNode { - // x = y.right - // } x := ivt.nilNode if y.left != ivt.nilNode { x = y.left @@ -218,9 +211,6 @@ func (ivt *IntervalTree) Delete(ivl Interval) bool { if y.parent == ivt.nilNode { ivt.root = x - //ivt.nilNode.left = ivt.root - //ivt.nilNode.right = ivt.root - //ivt.nilNode.parent = ivt.root } else { if y == y.parent.left { y.parent.left = x @@ -234,8 +224,7 @@ func (ivt *IntervalTree) Delete(ivl Interval) bool { z.updateMax(ivt.nilNode) } - //if y.color() == black && x != nil { - if y.color(ivt.nilNode) == black { //&& !(x == ivt.nilNode && x.parent == ivt.nilNode) { + if y.color(ivt.nilNode) == black { ivt.deleteFixup(x) } @@ -253,9 +242,6 @@ func (ivt *IntervalTree) deleteFixup(x *intervalNode) { ivt.rotateLeft(x.parent) w = x.parent.right } - // if w == ivt.nilNode { - // break - // } if w.left.color(ivt.nilNode) == black && w.right.color(ivt.nilNode) == black { w.c = red x = x.parent @@ -281,9 +267,6 @@ func (ivt *IntervalTree) deleteFixup(x *intervalNode) { ivt.rotateRight(x.parent) w = x.parent.left } - // if w == ivt.nilNode { - // break - // } if w.left.color(ivt.nilNode) == black && w.right.color(ivt.nilNode) == black { w.c = red x = x.parent @@ -302,10 +285,7 @@ func (ivt *IntervalTree) deleteFixup(x *intervalNode) { } } } - //if x != nil { - //ivt.nilNode.parent = ivt.root x.c = black - //} } // Insert adds a node with the given interval into the tree. @@ -332,10 +312,6 @@ func (ivt *IntervalTree) Insert(ivl Interval, val interface{}) { z.parent = y if y == ivt.nilNode { ivt.root = z - //ivt.root.parent = ivt.nilNode - //ivt.nilNode.parent = ivt.root - //ivt.nilNode.left = ivt.root - //ivt.nilNode.right = ivt.root } else { if z.iv.Ivl.Begin.Compare(y.iv.Ivl.Begin) < 0 { y.left = z @@ -432,9 +408,6 @@ func (ivt *IntervalTree) replaceParent(x *intervalNode, y *intervalNode) { y.parent = x.parent if x.parent == ivt.nilNode { ivt.root = y - //ivt.nilNode.left = ivt.root - //ivt.nilNode.right = ivt.root - //ivt.nilNode.parent = ivt.root } else { if x == x.parent.left { x.parent.left = y @@ -468,29 +441,48 @@ func (ivt *IntervalTree) Visit(ivl Interval, ivv IntervalVisitor) { // find the exact node for a given interval func (ivt *IntervalTree) find(ivl Interval) (ret *intervalNode) { - // f := func(n *intervalNode) bool { - // if n.iv.Ivl != ivl { - // return true - // } - // ret = n - // return false - // } - // ivt.root.visit(&ivl, ivt.nilNode, f) x := ivt.root + ok := false for x != ivt.nilNode { if ivl.Begin.Compare(x.iv.Ivl.Begin) == 0 && ivl.End.Compare(x.iv.Ivl.End) == 0 { + ok = true break } if ivl.End.Compare(x.max) > 0 { x = ivt.nilNode - } else if ivl.Begin.Compare(x.iv.Ivl.Begin) < 0 { + break + } + + if ivl.Begin.Compare(x.iv.Ivl.Begin) < 0 { x = x.left - } else { + continue + } + + if ivl.Begin.Compare(x.iv.Ivl.Begin) > 0 { x = x.right + continue + } + + // when ivt.Begin == x.iv.Ivl.Begin need visit all nodes x-subtree + break + } + + if !ok { + ret := ivt.nilNode + f := func(n *intervalNode) bool { + if n.iv.Ivl != ivl { + return true + } + ret = n + return false } + + x.visit(&ivl, ivt.nilNode, f) + + return ret } return x From 16a17bb3d43c5440e0fd162f22eebdf43d1028ed Mon Sep 17 00:00:00 2001 From: xkey Date: Thu, 11 Jul 2019 18:45:24 +0800 Subject: [PATCH 5/8] fix: find exact node --- pkg/adt/interval_tree.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/adt/interval_tree.go b/pkg/adt/interval_tree.go index 3f60948e44b..a84e6dd6f18 100644 --- a/pkg/adt/interval_tree.go +++ b/pkg/adt/interval_tree.go @@ -440,7 +440,7 @@ func (ivt *IntervalTree) Visit(ivl Interval, ivv IntervalVisitor) { } // find the exact node for a given interval -func (ivt *IntervalTree) find(ivl Interval) (ret *intervalNode) { +func (ivt *IntervalTree) find(ivl Interval) *intervalNode { x := ivt.root From f1218d78f17a46059b8bb46af3b7a4c2032ebf8d Mon Sep 17 00:00:00 2001 From: xkey Date: Fri, 12 Jul 2019 10:52:26 +0800 Subject: [PATCH 6/8] fix: gofmt checking failed: pkg/adt/interval_tree_test.go --- pkg/adt/interval_tree.go | 1 + pkg/adt/interval_tree_test.go | 95 ++++++++++++++++++----------------- 2 files changed, 49 insertions(+), 47 deletions(-) diff --git a/pkg/adt/interval_tree.go b/pkg/adt/interval_tree.go index a84e6dd6f18..2c8b665a605 100644 --- a/pkg/adt/interval_tree.go +++ b/pkg/adt/interval_tree.go @@ -452,6 +452,7 @@ func (ivt *IntervalTree) find(ivl Interval) *intervalNode { } if ivl.End.Compare(x.max) > 0 { + ok = true x = ivt.nilNode break } diff --git a/pkg/adt/interval_tree_test.go b/pkg/adt/interval_tree_test.go index 6ba25d0793b..bc418febec3 100644 --- a/pkg/adt/interval_tree_test.go +++ b/pkg/adt/interval_tree_test.go @@ -294,6 +294,7 @@ func TestIntervalTreeContains(t *testing.T) { } } +// 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) @@ -321,42 +322,42 @@ func TestIntervalTreeDeleteFixUp(t *testing.T) { rawTreeLevels := make([][]*intervalNodeValue, ivt.Height()) rawTreeLevels[0] = []*intervalNodeValue{ - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(510, 511), 123}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(510, 511), 123}}, black}, } rawTreeLevels[1] = []*intervalNodeValue{ - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(82, 83), 456}}, black}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(830, 831), 789}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(82, 83), 456}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(830, 831), 789}}, black}, } rawTreeLevels[2] = []*intervalNodeValue{ - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(11, 12), 999}}, black}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(383, 384), 1}}, red}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(647, 648), 2}}, black}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(899, 900), 3}}, red}, + {&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{ - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(261, 262), 4}}, black}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(410, 411), 5}}, black}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(514, 515), 6}}, red}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(815, 816), 7}}, red}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(888, 889), 8}}, black}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(972, 973), 9}}, black}, + {&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{ - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(238, 239), 10}}, red}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(292, 293), 11}}, red}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(953, 954), 12}}, red}, + {&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} + {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() @@ -376,56 +377,56 @@ func TestIntervalTreeDeleteFixUp(t *testing.T) { ivt.Delete(NewInt64Interval(514, 515)) /* - After Delete (514, 515) node: + 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} + {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: + 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} + {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{ - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(510, 511), 123}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(510, 511), 123}}, black}, } delTreeLevels[1] = []*intervalNodeValue{ - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(383, 384), 1}}, black}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(830, 831), 789}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(383, 384), 1}}, black}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(830, 831), 789}}, black}, } delTreeLevels[2] = []*intervalNodeValue{ - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(261, 262), 4}}, red}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(410, 411), 5}}, black}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(647, 648), 2}}, black}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(899, 900), 3}}, red}, + {&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{ - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(82, 83), 456}}, black}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(292, 293), 11}}, black}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(815, 816), 7}}, red}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(888, 889), 8}}, black}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(972, 973), 9}}, black}, + {&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{ - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(238, 239), 10}}, red}, - &intervalNodeValue{&intervalNode{iv: IntervalValue{NewInt64Interval(953, 954), 12}}, red}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(238, 239), 10}}, red}, + {&intervalNode{iv: IntervalValue{NewInt64Interval(953, 954), 12}}, red}, } levels = ivt.LevelOrder() From d736a7b6e59825fd20bddd6fd26456f1a6046e1c Mon Sep 17 00:00:00 2001 From: xkey Date: Tue, 30 Jul 2019 10:12:40 +0800 Subject: [PATCH 7/8] fix: pr code use go style --- .gitignore | 1 - pkg/adt/interval_tree.go | 30 --------------- pkg/adt/interval_tree_test.go | 72 ++++++++++++++++++++++------------- 3 files changed, 45 insertions(+), 58 deletions(-) diff --git a/.gitignore b/.gitignore index 8dcacdee4b4..e697be8125c 100644 --- a/.gitignore +++ b/.gitignore @@ -34,5 +34,4 @@ vendor/**/* vendor/**/*_test.go *.bak - .vscode/ \ No newline at end of file diff --git a/pkg/adt/interval_tree.go b/pkg/adt/interval_tree.go index 2c8b665a605..99967197d5d 100644 --- a/pkg/adt/interval_tree.go +++ b/pkg/adt/interval_tree.go @@ -367,7 +367,6 @@ 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 @@ -386,7 +385,6 @@ func (ivt *IntervalTree) rotateLeft(x *intervalNode) { // rotateRight moves x so it is right of its left child func (ivt *IntervalTree) rotateRight(x *intervalNode) { - // rotateRight x must have left child if x.left == ivt.nilNode { return @@ -441,7 +439,6 @@ func (ivt *IntervalTree) Visit(ivl Interval, ivv IntervalVisitor) { // find the exact node for a given interval func (ivt *IntervalTree) find(ivl Interval) *intervalNode { - x := ivt.root ok := false @@ -554,33 +551,6 @@ func (ivt *IntervalTree) Union(inIvt *IntervalTree, ivl Interval) { inIvt.Visit(ivl, f) } -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 -} - type StringComparable string func (s StringComparable) Compare(c Comparable) int { diff --git a/pkg/adt/interval_tree_test.go b/pkg/adt/interval_tree_test.go index bc418febec3..2b3fcd92217 100644 --- a/pkg/adt/interval_tree_test.go +++ b/pkg/adt/interval_tree_test.go @@ -294,6 +294,32 @@ 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() @@ -352,15 +378,13 @@ func TestIntervalTreeDeleteFixUp(t *testing.T) { {&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} - */ + // {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() + 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])) @@ -376,27 +400,21 @@ func TestIntervalTreeDeleteFixUp(t *testing.T) { 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} - */ + // 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} - */ + // 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()) @@ -429,7 +447,7 @@ func TestIntervalTreeDeleteFixUp(t *testing.T) { {&intervalNode{iv: IntervalValue{NewInt64Interval(953, 954), 12}}, red}, } - levels = ivt.LevelOrder() + levels = ivt.levelOrder() for i, curLevels := range levels { if len(curLevels) != len(delTreeLevels[i]) { From d915387cd662b1407612ba84a86da9c90c28a0dc Mon Sep 17 00:00:00 2001 From: xkey Date: Tue, 30 Jul 2019 11:11:35 +0800 Subject: [PATCH 8/8] fix: change the find function use visit --- pkg/adt/interval_tree.go | 49 +++++++--------------------------------- 1 file changed, 8 insertions(+), 41 deletions(-) diff --git a/pkg/adt/interval_tree.go b/pkg/adt/interval_tree.go index 99967197d5d..7263604633f 100644 --- a/pkg/adt/interval_tree.go +++ b/pkg/adt/interval_tree.go @@ -439,51 +439,18 @@ func (ivt *IntervalTree) Visit(ivl Interval, ivv IntervalVisitor) { // find the exact node for a given interval func (ivt *IntervalTree) find(ivl Interval) *intervalNode { - x := ivt.root - - ok := false - for x != ivt.nilNode { - if ivl.Begin.Compare(x.iv.Ivl.Begin) == 0 && ivl.End.Compare(x.iv.Ivl.End) == 0 { - ok = true - break - } - - if ivl.End.Compare(x.max) > 0 { - ok = true - x = ivt.nilNode - break - } - - if ivl.Begin.Compare(x.iv.Ivl.Begin) < 0 { - x = x.left - continue - } - - if ivl.Begin.Compare(x.iv.Ivl.Begin) > 0 { - x = x.right - continue + ret := ivt.nilNode + f := func(n *intervalNode) bool { + if n.iv.Ivl != ivl { + return true } - - // when ivt.Begin == x.iv.Ivl.Begin need visit all nodes x-subtree - break + ret = n + return false } - if !ok { - ret := ivt.nilNode - f := func(n *intervalNode) bool { - if n.iv.Ivl != ivl { - return true - } - ret = n - return false - } - - x.visit(&ivl, ivt.nilNode, f) + ivt.root.visit(&ivl, ivt.nilNode, f) - return ret - } - - return x + return ret } // Find gets the IntervalValue for the node matching the given interval