-
Notifications
You must be signed in to change notification settings - Fork 163
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 accumulator only accumulating direct children #524
Fix accumulator only accumulating direct children #524
Conversation
✅ Deploy Preview for salsa-rs canceled.
|
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.
Good catch! Silly me. This looks like a good fix, but I have a suggested rewrite.
src/function/accumulated.rs
Outdated
db, | ||
&mut |query| accumulator.produced_by(runtime, query, &mut output), | ||
&mut HashSet::new(), | ||
); |
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.
Rather than this recursive function let's just inline a loop here...
let db_key = self.database_key_index(key);
let mut visited: FxHashSet<DatabaseKeyIndex> = std::iter::once(db_key).collect();
let mut stack = vec![db_key];
while let Some(k) = stack.pop() {
accumulator.produced_by(runtime, k, &mut output);
for each successor s {
if visited.insert(s) {
stack.push(s);
}
}
}
}
Reasons:
- Overall simpler, less generics, etc
- Adding public methods, particularly those that can be called from outside the crate, is something to do with caution
- Using
FxHashSet
is better than just plain oldHashSet
if you don't need DOS protection -- more efficient - Using a vector to store the stack avoids risk of stack overflow
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.
Ah the pub
was a mistake, I didn't mean to expose it outside of the crate. I'll rewrite this using your suggestion - it's much cleaner :)
One question though - I think stack will change the accumulated diagnostic order. Do we care? I could also use a queue.
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.
Ok I pushed a refactor. This did change the order of accumulated values in some tests - let me know if I should use a queue instead.
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.
You're right. Let's use a queue.
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.
Updated. Let me know if there is another preferred queue struct.
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.
Or not, see my comment below.
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.
Ok one more try - thanks for being patient with me.
I pushed your suggestion of pushing children in reverse order onto a stack. This required me to change Iterator
to DoubleEndedIterator
in a few places - let me know if that's ok.
I can also go back to a recursion if you prefer that.
Hmm. Ideally we would accumulate in execution order, I think. A queue won't really do it, that will give us a breadth-first search. I think what we want to do is to push the children onto the stack but in reverse order -- something like this. But you also have to remove the hashset insertion I think and instead do the insertion when you pop off the stack. Otherwise this case would print wrong:
it would print like A, B, C, D instead of A, B, D, C. Or you could go back to a recursive function (I wouldn't bother with the generic method, I'd just pull out a simple helper function). I think that would be fine, especially since the recursion depth is reflecting an execution that already took place. =) |
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.
I like it! Left a suggestion for a comment.
@nikomatsakis is the failure a flake? |
Yeah, the miri failure is #520 |
I was thinking @PhoebeSzmucer that it'd be good to add a test for one of the more complex scenarios -- e.g. to test duplicates. Are you up to add something like that? |
@nikomatsakis yes if be happy to add more tests. I think there are accumulator tests that indirectly test for the lack of duplicates already (the accumulator-dag one, accumulator-execution-order one that I added here), but I can add some more. |
@nikomatsakis I added one more complex test here a85ac26 |
@PhoebeSzmucer nice! Approved. |
I noticed that some of the accumulated values were getting dropped, and I traced it to the
accumulated_by
function only accumulating from direct children.Let me know if this fix is any good - I'm quite new to Rust and this codebase, and I wasn't sure how to best implement this recursion.