Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: interval tree complete implemention based on red-black tree #10881

Closed
wants to merge 8 commits into from
Closed

Fix: interval tree complete implemention based on red-black tree #10881

wants to merge 8 commits into from

Conversation

xkeyideal
Copy link

#10877

Fixed interval tree

@@ -425,14 +475,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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not found, does find() return nil or nilNode?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

find() function return is nilNode, it is private function, I think its ok.

please help me check the code

@codecov-io
Copy link

codecov-io commented Jul 11, 2019

Codecov Report

Merging #10881 into master will increase coverage by 1.72%.
The diff coverage is 94.44%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master   #10881      +/-   ##
==========================================
+ Coverage   62.14%   63.86%   +1.72%     
==========================================
  Files         398      401       +3     
  Lines       37483    37483              
==========================================
+ Hits        23293    23939     +646     
+ Misses      12597    11930     -667     
- Partials     1593     1614      +21
Impacted Files Coverage Δ
proxy/grpcproxy/cache/store.go 91.54% <100%> (+0.12%) ⬆️
etcdserver/api/v3rpc/key.go 80.28% <100%> (ø) ⬆️
auth/range_perm_cache.go 60.75% <100%> (ø) ⬆️
mvcc/watcher_group.go 89.7% <100%> (+0.07%) ⬆️
pkg/adt/interval_tree.go 93.02% <94.04%> (+9.23%) ⬆️
client/client.go 53.26% <0%> (-11.77%) ⬇️
proxy/grpcproxy/watcher.go 85.71% <0%> (-8.17%) ⬇️
pkg/tlsutil/tlsutil.go 86.2% <0%> (-6.9%) ⬇️
raft/node.go 89.47% <0%> (-4.21%) ⬇️
raft/tracker/inflights.go 91.83% <0%> (-3.72%) ⬇️
... and 57 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0af1697...d915387. Read the comment docs.

@xkeyideal
Copy link
Author

@jingyih I had change the find function bugs, but Travis CI failed, please help see it.

@jingyih
Copy link
Contributor

jingyih commented Jul 12, 2019

https://travis-ci.com/etcd-io/etcd/jobs/215119452
This failed due to formatting issue. Can you gofmt the file you modified?

https://travis-ci.com/etcd-io/etcd/jobs/215119455
This failed due to some known flaky tests. It is unrelated to this PR.

@xkeyideal
Copy link
Author

@jingyih

Thank for your help.

This PR CI had passed.

@xkeyideal
Copy link
Author

The interval tree code visit() will call a node visitor on each node that overlaps the given interval.

can your optimize the function performance

@jingyih
Copy link
Contributor

jingyih commented Jul 12, 2019

@xiang90 PTAL.

@gyuho gyuho mentioned this pull request Jul 26, 2019
19 tasks
@@ -34,3 +34,5 @@ vendor/**/*
vendor/**/*_test.go

*.bak

.vscode/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line

@@ -171,45 +171,60 @@ type IntervalValue struct {
type IntervalTree struct {
root *intervalNode
count int

// red-black NIL node, can not use golang nil instead
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you explain why we cannot use golang nil to represent the NIL node? If we do need a NIL node instance for comparison, shall we make it a package global variable so that we do not need to pass it around?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xiang90 See the issue #10877 , when delete node 11, if use golang nil instead of rbtree NIL node, the tree is not rbtree.

Because of delete node 11, the NIL node should be coloring double black, but use golang nil will nothing to do.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xiang90
Because of the tree is also Binary Search Tree, so the code all cases are right.
image
The Introduction to algorithms tell us when delete leaf black node, then NIL node will be double black.

Red-black tree nature 5: For each node, the same number of black nodes are included on the path of the node nodes after reaching the node.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xiang90 The NIL node can not a package global variable. It's a pointer variable, there are many trees.

@gyuho gyuho self-assigned this Jul 30, 2019
@gyuho
Copy link
Contributor

gyuho commented Jul 30, 2019

@xkeyideal @xiang90 @jingyih I am writing a test case to validate the fix. Will cherry-pick this patch with some clean up + documentation.

@@ -353,45 +367,54 @@ func (ivt *IntervalTree) insertFixup(z *intervalNode) {

// rotateLeft moves x so it is left of its right child
func (ivt *IntervalTree) rotateLeft(x *intervalNode) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this empty line

func (ivt *IntervalTree) rotateRight(x *intervalNode) {
if x == nil {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

if n.iv.Ivl != ivl {
return true
func (ivt *IntervalTree) find(ivl Interval) *intervalNode {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

f := func(n *IntervalValue) bool {
ivt.Insert(n.Ivl, n.Val)
return true
}
inIvt.Visit(ivl, f)
}

func (ivt *IntervalTree) LevelOrder() [][]*intervalNode {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this only used by test? if so, move this to test file.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will change.

f := func(n *IntervalValue) bool {
ivt.Insert(n.Ivl, n.Val)
return true
}
inIvt.Visit(ivl, f)
}

func (ivt *IntervalTree) LevelOrder() [][]*intervalNode {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove empty line

{&intervalNode{iv: IntervalValue{NewInt64Interval(953, 954), 12}}, red},
}

/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use go style comment. do not use /*, use // instead.

}
ivt.root.visit(&ivl, f)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just call visit as before?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the visit function maybe visit all nodes for find one node, the new find function use BST nature can prune, but when find left interval same, the must use visit function visit the subtree all nodes for find the node

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this is an optimization, can we move this to a separate PR?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is just make it better, not optimization

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Then can we not include this enhancement in this PR?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, the change the find function just use visit

@xkeyideal
Copy link
Author

@xiang90 Please help me see the Travis CI why not build failed.

@gyuho
Copy link
Contributor

gyuho commented Jul 31, 2019

This doesn't seem to fix the issue. Let me rework on this.

@gyuho
Copy link
Contributor

gyuho commented Aug 1, 2019

@xkeyideal I tried your patch with sentinel node. It fixes the delete operation maintaining the black-height properties, but it breaks visit operation thus breaking contains and stab methods. Could you take a look #10965 and try again with latest changes? I refactored the code with failure test cases from this PR. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

5 participants