Avoid locking CTxMemPool::cs recursively in some cases #19872

pull hebasto wants to merge 10 commits into bitcoin:master from hebasto:200904-mmx4 changing 12 files +65 −48
  1. hebasto commented at 3:51 pm on September 4, 2020: member

    This is another step (after #19854) to transit CTxMemPool::cs from RecursiveMutex to Mutex.

    Split out from #19306. Thread safety annotations, lock assertions, and required explicit locking added. No behavior change.

    Please note that now, since #19668 has been merged, it is safe to apply AssertLockHeld() macros as they do not swallow compile time Thread Safety Analysis warnings.

  2. hebasto renamed this:
    200904 mmx4
    Avoid locking CTxMemPool::cs recursively in some cases
    on Sep 4, 2020
  3. hebasto commented at 3:53 pm on September 4, 2020: member
  4. DrahtBot added the label Mempool on Sep 4, 2020
  5. DrahtBot added the label Mining on Sep 4, 2020
  6. DrahtBot added the label P2P on Sep 4, 2020
  7. DrahtBot added the label RPC/REST/ZMQ on Sep 4, 2020
  8. DrahtBot added the label Validation on Sep 4, 2020
  9. hebasto force-pushed on Sep 4, 2020
  10. hebasto commented at 6:03 pm on September 4, 2020: member

    Updated c22c4d2320f288f57fd04515d29b72d6342ea11a -> e79bc0f275977fafcb98a3065256222639a46328 (pr19872.01 -> pr19872.02, diff):

    • fixed CentOS 32-bit build on Travis CI
  11. DrahtBot commented at 7:01 pm on September 4, 2020: member

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #19848 (Remove mempool global from interfaces by MarcoFalke)
    • #19791 ([net processing] Move Misbehaving() to PeerManager by jnewbery)
    • #19753 (p2p: don’t add AlreadyHave transactions to recentRejects by troygiorshev)
    • #19645 (Allow updating mempool-txn with cheaper witnesses by ariard)
    • #19572 (ZMQ: Create “sequence” notifier, enabling client-side mempool tracking by instagibbs)
    • #19556 (Remove mempool global by MarcoFalke)
    • #19498 (Tidy up ProcessOrphanTx by jnewbery)
    • #19488 (Refactor mempool.dat to be extensible, and store missing info by luke-jr)
    • #19478 (Remove CTxMempool::mapLinks data structure member by JeremyRubin)
    • #19339 (validation: re-delegate absurd fee checking from mempool to clients by gzhao408)
    • #12677 (RPC: Add ancestor{count,size,fees} to listunspent output by luke-jr)

    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.

  12. DrahtBot added the label Needs rebase on Sep 5, 2020
  13. hebasto force-pushed on Sep 5, 2020
  14. hebasto commented at 3:33 pm on September 5, 2020: member
    Rebased e79bc0f275977fafcb98a3065256222639a46328 -> 2a3e7cb01f4004310e0853d182e08574698db111 (pr19872.02 -> pr19872.03) due to the conflict with #19848.
  15. DrahtBot removed the label Needs rebase on Sep 5, 2020
  16. DrahtBot added the label Needs rebase on Sep 7, 2020
  17. hebasto force-pushed on Sep 7, 2020
  18. hebasto commented at 11:26 am on September 7, 2020: member
    Rebased 2a3e7cb01f4004310e0853d182e08574698db111 -> f594b9a4a2957b7ad2e95ad7b17cab858e15282f (pr19872.03 -> pr19872.04) due to the conflicts with #19478 and #19556.
  19. DrahtBot removed the label Needs rebase on Sep 7, 2020
  20. DrahtBot added the label Needs rebase on Sep 7, 2020
  21. refactor: CTxMemPool::check() requires CTxMemPool::cs lock
    No change in behavior, some call sites already held the lock and a lock
    is added in the remaining sites.
    0314abb56c
  22. refactor: CTxMemPool::GetMinFee() requires CTxMemPool::cs lock
    No change in behavior, some call sites already held the lock and a lock
    is added in the remaining sites.
    e0f3d72b80
  23. refactor: CTxMemPool::GetTransactionAncestry() requires cs lock
    No change in behavior, some call sites already held the lock and a lock
    is added in the remaining sites.
    ccb4694512
  24. refactor: CTxMemPool::IsLoaded() requires CTxMemPool::cs lock
    No change in behavior, some call sites already held the lock and a lock
    is added in the remaining sites.
    b256cc3a90
  25. refactor: CTxMemPool::size() requires CTxMemPool::cs lock
    No change in behavior, some call sites already held the lock and a lock
    is added in the remaining sites.
    e79f2a4e4b
  26. refactor: CTxMemPool::exists() requires CTxMemPool::cs lock
    No change in behavior, some call sites already held the lock and a lock
    is added in the remaining sites.
    049d8c54f4
  27. refactor: CTxMemPool::infoAll() requires CTxMemPool::cs lock
    No change in behavior, some call sites already held the lock and a lock
    is added in the remaining sites.
    598150bb1e
  28. refactor: CTxMemPool::RemoveUnbroadcastTx() requires CTxMemPool::cs lock
    No change in behavior, some call sites already held the lock and a lock
    is added in the remaining sites.
    551cf1bcf2
  29. refactor: CTxMemPool::GetUnbroadcastTxs() requires CTxMemPool::cs lock
    No change in behavior, some call sites already held the lock and a lock
    is added in the remaining sites.
    e546ffd7e4
  30. refactor: CTxMemPool::queryHashes() requires CTxMemPool::cs lock
    No change in behavior, some call sites already held the lock and a lock
    is added in the remaining sites.
    ff19c7ddb8
  31. hebasto force-pushed on Sep 7, 2020
  32. hebasto commented at 6:16 pm on September 7, 2020: member
    Rebased f594b9a4a2957b7ad2e95ad7b17cab858e15282f -> ff19c7ddb8b8b076e5c538be434abd53af572b8d (pr19872.04 -> pr19872.05) due to the conflict with #19791.
  33. DrahtBot removed the label Needs rebase on Sep 7, 2020
  34. in src/txmempool.cpp:618 in ff19c7ddb8
    614@@ -615,7 +615,7 @@ static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& m
    615 
    616 void CTxMemPool::check(const CCoinsViewCache *pcoins) const
    617 {
    618-    LOCK(cs);
    619+    AssertLockHeld(cs);
    


    jnewbery commented at 10:55 am on September 8, 2020:
    I don’t understand why this change is necessary. check() is never currently called with the lock held.

    jnewbery commented at 11:19 am on September 8, 2020:
    I don’t think this change is necessary. check() isn’t currently called anywhere with the lock held.

    vasild commented at 11:53 am on September 8, 2020:
    It is here (mutex locked a little bit earlier).
  35. in src/txmempool.cpp:1095 in ff19c7ddb8
    1089@@ -1090,8 +1090,9 @@ uint64_t CTxMemPool::CalculateDescendantMaximum(txiter entry) const {
    1090     return maximum;
    1091 }
    1092 
    1093-void CTxMemPool::GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) const {
    1094-    LOCK(cs);
    1095+void CTxMemPool::GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) const
    1096+{
    1097+    AssertLockHeld(cs);
    


    jnewbery commented at 11:20 am on September 8, 2020:
    Again, I don’t think this change is necessary. GetTransactionAncestry() is only called with the lock held in the tests, which can be updated.

    vasild commented at 12:00 pm on September 8, 2020:
    Right, I also saw that. I guess @hebasto preferred this approach because the changes to tests would be too big and ugly? (if we mandate that GetTransactionAncestry() will lock the mutex itself and the callers should not be holding it)

    hebasto commented at 1:19 pm on September 8, 2020:
    @vasild Correct.
  36. jnewbery commented at 11:20 am on September 8, 2020: member
    I’ve reviewed the first three commits, and I’m not sure this is the right direction. Adding locks to lots of places outside the mempool seems unnecessary.
  37. promag commented at 11:40 am on September 8, 2020: member
    IMO we should move the lock up the stack if it prevents unnecessary unlocks/locks. That’s not the case, for instance in CTxMemPool::exists. Looks like it’s a premature change.
  38. vasild commented at 12:20 pm on September 8, 2020: member

    Concept ACK.

    Similar changes are justified, assuming we want to get rid of recursive mutexes.

    Recursive mutexes are used by functions that need to own a mutex to do their stuff, but some of the callers of those functions own the mutex and some don’t. So the function does not have a clear interface wrt the mutex, rather it has a vague interface like “the caller may own the mutex and I will lock it myself anyway”.

    IMO the cleaner interface is if the mutex is acquired inside the function and none of the callers own it. If that is not possible then the function must not lock it and mandate that the callers own it. If that is too verbose for the callers, then two functions could be used - one that locks and another that does not:

     0funcUnprotected() EXCLUSIVE_LOCKS_REQUIRED(cs)
     1{
     2    AssertLockHeld(cs);
     3    ...
     4}
     5
     6func() EXCLUSIVE_LOCKS_REQUIRED(!cs)
     7{
     8    LOCK(cs);
     9    funcUnprotected();
    10}
    
  39. hebasto commented at 1:05 pm on September 8, 2020: member

    Many thanks to @jnewbery, @promag and @vasild for your attention to thread safety design!

    Let me summarize the two approaches to preventing recursive locking of a mutex that are suggested/discussed/used in the repo:

    1. “move the lock up the stack if it prevents unnecessary unlocks/locks” (credits to @promag) E.g., #19833, this PR (in its current state, ff19c7ddb8b8b076e5c538be434abd53af572b8d)

    2. “two functions could be used - one that locks and another that does not” (credits to @vasild) E.g., #19238

    I believe we should reach the consensus about approach we will use while migrating from RecursiveMutex to Mutex before any further step.

    Is it a topic for meeting?

  40. vasild commented at 1:10 pm on September 8, 2020: member
    1. (most preferred, if possible) lock the mutex only inside the function that needs it
  41. hebasto commented at 1:13 pm on September 8, 2020: member
    1. (most preferred, if possible) lock the mutex only inside the function that needs it

    Sure! I just described variants when this is not possible :)

  42. hebasto commented at 1:25 pm on September 8, 2020: member

    @promag

    IMO we should move the lock up the stack if it prevents unnecessary unlocks/locks. That’s not the case, for instance in CTxMemPool::exists. Looks like it’s a premature change.

    https://github.com/bitcoin/bitcoin/blob/147d50d63e07f600b414273a9f6b84f9f4ad9696/src/txmempool.h#L755-L761

    and mempool_tests.cpp

  43. hebasto commented at 1:36 pm on September 8, 2020: member
    For unit tests also there is @MarcoFalke’s approach (fad3a7c5b9118d4d190401c0fbbd3e2068dffadc from #19909) to subclass CTxMemPool, and add member functions with locking required for tests.
  44. DrahtBot added the label Needs rebase on Sep 16, 2020
  45. DrahtBot commented at 0:14 am on September 16, 2020: member

    🐙 This pull request conflicts with the target branch and needs rebase.

    Want to unsubscribe from rebase notifications on this pull request? Just convert this pull request to a “draft”.

  46. hebasto marked this as a draft on Nov 8, 2020
  47. hebasto closed this on Aug 24, 2021

  48. DrahtBot locked this on Aug 24, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-07-01 13:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me