-
Notifications
You must be signed in to change notification settings - Fork 10
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
Stack overflow in Query::next #1
Comments
@t-veor, thank you for this exhaustive and extremely helpful bug report! I am delighted to see someone else is using this library in a complex enough way to catch a bug. If you don't mind, I would be interested to hear what you are using it for. It seems you have already written a fix for the I think you are right about improving |
Hi, Is there any update on improving |
Hey, I've noticed a great performance improvement in HandleIter just by changing the function from a recursive to a iterative structure like so: fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(handle) = self.handle_stack.pop() {
if !self.visited.insert(handle) {
continue;
}
return Some(handle);
}
// Then check the qt_stack.
if let Some(qt) = self.qt_stack.pop() {
// Push my regions onto the region stack
self.handle_stack.extend(qt.handles());
// Push my sub quadrants onto the qt_stack too.
if let Some(sub_quadrants) = qt.subquadrants().as_ref() {
self.qt_stack.extend(sub_quadrants.iter().map(|x| x.deref()));
}
continue;
}
// Else there's nothing left to search.
return None;
}
} Another possibility would be to first search the sub-quadrants with the greatest overlap to the search area, so maybe fewer iterations would be necessary in most usecases? |
After inserting a large amount of points into a quadtree, making queries can cause a stack overflow when iterating through results. I've cut down to a reproducing example here:
Expected output:
Actual output:
My active toolchain:
Looking at it through a debugger, it looks like the problem is that Rust can't figure out
Query::next
is tail-recursive:I'm not sure why, since it looks like all this function is dealing with is references and
u64
s. Maybe theOption
s confuse it?In any case, replacing it with a semantically-equivalent iterative version fixes the issue:
By the way, the pattern of regions I used for the example seems to demonstrate the worst case for
HandlerIter
, becauseHandleIter::query_optimization
can't optimise at all since the query area spans all four subquadrants of the root, and the behaviour ofHandleIter::next()
appears to be to evaluate every single handle past that, which in this case means going through literally every single subquadrant andhandle in the entire tree.Surely this could be improved by
HandleIter
skipping over subquadrants that do not overlap with the query area at all? ThenHandleIter::query_optimization
shouldn't even be needed.The text was updated successfully, but these errors were encountered: