mempool, validation: Explain cs_main locking semantics #14963

pull MarcoFalke wants to merge 4 commits into bitcoin:master from MarcoFalke:Mf1812-docValLocks changing 8 files +67 −22
  1. MarcoFalke commented at 10:07 pm on December 14, 2018: member

    Both the chain state and the transaction pool are validation specific, but access to them is protected by two locks. The two locks have the following semantics:

    • Writing to the chain state or adding transactions to the transaction pool -> Take both cs_main and mempool::cs
    • Reading either or removing transactions from the the transaction pool -> Take only the appropriate lock
  2. sync: Add RecursiveMutex type alias fac4558462
  3. MarcoFalke added the label Docs on Dec 14, 2018
  4. MarcoFalke force-pushed on Dec 14, 2018
  5. MarcoFalke force-pushed on Dec 14, 2018
  6. MarcoFalke force-pushed on Dec 14, 2018
  7. DrahtBot commented at 0:27 am on December 15, 2018: 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:

    • #11652 (Add missing locks: validation.cpp + related by practicalswift)
    • #10443 (Add fee_est tool for debugging fee estimation code by ryanofsky)

    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.

  8. in src/validation.cpp:220 in fa5ed69b02 outdated
    218+ * or changing the chainstate.
    219+ *
    220+ * This must also be locked when updating the transaction pool, e.g. on
    221+ * AcceptToMemoryPool.
    222+ *
    223+ * The transaction pool has a separate lock to allow rading it and the
    


    ch4ot1c commented at 2:56 am on December 15, 2018:
    rading it -> reading from it
  9. in src/validation.cpp:214 in fa5ed69b02 outdated
    209@@ -210,9 +210,17 @@ class CChainState {
    210     bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
    211 } g_chainstate;
    212 
    213-
    214-
    215-CCriticalSection cs_main;
    216+/**
    217+ * Mutex to guard access to validation specific variables, such as reading
    


    ch4ot1c commented at 2:57 am on December 15, 2018:
    such as -> in cases such as?

    promag commented at 2:54 pm on December 15, 2018:
    Recursive mutex to ...
  10. ch4ot1c changes_requested
  11. in src/txmempool.h:491 in fa5ed69b02 outdated
    484@@ -485,7 +485,13 @@ class CTxMemPool
    485         >
    486     > indexed_transaction_set;
    487 
    488-    mutable CCriticalSection cs;
    489+    /**
    490+     * Mutex that guards reads.
    491+     *
    492+     * The validation mutex cs_main should be locked in addition to this lock
    


    promag commented at 2:53 pm on December 15, 2018:
    ... should be locked before in addition ...
  12. in src/txmempool.h:489 in fa5ed69b02 outdated
    484@@ -485,7 +485,13 @@ class CTxMemPool
    485         >
    486     > indexed_transaction_set;
    487 
    488-    mutable CCriticalSection cs;
    489+    /**
    490+     * Mutex that guards reads.
    


    promag commented at 2:53 pm on December 15, 2018:
    Recursive mutex ...

    MarcoFalke commented at 4:15 pm on December 17, 2018:
    Recursive is already clear from the variable type and I plan to make it non-recursive

    ryanofsky commented at 6:42 pm on December 17, 2018:

    In commit “doc: Add comment to cs_main and mempool::cs” (fa64bb42e97b6c6c58e83badca88d386f99dbcd2)

    I think making a comparison to read/write locks makes this more confusing than it needs to be. Read locks normally are shared, not exclusive. And the requirement to lock cs_main for write access seems too broad, and doesn’t give a justification.

    I would suggest a comment that just says when you need to lock the mutexes and why:

    0/**
    1 * This mutex needs to be locked when accessing mapTx.
    2 *
    3 * [@par](/bitcoin-bitcoin/contributor/par/) Relationship to cs_main
    4 * Locking both mempool.cs and cs_main gives a view of the mempool which is
    5 * compatible with the current chain tip. To guarantee this, both mutexes need
    6 * to be locked when adding transactions to the mempool or changing the
    7 * chain tip. But locking mempool.cs by itself is sufficient for reading
    8 * transactions from the mempool, or removing transactions from it.
    9 */
    

    MarcoFalke commented at 7:47 pm on December 17, 2018:
    It could also be used to guard other members, like prioritization data, no?

    MarcoFalke commented at 7:48 pm on December 17, 2018:
    Otherwise done
  13. promag commented at 2:56 pm on December 15, 2018: member
    Concept ACK. Title prefix suggests this is documentation only change, which is not. Some nits though.
  14. MarcoFalke force-pushed on Dec 17, 2018
  15. MarcoFalke commented at 4:17 pm on December 17, 2018: member
    Fixed up some of the language. Any suggestions for the pull request subject line?
  16. promag commented at 4:26 pm on December 17, 2018: member

    I think the most important change is mempool: Add missing locks to `cs_main` , the remaining change is a consequence of that.

    Could also say:

    • only tests are affected
    • fix related annotations and improve documentation
  17. in src/bench/mempool_eviction.cpp:111 in fa64bb42e9 outdated
    107@@ -108,7 +108,7 @@ static void MempoolEviction(benchmark::State& state)
    108     tx7.vout[1].nValue = 10 * COIN;
    109 
    110     CTxMemPool pool;
    111-    LOCK(pool.cs);
    112+    LOCK2(cs_main, pool.cs);
    


    ryanofsky commented at 5:13 pm on December 17, 2018:

    In commit “doc: Add comment to cs_main and mempool::cs” (fa64bb42e97b6c6c58e83badca88d386f99dbcd2)

    Would suggest moving the test and bench changes in this commit into a different commit, since they aren’t really what you’d normally think of as documentation changes.


    MarcoFalke commented at 7:46 pm on December 17, 2018:
    Done
  18. MarcoFalke renamed this:
    doc: Add comment to cs_main and mempool::cs
    mempool, validation: Explain cs_main locking semantics
    on Dec 17, 2018
  19. MarcoFalke added the label Validation on Dec 17, 2018
  20. MarcoFalke added the label Mempool on Dec 17, 2018
  21. MarcoFalke removed the label Docs on Dec 17, 2018
  22. in src/validation.cpp:217 in fa64bb42e9 outdated
    215-CCriticalSection cs_main;
    216+/**
    217+ * Mutex to guard access to validation specific variables, such as reading
    218+ * or changing the chainstate.
    219+ *
    220+ * This must also be locked when updating the transaction pool, e.g. on
    


    ryanofsky commented at 6:39 pm on December 17, 2018:

    In commit “doc: Add comment to cs_main and mempool::cs” (fa64bb42e97b6c6c58e83badca88d386f99dbcd2)

    I would say “may also need to be locked” instead of “must also be locked”, and add “see CTxMemPool::cs comment for details.”


    MarcoFalke commented at 7:46 pm on December 17, 2018:
    Done
  23. ryanofsky approved
  24. ryanofsky commented at 6:46 pm on December 17, 2018: member
    utACK fa64bb42e97b6c6c58e83badca88d386f99dbcd2
  25. test: Add missing validation locks fafe941bdd
  26. MarcoFalke force-pushed on Dec 17, 2018
  27. MarcoFalke force-pushed on Dec 17, 2018
  28. laanwj commented at 10:01 am on December 19, 2018: member
    ACK
  29. in src/txmempool.h:524 in fa5c7671aa outdated
    495+     * compatible with the current chain tip. To guarantee this, both mutexes need
    496+     * to be locked when adding transactions to the mempool or changing the
    497+     * chain tip. But locking mempool.cs by itself is sufficient for reading
    498+     * transactions from the mempool, or removing transactions from it.
    499+     */
    500+    mutable RecursiveMutex cs;
    


    ryanofsky commented at 6:38 pm on December 19, 2018:

    This comment comes from #14963 (review) and I think it is still ok as a description of how the code currently works. But talking to @morcos, @sdaftuar, and you Monday, it sounds like this is not actually how things are intended to work. After that conversation, I think the following might be more accurate:

     0/**
     1 * This mutex needs to be locked when accessing `mapTx` or other members
     2 * that are guarded by it.
     3 *
     4 * [@par](/bitcoin-bitcoin/contributor/par/) Consistency guarantees
     5 *
     6 * By design, it is guaranteed that:
     7 *
     8 * 1. Locking both `cs_main` and `mempool.cs` will give a view of mempool
     9 *    that is consistent with current chain tip (`chainActive` and
    10 *    `pcoinsTip`) and is fully populated. Fully populated means that if the
    11 *    current active chain is missing transactions that were present in a
    12 *    previously active chain, all the missing transactions will have been
    13 *    re-added to the mempool and should be present if they meet size and
    14 *    consistency constraints.
    15 *
    16 * 2. Locking `mempool.cs` without `cs_main` will give a view of a mempool
    17 *    consistent with some chain that was active since `cs_main` was last
    18 *    locked, and that is fully populated as described above. It is ok for
    19 *    code that only needs to query or remove transactions from the mempool
    20 *    to lock just `mempool.cs` without `cs_main`.
    21 *
    22 * To provide these guarantees, it is necessary to lock both `cs_main` and
    23 * `mempool.cs` whenever adding transactions to the mempool and whenever
    24 * changing the chain tip. It's necessary to keep both mutexes locked until
    25 * the mempool is consistent with the new chain tip and fully populated.
    26 *
    27 * [@par](/bitcoin-bitcoin/contributor/par/) Consistency bug
    28 *
    29 * The second guarantee above is not currently enforced, but
    30 * [#14193](/bitcoin-bitcoin/14193/) will fix it. No known code
    31 * in bitcoin currently depends on second guarantee, but it is important to
    32 * fix for third party code that needs be able to frequently poll the
    33 * mempool without locking `cs_main` and without encountering missing
    34 * transactions during reorgs.
    35 */
    

    MarcoFalke commented at 7:11 pm on December 19, 2018:
    Wow, excellent write-up. Will pull that in to replace my clumsy explanation
  30. in src/validation.cpp:217 in fa5c7671aa outdated
    215-CCriticalSection cs_main;
    216+/**
    217+ * Mutex to guard access to validation specific variables, such as reading
    218+ * or changing the chainstate.
    219+ *
    220+ * This may also be locked when updating the transaction pool, e.g. on
    


    ryanofsky commented at 6:39 pm on December 19, 2018:
    Should say “may also need to be locked” instead of “may also be locked”.
  31. ryanofsky approved
  32. ryanofsky commented at 6:47 pm on December 19, 2018: member
    utACK fa5c7671aa4c916b191d0423309f89b69568c7f9. The only changes since my previous review were applying suggestions.
  33. doc: Add comment to cs_main and mempool::cs fa5c346c5a
  34. MarcoFalke force-pushed on Dec 19, 2018
  35. MarcoFalke force-pushed on Dec 19, 2018
  36. MarcoFalke force-pushed on Dec 19, 2018
  37. validation: Add cs_main locking annotations fa5e373365
  38. MarcoFalke force-pushed on Dec 22, 2018
  39. ryanofsky approved
  40. ryanofsky commented at 5:49 pm on January 4, 2019: member

    utACK fa5e373365b8e88fc9894f53f618d3e89f1bec14. Changes since last review: adding longer mempool.cs comment and adding a commit with some new locking annotations.

    Also, I don’t think this needs to hold up merging, but I think it would be good if a reviewer with more mempool expertise could read the new code comments and ACK if they are correct.

  41. in src/txmempool.h:580 in fa5e373365
    576@@ -541,8 +577,8 @@ class CTxMemPool
    577     // Note that addUnchecked is ONLY called from ATMP outside of tests
    578     // and any other callers may break wallet's in-mempool tracking (due to
    579     // lack of CValidationInterface::TransactionAddedToMempool callbacks).
    580-    void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs);
    581-    void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs);
    582+    void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
    


    practicalswift commented at 4:36 pm on January 5, 2019:
    Changer order of cs and cs_main here to make locking order consistent?
  42. in src/txmempool.h:581 in fa5e373365
    576@@ -541,8 +577,8 @@ class CTxMemPool
    577     // Note that addUnchecked is ONLY called from ATMP outside of tests
    578     // and any other callers may break wallet's in-mempool tracking (due to
    579     // lack of CValidationInterface::TransactionAddedToMempool callbacks).
    580-    void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs);
    581-    void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs);
    582+    void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
    583+    void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
    


    practicalswift commented at 4:36 pm on January 5, 2019:
    Changer order of cs and cs_main here to make locking order consistent?
  43. practicalswift commented at 4:36 pm on January 5, 2019: contributor
    utACK fa5e373365b8e88fc9894f53f618d3e89f1bec14 modulo nits
  44. in src/validation.cpp:217 in fa5c346c5a outdated
    215-CCriticalSection cs_main;
    216+/**
    217+ * Mutex to guard access to validation specific variables, such as reading
    218+ * or changing the chainstate.
    219+ *
    220+ * This may also need to be locked when updating the transaction pool, e.g. on
    


    sdaftuar commented at 6:19 pm on January 15, 2019:
    We call the “transaction pool” the “mempool” in so many places in this file, I find the usage of “transaction pool” to be odd…
  45. sdaftuar approved
  46. sdaftuar commented at 6:38 pm on January 15, 2019: member
    utACK fa5e373365b8e88fc9894f53f618d3e89f1bec14
  47. MarcoFalke merged this on Jan 15, 2019
  48. MarcoFalke closed this on Jan 15, 2019

  49. MarcoFalke referenced this in commit 82ffd4d918 on Jan 15, 2019
  50. MarcoFalke deleted the branch on Jan 15, 2019
  51. jasonbcox referenced this in commit 8408a0cdcf on Oct 11, 2019
  52. Munkybooty referenced this in commit 97a1d0e571 on Aug 21, 2021
  53. Munkybooty referenced this in commit 9ed410f131 on Aug 23, 2021
  54. Munkybooty referenced this in commit 3f0c65bf2e on Aug 24, 2021
  55. Munkybooty referenced this in commit 27d02c4058 on Aug 24, 2021
  56. Munkybooty referenced this in commit 8a7a2fc8d7 on Aug 24, 2021
  57. UdjinM6 referenced this in commit 559df3df9b on Aug 24, 2021
  58. Munkybooty referenced this in commit d5f50c3df8 on Aug 24, 2021
  59. DrahtBot locked this on Dec 16, 2021

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-06-29 10:13 UTC

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