-
Notifications
You must be signed in to change notification settings - Fork 860
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
Synchronize access to block header #6143
Synchronize access to block header #6143
Conversation
Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>
|
Should we need to synchronize blockheader access? This isn't something that typically needs concurrency safety, except of course near-head.
Without context, this seems like an issue that should be solved by ensuring we commit and persist the blockchain rocksdb transaction rather than paying a synchronization overhead cost when trying to access block headers. edit: Has this fixed the issue in your test case? If so, perhaps we should overload with synchonized access, that way we can have synchronization when necessary, and not pay the cost for operations that do not require it |
Yeah it's exactly the near-head case that the problem occurs. Basically the chain header is updated (inside a synchronized function) and then storage is updated and committed (in the same synchronized function). But the getter for the chain head can be called at any time, and because it's not synchronized it can retrieve the new value before the storage commit has happened. So possibly an alternative to synchronizing on |
Going to run some tests with a change to synchronizing |
Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>
@garyschulte I'm running my tests again using your suggestion of overloading |
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.
Seems good to me, but I think we can DRY it up a bit
// Optimistically get the chain head. getChainHeadBlockHeader() doesn't take any locks, | ||
// which might mean that the latest block is still being committed to storage. If this | ||
// call fails try the synchronized alternative, and if that fails give up. | ||
BlockHeader chainHeadBlockHeader = getChainHeadBlockHeader().orElse(null); |
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.
how about we leave this as it is and have this logic directly in getChainBlockHeader()?
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 that's a good thought. I'll tidy it up and push a new commit.
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.
New commits pushed @garyschulte. I'll mark as auto-merge once you're happy with them.
private Optional<BlockHeader> getChainHeadBlockHeaderSafe() { | ||
final MutableBlockchain blockchain = protocolContext.getBlockchain(); | ||
return blockchain.getBlockHeaderSafe(blockchain.getChainHeadHash()); | ||
} | ||
|
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.
how about instead of adding here we add the safe call to the existing getChainHeadBlockHeader(), e.g.:
private Optional<BlockHeader> getChainHeadBlockHeader() {
final MutableBlockchain blockchain = protocolContext.getBlockchain();
return blockchain.getBlockHeader(blockchain.getChainHeadHash())
.or(() -> blockchain.getBlockHeaderSafe(blockchain.getChainHeadHash()));
}
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.
See latest commits
Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>
Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>
I like the approach of the |
The current PR definitely fixes the issue - no failures after >10 hours running a single validator at 50TPS. Question is whether we stick with the refactor I did under 1641b23 or revert to having separate @garyschulte any thoughts? It would be nice to get this into |
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.
👍 LGTM, especially if this solves the case you are encountering.
* Synchronize access to block header Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Add 'safe' version of getBlockHeader Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Move retry with lock into getChainHeadBlockHeader() Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Reinstate 'final' modifier Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> --------- Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> Signed-off-by: Justin Florentine <justin+github@florentine.us>
* Synchronize access to block header Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Add 'safe' version of getBlockHeader Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Move retry with lock into getChainHeadBlockHeader() Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Reinstate 'final' modifier Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> --------- Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> Signed-off-by: Justin Florentine <justin+github@florentine.us>
* Synchronize access to block header Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Add 'safe' version of getBlockHeader Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Move retry with lock into getChainHeadBlockHeader() Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Reinstate 'final' modifier Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> --------- Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> Signed-off-by: Justin Florentine <justin+github@florentine.us>
* Synchronize access to block header Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Add 'safe' version of getBlockHeader Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Move retry with lock into getChainHeadBlockHeader() Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Reinstate 'final' modifier Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> --------- Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>
PR description
As outlined in the comment in #6140 it appears to be the case that access to the block header isn't thread safe when the block being requested is a newly added chain head.
Fixed Issue(s)
Fixes #6140