[depends] native ccache 3.2.4
[bitcoinplatinum.git] / src / wallet / db.h
blob46bc0ac0a9f25992199931a3802ae3749ea1db9c
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.
6 #ifndef BITCOIN_WALLET_DB_H
7 #define BITCOIN_WALLET_DB_H
9 #include "clientversion.h"
10 #include "serialize.h"
11 #include "streams.h"
12 #include "sync.h"
13 #include "version.h"
15 #include <map>
16 #include <string>
17 #include <vector>
19 #include <boost/filesystem/path.hpp>
21 #include <db_cxx.h>
23 static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
25 extern unsigned int nWalletDBUpdated;
27 class CDBEnv
29 private:
30 bool fDbEnvInit;
31 bool fMockDb;
32 // Don't change into boost::filesystem::path, as that can result in
33 // shutdown problems/crashes caused by a static initialized internal pointer.
34 std::string strPath;
36 void EnvShutdown();
38 public:
39 mutable CCriticalSection cs_db;
40 DbEnv *dbenv;
41 std::map<std::string, int> mapFileUseCount;
42 std::map<std::string, Db*> mapDb;
44 CDBEnv();
45 ~CDBEnv();
46 void Reset();
48 void MakeMock();
49 bool IsMock() { return fMockDb; }
51 /**
52 * Verify that database file strFile is OK. If it is not,
53 * call the callback to try to recover.
54 * This must be called BEFORE strFile is opened.
55 * Returns true if strFile is OK.
57 enum VerifyResult { VERIFY_OK,
58 RECOVER_OK,
59 RECOVER_FAIL };
60 VerifyResult Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const 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.
68 typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
69 bool Salvage(const std::string& strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
71 bool Open(const boost::filesystem::path& path);
72 void Close();
73 void Flush(bool fShutdown);
74 void CheckpointLSN(const std::string& strFile);
76 void CloseDb(const std::string& strFile);
77 bool RemoveDb(const std::string& strFile);
79 DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
81 DbTxn* ptxn = NULL;
82 int ret = dbenv->txn_begin(NULL, &ptxn, flags);
83 if (!ptxn || ret != 0)
84 return NULL;
85 return ptxn;
89 extern CDBEnv bitdb;
92 /** RAII class that provides access to a Berkeley database */
93 class CDB
95 protected:
96 Db* pdb;
97 std::string strFile;
98 DbTxn* activeTxn;
99 bool fReadOnly;
100 bool fFlushOnClose;
102 explicit CDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
103 ~CDB() { Close(); }
105 public:
106 void Flush();
107 void Close();
109 private:
110 CDB(const CDB&);
111 void operator=(const CDB&);
113 protected:
114 template <typename K, typename T>
115 bool Read(const K& key, T& value)
117 if (!pdb)
118 return false;
120 // Key
121 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
122 ssKey.reserve(1000);
123 ssKey << key;
124 Dbt datKey(&ssKey[0], ssKey.size());
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;
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 } catch (const std::exception&) {
139 return false;
142 // Clear and free memory
143 memset(datValue.get_data(), 0, datValue.get_size());
144 free(datValue.get_data());
145 return (ret == 0);
148 template <typename K, typename T>
149 bool Write(const K& key, const T& value, bool fOverwrite = true)
151 if (!pdb)
152 return false;
153 if (fReadOnly)
154 assert(!"Write called on database in read-only mode");
156 // Key
157 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
158 ssKey.reserve(1000);
159 ssKey << key;
160 Dbt datKey(&ssKey[0], ssKey.size());
162 // Value
163 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
164 ssValue.reserve(10000);
165 ssValue << value;
166 Dbt datValue(&ssValue[0], ssValue.size());
168 // Write
169 int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
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);
177 template <typename K>
178 bool Erase(const K& key)
180 if (!pdb)
181 return false;
182 if (fReadOnly)
183 assert(!"Erase called on database in read-only mode");
185 // Key
186 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
187 ssKey.reserve(1000);
188 ssKey << key;
189 Dbt datKey(&ssKey[0], ssKey.size());
191 // Erase
192 int ret = pdb->del(activeTxn, &datKey, 0);
194 // Clear memory
195 memset(datKey.get_data(), 0, datKey.get_size());
196 return (ret == 0 || ret == DB_NOTFOUND);
199 template <typename K>
200 bool Exists(const K& key)
202 if (!pdb)
203 return false;
205 // Key
206 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
207 ssKey.reserve(1000);
208 ssKey << key;
209 Dbt datKey(&ssKey[0], ssKey.size());
211 // Exists
212 int ret = pdb->exists(activeTxn, &datKey, 0);
214 // Clear memory
215 memset(datKey.get_data(), 0, datKey.get_size());
216 return (ret == 0);
219 Dbc* GetCursor()
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;
230 int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT)
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 datKey.set_data(&ssKey[0]);
236 datKey.set_size(ssKey.size());
238 Dbt datValue;
239 if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
240 datValue.set_data(&ssValue[0]);
241 datValue.set_size(ssValue.size());
243 datKey.set_flags(DB_DBT_MALLOC);
244 datValue.set_flags(DB_DBT_MALLOC);
245 int ret = pcursor->get(&datKey, &datValue, fFlags);
246 if (ret != 0)
247 return ret;
248 else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
249 return 99999;
251 // Convert to streams
252 ssKey.SetType(SER_DISK);
253 ssKey.clear();
254 ssKey.write((char*)datKey.get_data(), datKey.get_size());
255 ssValue.SetType(SER_DISK);
256 ssValue.clear();
257 ssValue.write((char*)datValue.get_data(), datValue.get_size());
259 // Clear and free memory
260 memset(datKey.get_data(), 0, datKey.get_size());
261 memset(datValue.get_data(), 0, datValue.get_size());
262 free(datKey.get_data());
263 free(datValue.get_data());
264 return 0;
267 public:
268 bool TxnBegin()
270 if (!pdb || activeTxn)
271 return false;
272 DbTxn* ptxn = bitdb.TxnBegin();
273 if (!ptxn)
274 return false;
275 activeTxn = ptxn;
276 return true;
279 bool TxnCommit()
281 if (!pdb || !activeTxn)
282 return false;
283 int ret = activeTxn->commit(0);
284 activeTxn = NULL;
285 return (ret == 0);
288 bool TxnAbort()
290 if (!pdb || !activeTxn)
291 return false;
292 int ret = activeTxn->abort();
293 activeTxn = NULL;
294 return (ret == 0);
297 bool ReadVersion(int& nVersion)
299 nVersion = 0;
300 return Read(std::string("version"), nVersion);
303 bool WriteVersion(int nVersion)
305 return Write(std::string("version"), nVersion);
308 bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
311 #endif // BITCOIN_WALLET_DB_H