]> Git Repo - VerusCoin.git/blob - src/wallet/db.h
Make GetSerializeSize a wrapper on top of CSizeComputer
[VerusCoin.git] / src / wallet / db.h
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     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     DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
78     {
79         DbTxn* ptxn = NULL;
80         int ret = dbenv->txn_begin(NULL, &ptxn, flags);
81         if (!ptxn || ret != 0)
82             return NULL;
83         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     ~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     bool Read(const K& key, T& value)
114     {
115         if (!pdb)
116             return false;
117
118         // Key
119         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
120         ssKey.reserve(1000);
121         ssKey << key;
122         Dbt datKey(&ssKey[0], ssKey.size());
123
124         // Read
125         Dbt datValue;
126         datValue.set_flags(DB_DBT_MALLOC);
127         int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
128         memset(datKey.get_data(), 0, datKey.get_size());
129         if (datValue.get_data() == NULL)
130             return false;
131
132         // Unserialize value
133         try {
134             CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
135             ssValue >> value;
136         } catch (const std::exception&) {
137             return false;
138         }
139
140         // Clear and free memory
141         memset(datValue.get_data(), 0, datValue.get_size());
142         free(datValue.get_data());
143         return (ret == 0);
144     }
145
146     template <typename K, typename T>
147     bool Write(const K& key, const T& value, bool fOverwrite = true)
148     {
149         if (!pdb)
150             return false;
151         if (fReadOnly)
152             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         Dbt datKey(&ssKey[0], ssKey.size());
159
160         // Value
161         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
162         ssValue.reserve(10000);
163         ssValue << value;
164         Dbt datValue(&ssValue[0], ssValue.size());
165
166         // Write
167         int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
168
169         // Clear memory in case it was a private key
170         memset(datKey.get_data(), 0, datKey.get_size());
171         memset(datValue.get_data(), 0, datValue.get_size());
172         return (ret == 0);
173     }
174
175     template <typename K>
176     bool Erase(const K& key)
177     {
178         if (!pdb)
179             return false;
180         if (fReadOnly)
181             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         Dbt datKey(&ssKey[0], ssKey.size());
188
189         // Erase
190         int ret = pdb->del(activeTxn, &datKey, 0);
191
192         // Clear memory
193         memset(datKey.get_data(), 0, datKey.get_size());
194         return (ret == 0 || ret == DB_NOTFOUND);
195     }
196
197     template <typename K>
198     bool Exists(const K& key)
199     {
200         if (!pdb)
201             return false;
202
203         // Key
204         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
205         ssKey.reserve(1000);
206         ssKey << key;
207         Dbt datKey(&ssKey[0], ssKey.size());
208
209         // Exists
210         int ret = pdb->exists(activeTxn, &datKey, 0);
211
212         // Clear memory
213         memset(datKey.get_data(), 0, datKey.get_size());
214         return (ret == 0);
215     }
216
217     Dbc* GetCursor()
218     {
219         if (!pdb)
220             return NULL;
221         Dbc* pcursor = NULL;
222         int ret = pdb->cursor(NULL, &pcursor, 0);
223         if (ret != 0)
224             return NULL;
225         return pcursor;
226     }
227
228     int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT)
229     {
230         // Read at cursor
231         Dbt datKey;
232         if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
233             datKey.set_data(&ssKey[0]);
234             datKey.set_size(ssKey.size());
235         }
236         Dbt datValue;
237         if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
238             datValue.set_data(&ssValue[0]);
239             datValue.set_size(ssValue.size());
240         }
241         datKey.set_flags(DB_DBT_MALLOC);
242         datValue.set_flags(DB_DBT_MALLOC);
243         int ret = pcursor->get(&datKey, &datValue, fFlags);
244         if (ret != 0)
245             return ret;
246         else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
247             return 99999;
248
249         // Convert to streams
250         ssKey.SetType(SER_DISK);
251         ssKey.clear();
252         ssKey.write((char*)datKey.get_data(), datKey.get_size());
253         ssValue.SetType(SER_DISK);
254         ssValue.clear();
255         ssValue.write((char*)datValue.get_data(), datValue.get_size());
256
257         // Clear and free memory
258         memset(datKey.get_data(), 0, datKey.get_size());
259         memset(datValue.get_data(), 0, datValue.get_size());
260         free(datKey.get_data());
261         free(datValue.get_data());
262         return 0;
263     }
264
265 public:
266     bool TxnBegin()
267     {
268         if (!pdb || activeTxn)
269             return false;
270         DbTxn* ptxn = bitdb.TxnBegin();
271         if (!ptxn)
272             return false;
273         activeTxn = ptxn;
274         return true;
275     }
276
277     bool TxnCommit()
278     {
279         if (!pdb || !activeTxn)
280             return false;
281         int ret = activeTxn->commit(0);
282         activeTxn = NULL;
283         return (ret == 0);
284     }
285
286     bool TxnAbort()
287     {
288         if (!pdb || !activeTxn)
289             return false;
290         int ret = activeTxn->abort();
291         activeTxn = NULL;
292         return (ret == 0);
293     }
294
295     bool ReadVersion(int& nVersion)
296     {
297         nVersion = 0;
298         return Read(std::string("version"), nVersion);
299     }
300
301     bool WriteVersion(int nVersion)
302     {
303         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
This page took 0.041034 seconds and 4 git commands to generate.