changeset 98:0d4936cc5f56 draft

better wallet.dat flush, consolidated QueryPerformanceCounter, PRI64d printf portability
author s_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>
date Thu, 29 Oct 2009 20:10:46 +0000
parents 6772ea5d0b47
children c180d1d994f5
files build.txt db.cpp db.h main.cpp main.h makefile.vc net.h ui.cpp util.cpp util.h
diffstat 10 files changed, 121 insertions(+), 75 deletions(-) [+]
line wrap: on
line diff
--- a/build.txt
+++ b/build.txt
@@ -10,7 +10,7 @@
 
 Compilers Supported
 -------------------
-MinGW GCC (currently v3.4.5)
+MinGW GCC
 Microsoft Visual C++ 6.0 SP6
 
 
@@ -20,6 +20,7 @@
 
               default path   download
 wxWidgets      \wxwidgets     http://www.wxwidgets.org/downloads/
+                                or prebuilt: http://wxpack.sourceforge.net
 OpenSSL        \openssl       http://www.openssl.org/source/
 Berkeley DB    \db            http://www.oracle.com/technology/software/products/berkeley-db/index.html
 Boost          \boost         http://www.boost.org/users/download/
--- a/db.cpp
+++ b/db.cpp
@@ -4,8 +4,11 @@
 
 #include "headers.h"
 
+void ThreadFlushWalletDB(void* parg);
 
 
+unsigned int nWalletDBUpdated;
+
 
 
 
@@ -56,6 +59,8 @@
     {
         if (!fDbEnvInit)
         {
+            if (fShutdown)
+                return;
             string strAppDir = GetAppDir();
             string strLogDir = strAppDir + "\\database";
             _mkdir(strLogDir.c_str());
@@ -121,12 +126,10 @@
     pdb->close(0);
     delete pdb;
     pdb = NULL;
+    dbenv.txn_checkpoint(0, 0, 0);
 
     CRITICAL_BLOCK(cs_db)
-    {
-        dbenv.txn_checkpoint(0, 0, 0);
         --mapFileUseCount[strFile];
-    }
 
     RandAddSeed();
 }
@@ -499,25 +502,6 @@
 // CWalletDB
 //
 
-CWalletDB::~CWalletDB()
-{
-    // Flush whenever all handles to wallet.dat are closed
-    CRITICAL_BLOCK(cs_db)
-    {
-        Close(); // close includes a txn_checkpoint
-        map<string, int>::iterator mi = mapFileUseCount.find(strFile);
-        if (mi != mapFileUseCount.end())
-        {
-            int nRefCount = (*mi).second;
-            if (nRefCount == 0)
-            {
-                dbenv.lsn_reset(strFile.c_str(), 0);
-                mapFileUseCount.erase(mi++);
-            }
-        }
-    }
-}
-
 bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet)
 {
     vchDefaultKeyRet.clear();
@@ -610,7 +594,7 @@
 
     printf("fShowGenerated = %d\n", fShowGenerated);
     printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
-    printf("nTransactionFee = %I64d\n", nTransactionFee);
+    printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
     printf("addrIncoming = %s\n", addrIncoming.ToString().c_str());
     printf("fMinimizeToTray = %d\n", fMinimizeToTray);
     printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
@@ -655,5 +639,51 @@
         CWalletDB().WriteDefaultKey(keyUser.GetPubKey());
     }
 
+    _beginthread(ThreadFlushWalletDB, 0, NULL);
     return true;
 }
+
+void ThreadFlushWalletDB(void* parg)
+{
+    static bool fOneThread;
+    if (fOneThread)
+        return;
+    fOneThread = true;
+
+    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 && nLastWalletUpdate < GetTime() - 1)
+        {
+            TRY_CRITICAL_BLOCK(cs_db)
+            {
+                string strFile = "wallet.dat";
+                map<string, int>::iterator mi = mapFileUseCount.find(strFile);
+                if (mi != mapFileUseCount.end())
+                {
+                    int nRefCount = (*mi).second;
+                    if (nRefCount == 0 && !fShutdown)
+                    {
+                        // Flush wallet.dat so it's self contained
+                        nLastFlushed == nWalletDBUpdated;
+                        int64 nStart = PerformanceCounter();
+                        dbenv.txn_checkpoint(0, 0, 0);
+                        dbenv.lsn_reset(strFile.c_str(), 0);
+                        printf("Flushed wallet.dat %15"PRI64d"\n", PerformanceCounter() - nStart);
+                        mapFileUseCount.erase(mi++);
+                    }
+                }
+            }
+        }
+    }
+}
--- a/db.h
+++ b/db.h
@@ -17,7 +17,10 @@
 extern bool fClient;
 
 
+extern unsigned int nWalletDBUpdated;
 extern DbEnv dbenv;
+
+
 extern void DBFlush(bool fShutdown);
 
 
@@ -334,11 +337,11 @@
 
 
 
+
 class CWalletDB : public CDB
 {
 public:
     CWalletDB(const char* pszMode="r+", bool fTxn=false) : CDB("wallet.dat", pszMode, fTxn) { }
-    ~CWalletDB();
 private:
     CWalletDB(const CWalletDB&);
     void operator=(const CWalletDB&);
@@ -351,12 +354,14 @@
 
     bool WriteName(const string& strAddress, const string& strName)
     {
+        nWalletDBUpdated++;
         mapAddressBook[strAddress] = strName;
         return Write(make_pair(string("name"), strAddress), strName);
     }
 
     bool EraseName(const string& strAddress)
     {
+        nWalletDBUpdated++;
         mapAddressBook.erase(strAddress);
         return Erase(make_pair(string("name"), strAddress));
     }
@@ -368,11 +373,13 @@
 
     bool WriteTx(uint256 hash, const CWalletTx& wtx)
     {
+        nWalletDBUpdated++;
         return Write(make_pair(string("tx"), hash), wtx);
     }
 
     bool EraseTx(uint256 hash)
     {
+        nWalletDBUpdated++;
         return Erase(make_pair(string("tx"), hash));
     }
 
@@ -384,6 +391,7 @@
 
     bool WriteKey(const vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
     {
+        nWalletDBUpdated++;
         return Write(make_pair(string("key"), vchPubKey), vchPrivKey, false);
     }
 
@@ -395,6 +403,7 @@
 
     bool WriteDefaultKey(const vector<unsigned char>& vchPubKey)
     {
+        nWalletDBUpdated++;
         return Write(string("defaultkey"), vchPubKey);
     }
 
@@ -407,6 +416,7 @@
     template<typename T>
     bool WriteSetting(const string& strKey, const T& value)
     {
+        nWalletDBUpdated++;
         return Write(make_pair(string("setting"), strKey), value);
     }
 
--- a/main.cpp
+++ b/main.cpp
@@ -2518,8 +2518,7 @@
 
 int64 GetBalance()
 {
-    int64 nStart, nEnd;
-    QueryPerformanceCounter((LARGE_INTEGER*)&nStart);
+    int64 nStart = PerformanceCounter();
 
     int64 nTotal = 0;
     CRITICAL_BLOCK(cs_mapWallet)
@@ -2533,8 +2532,7 @@
         }
     }
 
-    QueryPerformanceCounter((LARGE_INTEGER*)&nEnd);
-    ///printf(" GetBalance() time = %16I64d\n", nEnd - nStart);
+    ///printf(" GetBalance() time = %15"PRI64d"\n", PerformanceCounter() - nStart);
     return nTotal;
 }
 
--- a/main.h
+++ b/main.h
@@ -344,7 +344,7 @@
     {
         if (scriptPubKey.size() < 6)
             return "CTxOut(error)";
-        return strprintf("CTxOut(nValue=%I64d.%08I64d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,24).c_str());
+        return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,24).c_str());
     }
 
     void print() const
--- a/makefile.vc
+++ b/makefile.vc
@@ -13,8 +13,8 @@
 
 
 
-INCLUDEPATHS=/I"/boost" /I"/DB/build_windows" /I"/OpenSSL/include" /I"/wxWidgets/lib/vc_lib/mswd" /I"/wxWidgets/include"
-LIBPATHS=/LIBPATH:"/DB/build_windows/$(BUILD)" /LIBPATH:"/OpenSSL/out" /LIBPATH:"/wxWidgets/lib/vc_lib"
+INCLUDEPATHS=/I"/boost" /I"/db/build_windows" /I"/openssl/include" /I"/wxwidgets/lib/vc_lib/mswd" /I"/wxwidgets/include"
+LIBPATHS=/LIBPATH:"/db/build_windows/$(BUILD)" /LIBPATH:"/openssl/out" /LIBPATH:"/wxwidgets/lib/vc_lib"
 LIBS= \
     libdb47s$(D).lib \
     libeay32.lib \
--- a/net.h
+++ b/net.h
@@ -589,7 +589,7 @@
         // We're using mapAskFor as a priority queue,
         // the key is the earliest time the request can be sent
         int64& nRequestTime = mapAlreadyAskedFor[inv];
-        printf("askfor %s  %I64d\n", inv.ToString().c_str(), nRequestTime);
+        printf("askfor %s  %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
 
         // Make sure not to reuse time indexes to keep things in the same order
         int64 nNow = (GetTime() - 1) * 1000000;
--- a/ui.cpp
+++ b/ui.cpp
@@ -3414,28 +3414,25 @@
     //
     bool fFirstRun;
     string strErrors;
-    int64 nStart, nEnd;
+    int64 nStart;
 
     printf("Loading addresses...\n");
-    QueryPerformanceCounter((LARGE_INTEGER*)&nStart);
+    nStart = PerformanceCounter();
     if (!LoadAddresses())
         strErrors += "Error loading addr.dat      \n";
-    QueryPerformanceCounter((LARGE_INTEGER*)&nEnd);
-    printf(" addresses   %20I64d\n", nEnd - nStart);
+    printf(" addresses   %15"PRI64d"\n", PerformanceCounter() - nStart);
 
     printf("Loading block index...\n");
-    QueryPerformanceCounter((LARGE_INTEGER*)&nStart);
+    nStart = PerformanceCounter();
     if (!LoadBlockIndex())
         strErrors += "Error loading blkindex.dat      \n";
-    QueryPerformanceCounter((LARGE_INTEGER*)&nEnd);
-    printf(" block index %20I64d\n", nEnd - nStart);
+    printf(" block index %15"PRI64d"\n", PerformanceCounter() - nStart);
 
     printf("Loading wallet...\n");
-    QueryPerformanceCounter((LARGE_INTEGER*)&nStart);
+    nStart = PerformanceCounter();
     if (!LoadWallet(fFirstRun))
         strErrors += "Error loading wallet.dat      \n";
-    QueryPerformanceCounter((LARGE_INTEGER*)&nEnd);
-    printf(" wallet      %20I64d\n", nEnd - nStart);
+    printf(" wallet      %15"PRI64d"\n", PerformanceCounter() - nStart);
 
     printf("Done loading\n");
 
@@ -3742,7 +3739,7 @@
         return;
     }
 
-    loop
+    while (!fShutdown)
     {
         Sleep(GetRand(30) * 1000 + 100);
 
@@ -3767,6 +3764,8 @@
         CScript scriptPubKey;
         scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
 
+        if (fShutdown)
+            return;
         if (!SendMoney(scriptPubKey, nValue, wtx))
             return;
     }
@@ -3776,8 +3775,6 @@
 // randsendtest to any connected node
 void RandSend()
 {
-    CWalletTx wtx;
-
     while (vNodes.empty())
         Sleep(1000);
     CAddress addr;
@@ -3785,6 +3782,7 @@
         addr = vNodes[GetRand(vNodes.size())]->addr;
 
     // Message
+    CWalletTx wtx;
     wtx.mapValue["to"] = addr.ToString();
     wtx.mapValue["from"] = addrLocalHost.ToString();
     static int nRep;
@@ -3799,6 +3797,8 @@
     }
 
     // Send to IP address
+    if (fShutdown)
+        return;
     CSendingDialog* pdialog = new CSendingDialog(pframeMain, addr, nValue, wtx);
     if (!pdialog->Show())
         wxMessageBox("ShowModal Failed  ");
--- a/util.cpp
+++ b/util.cpp
@@ -14,8 +14,7 @@
 
 // Init openssl library multithreading support
 static wxMutex** ppmutexOpenSSL;
-
-void win32_locking_callback(int mode, int i, const char* file, int line)
+void locking_callback(int mode, int i, const char* file, int line)
 {
     if (mode & CRYPTO_LOCK)
         ppmutexOpenSSL[i]->Lock();
@@ -33,7 +32,7 @@
         ppmutexOpenSSL = (wxMutex**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(wxMutex*));
         for (int i = 0; i < CRYPTO_num_locks(); i++)
             ppmutexOpenSSL[i] = new wxMutex();
-        CRYPTO_set_locking_callback(win32_locking_callback);
+        CRYPTO_set_locking_callback(locking_callback);
 
         // Seed random number generator with screen scrape and other hardware sources
         RAND_screen();
@@ -45,7 +44,7 @@
     {
         // Shutdown openssl library multithreading support
         CRYPTO_set_locking_callback(NULL);
-        for (int i =0 ; i < CRYPTO_num_locks(); i++)
+        for (int i = 0; i < CRYPTO_num_locks(); i++)
             delete ppmutexOpenSSL[i];
         OPENSSL_free(ppmutexOpenSSL);
     }
@@ -62,10 +61,9 @@
 void RandAddSeed()
 {
     // Seed with CPU performance counter
-    LARGE_INTEGER PerformanceCount;
-    QueryPerformanceCounter(&PerformanceCount);
-    RAND_add(&PerformanceCount, sizeof(PerformanceCount), 1.5);
-    memset(&PerformanceCount, 0, sizeof(PerformanceCount));
+    int64 nCounter = PerformanceCounter();
+    RAND_add(&nCounter, sizeof(nCounter), 1.5);
+    memset(&nCounter, 0, sizeof(nCounter));
 }
 
 void RandAddSeedPerfmon()
@@ -196,7 +194,7 @@
 string FormatMoney(int64 n, bool fPlus)
 {
     n /= CENT;
-    string str = strprintf("%I64d.%02I64d", (n > 0 ? n : -n)/100, (n > 0 ? n : -n)%100);
+    string str = strprintf("%"PRI64d".%02"PRI64d, (n > 0 ? n : -n)/100, (n > 0 ? n : -n)%100);
     for (int i = 6; i < str.size(); i += 4)
         if (isdigit(str[str.size() - i - 1]))
             str.insert(str.size() - i, 1, ',');
@@ -435,7 +433,7 @@
     if (vTimeOffsets.empty())
         vTimeOffsets.push_back(0);
     vTimeOffsets.push_back(nOffsetSample);
-    printf("Added time data, samples %d, offset %+I64d (%+I64d minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60);
+    printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60);
     if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
     {
         sort(vTimeOffsets.begin(), vTimeOffsets.end());
@@ -449,7 +447,7 @@
             ///    to make sure it doesn't get changed again
         }
         foreach(int64 n, vTimeOffsets)
-            printf("%+I64d  ", n);
-        printf("|  nTimeOffset = %+I64d  (%+I64d minutes)\n", nTimeOffset, nTimeOffset/60);
+            printf("%+"PRI64d"  ", n);
+        printf("|  nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
     }
 }
--- a/util.h
+++ b/util.h
@@ -13,7 +13,6 @@
 #if defined(_MSC_VER) && _MSC_VER < 1300
 #define for  if (false) ; else for
 #endif
-
 #ifndef _MSC_VER
 #define __forceinline  inline
 #endif
@@ -25,25 +24,22 @@
 #define UBEGIN(a)           ((unsigned char*)&(a))
 #define UEND(a)             ((unsigned char*)&((&(a))[1]))
 #define ARRAYLEN(array)     (sizeof(array)/sizeof((array)[0]))
-
-#ifdef _WINDOWS
 #define printf              OutputDebugStringF
-#endif
 
 #ifdef snprintf
 #undef snprintf
 #endif
 #define snprintf my_snprintf
 
-#ifndef PRId64
+#ifndef PRI64d
 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MSVCRT__)
-#define PRId64  "I64d"
-#define PRIu64  "I64u"
-#define PRIx64  "I64x"
+#define PRI64d  "I64d"
+#define PRI64u  "I64u"
+#define PRI64x  "I64x"
 #else
-#define PRId64  "lld"
-#define PRIu64  "llu"
-#define PRIx64  "llx"
+#define PRI64d  "lld"
+#define PRI64u  "llu"
+#define PRI64x  "llx"
 #endif
 #endif
 
@@ -64,8 +60,6 @@
 
 
 
-
-
 extern bool fDebug;
 extern bool fPrintToDebugger;
 extern bool fPrintToConsole;
@@ -101,9 +95,7 @@
 
 
 
-
-// Wrapper to automatically initialize critical section
-// Could use wxCriticalSection for portability, but it doesn't support TryEnterCriticalSection
+// Wrapper to automatically initialize critical sections
 class CCriticalSection
 {
 #ifdef __WXMSW__
@@ -191,6 +183,7 @@
         }
     }
 
+#ifdef __WXMSW__
     if (fPrintToDebugger)
     {
         // accumulate a line at a time
@@ -231,6 +224,7 @@
         }
     }
 #endif
+#endif
 
     if (fPrintToConsole)
     {
@@ -254,7 +248,7 @@
 
 inline string i64tostr(int64 n)
 {
-    return strprintf("%"PRId64, n);
+    return strprintf("%"PRI64d, n);
 }
 
 inline string itostr(int n)
@@ -328,6 +322,20 @@
     printf(pszFormat, HexStr(vch, fSpaces).c_str());
 }
 
+inline int64 PerformanceCounter()
+{
+    int64 nCounter = 0;
+    QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
+    return nCounter;
+}
+
+#ifndef __WXMSW__
+inline void Sleep(unsigned int nMilliseconds)
+{
+    wxMilliSleep(nMilliseconds);
+}
+#endif
+
 
 
 
@@ -370,6 +378,7 @@
 
 
 
+
 template<typename T1>
 inline uint256 Hash(const T1 pbegin, const T1 pend)
 {