X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fdb.cpp;h=04f400e29a55c2a3b278a7c86a1960cc67f83ad9;hb=0561bbd1c69263dceb24ffacf850788e6e961a13;hp=2dddcf095a0e59d6e4fb2c2c2bb948ff2cc4b77a;hpb=d11488abd05cb39a9f481e7c4c35f780197a3d28;p=novacoin.git diff --git a/src/db.cpp b/src/db.cpp index 2dddcf0..04f400e 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -1,21 +1,27 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers +// Copyright (c) 2011-2012 The PPCoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "headers.h" #include "db.h" #include "net.h" +#include "checkpoints.h" +#include "util.h" +#include "main.h" #include #include #include +#ifndef WIN32 +#include "sys/stat.h" +#endif + using namespace std; using namespace boost; unsigned int nWalletDBUpdated; -uint64 nAccountingEntryNumber = 0; @@ -23,12 +29,12 @@ uint64 nAccountingEntryNumber = 0; // CDB // -static CCriticalSection cs_db; +CCriticalSection cs_db; static bool fDbEnvInit = false; +bool fDetachDB = false; DbEnv dbenv(0); -static map mapFileUseCount; +map mapFileUseCount; static map mapDb; -static int64 nTxn = 0; static void EnvShutdown() { @@ -44,7 +50,7 @@ static void EnvShutdown() { printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno()); } - DbEnv(0).remove(GetDataDir().c_str(), 0); + DbEnv(0).remove(GetDataDir().string().c_str(), 0); } class CDBInit @@ -61,7 +67,7 @@ public: instance_of_cdbinit; -CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL) +CDB::CDB(const char *pszFile, const char* pszMode) : pdb(NULL) { int ret; if (pszFile == NULL) @@ -73,29 +79,30 @@ CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL) if (fCreate) nFlags |= DB_CREATE; - CRITICAL_BLOCK(cs_db) { + LOCK(cs_db); if (!fDbEnvInit) { if (fShutdown) return; - string strDataDir = GetDataDir(); - string strLogDir = strDataDir + "/database"; - filesystem::create_directory(strLogDir.c_str()); - string strErrorFile = strDataDir + "/db.log"; - printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str()); + filesystem::path pathDataDir = GetDataDir(); + filesystem::path pathLogDir = pathDataDir / "database"; + filesystem::create_directory(pathLogDir); + filesystem::path pathErrorFile = pathDataDir / "db.log"; + printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str()); int nDbCache = GetArg("-dbcache", 25); - dbenv.set_lg_dir(strLogDir.c_str()); + dbenv.set_lg_dir(pathLogDir.string().c_str()); dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1); dbenv.set_lg_bsize(1048576); dbenv.set_lg_max(10485760); dbenv.set_lk_max_locks(10000); dbenv.set_lk_max_objects(10000); - dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug + dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug + dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); dbenv.set_flags(DB_AUTO_COMMIT, 1); dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); - ret = dbenv.open(strDataDir.c_str(), + ret = dbenv.open(pathDataDir.string().c_str(), DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | @@ -127,8 +134,10 @@ CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL) { delete pdb; pdb = NULL; - CRITICAL_BLOCK(cs_db) + { + LOCK(cs_db); --mapFileUseCount[strFile]; + } strFile = ""; throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret)); } @@ -161,25 +170,23 @@ void CDB::Close() nMinutes = 1; if (strFile == "addr.dat") nMinutes = 2; + if (strFile == "blkindex.dat") + nMinutes = 2; if (strFile == "blkindex.dat" && IsInitialBlockDownload()) nMinutes = 5; - if (nMinutes == 0 || nTxn > 200000) - { - nTxn = 0; - nMinutes = 0; - } - - dbenv.txn_checkpoint(0, nMinutes, 0); + dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0); - CRITICAL_BLOCK(cs_db) + { + LOCK(cs_db); --mapFileUseCount[strFile]; + } } -void static CloseDb(const string& strFile) +void CloseDb(const string& strFile) { - CRITICAL_BLOCK(cs_db) { + LOCK(cs_db); if (mapDb[strFile] != NULL) { // Close the database handle @@ -195,8 +202,8 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) { while (!fShutdown) { - CRITICAL_BLOCK(cs_db) { + LOCK(cs_db); if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0) { // Flush log data to the dat file @@ -228,8 +235,8 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) if (pcursor) while (fSuccess) { - CDataStream ssKey; - CDataStream ssValue; + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT); if (ret == DB_NOTFOUND) { @@ -293,8 +300,8 @@ void DBFlush(bool fShutdown) printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started"); if (!fDbEnvInit) return; - CRITICAL_BLOCK(cs_db) { + LOCK(cs_db); map::iterator mi = mapFileUseCount.begin(); while (mi != mapFileUseCount.end()) { @@ -305,9 +312,13 @@ void DBFlush(bool fShutdown) { // Move log data to the dat file CloseDb(strFile); + printf("%s checkpoint\n", strFile.c_str()); dbenv.txn_checkpoint(0, 0, 0); - printf("%s flush\n", strFile.c_str()); - dbenv.lsn_reset(strFile.c_str(), 0); + if ((strFile != "blkindex.dat" && strFile != "addr.dat") || fDetachDB) { + printf("%s detach\n", strFile.c_str()); + dbenv.lsn_reset(strFile.c_str(), 0); + } + printf("%s closed\n", strFile.c_str()); mapFileUseCount.erase(mi++); } else @@ -344,7 +355,6 @@ bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex) bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex) { assert(!fClient); - nTxn++; return Write(make_pair(string("tx"), hash), txindex); } @@ -355,7 +365,6 @@ bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeigh // Add to tx index uint256 hash = tx.GetHash(); CTxIndex txindex(pos, tx.vout.size()); - nTxn++; return Write(make_pair(string("tx"), hash), txindex); } @@ -387,10 +396,10 @@ bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector& loop { // Read next record - CDataStream ssKey; + CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0); - CDataStream ssValue; + CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; if (ret == DB_NOTFOUND) @@ -405,9 +414,15 @@ bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector& string strType; uint160 hashItem; CDiskTxPos pos; - ssKey >> strType >> hashItem >> pos; int nItemHeight; - ssValue >> nItemHeight; + + try { + ssKey >> strType >> hashItem >> pos; + ssValue >> nItemHeight; + } + catch (std::exception &e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); + } // Read transaction if (strType != "owner" || hashItem != hash160) @@ -473,14 +488,34 @@ bool CTxDB::WriteHashBestChain(uint256 hashBestChain) return Write(string("hashBestChain"), hashBestChain); } -bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork) +bool CTxDB::ReadBestInvalidTrust(uint64& nBestInvalidTrust) +{ + return Read(string("nBestInvalidTrust"), nBestInvalidTrust); +} + +bool CTxDB::WriteBestInvalidTrust(uint64 nBestInvalidTrust) +{ + return Write(string("nBestInvalidTrust"), nBestInvalidTrust); +} + +bool CTxDB::ReadSyncCheckpoint(uint256& hashCheckpoint) +{ + return Read(string("hashSyncCheckpoint"), hashCheckpoint); +} + +bool CTxDB::WriteSyncCheckpoint(uint256 hashCheckpoint) +{ + return Write(string("hashSyncCheckpoint"), hashCheckpoint); +} + +bool CTxDB::ReadCheckpointPubKey(string& strPubKey) { - return Read(string("bnBestInvalidWork"), bnBestInvalidWork); + return Read(string("strCheckpointPubKey"), strPubKey); } -bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork) +bool CTxDB::WriteCheckpointPubKey(const string& strPubKey) { - return Write(string("bnBestInvalidWork"), bnBestInvalidWork); + return Write(string("strCheckpointPubKey"), strPubKey); } CBlockIndex static * InsertBlockIndex(uint256 hash) @@ -515,10 +550,10 @@ bool CTxDB::LoadBlockIndex() loop { // Read next record - CDataStream ssKey; + CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) ssKey << make_pair(string("blockindex"), uint256(0)); - CDataStream ssValue; + CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; if (ret == DB_NOTFOUND) @@ -527,9 +562,11 @@ bool CTxDB::LoadBlockIndex() return false; // Unserialize + + try { string strType; ssKey >> strType; - if (strType == "blockindex") + if (strType == "blockindex" && !fRequestShutdown) { CDiskBlockIndex diskindex; ssValue >> diskindex; @@ -540,7 +577,10 @@ bool CTxDB::LoadBlockIndex() pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); pindexNew->nFile = diskindex.nFile; pindexNew->nBlockPos = diskindex.nBlockPos; + pindexNew->nChainTrust = diskindex.nChainTrust; pindexNew->nHeight = diskindex.nHeight; + pindexNew->fProofOfStake = diskindex.fProofOfStake; + pindexNew->prevoutStake = diskindex.prevoutStake; pindexNew->nVersion = diskindex.nVersion; pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->nTime = diskindex.nTime; @@ -553,28 +593,24 @@ bool CTxDB::LoadBlockIndex() if (!pindexNew->CheckIndex()) return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight); + + // ppcoin: build setStakeSeen + if (pindexNew->fProofOfStake) + setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); } else { - break; + break; // if shutdown requested or finished loading block index + } + } // try + catch (std::exception &e) { + return error("%s() : deserialize error", __PRETTY_FUNCTION__); } } pcursor->close(); - // Calculate bnChainWork - vector > vSortedByHeight; - vSortedByHeight.reserve(mapBlockIndex.size()); - BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) - { - CBlockIndex* pindex = item.second; - vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); - } - sort(vSortedByHeight.begin(), vSortedByHeight.end()); - BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) - { - CBlockIndex* pindex = item.second; - pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork(); - } + if (fRequestShutdown) + return true; // Load hashBestChain pointer to end of best chain if (!ReadHashBestChain(hashBestChain)) @@ -587,11 +623,16 @@ bool CTxDB::LoadBlockIndex() return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index"); pindexBest = mapBlockIndex[hashBestChain]; nBestHeight = pindexBest->nHeight; - bnBestChainWork = pindexBest->bnChainWork; - printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight); + nBestChainTrust = pindexBest->nChainTrust; + printf("LoadBlockIndex(): hashBestChain=%s height=%d trust=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, nBestChainTrust); + + // ppcoin: load hashSyncCheckpoint + if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint)) + return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded"); + printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str()); - // Load bnBestInvalidWork, OK if it doesn't exist - ReadBestInvalidWork(bnBestInvalidWork); + // Load nBestInvalidTrust, OK if it doesn't exist + ReadBestInvalidTrust(nBestInvalidTrust); // Verify blocks in the best chain int nCheckLevel = GetArg("-checklevel", 1); @@ -645,7 +686,7 @@ bool CTxDB::LoadBlockIndex() } } // check level 4: check whether spent txouts were spent within the main chain - int nOutput = 0; + unsigned int nOutput = 0; if (nCheckLevel>3) { BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent) @@ -755,8 +796,8 @@ bool CAddrDB::LoadAddresses() loop { // Read next record - CDataStream ssKey; - CDataStream ssValue; + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue); if (ret == DB_NOTFOUND) break; @@ -791,419 +832,3 @@ bool LoadAddresses() } - - -// -// CWalletDB -// - -bool CWalletDB::WriteName(const string& strAddress, const string& strName) -{ - nWalletDBUpdated++; - return Write(make_pair(string("name"), strAddress), strName); -} - -bool CWalletDB::EraseName(const string& strAddress) -{ - // 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. - nWalletDBUpdated++; - return Erase(make_pair(string("name"), strAddress)); -} - -bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account) -{ - account.SetNull(); - return Read(make_pair(string("acc"), strAccount), account); -} - -bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account) -{ - return Write(make_pair(string("acc"), strAccount), account); -} - -bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry) -{ - return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry); -} - -int64 CWalletDB::GetAccountCreditDebit(const string& strAccount) -{ - list entries; - ListAccountCreditDebit(strAccount, entries); - - int64 nCreditDebit = 0; - BOOST_FOREACH (const CAccountingEntry& entry, entries) - nCreditDebit += entry.nCreditDebit; - - return nCreditDebit; -} - -void CWalletDB::ListAccountCreditDebit(const string& strAccount, list& entries) -{ - bool fAllAccounts = (strAccount == "*"); - - Dbc* pcursor = GetCursor(); - if (!pcursor) - throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor"); - unsigned int fFlags = DB_SET_RANGE; - loop - { - // Read next record - CDataStream ssKey; - if (fFlags == DB_SET_RANGE) - ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0)); - CDataStream ssValue; - int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); - fFlags = DB_NEXT; - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - { - pcursor->close(); - throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB"); - } - - // Unserialize - string strType; - ssKey >> strType; - if (strType != "acentry") - break; - CAccountingEntry acentry; - ssKey >> acentry.strAccount; - if (!fAllAccounts && acentry.strAccount != strAccount) - break; - - ssValue >> acentry; - entries.push_back(acentry); - } - - pcursor->close(); -} - - -int CWalletDB::LoadWallet(CWallet* pwallet) -{ - pwallet->vchDefaultKey.clear(); - int nFileVersion = 0; - vector vWalletUpgrade; - bool fIsEncrypted = false; - - //// todo: shouldn't we catch exceptions and try to recover and continue? - CRITICAL_BLOCK(pwallet->cs_wallet) - { - int nMinVersion = 0; - if (Read((string)"minversion", nMinVersion)) - { - if (nMinVersion > CLIENT_VERSION) - return DB_TOO_NEW; - pwallet->LoadMinVersion(nMinVersion); - } - - // Get cursor - Dbc* pcursor = GetCursor(); - if (!pcursor) - { - printf("Error getting wallet database cursor\n"); - return DB_CORRUPT; - } - - loop - { - // Read next record - CDataStream ssKey; - CDataStream ssValue; - int ret = ReadAtCursor(pcursor, ssKey, ssValue); - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - { - printf("Error reading next record from wallet database\n"); - return DB_CORRUPT; - } - - // Unserialize - // Taking advantage of the fact that pair serialization - // is just the two items serialized one after the other - string strType; - ssKey >> strType; - if (strType == "name") - { - string strAddress; - ssKey >> strAddress; - ssValue >> pwallet->mapAddressBook[strAddress]; - } - else if (strType == "tx") - { - uint256 hash; - ssKey >> hash; - CWalletTx& wtx = pwallet->mapWallet[hash]; - ssValue >> wtx; - wtx.BindWallet(pwallet); - - if (wtx.GetHash() != hash) - printf("Error in wallet.dat, hash mismatch\n"); - - // Undo serialize changes in 31600 - if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703) - { - if (!ssValue.empty()) - { - char fTmp; - char fUnused; - ssValue >> fTmp >> fUnused >> wtx.strFromAccount; - printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str()); - wtx.fTimeReceivedIsTxTime = fTmp; - } - else - { - printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str()); - wtx.fTimeReceivedIsTxTime = 0; - } - vWalletUpgrade.push_back(hash); - } - - //// debug print - //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str()); - //printf(" %12"PRI64d" %s %s %s\n", - // wtx.vout[0].nValue, - // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(), - // wtx.hashBlock.ToString().substr(0,20).c_str(), - // wtx.mapValue["message"].c_str()); - } - else if (strType == "acentry") - { - string strAccount; - ssKey >> strAccount; - uint64 nNumber; - ssKey >> nNumber; - if (nNumber > nAccountingEntryNumber) - nAccountingEntryNumber = nNumber; - } - else if (strType == "key" || strType == "wkey") - { - vector vchPubKey; - ssKey >> vchPubKey; - CKey key; - if (strType == "key") - { - CPrivKey pkey; - ssValue >> pkey; - key.SetPubKey(vchPubKey); - key.SetPrivKey(pkey); - if (key.GetPubKey() != vchPubKey) - { - printf("Error reading wallet database: CPrivKey pubkey inconsistency\n"); - return DB_CORRUPT; - } - if (!key.IsValid()) - { - printf("Error reading wallet database: invalid CPrivKey\n"); - return DB_CORRUPT; - } - } - else - { - CWalletKey wkey; - ssValue >> wkey; - key.SetPubKey(vchPubKey); - key.SetPrivKey(wkey.vchPrivKey); - if (key.GetPubKey() != vchPubKey) - { - printf("Error reading wallet database: CWalletKey pubkey inconsistency\n"); - return DB_CORRUPT; - } - if (!key.IsValid()) - { - printf("Error reading wallet database: invalid CWalletKey\n"); - return DB_CORRUPT; - } - } - if (!pwallet->LoadKey(key)) - { - printf("Error reading wallet database: LoadKey failed\n"); - return DB_CORRUPT; - } - } - else if (strType == "mkey") - { - unsigned int nID; - ssKey >> nID; - CMasterKey kMasterKey; - ssValue >> kMasterKey; - if(pwallet->mapMasterKeys.count(nID) != 0) - { - printf("Error reading wallet database: duplicate CMasterKey id %u\n", nID); - return DB_CORRUPT; - } - pwallet->mapMasterKeys[nID] = kMasterKey; - if (pwallet->nMasterKeyMaxID < nID) - pwallet->nMasterKeyMaxID = nID; - } - else if (strType == "ckey") - { - vector vchPubKey; - ssKey >> vchPubKey; - vector vchPrivKey; - ssValue >> vchPrivKey; - if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey)) - { - printf("Error reading wallet database: LoadCryptedKey failed\n"); - return DB_CORRUPT; - } - fIsEncrypted = true; - } - else if (strType == "defaultkey") - { - ssValue >> pwallet->vchDefaultKey; - } - else if (strType == "pool") - { - int64 nIndex; - ssKey >> nIndex; - pwallet->setKeyPool.insert(nIndex); - } - else if (strType == "version") - { - ssValue >> nFileVersion; - if (nFileVersion == 10300) - nFileVersion = 300; - } - else if (strType == "cscript") - { - uint160 hash; - ssKey >> hash; - CScript script; - ssValue >> script; - if (!pwallet->LoadCScript(script)) - { - printf("Error reading wallet database: LoadCScript failed\n"); - return DB_CORRUPT; - } - } - } - pcursor->close(); - } - - BOOST_FOREACH(uint256 hash, vWalletUpgrade) - WriteTx(hash, pwallet->mapWallet[hash]); - - printf("nFileVersion = %d\n", nFileVersion); - - - // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: - if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000)) - return DB_NEED_REWRITE; - - if (nFileVersion < CLIENT_VERSION) // Update - { - // Get rid of old debug.log file in current directory - if (nFileVersion <= 105 && !pszSetDataDir[0]) - unlink("debug.log"); - - WriteVersion(CLIENT_VERSION); - } - - return DB_LOAD_OK; -} - -void ThreadFlushWalletDB(void* parg) -{ - const string& strFile = ((const string*)parg)[0]; - static bool fOneThread; - if (fOneThread) - return; - fOneThread = true; - if (!GetBoolArg("-flushwallet", true)) - return; - - unsigned int nLastSeen = nWalletDBUpdated; - unsigned int nLastFlushed = nWalletDBUpdated; - int64 nLastWalletUpdate = GetTime(); - while (!fShutdown) - { - Sleep(500); - - if (nLastSeen != nWalletDBUpdated) - { - nLastSeen = nWalletDBUpdated; - nLastWalletUpdate = GetTime(); - } - - if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2) - { - TRY_CRITICAL_BLOCK(cs_db) - { - // Don't do this if any databases are in use - int nRefCount = 0; - map::iterator mi = mapFileUseCount.begin(); - while (mi != mapFileUseCount.end()) - { - nRefCount += (*mi).second; - mi++; - } - - if (nRefCount == 0 && !fShutdown) - { - map::iterator mi = mapFileUseCount.find(strFile); - if (mi != mapFileUseCount.end()) - { - printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); - printf("Flushing wallet.dat\n"); - nLastFlushed = nWalletDBUpdated; - int64 nStart = GetTimeMillis(); - - // Flush wallet.dat so it's self contained - CloseDb(strFile); - dbenv.txn_checkpoint(0, 0, 0); - dbenv.lsn_reset(strFile.c_str(), 0); - - mapFileUseCount.erase(mi++); - printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart); - } - } - } - } - } -} - -bool BackupWallet(const CWallet& wallet, const string& strDest) -{ - if (!wallet.fFileBacked) - return false; - while (!fShutdown) - { - CRITICAL_BLOCK(cs_db) - { - if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0) - { - // Flush log data to the dat file - CloseDb(wallet.strWalletFile); - dbenv.txn_checkpoint(0, 0, 0); - dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0); - mapFileUseCount.erase(wallet.strWalletFile); - - // Copy wallet.dat - filesystem::path pathSrc(GetDataDir() + "/" + wallet.strWalletFile); - filesystem::path pathDest(strDest); - if (filesystem::is_directory(pathDest)) - pathDest = pathDest / wallet.strWalletFile; - - try { -#if BOOST_VERSION >= 104000 - filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists); -#else - filesystem::copy_file(pathSrc, pathDest); -#endif - printf("copied wallet.dat to %s\n", pathDest.string().c_str()); - return true; - } catch(const filesystem::filesystem_error &e) { - printf("error copying wallet.dat to %s - %s\n", pathDest.string().c_str(), e.what()); - return false; - } - } - } - Sleep(100); - } - return false; -}