From 9e9869d0fe9c5cb38273a557e28b1922356d0e11 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 10 Nov 2011 21:29:23 +0100 Subject: [PATCH] Resilvering --- src/db.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/db.h | 5 ++- src/wallet.cpp | 10 ++++++ 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/src/db.cpp b/src/db.cpp index 7de1f8df..f083c777 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -165,6 +165,90 @@ void static CloseDb(const string& strFile) } } +bool Resilver(const string& strFile) +{ + while (!fShutdown) + { + CRITICAL_BLOCK(cs_db) + { + if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0) + { + // Flush log data to the dat file + CloseDb(strFile); + dbenv.txn_checkpoint(0, 0, 0); + dbenv.lsn_reset(strFile.c_str(), 0); + mapFileUseCount.erase(strFile); + + bool fSuccess = true; + printf("Resilvering %s...\n", strFile.c_str()); + string strFileRes = strFile + ".resilver"; + CDB db(strFile.c_str(), "r"); + Db* pdbCopy = new Db(&dbenv, 0); + + int ret = pdbCopy->open(NULL, // Txn pointer + strFileRes.c_str(), // Filename + "main", // Logical db name + DB_BTREE, // Database type + DB_CREATE, // Flags + 0); + if (ret > 0) + { + printf("Cannot create database file %s\n", strFileRes.c_str()); + fSuccess = false; + } + + Dbc* pcursor = db.GetCursor(); + if (pcursor) + while (fSuccess) + { + CDataStream ssKey; + CDataStream ssValue; + int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT); + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) + { + pcursor->close(); + fSuccess = false; + break; + } + Dbt datKey(&ssKey[0], ssKey.size()); + Dbt datValue(&ssValue[0], ssValue.size()); + int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE); + if (ret2 > 0) + fSuccess = false; + } + if (fSuccess) + { + Db* pdb = mapDb[strFile]; + if (pdb->close(0)) + fSuccess = false; + if (pdbCopy->close(0)) + fSuccess = false; + delete pdb; + delete pdbCopy; + mapDb[strFile] = NULL; + } + if (fSuccess) + { + Db dbA(&dbenv, 0); + if (dbA.remove(strFile.c_str(), NULL, 0)) + fSuccess = false; + Db dbB(&dbenv, 0); + if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) + fSuccess = false; + } + if (!fSuccess) + printf("Resilvering of %s FAILED!\n", strFileRes.c_str()); + return fSuccess; + } + } + Sleep(100); + } + return false; +} + + void DBFlush(bool fShutdown) { // Flush log data to the actual data file @@ -656,6 +740,8 @@ int CWalletDB::LoadWallet(CWallet* pwallet) pwallet->vchDefaultKey.clear(); int nFileVersion = 0; vector vWalletUpgrade; + bool fIsResilvered = false; + bool fIsEncrypted = false; // Modify defaults #ifndef WIN32 @@ -781,6 +867,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet) ssValue >> vchPrivKey; if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey)) return DB_CORRUPT; + fIsEncrypted = true; } else if (strType == "defaultkey") { @@ -814,6 +901,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet) if (strKey == "fMinimizeOnClose") ssValue >> fMinimizeOnClose; if (strKey == "fUseProxy") ssValue >> fUseProxy; if (strKey == "addrProxy") ssValue >> addrProxy; + if (strKey == "fIsResilvered") ssValue >> fIsResilvered; if (fHaveUPnP && strKey == "fUseUPnP") ssValue >> fUseUPnP; } else if (strType == "minversion") @@ -851,6 +939,8 @@ int CWalletDB::LoadWallet(CWallet* pwallet) WriteVersion(VERSION); } + if (fIsEncrypted && !fIsResilvered) + return DB_NEED_RESILVER; return DB_LOAD_OK; } diff --git a/src/db.h b/src/db.h index 73ea1902..75748ace 100644 --- a/src/db.h +++ b/src/db.h @@ -32,7 +32,7 @@ extern DbEnv dbenv; extern void DBFlush(bool fShutdown); void ThreadFlushWalletDB(void* parg); bool BackupWallet(const CWallet& wallet, const std::string& strDest); - +extern bool Resilver(const std::string& strFile); @@ -257,6 +257,8 @@ public: { return Write(std::string("version"), nVersion); } + + friend bool Resilver(const std::string&); }; @@ -349,6 +351,7 @@ enum DBErrors DB_CORRUPT, DB_TOO_NEW, DB_LOAD_FAIL, + DB_NEED_RESILVER }; class CWalletDB : public CDB diff --git a/src/wallet.cpp b/src/wallet.cpp index 64ee5c3b..3ed880f6 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -189,6 +189,9 @@ bool CWallet::EncryptWallet(const string& strWalletPassphrase) Lock(); } + if (Resilver(strWalletFile)) + CWalletDB(strWalletFile, "r+").WriteSetting("fIsResilvered", true); + return true; } @@ -1142,6 +1145,13 @@ int CWallet::LoadWallet(bool& fFirstRunRet) return false; fFirstRunRet = false; int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this); + if (nLoadWalletRet == DB_NEED_RESILVER) + { + if (Resilver(strWalletFile)) + CWalletDB(strWalletFile, "r+").WriteSetting("fIsResilvered", true); + nLoadWalletRet = DB_LOAD_OK; + } + if (nLoadWalletRet != DB_LOAD_OK) return nLoadWalletRet; fFirstRunRet = vchDefaultKey.empty();