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