LCOV - code coverage report
Current view: top level - src/wallet - db.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 79 92 85.9 %
Date: 2015-10-12 22:39:14 Functions: 31 45 68.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2014 The Bitcoin Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #ifndef BITCOIN_WALLET_DB_H
       7             : #define BITCOIN_WALLET_DB_H
       8             : 
       9             : #include "clientversion.h"
      10             : #include "serialize.h"
      11             : #include "streams.h"
      12             : #include "sync.h"
      13             : #include "version.h"
      14             : 
      15             : #include <map>
      16             : #include <string>
      17             : #include <vector>
      18             : 
      19             : #include <boost/filesystem/path.hpp>
      20             : 
      21             : #include <db_cxx.h>
      22             : 
      23             : extern unsigned int nWalletDBUpdated;
      24             : 
      25             : class CDBEnv
      26             : {
      27             : private:
      28             :     bool fDbEnvInit;
      29             :     bool fMockDb;
      30             :     // Don't change into boost::filesystem::path, as that can result in
      31             :     // shutdown problems/crashes caused by a static initialized internal pointer.
      32             :     std::string strPath;
      33             : 
      34             :     void EnvShutdown();
      35             : 
      36             : public:
      37             :     mutable CCriticalSection cs_db;
      38             :     DbEnv *dbenv;
      39             :     std::map<std::string, int> mapFileUseCount;
      40             :     std::map<std::string, Db*> mapDb;
      41             : 
      42             :     CDBEnv();
      43             :     ~CDBEnv();
      44             :     void Reset();
      45             : 
      46             :     void MakeMock();
      47           0 :     bool IsMock() { return fMockDb; }
      48             : 
      49             :     /**
      50             :      * Verify that database file strFile is OK. If it is not,
      51             :      * call the callback to try to recover.
      52             :      * This must be called BEFORE strFile is opened.
      53             :      * Returns true if strFile is OK.
      54             :      */
      55             :     enum VerifyResult { VERIFY_OK,
      56             :                         RECOVER_OK,
      57             :                         RECOVER_FAIL };
      58             :     VerifyResult Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const std::string& strFile));
      59             :     /**
      60             :      * Salvage data from a file that Verify says is bad.
      61             :      * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).
      62             :      * Appends binary key/value pairs to vResult, returns true if successful.
      63             :      * NOTE: reads the entire database into memory, so cannot be used
      64             :      * for huge databases.
      65             :      */
      66             :     typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
      67             :     bool Salvage(const std::string& strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
      68             : 
      69             :     bool Open(const boost::filesystem::path& path);
      70             :     void Close();
      71             :     void Flush(bool fShutdown);
      72             :     void CheckpointLSN(const std::string& strFile);
      73             : 
      74             :     void CloseDb(const std::string& strFile);
      75             :     bool RemoveDb(const std::string& strFile);
      76             : 
      77           1 :     DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
      78             :     {
      79           1 :         DbTxn* ptxn = NULL;
      80           1 :         int ret = dbenv->txn_begin(NULL, &ptxn, flags);
      81           1 :         if (!ptxn || ret != 0)
      82             :             return NULL;
      83           0 :         return ptxn;
      84             :     }
      85             : };
      86             : 
      87             : extern CDBEnv bitdb;
      88             : 
      89             : 
      90             : /** RAII class that provides access to a Berkeley database */
      91             : class CDB
      92             : {
      93             : protected:
      94             :     Db* pdb;
      95             :     std::string strFile;
      96             :     DbTxn* activeTxn;
      97             :     bool fReadOnly;
      98             :     bool fFlushOnClose;
      99             : 
     100             :     explicit CDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
     101       19772 :     ~CDB() { Close(); }
     102             : 
     103             : public:
     104             :     void Flush();
     105             :     void Close();
     106             : 
     107             : private:
     108             :     CDB(const CDB&);
     109             :     void operator=(const CDB&);
     110             : 
     111             : protected:
     112             :     template <typename K, typename T>
     113        1248 :     bool Read(const K& key, T& value)
     114             :     {
     115        1248 :         if (!pdb)
     116             :             return false;
     117             : 
     118             :         // Key
     119             :         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
     120             :         ssKey.reserve(1000);
     121             :         ssKey << key;
     122        3744 :         Dbt datKey(&ssKey[0], ssKey.size());
     123             : 
     124             :         // Read
     125        2496 :         Dbt datValue;
     126        1248 :         datValue.set_flags(DB_DBT_MALLOC);
     127        1248 :         int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
     128        1248 :         memset(datKey.get_data(), 0, datKey.get_size());
     129        1248 :         if (datValue.get_data() == NULL)
     130             :             return false;
     131             : 
     132             :         // Unserialize value
     133             :         try {
     134        1182 :             CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
     135             :             ssValue >> value;
     136           0 :         } catch (const std::exception&) {
     137             :             return false;
     138             :         }
     139             : 
     140             :         // Clear and free memory
     141        1182 :         memset(datValue.get_data(), 0, datValue.get_size());
     142        1182 :         free(datValue.get_data());
     143        1182 :         return (ret == 0);
     144             :     }
     145             : 
     146             :     template <typename K, typename T>
     147        8235 :     bool Write(const K& key, const T& value, bool fOverwrite = true)
     148             :     {
     149        8235 :         if (!pdb)
     150             :             return false;
     151        8235 :         if (fReadOnly)
     152           0 :             assert(!"Write called on database in read-only mode");
     153             : 
     154             :         // Key
     155             :         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
     156             :         ssKey.reserve(1000);
     157             :         ssKey << key;
     158       24705 :         Dbt datKey(&ssKey[0], ssKey.size());
     159             : 
     160             :         // Value
     161             :         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
     162             :         ssValue.reserve(10000);
     163        1730 :         ssValue << value;
     164       24705 :         Dbt datValue(&ssValue[0], ssValue.size());
     165             : 
     166             :         // Write
     167        8235 :         int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
     168             : 
     169             :         // Clear memory in case it was a private key
     170        8235 :         memset(datKey.get_data(), 0, datKey.get_size());
     171        8235 :         memset(datValue.get_data(), 0, datValue.get_size());
     172        8235 :         return (ret == 0);
     173             :     }
     174             : 
     175             :     template <typename K>
     176         752 :     bool Erase(const K& key)
     177             :     {
     178         752 :         if (!pdb)
     179             :             return false;
     180         752 :         if (fReadOnly)
     181           0 :             assert(!"Erase called on database in read-only mode");
     182             : 
     183             :         // Key
     184             :         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
     185             :         ssKey.reserve(1000);
     186             :         ssKey << key;
     187        2256 :         Dbt datKey(&ssKey[0], ssKey.size());
     188             : 
     189             :         // Erase
     190         752 :         int ret = pdb->del(activeTxn, &datKey, 0);
     191             : 
     192             :         // Clear memory
     193         752 :         memset(datKey.get_data(), 0, datKey.get_size());
     194         752 :         return (ret == 0 || ret == DB_NOTFOUND);
     195             :     }
     196             : 
     197             :     template <typename K>
     198         119 :     bool Exists(const K& key)
     199             :     {
     200         119 :         if (!pdb)
     201             :             return false;
     202             : 
     203             :         // Key
     204             :         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
     205             :         ssKey.reserve(1000);
     206             :         ssKey << key;
     207         357 :         Dbt datKey(&ssKey[0], ssKey.size());
     208             : 
     209             :         // Exists
     210         119 :         int ret = pdb->exists(activeTxn, &datKey, 0);
     211             : 
     212             :         // Clear memory
     213         119 :         memset(datKey.get_data(), 0, datKey.get_size());
     214         119 :         return (ret == 0);
     215             :     }
     216             : 
     217        1539 :     Dbc* GetCursor()
     218             :     {
     219        1539 :         if (!pdb)
     220             :             return NULL;
     221        1539 :         Dbc* pcursor = NULL;
     222        1539 :         int ret = pdb->cursor(NULL, &pcursor, 0);
     223        1539 :         if (ret != 0)
     224             :             return NULL;
     225        1539 :         return pcursor;
     226             :     }
     227             : 
     228       10700 :     int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT)
     229             :     {
     230             :         // Read at cursor
     231       10700 :         Dbt datKey;
     232       10700 :         if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
     233        1418 :             datKey.set_data(&ssKey[0]);
     234        1418 :             datKey.set_size(ssKey.size());
     235             :         }
     236       21400 :         Dbt datValue;
     237       10700 :         if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
     238           0 :             datValue.set_data(&ssValue[0]);
     239           0 :             datValue.set_size(ssValue.size());
     240             :         }
     241       10700 :         datKey.set_flags(DB_DBT_MALLOC);
     242       10700 :         datValue.set_flags(DB_DBT_MALLOC);
     243       10700 :         int ret = pcursor->get(&datKey, &datValue, fFlags);
     244       10700 :         if (ret != 0)
     245             :             return ret;
     246       10579 :         else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
     247             :             return 99999;
     248             : 
     249             :         // Convert to streams
     250       10579 :         ssKey.SetType(SER_DISK);
     251             :         ssKey.clear();
     252       10579 :         ssKey.write((char*)datKey.get_data(), datKey.get_size());
     253       10579 :         ssValue.SetType(SER_DISK);
     254             :         ssValue.clear();
     255       10579 :         ssValue.write((char*)datValue.get_data(), datValue.get_size());
     256             : 
     257             :         // Clear and free memory
     258       10579 :         memset(datKey.get_data(), 0, datKey.get_size());
     259       10579 :         memset(datValue.get_data(), 0, datValue.get_size());
     260       10579 :         free(datKey.get_data());
     261       10579 :         free(datValue.get_data());
     262       21279 :         return 0;
     263             :     }
     264             : 
     265             : public:
     266           1 :     bool TxnBegin()
     267             :     {
     268           1 :         if (!pdb || activeTxn)
     269             :             return false;
     270           1 :         DbTxn* ptxn = bitdb.TxnBegin();
     271           1 :         if (!ptxn)
     272             :             return false;
     273           1 :         activeTxn = ptxn;
     274           0 :         return true;
     275             :     }
     276             : 
     277           1 :     bool TxnCommit()
     278             :     {
     279           1 :         if (!pdb || !activeTxn)
     280             :             return false;
     281           1 :         int ret = activeTxn->commit(0);
     282           1 :         activeTxn = NULL;
     283           1 :         return (ret == 0);
     284             :     }
     285             : 
     286           0 :     bool TxnAbort()
     287             :     {
     288           0 :         if (!pdb || !activeTxn)
     289             :             return false;
     290           0 :         int ret = activeTxn->abort();
     291           0 :         activeTxn = NULL;
     292           0 :         return (ret == 0);
     293             :     }
     294             : 
     295             :     bool ReadVersion(int& nVersion)
     296             :     {
     297             :         nVersion = 0;
     298             :         return Read(std::string("version"), nVersion);
     299             :     }
     300             : 
     301          62 :     bool WriteVersion(int nVersion)
     302             :     {
     303         186 :         return Write(std::string("version"), nVersion);
     304             :     }
     305             : 
     306             :     bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
     307             : };
     308             : 
     309             : #endif // BITCOIN_WALLET_DB_H

Generated by: LCOV version 1.11