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