Skip to content

Commit 3e7c891

Browse files
committed
Optimisation: Store transaction list order in memory rather than compute it every need
Huge performance improvement (450%) for zapwallettxes
1 parent eac53ec commit 3e7c891

File tree

6 files changed

+44
-52
lines changed

6 files changed

+44
-52
lines changed

src/test/accounting_tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
4545
ae.nTime = 1333333333;
4646
ae.strOtherAccount = "b";
4747
ae.strComment = "";
48-
walletdb.WriteAccountingEntry(ae);
48+
pwalletMain->AddAccountingEntry(ae, walletdb);
4949

5050
wtx.mapValue["comment"] = "z";
5151
pwalletMain->AddToWallet(wtx, false, &walletdb);
@@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
5555

5656
ae.nTime = 1333333336;
5757
ae.strOtherAccount = "c";
58-
walletdb.WriteAccountingEntry(ae);
58+
pwalletMain->AddAccountingEntry(ae, walletdb);
5959

6060
GetResults(walletdb, results);
6161

@@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
7171
ae.nTime = 1333333330;
7272
ae.strOtherAccount = "d";
7373
ae.nOrderPos = pwalletMain->IncOrderPosNext();
74-
walletdb.WriteAccountingEntry(ae);
74+
pwalletMain->AddAccountingEntry(ae, walletdb);
7575

7676
GetResults(walletdb, results);
7777

@@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
121121
ae.nTime = 1333333334;
122122
ae.strOtherAccount = "e";
123123
ae.nOrderPos = -1;
124-
walletdb.WriteAccountingEntry(ae);
124+
pwalletMain->AddAccountingEntry(ae, walletdb);
125125

126126
GetResults(walletdb, results);
127127

src/wallet/rpcwallet.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ UniValue movecmd(const UniValue& params, bool fHelp)
835835
debit.nTime = nNow;
836836
debit.strOtherAccount = strTo;
837837
debit.strComment = strComment;
838-
walletdb.WriteAccountingEntry(debit);
838+
pwalletMain->AddAccountingEntry(debit, walletdb);
839839

840840
// Credit
841841
CAccountingEntry credit;
@@ -845,7 +845,7 @@ UniValue movecmd(const UniValue& params, bool fHelp)
845845
credit.nTime = nNow;
846846
credit.strOtherAccount = strFrom;
847847
credit.strComment = strComment;
848-
walletdb.WriteAccountingEntry(credit);
848+
pwalletMain->AddAccountingEntry(credit, walletdb);
849849

850850
if (!walletdb.TxnCommit())
851851
throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
@@ -1470,11 +1470,10 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
14701470

14711471
UniValue ret(UniValue::VARR);
14721472

1473-
std::list<CAccountingEntry> acentries;
1474-
CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1473+
const CWallet::TxItems & txOrdered = pwalletMain->wtxOrdered;
14751474

14761475
// iterate backwards until we have nCount items to return:
1477-
for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1476+
for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
14781477
{
14791478
CWalletTx *const pwtx = (*it).second.first;
14801479
if (pwtx != 0)
@@ -1579,8 +1578,7 @@ UniValue listaccounts(const UniValue& params, bool fHelp)
15791578
}
15801579
}
15811580

1582-
list<CAccountingEntry> acentries;
1583-
CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1581+
const list<CAccountingEntry> & acentries = pwalletMain->laccentries;
15841582
BOOST_FOREACH(const CAccountingEntry& entry, acentries)
15851583
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
15861584

src/wallet/wallet.cpp

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -588,31 +588,6 @@ int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
588588
return nRet;
589589
}
590590

591-
CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount)
592-
{
593-
AssertLockHeld(cs_wallet); // mapWallet
594-
CWalletDB walletdb(strWalletFile);
595-
596-
// First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap.
597-
TxItems txOrdered;
598-
599-
// Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
600-
// would make this much faster for applications that do this a lot.
601-
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
602-
{
603-
CWalletTx* wtx = &((*it).second);
604-
txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0)));
605-
}
606-
acentries.clear();
607-
walletdb.ListAccountCreditDebit(strAccount, acentries);
608-
BOOST_FOREACH(CAccountingEntry& entry, acentries)
609-
{
610-
txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
611-
}
612-
613-
return txOrdered;
614-
}
615-
616591
void CWallet::MarkDirty()
617592
{
618593
{
@@ -629,7 +604,9 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
629604
if (fFromLoadWallet)
630605
{
631606
mapWallet[hash] = wtxIn;
632-
mapWallet[hash].BindWallet(this);
607+
CWalletTx& wtx = mapWallet[hash];
608+
wtx.BindWallet(this);
609+
wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
633610
AddToSpends(hash);
634611
}
635612
else
@@ -644,6 +621,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
644621
{
645622
wtx.nTimeReceived = GetAdjustedTime();
646623
wtx.nOrderPos = IncOrderPosNext(pwalletdb);
624+
wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
647625

648626
wtx.nTimeSmart = wtx.nTimeReceived;
649627
if (!wtxIn.hashBlock.IsNull())
@@ -655,9 +633,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
655633
{
656634
// Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
657635
int64_t latestTolerated = latestNow + 300;
658-
std::list<CAccountingEntry> acentries;
659-
TxItems txOrdered = OrderedTxItems(acentries);
660-
for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
636+
const TxItems & txOrdered = wtxOrdered;
637+
for (TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
661638
{
662639
CWalletTx *const pwtx = (*it).second.first;
663640
if (pwtx == &wtx)
@@ -2118,6 +2095,18 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
21182095
return true;
21192096
}
21202097

2098+
bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB & pwalletdb)
2099+
{
2100+
if (!pwalletdb.WriteAccountingEntry_Backend(acentry))
2101+
return false;
2102+
2103+
laccentries.push_back(acentry);
2104+
CAccountingEntry & entry = laccentries.back();
2105+
wtxOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
2106+
2107+
return true;
2108+
}
2109+
21212110
CAmount CWallet::GetRequiredFee(unsigned int nTxBytes)
21222111
{
21232112
return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));

src/wallet/wallet.h

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,11 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
531531
}
532532

533533
std::map<uint256, CWalletTx> mapWallet;
534+
std::list<CAccountingEntry> laccentries;
535+
536+
typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
537+
typedef std::multimap<int64_t, TxPair > TxItems;
538+
TxItems wtxOrdered;
534539

535540
int64_t nOrderPosNext;
536541
std::map<uint256, int> mapRequestCount;
@@ -617,16 +622,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
617622
*/
618623
int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL);
619624

620-
typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
621-
typedef std::multimap<int64_t, TxPair > TxItems;
622-
623-
/**
624-
* Get the wallet's activity log
625-
* @return multimap of ordered transactions and accounting entries
626-
* @warning Returned pointers are *only* valid within the scope of passed acentries
627-
*/
628-
TxItems OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount = "");
629-
630625
void MarkDirty();
631626
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb);
632627
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
@@ -656,6 +651,8 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
656651
std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
657652
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
658653

654+
bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb);
655+
659656
static CFeeRate minTxFee;
660657
/**
661658
* Estimate the minimum fee considering user set parameters

src/wallet/walletdb.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccount
191191
return Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
192192
}
193193

194-
bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
194+
bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry)
195195
{
196196
return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
197197
}
@@ -709,6 +709,12 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
709709
if (wss.fAnyUnordered)
710710
result = ReorderTransactions(pwallet);
711711

712+
pwallet->laccentries.clear();
713+
ListAccountCreditDebit("*", pwallet->laccentries);
714+
BOOST_FOREACH(CAccountingEntry& entry, pwallet->laccentries) {
715+
pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry)));
716+
}
717+
712718
return result;
713719
}
714720

src/wallet/walletdb.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ class CWalletDB : public CDB
110110

111111
bool WriteMinVersion(int nVersion);
112112

113+
/// This writes directly to the database, and will not update the CWallet's cached accounting entries!
114+
/// Use wallet.AddAccountingEntry instead, to write *and* update its caches.
115+
bool WriteAccountingEntry_Backend(const CAccountingEntry& acentry);
113116
bool ReadAccount(const std::string& strAccount, CAccount& account);
114117
bool WriteAccount(const std::string& strAccount, const CAccount& account);
115118

@@ -118,7 +121,6 @@ class CWalletDB : public CDB
118121
/// Erase destination data tuple from wallet database
119122
bool EraseDestData(const std::string &address, const std::string &key);
120123

121-
bool WriteAccountingEntry(const CAccountingEntry& acentry);
122124
CAmount GetAccountCreditDebit(const std::string& strAccount);
123125
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
124126

0 commit comments

Comments
 (0)