-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Avoid cs_main during ReadBlockFromDisk Calls #11913
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
Avoid cs_main during ReadBlockFromDisk Calls #11913
Conversation
c20ff7d
to
571f4ad
Compare
Concept ACK. Good to have less contention on the cs_main lock, it seems a good idea to release it during I/O. |
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 571f4ad.
src/rpc/blockchain.cpp
Outdated
@@ -144,6 +138,12 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx | |||
|
|||
if (blockindex->pprev) | |||
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); | |||
LOCK(cs_main); | |||
int confirmations = -1; |
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.
Avoid lock here by receiving the pindex tip? (with the cost of jumping thru pprev).
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.
That still wouldn't solve it for the chainActive.Next() call, so you'd need cs_main either way. Less code diff to just do it 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.
Something along this should work:
const CBlockIndex* pindex = tip;
const CBlockIndex* pnext = nullptr;
int confirmations = 0;
while (pindex && pindex != blockindex && pindex->nHeight >= blockindex->nHeight) {
pnext = pindex;
pindex = pindex->pprev;
confirmations++;
}
if (pindex != blockindex) confirmations = -1;
This approach avoids accessing chainActive
, blockToJSON
just needs to receive the tip. This sounds more correct to me because a RPC can take a snapshot of the tip (and then leave cs_main) and all the remaining execution is consistent with that tip.
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.
Submitted suggestion as #12151.
Needs rebase on rebased #11281 |
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.
Needs rebase.
src/rpc/blockchain.cpp
Outdated
@@ -144,6 +138,12 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx | |||
|
|||
if (blockindex->pprev) | |||
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); | |||
LOCK(cs_main); | |||
int confirmations = -1; |
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.
Submitted suggestion as #12151.
Awaiting re-rebase of #11281. Will probably just wait for that to get merged. |
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 concurrent access to data on disk makes me a little nervous. Is it worth having a separate read-write lock around reading/writing block files?
src/net_processing.cpp
Outdated
@@ -1044,6 +1044,8 @@ bool static ProcessGetBlockData(CNode* pfrom, const Consensus::Params& consensus | |||
fWitnessesPresentInARecentCompactBlock = fWitnessesPresentInMostRecentCompactBlock; | |||
} | |||
|
|||
const CBlockIndex *pindex = nullptr; | |||
{ |
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 find the indentation here confusing. I assume it's not indented to help reviewers, so maybe indent in a separate commit?
src/net_processing.cpp
Outdated
@@ -1085,16 +1089,20 @@ bool static ProcessGetBlockData(CNode* pfrom, const Consensus::Params& consensus | |||
} | |||
// Pruned nodes may have deleted the block, so check whether | |||
// it's available before trying to send. | |||
if (send && (mi->second->nStatus & BLOCK_HAVE_DATA)) | |||
} |
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.
Add a // releases cs_main
if there is no indentation.
@@ -1085,16 +1089,20 @@ bool static ProcessGetBlockData(CNode* pfrom, const Consensus::Params& consensus | |||
} | |||
// Pruned nodes may have deleted the block, so check whether |
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 comment should get moved up to line 1066.
@jimpo are you aware of any modern systems that have an issue reading from the middle of a file while it is being appended to? That sounds like it should be considered a critical kernel bug if anything, no? |
I say that mostly because of the pruning race. |
Pruning should be atomic still, no? Either we opened the file, then any unlink operations on the underlying file will result in us being able to finish reading, or we didn't open the file, so we can return false. I'm skeptical it can ever result in corrupt data, or am I missing some way Windows operates? It's definitely worth auditing that ReadBlockFromDisk returning false is handled properly everywhere! |
Needs rebase. |
571f4ad
to
030c233
Compare
Rebased. |
030c233
to
7f538c1
Compare
7f538c1
to
44d93b3
Compare
Rebased. In addition to RPC latency in some calls, this should also now make a nontrivial difference to -txindex nodes restart resync after an unclean shutdown (which, at least, should be useful to me). |
44d93b3
to
b49fa7c
Compare
b49fa7c
to
cb14810
Compare
Needs rebase. |
…ockheaderToJSON b9f226b rpc: Remove cs_main lock from blockToJSON and blockHeaderToJSON (João Barbosa) 343b98c rpc: Specify chain tip instead of chain in GetDifficulty (João Barbosa) 54dc13b rpc: Fix SoftForkMajorityDesc and SoftForkDesc signatures (João Barbosa) Pull request description: Motivated by bitcoin#11913 (comment), this pull makes `blockToJSON` and `blockheaderToJSON` free of `cs_main` locks. Locking `cs_main` was required to access `chainActive` in order to check if the block was in the chain and to retrieve the next block index. With the this approach, `CBlockIndex::GetAncestor()` is used in a way to check if the block belongs to the specified chain tip and, at the same time, get the next block index. Tree-SHA512: a6720ace0182c19033bbed1a404f729d793574db8ab16e0966ffe412145611e32c30aaab02975d225df6d439d7b9ef2070e732b16137a902b0293c8cddfeb85f
…erToJSON Summary: backport PR12151 https://github.com/bitcoin/bitcoin/pull/12151/files b9f226b41f rpc: Remove cs_main lock from blockToJSON and blockHeaderToJSON (João Barbosa) 343b98cbcd rpc: Specify chain tip instead of chain in GetDifficulty (João Barbosa) 54dc13b6a2 rpc: Fix SoftForkMajorityDesc and SoftForkDesc signatures (João Barbosa) Pull request description: Motivated by bitcoin/bitcoin#11913 (comment), this pull makes `blockToJSON` and `blockheaderToJSON` free of `cs_main` locks. Locking `cs_main` was required to access `chainActive` in order to check if the block was in the chain and to retrieve the next block index. With the this approach, `CBlockIndex::GetAncestor()` is used in a way to check if the block belongs to the specified chain tip and, at the same time, get the next block index. Backport note: The modification of `get_difficulty_for_null_tip cannot` be included in this due to divergent and conflicting histories; this situation will be amended in D3012. Depends on D3070 Test Plan: `make check` `test_runner.py` Reviewers: jasonbcox, Fabien, #bitcoin_abc, deadalnix Reviewed By: jasonbcox, Fabien, #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D3021
…erToJSON Summary: backport PR12151 https://github.com/bitcoin/bitcoin/pull/12151/files b9f226b41f rpc: Remove cs_main lock from blockToJSON and blockHeaderToJSON (João Barbosa) 343b98cbcd rpc: Specify chain tip instead of chain in GetDifficulty (João Barbosa) 54dc13b6a2 rpc: Fix SoftForkMajorityDesc and SoftForkDesc signatures (João Barbosa) Pull request description: Motivated by bitcoin/bitcoin#11913 (comment), this pull makes `blockToJSON` and `blockheaderToJSON` free of `cs_main` locks. Locking `cs_main` was required to access `chainActive` in order to check if the block was in the chain and to retrieve the next block index. With the this approach, `CBlockIndex::GetAncestor()` is used in a way to check if the block belongs to the specified chain tip and, at the same time, get the next block index. Backport note: The modification of `get_difficulty_for_null_tip cannot` be included in this due to divergent and conflicting histories; this situation will be amended in D3012. Depends on D3070 Test Plan: `make check` `test_runner.py` Reviewers: jasonbcox, Fabien, #bitcoin_abc, deadalnix Reviewed By: jasonbcox, Fabien, #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D3021
…erToJSON Summary: backport PR12151 https://github.com/bitcoin/bitcoin/pull/12151/files b9f226b41f rpc: Remove cs_main lock from blockToJSON and blockHeaderToJSON (João Barbosa) 343b98cbcd rpc: Specify chain tip instead of chain in GetDifficulty (João Barbosa) 54dc13b6a2 rpc: Fix SoftForkMajorityDesc and SoftForkDesc signatures (João Barbosa) Pull request description: Motivated by bitcoin/bitcoin#11913 (comment), this pull makes `blockToJSON` and `blockheaderToJSON` free of `cs_main` locks. Locking `cs_main` was required to access `chainActive` in order to check if the block was in the chain and to retrieve the next block index. With the this approach, `CBlockIndex::GetAncestor()` is used in a way to check if the block belongs to the specified chain tip and, at the same time, get the next block index. Backport note: The modification of `get_difficulty_for_null_tip cannot` be included in this due to divergent and conflicting histories; this situation will be amended in D3012. Depends on D3070 Test Plan: `make check` `test_runner.py` Reviewers: jasonbcox, Fabien, #bitcoin_abc, deadalnix Reviewed By: jasonbcox, Fabien, #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D3021
…erToJSON Summary: backport PR12151 https://github.com/bitcoin/bitcoin/pull/12151/files b9f226b41f rpc: Remove cs_main lock from blockToJSON and blockHeaderToJSON (João Barbosa) 343b98cbcd rpc: Specify chain tip instead of chain in GetDifficulty (João Barbosa) 54dc13b6a2 rpc: Fix SoftForkMajorityDesc and SoftForkDesc signatures (João Barbosa) Pull request description: Motivated by bitcoin/bitcoin#11913 (comment), this pull makes `blockToJSON` and `blockheaderToJSON` free of `cs_main` locks. Locking `cs_main` was required to access `chainActive` in order to check if the block was in the chain and to retrieve the next block index. With the this approach, `CBlockIndex::GetAncestor()` is used in a way to check if the block belongs to the specified chain tip and, at the same time, get the next block index. Backport note: The modification of `get_difficulty_for_null_tip cannot` be included in this due to divergent and conflicting histories; this situation will be amended in D3012. Depends on D3070 Test Plan: `make check` `test_runner.py` Reviewers: jasonbcox, Fabien, #bitcoin_abc, deadalnix Reviewed By: jasonbcox, Fabien, #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D3021
…ockheaderToJSON b9f226b rpc: Remove cs_main lock from blockToJSON and blockHeaderToJSON (João Barbosa) 343b98c rpc: Specify chain tip instead of chain in GetDifficulty (João Barbosa) 54dc13b rpc: Fix SoftForkMajorityDesc and SoftForkDesc signatures (João Barbosa) Pull request description: Motivated by bitcoin#11913 (comment), this pull makes `blockToJSON` and `blockheaderToJSON` free of `cs_main` locks. Locking `cs_main` was required to access `chainActive` in order to check if the block was in the chain and to retrieve the next block index. With the this approach, `CBlockIndex::GetAncestor()` is used in a way to check if the block belongs to the specified chain tip and, at the same time, get the next block index. Tree-SHA512: a6720ace0182c19033bbed1a404f729d793574db8ab16e0966ffe412145611e32c30aaab02975d225df6d439d7b9ef2070e732b16137a902b0293c8cddfeb85f
…ockheaderToJSON b9f226b rpc: Remove cs_main lock from blockToJSON and blockHeaderToJSON (João Barbosa) 343b98c rpc: Specify chain tip instead of chain in GetDifficulty (João Barbosa) 54dc13b rpc: Fix SoftForkMajorityDesc and SoftForkDesc signatures (João Barbosa) Pull request description: Motivated by bitcoin#11913 (comment), this pull makes `blockToJSON` and `blockheaderToJSON` free of `cs_main` locks. Locking `cs_main` was required to access `chainActive` in order to check if the block was in the chain and to retrieve the next block index. With the this approach, `CBlockIndex::GetAncestor()` is used in a way to check if the block belongs to the specified chain tip and, at the same time, get the next block index. Tree-SHA512: a6720ace0182c19033bbed1a404f729d793574db8ab16e0966ffe412145611e32c30aaab02975d225df6d439d7b9ef2070e732b16137a902b0293c8cddfeb85f
…ockheaderToJSON b9f226b rpc: Remove cs_main lock from blockToJSON and blockHeaderToJSON (João Barbosa) 343b98c rpc: Specify chain tip instead of chain in GetDifficulty (João Barbosa) 54dc13b rpc: Fix SoftForkMajorityDesc and SoftForkDesc signatures (João Barbosa) Pull request description: Motivated by bitcoin#11913 (comment), this pull makes `blockToJSON` and `blockheaderToJSON` free of `cs_main` locks. Locking `cs_main` was required to access `chainActive` in order to check if the block was in the chain and to retrieve the next block index. With the this approach, `CBlockIndex::GetAncestor()` is used in a way to check if the block belongs to the specified chain tip and, at the same time, get the next block index. Tree-SHA512: a6720ace0182c19033bbed1a404f729d793574db8ab16e0966ffe412145611e32c30aaab02975d225df6d439d7b9ef2070e732b16137a902b0293c8cddfeb85f
…ockheaderToJSON b9f226b rpc: Remove cs_main lock from blockToJSON and blockHeaderToJSON (João Barbosa) 343b98c rpc: Specify chain tip instead of chain in GetDifficulty (João Barbosa) 54dc13b rpc: Fix SoftForkMajorityDesc and SoftForkDesc signatures (João Barbosa) Pull request description: Motivated by bitcoin#11913 (comment), this pull makes `blockToJSON` and `blockheaderToJSON` free of `cs_main` locks. Locking `cs_main` was required to access `chainActive` in order to check if the block was in the chain and to retrieve the next block index. With the this approach, `CBlockIndex::GetAncestor()` is used in a way to check if the block belongs to the specified chain tip and, at the same time, get the next block index. Tree-SHA512: a6720ace0182c19033bbed1a404f729d793574db8ab16e0966ffe412145611e32c30aaab02975d225df6d439d7b9ef2070e732b16137a902b0293c8cddfeb85f
…ockheaderToJSON b9f226b rpc: Remove cs_main lock from blockToJSON and blockHeaderToJSON (João Barbosa) 343b98c rpc: Specify chain tip instead of chain in GetDifficulty (João Barbosa) 54dc13b rpc: Fix SoftForkMajorityDesc and SoftForkDesc signatures (João Barbosa) Pull request description: Motivated by bitcoin#11913 (comment), this pull makes `blockToJSON` and `blockheaderToJSON` free of `cs_main` locks. Locking `cs_main` was required to access `chainActive` in order to check if the block was in the chain and to retrieve the next block index. With the this approach, `CBlockIndex::GetAncestor()` is used in a way to check if the block belongs to the specified chain tip and, at the same time, get the next block index. Tree-SHA512: a6720ace0182c19033bbed1a404f729d793574db8ab16e0966ffe412145611e32c30aaab02975d225df6d439d7b9ef2070e732b16137a902b0293c8cddfeb85f
…ockheaderToJSON b9f226b rpc: Remove cs_main lock from blockToJSON and blockHeaderToJSON (João Barbosa) 343b98c rpc: Specify chain tip instead of chain in GetDifficulty (João Barbosa) 54dc13b rpc: Fix SoftForkMajorityDesc and SoftForkDesc signatures (João Barbosa) Pull request description: Motivated by bitcoin#11913 (comment), this pull makes `blockToJSON` and `blockheaderToJSON` free of `cs_main` locks. Locking `cs_main` was required to access `chainActive` in order to check if the block was in the chain and to retrieve the next block index. With the this approach, `CBlockIndex::GetAncestor()` is used in a way to check if the block belongs to the specified chain tip and, at the same time, get the next block index. Tree-SHA512: a6720ace0182c19033bbed1a404f729d793574db8ab16e0966ffe412145611e32c30aaab02975d225df6d439d7b9ef2070e732b16137a902b0293c8cddfeb85f
Built on #11281 and one commit from #11824, this removes almost all cs_main holds in ReadBlockFromDisk calls in net_processing/RPC/REST. Only real worry here is if something gets pruned out from under us during reading, so some previously-asserts in net_processing are now LogPrints.