Skip to content

Commit

Permalink
Optimize OverviewPage::updateTransactions()
Browse files Browse the repository at this point in the history
For wallets with a very large number of transactions, the
filter->setLimit(numItems) is extremely expensive... on the order
of a few seconds, because it also resorts the list if sort is
defined (and it is).

This simply stores the number of rows required for the overview
page in the filter, and only calls setLimit if the number of rows
is changed with a resize, etc. beyond a reasonable point (3x on
purpose). Instead the ui->listTransactions->setRowHidden function
is called in a for loop that dynamically sets the rows hidden that
are not displayable between the actual display limit and the setLimit
value (which is sized initially 3x the number of rows displayable).

This eliminates the delay when flipping back and forth between the
overview and the send, receive, or transaction views. It also improves
the resize of the window. I have picked scaling parameters on the size
of getLimit versus the number of rows displayable that should minimize
or eliminate GUI freezes under normal window resizing.

The wallet still does a list resort every time a block is received,
because the underlying wallet model is updated, so that will still cause
a GUI freeze for wallets with a large number of transactions. (Note
that I am talking about 40000+ transactions.)

This cannot be fixed without a major overhaul architecturally.
  • Loading branch information
jamescowens committed Jul 22, 2020
1 parent f023319 commit 93d3e39
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 9 deletions.
45 changes: 37 additions & 8 deletions src/qt/overviewpage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,16 +161,45 @@ void OverviewPage::showEvent(QShowEvent *event)
updateTransactions();
}

int OverviewPage::getNumTransactionsForView()
{
// Compute the maximum number of transactions the transaction list widget
// can hold without overflowing.
const size_t itemHeight = DECORATION_SIZE + ui->listTransactions->spacing();
const size_t contentsHeight = ui->listTransactions->height();
const int numItems = contentsHeight / itemHeight;

return numItems;
}


void OverviewPage::updateTransactions()
{
if(filter)
if (filter)
{
// Show the maximum number of transactions the transaction list widget
// can hold without overflowing.
const size_t itemHeight = DECORATION_SIZE + ui->listTransactions->spacing();
const size_t contentsHeight = ui->listTransactions->height();
const size_t numItems = contentsHeight / itemHeight;
filter->setLimit(numItems);
int numItems = getNumTransactionsForView();

// This is a "stairstep" approach, using x3 to x6 factors to size the getLimit.
// Based on testing with a wallet with a large number of transactions (40k+)
// Using a factor of three is a good balance between the setRowHidden loop
// and the very high expense of the getLimit call, which invalidates the filter
// and sort, and implicitly redoes the sort, which can take seconds.

// Most main window resizes will be done without an actual call to getLimit.
if (filter->getLimit() < numItems)
{
filter->setLimit(numItems * 3);
}
else if (filter->getLimit() > numItems * 6)
{
filter->setLimit(numItems * 3);
}

for (int i = 0; i <= filter->getLimit(); ++i)
{
ui->listTransactions->setRowHidden(i, i >= numItems);
}

ui->listTransactions->update();
}
}
Expand Down Expand Up @@ -240,8 +269,8 @@ void OverviewPage::setWalletModel(WalletModel *model)
filter->setDynamicSortFilter(true);
filter->setSortRole(Qt::EditRole);
filter->setShowInactive(false);
filter->setLimit(getNumTransactionsForView());
filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);

ui->listTransactions->setModel(filter.get());
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);

Expand Down
1 change: 1 addition & 0 deletions src/qt/overviewpage.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public slots:
void showEvent(QShowEvent *event);

private:
int getNumTransactionsForView();
void updateTransactions();

Ui::OverviewPage *ui;
Expand Down
5 changes: 5 additions & 0 deletions src/qt/transactionfilterproxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ void TransactionFilterProxy::setLimit(int limit)
invalidate();
}

int TransactionFilterProxy::getLimit()
{
return this->limitRows;
}

void TransactionFilterProxy::setShowInactive(bool showInactive)
{
this->showInactive = showInactive;
Expand Down
3 changes: 3 additions & 0 deletions src/qt/transactionfilterproxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class TransactionFilterProxy : public QSortFilterProxyModel
/** Set maximum number of rows returned, -1 if unlimited. */
void setLimit(int limit);

/** Get maximum number of rows returned, -1 if unlimited. */
int getLimit();

/** Set whether to show conflicted transactions. */
void setShowInactive(bool showInactive);

Expand Down
3 changes: 2 additions & 1 deletion src/qt/transactiontablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ class TransactionTablePriv
status = CT_DELETED; /* In model, but want to hide, treat as deleted */
}

LogPrint(BCLog::LogFlags::VERBOSE, " inWallet=%i inModel=%i Index=%i-%i showTransaction=%i derivedStatus=%i", inWallet, inModel, lowerIndex, upperIndex, showTransaction, status);
LogPrint(BCLog::LogFlags::VERBOSE, " inWallet=%i inModel=%i Index=%i-%i showTransaction=%i derivedStatus=%i",
inWallet, inModel, lowerIndex, upperIndex, showTransaction, status);


switch(status)
Expand Down

0 comments on commit 93d3e39

Please sign in to comment.