Merge #9227: Make nWalletDBUpdated atomic to avoid a potential race.

d63ff62 Make nWalletDBUpdated atomic to avoid a potential race. (Patrick Strateman)
This commit is contained in:
Wladimir J. van der Laan 2017-02-06 15:01:49 +01:00 committed by Alexander Block
parent 72a0d05d6b
commit eb4c5bac6d
5 changed files with 45 additions and 35 deletions

View File

@ -24,9 +24,6 @@
using namespace std; using namespace std;
unsigned int nWalletDBUpdated;
// //
// CDB // CDB
// //

View File

@ -23,8 +23,6 @@
static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100; static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
static const bool DEFAULT_WALLET_PRIVDB = true; static const bool DEFAULT_WALLET_PRIVDB = true;
extern unsigned int nWalletDBUpdated;
class CDBEnv class CDBEnv
{ {
private: private:

View File

@ -4892,7 +4892,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
walletInstance->ScanForWalletTransactions(pindexRescan, true); walletInstance->ScanForWalletTransactions(pindexRescan, true);
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
walletInstance->SetBestChain(chainActive.GetLocator()); walletInstance->SetBestChain(chainActive.GetLocator());
nWalletDBUpdated++; CWalletDB::IncrementUpdateCounter();
// Restore wallet transaction metadata after -zapwallettxes=1 // Restore wallet transaction metadata after -zapwallettxes=1
if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2")

View File

@ -16,6 +16,8 @@
#include "utiltime.h" #include "utiltime.h"
#include "wallet/wallet.h" #include "wallet/wallet.h"
#include <atomic>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
@ -24,13 +26,15 @@ using namespace std;
static uint64_t nAccountingEntryNumber = 0; static uint64_t nAccountingEntryNumber = 0;
static std::atomic<unsigned int> nWalletDBUpdateCounter;
// //
// CWalletDB // CWalletDB
// //
bool CWalletDB::WriteName(const string& strAddress, const string& strName) bool CWalletDB::WriteName(const string& strAddress, const string& strName)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Write(make_pair(string("name"), strAddress), strName); return Write(make_pair(string("name"), strAddress), strName);
} }
@ -38,37 +42,37 @@ bool CWalletDB::EraseName(const string& strAddress)
{ {
// This should only be used for sending addresses, never for receiving addresses, // This should only be used for sending addresses, never for receiving addresses,
// receiving addresses must always have an address book entry if they're not change return. // receiving addresses must always have an address book entry if they're not change return.
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Erase(make_pair(string("name"), strAddress)); return Erase(make_pair(string("name"), strAddress));
} }
bool CWalletDB::WritePurpose(const string& strAddress, const string& strPurpose) bool CWalletDB::WritePurpose(const string& strAddress, const string& strPurpose)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Write(make_pair(string("purpose"), strAddress), strPurpose); return Write(make_pair(string("purpose"), strAddress), strPurpose);
} }
bool CWalletDB::ErasePurpose(const string& strPurpose) bool CWalletDB::ErasePurpose(const string& strPurpose)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Erase(make_pair(string("purpose"), strPurpose)); return Erase(make_pair(string("purpose"), strPurpose));
} }
bool CWalletDB::WriteTx(const CWalletTx& wtx) bool CWalletDB::WriteTx(const CWalletTx& wtx)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx); return Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
} }
bool CWalletDB::EraseTx(uint256 hash) bool CWalletDB::EraseTx(uint256 hash)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Erase(std::make_pair(std::string("tx"), hash)); return Erase(std::make_pair(std::string("tx"), hash));
} }
bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta) bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey), if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
keyMeta, false)) keyMeta, false))
@ -88,7 +92,7 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
const CKeyMetadata &keyMeta) const CKeyMetadata &keyMeta)
{ {
const bool fEraseUnencryptedKey = true; const bool fEraseUnencryptedKey = true;
nWalletDBUpdated++; nWalletDBUpdateCounter++;
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey), if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
keyMeta)) keyMeta))
@ -106,31 +110,31 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey) bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true); return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
} }
bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript) bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false); return Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false);
} }
bool CWalletDB::WriteWatchOnly(const CScript &dest) bool CWalletDB::WriteWatchOnly(const CScript &dest)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1'); return Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1');
} }
bool CWalletDB::EraseWatchOnly(const CScript &dest) bool CWalletDB::EraseWatchOnly(const CScript &dest)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest))); return Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)));
} }
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator) bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
Write(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan Write(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
return Write(std::string("bestblock_nomerkle"), locator); return Write(std::string("bestblock_nomerkle"), locator);
} }
@ -143,13 +147,13 @@ bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext) bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Write(std::string("orderposnext"), nOrderPosNext); return Write(std::string("orderposnext"), nOrderPosNext);
} }
bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey) bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Write(std::string("defaultkey"), vchPubKey); return Write(std::string("defaultkey"), vchPubKey);
} }
@ -160,13 +164,13 @@ bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool) bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("pool"), nPool), keypool); return Write(std::make_pair(std::string("pool"), nPool), keypool);
} }
bool CWalletDB::ErasePool(int64_t nPool) bool CWalletDB::ErasePool(int64_t nPool)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Erase(std::make_pair(std::string("pool"), nPool)); return Erase(std::make_pair(std::string("pool"), nPool));
} }
@ -813,20 +817,20 @@ void ThreadFlushWalletDB()
if (!GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) if (!GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET))
return; return;
unsigned int nLastSeen = nWalletDBUpdated; unsigned int nLastSeen = CWalletDB::GetUpdateCounter();
unsigned int nLastFlushed = nWalletDBUpdated; unsigned int nLastFlushed = CWalletDB::GetUpdateCounter();
int64_t nLastWalletUpdate = GetTime(); int64_t nLastWalletUpdate = GetTime();
while (true) while (true)
{ {
MilliSleep(500); MilliSleep(500);
if (nLastSeen != nWalletDBUpdated) if (nLastSeen != CWalletDB::GetUpdateCounter())
{ {
nLastSeen = nWalletDBUpdated; nLastSeen = CWalletDB::GetUpdateCounter();
nLastWalletUpdate = GetTime(); nLastWalletUpdate = GetTime();
} }
if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2) if (nLastFlushed != CWalletDB::GetUpdateCounter() && GetTime() - nLastWalletUpdate >= 2)
{ {
TRY_LOCK(bitdb.cs_db,lockDb); TRY_LOCK(bitdb.cs_db,lockDb);
if (lockDb) if (lockDb)
@ -848,7 +852,7 @@ void ThreadFlushWalletDB()
if (_mi != bitdb.mapFileUseCount.end()) if (_mi != bitdb.mapFileUseCount.end())
{ {
LogPrint("db", "Flushing %s\n", strFile); LogPrint("db", "Flushing %s\n", strFile);
nLastFlushed = nWalletDBUpdated; nLastFlushed = CWalletDB::GetUpdateCounter();
int64_t nStart = GetTimeMillis(); int64_t nStart = GetTimeMillis();
// Flush wallet file so it's self contained // Flush wallet file so it's self contained
@ -955,25 +959,25 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename)
bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value) bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Write(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value); return Write(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
} }
bool CWalletDB::EraseDestData(const std::string &address, const std::string &key) bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key))); return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
} }
bool CWalletDB::WriteHDChain(const CHDChain& chain) bool CWalletDB::WriteHDChain(const CHDChain& chain)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
return Write(std::string("hdchain"), chain); return Write(std::string("hdchain"), chain);
} }
bool CWalletDB::WriteCryptedHDChain(const CHDChain& chain) bool CWalletDB::WriteCryptedHDChain(const CHDChain& chain)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
if (!Write(std::string("chdchain"), chain)) if (!Write(std::string("chdchain"), chain))
return false; return false;
@ -985,10 +989,20 @@ bool CWalletDB::WriteCryptedHDChain(const CHDChain& chain)
bool CWalletDB::WriteHDPubKey(const CHDPubKey& hdPubKey, const CKeyMetadata& keyMeta) bool CWalletDB::WriteHDPubKey(const CHDPubKey& hdPubKey, const CKeyMetadata& keyMeta)
{ {
nWalletDBUpdated++; nWalletDBUpdateCounter++;
if (!Write(std::make_pair(std::string("keymeta"), hdPubKey.extPubKey.pubkey), keyMeta, false)) if (!Write(std::make_pair(std::string("keymeta"), hdPubKey.extPubKey.pubkey), keyMeta, false))
return false; return false;
return Write(std::make_pair(std::string("hdpubkey"), hdPubKey.extPubKey.pubkey), hdPubKey, false); return Write(std::make_pair(std::string("hdpubkey"), hdPubKey.extPubKey.pubkey), hdPubKey, false);
} }
void CWalletDB::IncrementUpdateCounter()
{
nWalletDBUpdateCounter++;
}
unsigned int CWalletDB::GetUpdateCounter()
{
return nWalletDBUpdateCounter;
}

View File

@ -139,10 +139,11 @@ public:
bool WriteCryptedHDChain(const CHDChain& chain); bool WriteCryptedHDChain(const CHDChain& chain);
bool WriteHDPubKey(const CHDPubKey& hdPubKey, const CKeyMetadata& keyMeta); bool WriteHDPubKey(const CHDPubKey& hdPubKey, const CKeyMetadata& keyMeta);
static void IncrementUpdateCounter();
static unsigned int GetUpdateCounter();
private: private:
CWalletDB(const CWalletDB&); CWalletDB(const CWalletDB&);
void operator=(const CWalletDB&); void operator=(const CWalletDB&);
}; };
void ThreadFlushWalletDB(); void ThreadFlushWalletDB();