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