-
Notifications
You must be signed in to change notification settings - Fork 35.5k
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
locks: introduce mutex for tx download, flush rejection filters on UpdatedBlockTip #30111
base: master
Are you sure you want to change the base?
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
c280fe7
to
5ba125d
Compare
} | ||
} // release MempoolMutex | ||
if (m_chainman.m_options.signals) { | ||
m_chainman.m_options.signals->UpdatedBlockTipSync(pindexNewTip); |
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.
This call invokes logging, i.e. I/O operations, while holding the ::cs_main
and mutexm_mempool->cs
es. It is considered as a suboptimal approach from the performance point of view. Could it be avoided?
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 don't think it's true that m_mempool->cs
is still held here (see line above)?
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 don't think it's true that
m_mempool->cs
is still held here (see line above)?
You're right. I was confused by indentation. My apologies.
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.
As for cs_main
, it seems necessary for the chain tip to be what we think it is when the callback happens. IIUC the logging only happens in debug?
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 sure how to be confident that the UpdateBlockTipSync
/ hashRecentRejectsChainTip
would be correct and didn't miss an edge case. Rest looks good to me.
@@ -183,6 +183,12 @@ void ValidationSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlo | |||
fInitialDownload); | |||
} | |||
|
|||
void ValidationSignals::UpdatedBlockTipSync(const CBlockIndex *pindexNew) |
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.
Doesn't this also need to be called from InvalidateBlock()
, potentially each time the tip is updated?
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 to be covered at 9d413af#diff-97c3a52bc5fad452d82670a7fd291800bae20c7bc35bb82686c2c0a4ea7b5b98R3635 now
5ba125d
to
063fc63
Compare
I (locally) split the commit into (1) update on validation interface callback and asserting that I've (locally) hit a bug though, so will figure out what's wrong and then push. |
FWIW I tried something similar, and got an assertion failure in one of the mempool functional tests (maybe mempool_reorg, and thus due to an invalidateblock call?), but it wasn't reliable, it only occurred when I ran many tests in parallel, not when I reran that test on its own. The bug will only trigger if the tip is updated via some other path and AlreadyHave is called before the tip is further updated via the expected path, so (1) doesn't seem like a terribly reliable check to me. |
063fc63
to
a1f36eb
Compare
Was it mempool_packages.py maybe? Mine tripped there on Hm. The alternative is to hold |
Ah, yes, I think it was. |
thanks for splitting this up, next on my review docket |
a1f36eb
to
7c3fb97
Compare
Rebased for #29817 |
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.
looking pretty straightforward but I'm not an expert in the current locking setup
will give another pass in a bit
@@ -183,6 +183,12 @@ void ValidationSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlo | |||
fInitialDownload); | |||
} | |||
|
|||
void ValidationSignals::UpdatedBlockTipSync(const CBlockIndex *pindexNew) |
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 to be covered at 9d413af#diff-97c3a52bc5fad452d82670a7fd291800bae20c7bc35bb82686c2c0a4ea7b5b98R3635 now
src/net_processing.cpp
Outdated
@@ -493,9 +493,9 @@ class PeerManagerImpl final : public PeerManager | |||
|
|||
/** Overridden from CValidationInterface. */ | |||
void BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override | |||
EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex); | |||
EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex, !m_tx_download_mutex); |
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.
not a locking expert but would LOCKS_EXCLUDED
be easier to read?
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.
Oh, I didn't know you could do both. Happy to change if people want, but generally prefer to follow convention of the existing annotations.
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.
EXCLUSIVE_LOCKS_REQUIRED(!foo)
is a stronger assertion; it says that if the caller can see the mutex, it also has to have the same assertion. LOCKS_EXCLUDED(foo)
just says you can't LOCK()
or have EXCLUSIVE_LOCKS_REQUIRED(foo)
-- so there's nothing preventing the caller's caller from having taken the lock.
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 that makes sense. I will leave this as is.
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, makes sense why I only see it used in cs_main
contexts, since it's a global mutex. thanks
We need to synchronize between various tx download structures. TxRequest does not inherently need cs_main for synchronization, and it's not appropriate to lock all of the tx download logic under cs_main.
This is a synchronous version of UpdatedBlockTip. It allows clients to respond to a new block immediately after it is connected. The synchronicity is important for things like m_recent_rejects, in which a transaction's validity can change (rejected vs accepted) when this event is processed (e.g. it has a timelock condition that has just been met). This is distinct from something like m_recent_confirmed_transactions in which the validation outcome is the same (valid vs already-have).
Resetting m_recent_rejects once per block is more efficient than comparing hashRecentRejectsChainTip with the chain tip every time we call AlreadyHaveTx. We keep hashRecentRejectsChainTip for now to assert that updates happen correctly; it is removed in the next commit.
This also means AlreadyHaveTx no longer needs cs_main held.
The TxOrphanage is now guarded externally by m_tx_download_mutex.
7c3fb97
to
ef8de26
Compare
suggested changes were done, reviewed via |
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.
utACK ef8de26
@@ -779,7 +779,10 @@ class PeerManagerImpl final : public PeerManager | |||
BanMan* const m_banman; | |||
ChainstateManager& m_chainman; | |||
CTxMemPool& m_mempool; | |||
TxRequestTracker m_txrequest GUARDED_BY(::cs_main); | |||
|
|||
/** Protects tx download including TxRequestTracker, rejection filters, and TxOrphanage. */ |
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.
non-blocking nit: commit message still referencing TxRequest
See #27463 for full project tracking.
This contains the first 4 commits of #30110, which require some thinking about thread safety in review.
m_tx_download_mutex
which guards the transaction download data structures includingm_txrequest
, the rolling bloom filters, andm_orphanage
. Later this should become the mutex guardingTxDownloadManager
.m_txrequest
doesn't need to be guarded usingcs_main
anymorem_recent_confirmed_transactions
doesn't need its own lock anymorem_orphanage
doesn't need its own lock anymoreValidationInterface
event,UpdatedBlockTipSync
, which is a synchronous version ofUpdatedBlockTip
.m_recent_rejects
andm_recent_rejects_reconsiderable
onUpdatedBlockTipSync
just once instead of every timeAlreadyHaveTx
is called. This should speed up calls to that function and removes the need to lockcs_main
every time it is called.