-
Notifications
You must be signed in to change notification settings - Fork 254
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: don't unpin blocks that may show up again #1368
Conversation
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
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.
Looks good to me! I think one adjustment should be made to never_unpin_new_block_before_finalized
to make it pass (drop(_i0)
the initialized event)
Just to double check I got this right, we store an extra bit of information in the pinning details, the can_be_unpinned
.
We then set can_be_unpinned = true
for Finalized
and Pruned
events. Then use this flag in combination with the UnpinFlags
to make a call to chainHead_unpin
.
And this works for the following edge-case:
- NewBlockRef kept around
- FinalizedBlockRef (can_be_unpinned = true) and block ref dropped immediately -> hash is not added to the
UnpinFlags
yet - NewBlockRef is used as normal; then dropped and this time is added to the
UnpinFlags
- the next finalized event will clear out the block generating an unpin
In other words, this is safe for NewBlock
references that outlive Finalized
references 👍
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.
Great job figuring this out, the entire pinning/unpinning API feels quite complicated.
I had a general pass over this test just now to clarify it all a little so hopefully it makes sense now :)
Yup; so we should only actually unpin blocks that we've flagged we are no longer using (ie in the
It should be yup (there's a test for this)
I think this will be ok; pinned but finalized blocks should now have
These blocks should now continue to be kept pinned until they are finalized or pruned, at which point they will now be unpinned on the next finalized event after that.
Yeah; it's a bit hairy for sure; the goal is to hide this hairyness away behind this abstraction and hopefully everything above it should "just work" without needing to fuss over any details (but of course, if we can simplify it then that'd be great too!) :) |
/// | ||
/// This is the same as [`Self::pin_block_at`], except that it also marks the block as being unpinnable now, | ||
/// which should be done for any block that will no longer be seen in future events. | ||
fn pin_unpinnable_block_at(&mut self, rel_block_num: usize, hash: Hash) -> BlockRef<Hash> { |
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'm not a fan of the naming pin_unpinnable_block_at
it just confuses me but I don't have any good suggestion for it... maybe I'm just not used to this language.
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.
Yeah; I couldn't think of a good name either! I'm trying to say "pin a block that can be unpinned" versus "pin a block that can't yet be unpinned"
&mut self, | ||
rel_block_num: usize, | ||
hash: Hash, | ||
can_be_unpinned: bool, |
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 would prefer an enum here called BlockStatus such as:
enum BlockStatus {
/// The block has been seen in a finalized block or a pruned block, it's ok to be unpinned and future events are of no interest
Processed
/// Waiting for the block to be finalized or pruned.
Pending
}
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 guess I feel like the boolean is clear enough here (can the block be unpinned; true or false), and then the functions you call to pin a block hide it anyway (but their name is another issue :D). So maybe having a nenum and only one pin function combined might be clearer hmmm
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 had a quick go at adding an enum and it felt messier to me offhand so I left it as a bool for now :)
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.
The logic looks good to me but not sure what's going on in the CI/tests..
This builds on #1367.
The intention behind the original unpin logic is that blocks that will never show up again in any future event can now be safely unpinned. The logic was flawed though; we'd unpin all flagged blocks when a finalized event comes in, even if some of those may later appear in another finalized event.
The intention behind this fix is to track of which of our pinned blocks have been pruned by the backend, and only actually unpin those blocks for real, leaving other blocks pinned until they eventually are pruned by the backend too.