blockstorage: do not flush block to disk if it is already there#27039
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. |
7a2e5cd to
a8db898
Compare
a8db898 to
a6b05f8
Compare
There was a problem hiding this comment.
Approach and code review ACK a6b05f8db63bae7eefb5330048d8b1441f1a9e5e
I don't understand why the test needs to start a second node or why -fastprune is needed (but that may just be me!).
EDIT: never mind, I see now why it's needed, you've documented it well.
reviewers can let me know if the changes should be combined
It seems fine to me that this is a separate PR, but I don't have a strong opinion.
a6b05f8 to
386faaf
Compare
LarryRuane
left a comment
There was a problem hiding this comment.
crtACK 386faaf76ea0edb2150725c5bdb69d234a2f2607
I'm still not able to figure out why two nodes are needed in the test. I tried modifying the test to use just one node, but the new test reindex_readonly(), didn't pass (the log file contained the unexpected string "failed to open file"). So the second node does seem to be needed.
386faaf to
ed57565
Compare
LarryRuane
left a comment
There was a problem hiding this comment.
ACK ed57565e36bf514fc4d063972464c9152a08fb8e
ec7dab6 to
e7a0339
Compare
LarryRuane
left a comment
There was a problem hiding this comment.
ACK e7a0339b8cb612088ca212c568c0499c0f02398b
|
Rebased on master and prepended an extra commit with a unit test for BlockManager. The test passes on master and the branch without modification, hopefully illustrating that at least some behaviors are not affected. It's hard to test precisely for the branch's change in a unit test because file-flushing is not something we can really predict or test for (sometimes it happens as soon as we The actual error in issue #2039 comes from an attempt to OPEN a file with Lines 81 to 86 in 82793f1 ...and this PR avoids the call to @jonatack lemme know if the new test is reassuring enough, or if you have advice for better coverage? |
b787dac to
5afd6bf
Compare
hebasto
left a comment
There was a problem hiding this comment.
Tested that this PR indeed fixes #2039:
- on master (82793f1):
$ chmod u-w ~/.bitcoin/signet/blocks/blk00003.dat
$ ./src/bitcoind -signet -reindex
...
2023-02-27T17:58:31Z Reindexing block file blk00003.dat...
2023-02-27T17:58:31Z Unable to open file /home/hebasto/.bitcoin/signet/blocks/blk00003.dat
2023-02-27T17:58:31Z ERROR: Flush: failed to open file 3
2023-02-27T17:58:31Z *** Flushing block file to disk failed. This is likely the result of an I/O error.
2023-02-27T17:58:31Z Error: A fatal internal error occurred, see debug.log for details
Error: A fatal internal error occurred, see debug.log for details
...
- this PR (5afd6bf274cf50743dc345eb9c0520c1b64c8069)
$ chmod u-w ~/.bitcoin/signet/blocks/blk00003.dat
$ ./src/bitcoind -signet -reindex # no errors
|
re-ACK, although now rebase is needed |
mzumsande
left a comment
There was a problem hiding this comment.
Concept ACK, will review more closely soon.
The added unit test seems to fail under Win64.
a9a9c86 to
e600eb4
Compare
|
force-push to e600eb442802ca7b23189c8ceee448730e22e75a:
|
|
@ryanofsky separate tests PR is ready for review: #27850 |
|
I think the milestone (#27039 (comment)) can be removed, given that this still needs rebase and is not a regression, or is it? |
|
Removed milestone. Let me know if it should be re-added. |
|
Rebased on master now that #27850 is merged. This PR becomes very slim, one line of code changed and switching the test from expected fail to expected pass. |
|
Should squash the two commits so that there isn't a commit for which the CI fails. |
done thanks |
furszy
left a comment
There was a problem hiding this comment.
Not blocking if others are happy with the current state.
I would prefer to split up FindBlockPos() prior to introducing any specific performance improvement. This method mixes two different functionalities with zero documentation and a misleading name. I think that we could move forward faster if the function wouldn't be that obscure.
I have an old branch for that (linked in the OP), was originally planning to PR it once this gets merged. |
There was a problem hiding this comment.
nit (only if you re-touch): I think you can just use self.start_node(0, ...)
|
Rebased on master to fix conflicts and address test changes in the followup #28660 Might be good to get review from @TheCharlatan because this PR touches code just updated in #27866 |
test: ensure we can reindex from read-only block files now
|
Thanks for the reviews, @mzumsande @furszy @pablomartin4btc @LarryRuane I just rebased on master to clean up CI |
|
utACK dfcef53 |
|
re-ACK dfcef53 |
|
ACK dfcef53 |
| self.nodes[0].assert_start_raises_init_error(extra_args=['-reindex', '-fastprune'], | ||
| expected_msg="Error: A fatal internal error occurred, see debug.log for details") | ||
| self.log.debug("Attempt to restart and reindex the node with the unwritable block file") | ||
| with self.nodes[0].wait_for_debug_log([b"Reindexing finished"]): |
There was a problem hiding this comment.
Any reason to change this to the aggressive busy-loop helper? The previous should work just fine with the right timeout. Also, I think wait_for_debug_log should be renamed to busy_wait_for_debug_log
There was a problem hiding this comment.
I'm not sure I understand. The previous code expected a crash so the test would know exactly when to check for the expected log message. In the new code bitcoind just runs fine so we have to poll the log for the success message.
There was a problem hiding this comment.
wait_for_debug_log (the variant of the function that accepts raw bytes) does not have a sleep, so it will try to maxx out IO at 100%, no?
There was a problem hiding this comment.
OK I see now thanks. So I guess... start_node calls wait_for_rpc_connection. Is RPC available before reindexing is finished? If we can rely on that to prevent race conditions then this could just be assert_debug_log.
There was a problem hiding this comment.
If we can rely on that to prevent race conditions then this could just be
assert_debug_log.
assert_debug_log is also syncing (it has a timeout argument), so no race should happen. My comment is only about the IO usage. assert_debug_log is not using a busy wait, but a sleepy wait. Otherwise they are exactly identical.
However, if assert_debug_log is used to sync, my personal preference is to provide the timeout argument, so that the code is self-documenting.
I think in this context my feedback is mostly of stylistic nature, but I could imagine other scenarios where a more expensive reindex in combination with the busy wait may lead to test timeouts on slow storage.
There was a problem hiding this comment.
Got it, thanks. Worth opening a new PR?
There was a problem hiding this comment.
If you want, yes, I am happy to review. Though, I won't create a pull myself.
Closes #2039
When reindexing from flat-file block storage there is no need to write anything back to disk, since the block data is already there. This PR skips flushing to disk those blocks that already have a known position in the datastore. Skipping this means that users can write-protect the
blkfiles on disk which may be useful for security or even safely sharing that data between multiple bitcoind instances.FindBlockPos()may also flush the undo data file, but again this is skipped if the corresponding block position is known, like during the initial stage of a reindex when block data is being indexed. Once the block index is complete the validation mechanism will callConnectBlock()which will save undo data at that time.The call stack looks like this:
A larger refactor of this part of the code was started by mzumsande here: https://github.com/mzumsande/bitcoin/tree/202207_refactor_findblockpos including this fix, reviewers can let me know if the changes should be combined.