Resilvering
authorPieter Wuille <pieter.wuille@gmail.com>
Thu, 10 Nov 2011 20:29:23 +0000 (21:29 +0100)
committerLuke Dashjr <luke-jr+git@utopios.org>
Tue, 15 Nov 2011 15:03:31 +0000 (10:03 -0500)
src/db.cpp
src/db.h
src/wallet.cpp

index a22b17e..d41da68 100644 (file)
@@ -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
@@ -674,6 +758,8 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
     pwallet->vchDefaultKey.clear();
     int nFileVersion = 0;
     vector<uint256> vWalletUpgrade;
+    bool fIsResilvered = false;
+    bool fIsEncrypted = false;
 
     // Modify defaults
 #ifndef __WXMSW__
@@ -799,6 +885,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
                 ssValue >> vchPrivKey;
                 if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
                     return DB_CORRUPT;
+                fIsEncrypted = true;
             }
             else if (strType == "defaultkey")
             {
@@ -832,6 +919,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")
@@ -869,6 +957,8 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
         WriteVersion(VERSION);
     }
 
+    if (fIsEncrypted && !fIsResilvered)
+        return DB_NEED_RESILVER;
 
     return DB_LOAD_OK;
 }
index 73ea190..75748ac 100644 (file)
--- 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
index 298a2c6..924700d 100644 (file)
@@ -190,6 +190,9 @@ bool CWallet::EncryptWallet(const string& strWalletPassphrase)
         Lock();
     }
 
+    if (Resilver(strWalletFile))
+        CWalletDB(strWalletFile, "r+").WriteSetting("fIsResilvered", true);
+
     return true;
 }
 
@@ -1122,6 +1125,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();