See https://github.com/bitcoin/bitcoin/pull/1767
[novacoin.git] / src / db.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #ifndef BITCOIN_DB_H
6 #define BITCOIN_DB_H
7
8 #include "main.h"
9
10 #include <map>
11 #include <string>
12 #include <vector>
13
14 #include <db_cxx.h>
15
16 class CAddress;
17 class CAddrMan;
18 class CBlockLocator;
19 class CDiskBlockIndex;
20 class CDiskTxPos;
21 class CMasterKey;
22 class COutPoint;
23 class CTxIndex;
24 class CWallet;
25 class CWalletTx;
26
27 extern unsigned int nWalletDBUpdated;
28
29 void ThreadFlushWalletDB(void* parg);
30 bool BackupWallet(const CWallet& wallet, const std::string& strDest);
31 bool DumpWallet(CWallet* pwallet, const std::string& strDest);
32 bool ImportWallet(CWallet* pwallet, const std::string& strLocation);
33
34 class CDBEnv
35 {
36 private:
37     bool fDetachDB;
38     bool fDbEnvInit;
39     bool fMockDb;
40     boost::filesystem::path pathEnv;
41     std::string strPath;
42
43     void EnvShutdown();
44
45 public:
46     mutable CCriticalSection cs_db;
47     DbEnv dbenv;
48     std::map<std::string, int> mapFileUseCount;
49     std::map<std::string, Db*> mapDb;
50
51     CDBEnv();
52     ~CDBEnv();
53
54     /*
55      * Verify that database file strFile is OK. If it is not,
56      * call the callback to try to recover.
57      * This must be called BEFORE strFile is opened.
58      * Returns true if strFile is OK.
59      */
60     enum VerifyResult { VERIFY_OK, RECOVER_OK, RECOVER_FAIL };
61     VerifyResult Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile));
62     /*
63      * Salvage data from a file that Verify says is bad.
64      * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).
65      * Appends binary key/value pairs to vResult, returns true if successful.
66      * NOTE: reads the entire database into memory, so cannot be used
67      * for huge databases.
68      */
69     typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
70     bool Salvage(std::string strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
71
72     bool Open(boost::filesystem::path pathEnv_);
73     void Close();
74     void Flush(bool fShutdown);
75     void CheckpointLSN(std::string strFile);
76     void SetDetach(bool fDetachDB_) { fDetachDB = fDetachDB_; }
77     bool GetDetach() { return fDetachDB; }
78
79     void CloseDb(const std::string& strFile);
80     bool RemoveDb(const std::string& strFile);
81
82     DbTxn *TxnBegin(int flags=DB_TXN_WRITE_NOSYNC);
83 };
84
85 extern CDBEnv bitdb;
86
87
88 /** RAII class that provides access to a Berkeley database */
89 class CDB
90 {
91 protected:
92     Db* pdb;
93     std::string strFile;
94     DbTxn *activeTxn;
95     bool fReadOnly;
96
97     explicit CDB(const char* pszFile, const char* pszMode="r+");
98     ~CDB() { Close(); }
99 public:
100     void Close();
101 private:
102     CDB(const CDB&);
103     void operator=(const CDB&);
104
105 protected:
106     template<typename K, typename T>
107     bool Read(const K& key, T& value)
108     {
109         if (!pdb)
110             return false;
111
112         // Key
113         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
114         ssKey.reserve(1000);
115         ssKey << key;
116         Dbt datKey(&ssKey[0], (uint32_t)ssKey.size());
117
118         // Read
119         Dbt datValue;
120         datValue.set_flags(DB_DBT_MALLOC);
121         int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
122         memset(datKey.get_data(), 0, datKey.get_size());
123         if (datValue.get_data() == NULL)
124             return false;
125
126         // Unserialize value
127         try {
128             CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
129             ssValue >> value;
130         }
131         catch (const std::exception&) {
132             return false;
133         }
134
135         // Clear and free memory
136         memset(datValue.get_data(), 0, datValue.get_size());
137         free(datValue.get_data());
138         return (ret == 0);
139     }
140
141     template<typename K, typename T>
142     bool Write(const K& key, const T& value, bool fOverwrite=true)
143     {
144         if (!pdb)
145             return false;
146         if (fReadOnly)
147             assert(!"Write called on database in read-only mode");
148
149         // Key
150         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
151         ssKey.reserve(1000);
152         ssKey << key;
153         Dbt datKey(&ssKey[0], (uint32_t)ssKey.size());
154
155         // Value
156         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
157         ssValue.reserve(10000);
158         ssValue << value;
159         Dbt datValue(&ssValue[0], (uint32_t)ssValue.size());
160
161         // Write
162         int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
163
164         // Clear memory in case it was a private key
165         memset(datKey.get_data(), 0, datKey.get_size());
166         memset(datValue.get_data(), 0, datValue.get_size());
167         return (ret == 0);
168     }
169
170     template<typename K>
171     bool Erase(const K& key)
172     {
173         if (!pdb)
174             return false;
175         if (fReadOnly)
176             assert(!"Erase called on database in read-only mode");
177
178         // Key
179         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
180         ssKey.reserve(1000);
181         ssKey << key;
182         Dbt datKey(&ssKey[0], (uint32_t)ssKey.size());
183
184         // Erase
185         int ret = pdb->del(activeTxn, &datKey, 0);
186
187         // Clear memory
188         memset(datKey.get_data(), 0, datKey.get_size());
189         return (ret == 0 || ret == DB_NOTFOUND);
190     }
191
192     template<typename K>
193     bool Exists(const K& key)
194     {
195         if (!pdb)
196             return false;
197
198         // Key
199         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
200         ssKey.reserve(1000);
201         ssKey << key;
202         Dbt datKey(&ssKey[0], (uint32_t)ssKey.size());
203
204         // Exists
205         int ret = pdb->exists(activeTxn, &datKey, 0);
206
207         // Clear memory
208         memset(datKey.get_data(), 0, datKey.get_size());
209         return (ret == 0);
210     }
211
212     Dbc* GetCursor();
213     int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT);
214
215 public:
216     bool TxnBegin();
217     bool TxnCommit();
218     bool TxnAbort();
219     bool ReadVersion(int& nVersion);
220     bool WriteVersion(int nVersion);
221     bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
222 };
223
224
225 /** Access to the (IP) address database (peers.dat) */
226 class CAddrDB
227 {
228 private:
229     boost::filesystem::path pathAddr;
230 public:
231     CAddrDB();
232     bool Write(const CAddrMan& addr);
233     bool Read(CAddrMan& addr);
234 };
235
236 #endif // BITCOIN_DB_H