-
Notifications
You must be signed in to change notification settings - Fork 333
wallet: Move wallets loading out from the main GUI thread #342
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
Conversation
|
Some occurrences of a seg fault in tests: |
promag
left a comment
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.
Concept ACK.
src/qt/guiutil.cpp
Outdated
| // Workaround for macOS-only Qt bug; see: QTBUG-65750, QTBUG-70357. | ||
| const int margin = TextWidth(dialog->fontMetrics(), ("X")); | ||
| dialog->resize(dialog->width() + 2 * margin, dialog->height()); | ||
| dialog->show(); |
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.
Direct call show() breaks that behavior on macos.
By "break" you mean it always shows, doesn't take into account minimumDuration. Only macos?
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.
By "break" you mean it always shows, doesn't take into account
minimumDuration.
Exactly.
Only macos?
The removed code is placed within #ifdef Q_OS_MAC.
| m_progress_dialog->setCancelButton(nullptr); | ||
| m_progress_dialog->setWindowModality(Qt::ApplicationModal); | ||
| GUIUtil::PolishProgressDialog(m_progress_dialog); | ||
| auto progress_dialog = new QProgressDialog(m_parent_widget); |
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 approach is fine for indeterminate progress dialog. If we want to change the progress or update the label text then having the member m_progress_dialog is better.
Either way, I think this change is unrelated to the goal of this PR.
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.
In commit "qt, wallet: Move activity progress dialog from data member to local" (6035536)
Either way, I think this change is unrelated to the goal of this PR.
People will have different ideas of what's related/unrelated, but I think this commit fits in with the rest of the PR by making sure activities are constructed/destroyed/used the same way. I can see how keeping m_progress_dialog pointer might make it possible to attach more inputs to the dialog later, but this apparently isn't needed right now, and even trying to do it seems like it would involve other complications like managing the pointer lifetime. By contrast the approach here of just connecting signals right away and not keeping the pointer seems simple while still being extensible.
| , m_wallet_controller(wallet_controller) | ||
| , m_parent_widget(parent_widget) | ||
| { | ||
| connect(this, &WalletControllerActivity::finished, this, &QObject::deleteLater); |
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.
Originally the idea was to allow the user to see activity details and then the user could dismiss or it could auto dismiss. I also think this is an unrelated change - this PR could also connect LoadWalletsActivity finished signal. But this is also fine and can be improved if later the original idea is implemented.
ryanofsky
left a comment
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.
Light code review ACK 8c9a9a3
I do think it is unfortunate so much boilerplate (WalletControllerActivity class definition, multiple methods, multiple single shot timers and signals) is added just to run 3 lines of code asynchronously.
It should be possible to have reusable utility:
RunAsynchronously([this] {
for (std::unique_ptr<interfaces::Wallet>& wallet : node().walletClient().getWallets()) {
m_wallet_controller->getOrCreateWallet(std::move(wallet));
}
})I did implement something like this previously (but with more features) as an experiment in bitcoin/bitcoin@master...ryanofsky:pr/gsync comment bitcoin/bitcoin#16874 (comment)
|
@ryanofsky agree, that or |
promag
left a comment
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.
@hebasto what do you think about splitting this PR?
shaavan
left a comment
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.
tACK 8c9a9a3
Tested on Ubuntu 20.04 (Using Qt version 5.12.8)
This PR adds a ‘Loading Wallet’ progress window for the initial loading of opened wallet after opening GUI. This PR also moves wallet loading out of the main GUI thread while simplifying some other aspects of the codebase.
I was able to test the PR successfully. I have added a screenshot for the resultant progress window I observed while opening the GUI.

The changes made in this PR are pretty extensive and detailed. Thanks for this fantastic work, @hebasto.
It took me quite a while to understand everything that has been done in this PR. That’s why I am sharing my notes that discuss the changes in quite detail. So that other reviewers could have an easier time reviewing this PR. If some of my observations are erroneous, please do inform me.
NOTES:
- qt, macos: Fix GUIUtil::PolishProgressDialog bug
- Done to prevent misbehaving of this PR in macOS.
- qt: Improve GUI responsiveness
- Removed
Q_UNUSEDbecause now dialog is being used at least once in any case under this function. setMinimumDurationis set through thePolishProgressDialogfunction. Since this function is used multiple times when settingsetMinimumDurationwas required, it makes sense to move that in this function. This change simplifies the code while maintaining the same functionality.- Under
WalletControllerActivity::showProgressDialogfunction,setValueis used for them_progress_dialogvariable. This starts the internal duration estimation. - The now redundant
setMinimumDurationinstruction fromBitcoinGUI::showProgressandWalletView::showProgressfunctions.
- Removed
- qt, wallet: Move activity progress dialog from data member to local
- Since the activity progress dialog has been moved from data member to local variable, subsequent changes have been made:
WalletControllerActivitydestructor has been restored to default destructor.- In
WalletControllerActivity::showProgressDialogfunction:m_progress_dialogvariable has been renamed toprogress_dialogto avoid naming confusion with a data member.- The non-existence of
m_progress_dialog(or progress_dialog) is not being asserted now.
- The
destroyProgressDialogfunction is also removed. Because now progress_dialog doesn’t exist out of the function scope and hence no need for aprogress_dialogdestructor.
- Since the activity progress dialog has been moved from data member to local variable, subsequent changes have been made:
- qt, wallet, refactor: Move connection to QObject::deleteLater to ctor
- Instead of creating similar connections multiple times for individual objects of class, the connection has been moved to the constructor of the common parent class itself, resulting in simplification of the code.
- qt, wallet: Add LoadWalletsActivity
- New
LoadWalletsActivityclass is declared as a child class of theWalletControllerActivityclass. - A function
Loadis added to the class that calls theshowProgressDialogfunction and loads the wallets. - This new class and its functions are appropriately declared under the
walletcontroler.hfile
- New
- qt, wallet: Move wallets loading out from the main GUI thread
- The new
LoadWalletActivity::Loadfunction is now used to load wallets at the start of the GUI. - The redundant code, which is now part of the Load function, has been removed from the WalletController constructor.
- The new
I hope these notes will be of some help to fellow reviewers.
8c9a9a3 to
e075098
Compare
ryanofsky
left a comment
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.
Code review ACK e075098. I still think the need for these activity classes and timer hacks is unfortunate, because it should be possible to have a utility function that takes a lambda, runs it asynchronously and posts a result back to the GUI thread. (The lambda would also be able to capture variables so would not be precluded from receiving input or posting incremental feedback either.) But the activity class here is pretty small and this suggestion isn't very important, just something to keep in mind if we are looking to reduce boilerplate and improve readability later.
| m_progress_dialog->setCancelButton(nullptr); | ||
| m_progress_dialog->setWindowModality(Qt::ApplicationModal); | ||
| GUIUtil::PolishProgressDialog(m_progress_dialog); | ||
| auto progress_dialog = new QProgressDialog(m_parent_widget); |
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.
In commit "qt, wallet: Move activity progress dialog from data member to local" (6035536)
Either way, I think this change is unrelated to the goal of this PR.
People will have different ideas of what's related/unrelated, but I think this commit fits in with the rest of the PR by making sure activities are constructed/destroyed/used the same way. I can see how keeping m_progress_dialog pointer might make it possible to attach more inputs to the dialog later, but this apparently isn't needed right now, and even trying to do it seems like it would involve other complications like managing the pointer lifetime. By contrast the approach here of just connecting signals right away and not keeping the pointer seems simple while still being extensible.
| GUIUtil::ExceptionSafeConnect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet); | ||
| connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet); | ||
|
|
||
| for (WalletModel* wallet_model : m_wallet_controller->getOpenWallets()) { |
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.
In commit "qt, wallet: Move wallets loading out from the main GUI thread" (e075098)
The getOpenWallets wallets method seems unused after this change and could be dropped
src/qt/walletcontroller.cpp
Outdated
| for (std::unique_ptr<interfaces::Wallet>& wallet : node().walletClient().getWallets()) { | ||
| m_wallet_controller->getOrCreateWallet(std::move(wallet)); | ||
| } |
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.
In commit "qt, wallet: Add LoadWalletsActivity" (6edff4d)
Note: This is not new code, this is existing code which is just being moved. The original code is deleted in the next commit. I would squash two commits for more clarity here, but it's not important, and of course the best way to split and group commits is subjective.
|
It seems like this would fix #247 by making the gui responsive during walletmodel loading. Is this the case? It might also be good to mention in the PR description |
Also this commit moves wallets loading out from the main GUI thread.
e075098 to
2fe69ef
Compare
|
Thank you for your reviews! Updated e075098 -> 2fe69ef (pr342.03 -> pr342.04):
UPDATE: #342 (comment)
Done. |
This is not true, in fact, it's the most expensive task, because on |
Yeah, |
I've re-read logs provided by @laanwj in #247 (comment) and I see now you are right. |
| { | ||
| showProgressDialog(tr("Loading wallets…")); | ||
|
|
||
| QTimer::singleShot(0, worker(), [this] { |
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.
Use GUIUtil::ObjectInvoke here and below?
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'd rather keep this PR as is, and in a follow up use GUIUtil::ObjectInvoke in a wider scope of all walletcontroller.cpp.
|
|
||
| QTimer::singleShot(0, worker(), [this] { | ||
| for (auto& wallet : node().walletClient().getWallets()) { | ||
| m_wallet_controller->getOrCreateWallet(std::move(wallet)); |
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.
nit, we could show progress and/or show each wallet name.
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.
Code review ACK 2fe69ef. Just suggested changes since last review: squashing commits and dropping unused method (thanks!)
shaavan
left a comment
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.
reACK 2fe69ef
Updates since my last review:
- PR rebased on current master
- Two Commits. qt, macOS: Fix GUIUtil::PolishProgressDialog bug and qt: Improve GUI responsiveness are dropped because they are no longer needed.
- Made appropriate changes to other commits and removed parts that are no longer needed or used.
- qt, wallet: Move wallets loading out from the main GUI thread and qt, wallet: Add LoadWalletsActivity class have been squashed together.
- New commit qt, wallet: Drop no longer used WalletController::getOpenWallets() which, as it say so, removed
getOpenWallets()function.
promag
left a comment
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.
Code review ACK 2fe69ef.
This PR improves the GUI responsiveness during initial wallets loading at startup (especially ones that have tons of txs), and shows a standard progress dialog for long loading:
Fixes #247.