8000 wallet: group independent db writes on single batched db transaction by furszy · Pull Request #25297 · bitcoin/bitcoin · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

wallet: group independent db writes on single batched db transaction #25297

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

Closed
wants to merge 23 commits into from

Conversation

furszy
Copy link
Member
@furszy furszy commented Jun 7, 2022

The block connection process, same as many other wallet processes, contains plenty individual db writes.

This PR batches all the db transaction that occurs along each wallet workflow. Dumping all the information to disk at once atomically at the end of the process.

Then, for BDB, fixed places where we are flushing to db directly on individual writes. e.g we do it in the in the chain sync/scan process, when an output that belongs to the wallet is found if the address is not inside the address book.


Plus, in several places across the wallet flows, we create new WalletBatch objects. Which, internally, mean: Increasing the db references number, try to open the db and, for SQLite, setup and bind the statements.
This PR avoids all this overhead by sharing the same db handler instance through each entire workflow.

@DrahtBot DrahtBot added the Wallet label Jun 7, 2022
@DrahtBot
Copy link
Contributor
DrahtBot commented Jun 8, 2022

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

Reviews

See the guideline for information on the review process.

Type Reviewers
Stale ACK w0xlt

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #bitcoin-core/gui/650 (Add Import to Wallet GUI by KolbyML)
  • #27601 (wallet: don't duplicate change output if already exist by furszy)
  • #27469 (wallet: improve IBD sync time by skipping block scanning prior birth time by furszy)
  • #27307 (wallet: track mempool conflicts with wallet transactions by ishaanam)
  • #27286 (wallet: Keep track of the wallet's own transaction outputs in memory by achow101)
  • #27145 (wallet: when a block is disconnected, update transactions that are no longer conflicted by ishaanam)
  • #26840 (refactor: importpubkey, importprivkey, importaddress, importmulti, and importdescriptors rpc by KolbyML)
  • #26728 (wallet: Have the wallet store the key for automatically generated descriptors by achow101)
  • #26715 (Introduce MockableDatabase for wallet unit tests by achow101)
  • #26627 (wallet: Migrate non-HD keys with single combo containing a list of keys by achow101)
  • #26008 (wallet: cache IsMine scriptPubKeys to improve performance of descriptor wallets by achow101)
  • #25907 (wallet: rpc to add automatically generated descriptors by achow101)
  • #25881 (wallet: remove unused DummySignTx and CKeyPool from GetReservedDestination by furszy)
  • #24914 (wallet: Load database records in a particular order by achow101)
  • #22838 (descriptors: Be able to specify change and receiving in a single descriptor string by achow101)
  • #22341 (rpc: add getxpub by Sjors)

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.

Copy link
Contributor
@w0xlt w0xlt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review ACK 843b987
These changes optimize and simplify the code.

Some nits. Feel free to ignore them.


if (auto* conf = std::get_if<TxStateConfirmed>(&state)) {
for (const CTxIn& txin : tx.vin) {
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
while (range.first != range.second) {
if (range.first->second != tx.GetHash()) {
WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), conf->confirmed_block_hash.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
MarkConflicted(batch, conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
MarkConflicted(batch, conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
MarkConflicted(batch, /*hashBlock=*/conf->confirmed_block_hash, /*conflicting_height=*/conf->confirmed_block_height, /*hashTx=*/range.first->second);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to do a const auto& txid = range.first->second; above the if block (the same value is accessed multiple times).

Will do it if have to retouch the area.

@furszy
Copy link
Member Author
furszy commented Jun 10, 2022

Thanks for the review w0xlt!

About the nits:
I don't think that the arguments names are needed in most of those cases, there isn't a real benefit adding them, the variables have a clear name that represent what they are (except one).

@achow101
Copy link
Member
achow101 commented Jun 13, 2022

Flush on close is probably not quite the performance improvement that you think it is. While it is an improvement for BDB, with SQLite, the argument is ignored. SQLite flushes after each write operation regardless. It would be better to use transactions with TxnBegin and TxnCommit as these do actually batch the operations into single atomic writes.

Otherwise, I think this is a good idea to be reusing the batches.

@furszy
Copy link
Member Author
furszy commented Jun 23, 2022

Thanks for the feedback 👌🏼

It would be better to use transactions with TxnBegin and TxnCommit as these do actually batch the operations into single atomic writes.

Almost there, been working on it :).

Otherwise, I think this is a good idea to be reusing the batches.

Have another branch with more of them (chained to the batched operations work). I'll probably end up decoupling some of them into another PR (otherwise this will end up being pretty big).

@furszy furszy force-pushed the 2022_wallet_unified_dbbatch branch 2 times, most recently from a26b1ea to e64d639 Compare June 28, 2022 22:14
@furszy
Copy link
Member Author
furszy commented Jun 28, 2022

Update:

Pushed the first step toward the implementation of db write batched operations for entire processes (single atomic writes).

Basically, is the utilization of the same db handler across all the methods, whom internally write to db, that are called during a specific process workflow (only the parent method who starts the process will construct the WalletBatch).

In order to provide the WalletBatch reference, without knowing if the underlying method/s will use it or not, implemented the capability to construct an uninitialized WalletBatch, who will be automatically initialized on the first write call.
If no db write method is called, the object will remain uninitialized for the entire process workflow without consuming any extra resource.

Note:
I haven't updated the PR description yet. Will do it once the work is finished (still have more to push).

@furszy furszy force-pushed the 2022_wallet_unified_dbbatch branch from 8c3c8e0 to 4be5200 Compare June 30, 2022 13:14
maflcko pushed a commit that referenced this pull request Jun 30, 2022
…h' is created

c318211 walletdb: fix last client version update (furszy)
bda8ebe wallet: don't read db every time that a new WalletBatch is created (furszy)

Pull request description:

  Found it while was working on #25297.

  We are performing a db read operation every time that a new `WalletBatch` is created, inside the constructor, just to check if the client version field is inside the db or not.

  As the client version field does not change in the entire db lifecycle, this operation can be done only once: The first time that the db is accessed/opened and the client version value can be cached.

ACKs for top commit:
  achow101:
    ACK c318211
  w0xlt:
    reACK c318211

Tree-SHA512: 7fb780c656e169e8eb21e7212242494a647f6506d6da2cca828703713d440d29c82bec9e7d2c410f37b49361226ccd80846d3eeb8168383d0c2a11d85d73bee2
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Jun 30, 2022
…letBatch' is created

c318211 walletdb: fix last client version update (furszy)
bda8ebe wallet: don't read db every time that a new WalletBatch is created (furszy)

Pull request description:

  Found it while was working on bitcoin#25297.

  We are performing a db read operation every time that a new `WalletBatch` is created, inside the constructor, just to check if the client version field is inside the db or not.

  As the client version field does not change in the entire db lifecycle, this operation can be done only once: The first time that the db is accessed/opened and the client version value can be cached.

ACKs for top commit:
  achow101:
    ACK c318211
  w0xlt:
    reACK bitcoin@c318211

Tree-SHA512: 7fb780c656e169e8eb21e7212242494a647f6506d6da2cca828703713d440d29c82bec9e7d2c410f37b49361226ccd80846d3eeb8168383d0c2a11d85d73bee2
@furszy furszy force-pushed the 2022_wallet_unified_dbbatch branch from 27d1315 to 21a914e Compare June 30, 2022 18:08
@furszy furszy changed the title wallet: speedup transactions sync, rescan and load not flushing to db constantly WIP, walXlet speedup transactions sync, rescan and load not flushing to db constantly Jul 1, 2022
furszy added 17 commits April 20, 2023 20:38
Add `initialize` flag to 'WalletBatch' constructor.

If "initialize=false" the handler will not open nor initialize the db on the constructor.

Users can create the handler object beforehand and pass it across different functions as ref.
Allowing an entire process to use the same handler, perform batched operations and
avoid db access acquisition if no write occurs.

The db access will, only, be initialized before the first write/erase operation.
So it can be re-used in time-long scenarios like whole chain scan/rescan
and walk-through a block vtx for connection/disconnection where we are
creating a new 'WalletBatch' on every single operation.

Example: new tx write, addressbook record storage, addressbook "mark used"
update, mark tx conflicted, update spent output etc.
…riteDescriptor

Instead of creating one internally.
… DeactivateScriptPubKeyMan

And remove unimplemented DescriptorScriptPubKeyMan::SetupDescriptor method.
@DrahtBot
Copy link
Contributor

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

@DrahtBot
Copy link
Contributor

There hasn't been much activity lately and the patch still needs rebase. What is the status here?

  • Is it still relevant? ➡️ Please solve the conflicts to make it ready for review and to ensure the CI passes.
  • Is it no longer relevant? ➡️ Please close.
  • Did the author lose interest or time to work on this? ➡️ Please close it and mark it 'Up for grabs' with the label, so that it can be picked up in the future.

1 similar comment
@DrahtBot
Copy link
Contributor

There hasn't been much activity lately and the patch still needs rebase. What is the status here?

  • Is it still relevant? ➡️ Please solve the conflicts to make it ready for review and to ensure the CI passes.
  • Is it no longer relevant? ➡️ Please close.
  • Did the author lose interest or time to work on this? ➡️ Please close it and mark it 'Up for grabs' with the label, so that it can be picked up in the future.

@furszy
Copy link
Member Author
furszy commented Nov 18, 2023

Still relevant and quite useful but closing it until #28574 and its derivatives are merged.

@furszy furszy closed this Nov 18, 2023
6DE7
@bitcoin bitcoin locked and limited conversation to collaborators Nov 17, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
0