Add Google's LevelDB support
[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
32
33 class CDBEnv
34 {
35 private:
36     bool fDetachDB;
37     bool fDbEnvInit;
38     bool fMockDb;
39     boost::filesystem::path pathEnv;
40     std::string strPath;
41
42     void EnvShutdown();
43
44 public:
45     mutable CCriticalSection cs_db;
46     DbEnv dbenv;
47     std::map<std::string, int> mapFileUseCount;
48     std::map<std::string, Db*> mapDb;
49
50     CDBEnv();
51     ~CDBEnv();
52     void MakeMock();
53     bool IsMock() { return fMockDb; };
54
55     /*
56      * Verify that database file strFile is OK. If it is not,
57      * call the callback to try to recover.
58      * This must be called BEFORE strFile is opened.
59      * Returns true if strFile is OK.
60      */
61     enum VerifyResult { VERIFY_OK, RECOVER_OK, RECOVER_FAIL };
62     VerifyResult Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile));
63     /*
64      * Salvage data from a file that Verify says is bad.
65      * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).
66      * Appends binary key/value pairs to vResult, returns true if successful.
67      * NOTE: reads the entire database into memory, so cannot be used
68      * for huge databases.
69      */
70     typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
71     bool Salvage(std::string strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
72
73     bool Open(boost::filesystem::path pathEnv_);
74     void Close();
75     void Flush(bool fShutdown);
76     void CheckpointLSN(std::string strFile);
77     void SetDetach(bool fDetachDB_) { fDetachDB = fDetachDB_; }
78     bool GetDetach() { return fDetachDB; }
79
80     void CloseDb(const std::string& strFile);
81     bool RemoveDb(const std::string& strFile);
82
83     DbTxn *TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
84     {
85         DbTxn* ptxn = NULL;
86         int ret = dbenv.txn_begin(NULL, &ptxn, flags);
87         if (!ptxn || ret != 0)
88             return NULL;
89         return ptxn;
90     }
91 };
92
93 extern CDBEnv bitdb;
94
95
96 /** RAII class that provides access to a Berkeley database */
97 class CDB
98 {
99 protected:
100     Db* pdb;
101     std::string strFile;
102     DbTxn *activeTxn;
103     bool fReadOnly;
104
105     explicit CDB(const char* pszFile, const char* pszMode="r+");
106     ~CDB() { Close(); }
107 public:
108     void Close();
109 private:
110     CDB(const CDB&);
111     void operator=(const CDB&);
112
113 protected:
114     template<typename K, typename T>
115     bool Read(const K& key, T& value)
116     {
117         if (!pdb)
118             return false;
119
120         // Key
121         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
122         ssKey.reserve(1000);
123         ssKey << key;
124         Dbt datKey(&ssKey[0], ssKey.size());
125
126         // Read
127         Dbt datValue;
128         datValue.set_flags(DB_DBT_MALLOC);
129         int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
130         memset(datKey.get_data(), 0, datKey.get_size());
131         if (datValue.get_data() == NULL)
132             return false;
133
134         // Unserialize value
135         try {
136             CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
137             ssValue >> value;
138         }
139         catch (std::exception &e) {
140             return false;
141         }
142
143         // Clear and free memory
144         memset(datValue.get_data(), 0, datValue.get_size());
145         free(datValue.get_data());
146         return (ret == 0);
147     }
148
149     template<typename K, typename T>
150     bool Write(const K& key, const T& value, bool fOverwrite=true)
151     {
152         if (!pdb)
153             return false;
154         if (fReadOnly)
155             assert(!"Write called on database in read-only mode");
156
157         // Key
158         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
159         ssKey.reserve(1000);
160         ssKey << key;
161         Dbt datKey(&ssKey[0], ssKey.size());
162
163         // Value
164         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
165         ssValue.reserve(10000);
166         ssValue << value;
167         Dbt datValue(&ssValue[0], ssValue.size());
168
169         // Write
170         int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
171
172         // Clear memory in case it was a private key
173         memset(datKey.get_data(), 0, datKey.get_size());
174         memset(datValue.get_data(), 0, datValue.get_size());
175         return (ret == 0);
176     }
177
178     template<typename K>
179     bool Erase(const K& key)
180     {
181         if (!pdb)
182             return false;
183         if (fReadOnly)
184             assert(!"Erase called on database in read-only mode");
185
186         // Key
187         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
188         ssKey.reserve(1000);
189         ssKey << key;
190         Dbt datKey(&ssKey[0], ssKey.size());
191
192         // Erase
193         int ret = pdb->del(activeTxn, &datKey, 0);
194
195         // Clear memory
196         memset(datKey.get_data(), 0, datKey.get_size());
197         return (ret == 0 || ret == DB_NOTFOUND);
198     }
199
200     template<typename K>
201     bool Exists(const K& key)
202     {
203         if (!pdb)
204             return false;
205
206         // Key
207         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
208         ssKey.reserve(1000);
209         ssKey << key;
210         Dbt datKey(&ssKey[0], ssKey.size());
211
212         // Exists
213         int ret = pdb->exists(activeTxn, &datKey, 0);
214
215         // Clear memory
216         memset(datKey.get_data(), 0, datKey.get_size());
217         return (ret == 0);
218     }
219
220     Dbc* GetCursor()
221     {
222         if (!pdb)
223             return NULL;
224         Dbc* pcursor = NULL;
225         int ret = pdb->cursor(NULL, &pcursor, 0);
226         if (ret != 0)
227             return NULL;
228         return pcursor;
229     }
230
231     int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT)
232     {
233         // Read at cursor
234         Dbt datKey;
235         if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
236         {
237             datKey.set_data(&ssKey[0]);
238             datKey.set_size(ssKey.size());
239         }
240         Dbt datValue;
241         if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
242         {
243             datValue.set_data(&ssValue[0]);
244             datValue.set_size(ssValue.size());
245         }
246         datKey.set_flags(DB_DBT_MALLOC);
247         datValue.set_flags(DB_DBT_MALLOC);
248         int ret = pcursor->get(&datKey, &datValue, fFlags);
249         if (ret != 0)
250             return ret;
251         else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
252             return 99999;
253
254         // Convert to streams
255         ssKey.SetType(SER_DISK);
256         ssKey.clear();
257         ssKey.write((char*)datKey.get_data(), datKey.get_size());
258         ssValue.SetType(SER_DISK);
259         ssValue.clear();
260         ssValue.write((char*)datValue.get_data(), datValue.get_size());
261
262         // Clear and free memory
263         memset(datKey.get_data(), 0, datKey.get_size());
264         memset(datValue.get_data(), 0, datValue.get_size());
265         free(datKey.get_data());
266         free(datValue.get_data());
267         return 0;
268     }
269
270 public:
271     bool TxnBegin()
272     {
273         if (!pdb || activeTxn)
274             return false;
275         DbTxn* ptxn = bitdb.TxnBegin();
276         if (!ptxn)
277             return false;
278         activeTxn = ptxn;
279         return true;
280     }
281
282     bool TxnCommit()
283     {
284         if (!pdb || !activeTxn)
285             return false;
286         int ret = activeTxn->commit(0);
287         activeTxn = NULL;
288         return (ret == 0);
289     }
290
291     bool TxnAbort()
292     {
293         if (!pdb || !activeTxn)
294             return false;
295         int ret = activeTxn->abort();
296         activeTxn = NULL;
297         return (ret == 0);
298     }
299
300     bool ReadVersion(int& nVersion)
301     {
302         nVersion = 0;
303         return Read(std::string("version"), nVersion);
304     }
305
306     bool WriteVersion(int nVersion)
307     {
308         return Write(std::string("version"), nVersion);
309     }
310
311     bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
312 };
313
314
315 /** Access to the (IP) address database (peers.dat) */
316 class CAddrDB
317 {
318 private:
319     boost::filesystem::path pathAddr;
320 public:
321     CAddrDB();
322     bool Write(const CAddrMan& addr);
323     bool Read(CAddrMan& addr);
324 };
325
326 #endif // BITCOIN_DB_H