-
Notifications
You must be signed in to change notification settings - Fork 10.1k
adt: split interval tree by right endpoint on matched left endpoints #19768
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -472,8 +472,16 @@ | |||||||||||||||||||||||||||||
x := ivt.root | ||||||||||||||||||||||||||||||
for x != ivt.sentinel { | ||||||||||||||||||||||||||||||
y = x | ||||||||||||||||||||||||||||||
if z.iv.Ivl.Begin.Compare(x.iv.Ivl.Begin) < 0 { | ||||||||||||||||||||||||||||||
// Split on left endpoint. If left endpoints match, instead split on right endpoint. | ||||||||||||||||||||||||||||||
beginCompare := z.iv.Ivl.Begin.Compare(x.iv.Ivl.Begin) | ||||||||||||||||||||||||||||||
if beginCompare < 0 { | ||||||||||||||||||||||||||||||
x = x.left | ||||||||||||||||||||||||||||||
} else if beginCompare == 0 { | ||||||||||||||||||||||||||||||
if z.iv.Ivl.End.Compare(x.iv.Ivl.End) < 0 { | ||||||||||||||||||||||||||||||
x = x.left | ||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||
x = x.right | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
Comment on lines
+479
to
+484
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You changed the behaviour, so it's a breaking change. Previously it only checks the interval's Now you not only checks the This PR's purpose is to optimize the exact search (find), I don't see a reason why update the Insert. So please consider to revert the change. Pls also see comment for the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ahrtr thanks very much for reviewing. So now I'm confused. The goal I had with this MR / issue is indeed to speed up There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
As mentioned above,
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you're proposing: keep the existing interval tree structure of splitting left if less than left endpoint, else split right. Update the With this logic I see the existing etcd interval tree tests fail. The issue is I think this approach doesn't preserve red-black tree rotation invariance. (code changes for below snippets on this branch 8412021) Here is updated
and a corresponding unit test (which fails) I think illustrating the point about rotations:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. I was thinking the The question for now is will In this PR, you updated both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not an expert on these algorithms, but my working assumption has been that the total ordering introduced by secondary split on right endpoints allows satisfying the tree rotation invariance needed of red-black tree structure. I think this is the textbook approach (eg. the Cormen exercise referenced earlier.) Any thoughts for how to further test/guarantee correctness? During development I relied on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Good question.
rotateLeft (a):
rotateRight (a):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mentioned in #19768 (comment), it changes the behaviour, but I think we are good as long as we don't break the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good, thanks for reviewing and investigating @ahrtr! |
||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||
x = x.right | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
@@ -483,8 +491,15 @@ | |||||||||||||||||||||||||||||
if y == ivt.sentinel { | ||||||||||||||||||||||||||||||
ivt.root = z | ||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||
if z.iv.Ivl.Begin.Compare(y.iv.Ivl.Begin) < 0 { | ||||||||||||||||||||||||||||||
beginCompare := z.iv.Ivl.Begin.Compare(y.iv.Ivl.Begin) | ||||||||||||||||||||||||||||||
if beginCompare < 0 { | ||||||||||||||||||||||||||||||
y.left = z | ||||||||||||||||||||||||||||||
} else if beginCompare == 0 { | ||||||||||||||||||||||||||||||
if z.iv.Ivl.End.Compare(y.iv.Ivl.End) < 0 { | ||||||||||||||||||||||||||||||
y.left = z | ||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||
y.right = z | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||
y.right = z | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
@@ -701,16 +716,29 @@ | |||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// find the exact node for a given interval | ||||||||||||||||||||||||||||||
func (ivt *intervalTree) find(ivl Interval) *intervalNode { | ||||||||||||||||||||||||||||||
redwrasse marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
ret := ivt.sentinel | ||||||||||||||||||||||||||||||
f := func(n *intervalNode) bool { | ||||||||||||||||||||||||||||||
if n.iv.Ivl != ivl { | ||||||||||||||||||||||||||||||
return true | ||||||||||||||||||||||||||||||
x := ivt.root | ||||||||||||||||||||||||||||||
// Search until hit sentinel or exact match. | ||||||||||||||||||||||||||||||
for x != ivt.sentinel { | ||||||||||||||||||||||||||||||
beginCompare := ivl.Begin.Compare(x.iv.Ivl.Begin) | ||||||||||||||||||||||||||||||
endCompare := ivl.End.Compare(x.iv.Ivl.End) | ||||||||||||||||||||||||||||||
if beginCompare == 0 && endCompare == 0 { | ||||||||||||||||||||||||||||||
return x | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
// Split on left endpoint. If left endpoints match, | ||||||||||||||||||||||||||||||
// instead split on right endpoints. | ||||||||||||||||||||||||||||||
if beginCompare < 0 { | ||||||||||||||||||||||||||||||
x = x.left | ||||||||||||||||||||||||||||||
} else if beginCompare == 0 { | ||||||||||||||||||||||||||||||
if endCompare < 0 { | ||||||||||||||||||||||||||||||
x = x.left | ||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||
x = x.right | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||
x = x.right | ||||||||||||||||||||||||||||||
Comment on lines
+729
to
+738
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pls revert the change to the
Suggested change
|
||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
ret = n | ||||||||||||||||||||||||||||||
return false | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
ivt.root.visit(&ivl, ivt.sentinel, f) | ||||||||||||||||||||||||||||||
return ret | ||||||||||||||||||||||||||||||
return x | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// Find gets the IntervalValue for the node matching the given interval | ||||||||||||||||||||||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you update the function docstring?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @redwrasse @ahrtr
Can we address this in followup?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, missed this comment. The comment for the Insert method isn't accurate anymore, we need to update it. We also need to add comment for the
find
method. @redwrasseetcd/pkg/adt/interval_tree.go
Lines 437 to 468 in c849507
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@serathius @ahrtr I'll open an MR for updating the comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created a pull request with docstring updates: #20015