Introduce enum ServiceFlags for service flags
[bitcoinplatinum.git] / src / wallet / db.h
blob01b8c71a04bbbeb4bd195df8267b37a22222e141
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2015 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;
24 static const bool DEFAULT_WALLET_PRIVDB = true;
26 extern unsigned int nWalletDBUpdated;
28 class CDBEnv
30 private:
31 bool fDbEnvInit;
32 bool fMockDb;
33 // Don't change into boost::filesystem::path, as that can result in
34 // shutdown problems/crashes caused by a static initialized internal pointer.
35 std::string strPath;
37 void EnvShutdown();
39 public:
40 mutable CCriticalSection cs_db;
41 DbEnv *dbenv;
42 std::map<std::string, int> mapFileUseCount;
43 std::map<std::string, Db*> mapDb;
45 CDBEnv();
46 ~CDBEnv();
47 void Reset();
49 void MakeMock();
50 bool IsMock() { return fMockDb; }
52 /**
53 * Verify that database file strFile is OK. If it is not,
54 * call the callback to try to recover.
55 * This must be called BEFORE strFile is opened.
56 * Returns true if strFile is OK.
58 enum VerifyResult { VERIFY_OK,
59 RECOVER_OK,
60 RECOVER_FAIL };
61 VerifyResult Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const std::string& strFile));
62 /**
63 * Salvage data from a file that Verify says is bad.
64 * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).
65 * Appends binary key/value pairs to vResult, returns true if successful.
66 * NOTE: reads the entire database into memory, so cannot be used
67 * for huge databases.
69 typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
70 bool Salvage(const std::string& strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
72 bool Open(const boost::filesystem::path& path);
73 void Close();
74 void Flush(bool fShutdown);
75 void CheckpointLSN(const std::string& strFile);
77 void CloseDb(const std::string& strFile);
78 bool RemoveDb(const std::string& strFile);
80 DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
82 DbTxn* ptxn = NULL;
83 int ret = dbenv->txn_begin(NULL, &ptxn, flags);
84 if (!ptxn || ret != 0)
85 return NULL;
86 return ptxn;
90 extern CDBEnv bitdb;
93 /** RAII class that provides access to a Berkeley database */
94 class CDB
96 protected:
97 Db* pdb;
98 std::string strFile;
99 DbTxn* activeTxn;
100 bool fReadOnly;
101 bool fFlushOnClose;
103 explicit CDB(const std::string& strFilename, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
104 ~CDB() { Close(); }
106 public:
107 void Flush();
108 void Close();
110 private:
111 CDB(const CDB&);
112 void operator=(const CDB&);
114 protected:
115 template <typename K, typename T>
116 bool Read(const K& key, T& value)
118 if (!pdb)
119 return false;
121 // Key
122 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
123 ssKey.reserve(1000);
124 ssKey << key;
125 Dbt datKey(&ssKey[0], ssKey.size());
127 // Read
128 Dbt datValue;
129 datValue.set_flags(DB_DBT_MALLOC);
130 int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
131 memset(datKey.get_data(), 0, datKey.get_size());
132 if (datValue.get_data() == NULL)
133 return false;
135 // Unserialize value
136 try {
137 CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
138 ssValue >> value;
139 } catch (const std::exception&) {
140 return false;
143 // Clear and free memory
144 memset(datValue.get_data(), 0, datValue.get_size());
145 free(datValue.get_data());
146 return (ret == 0);
149 template <typename K, typename T>
150 bool Write(const K& key, const T& value, bool fOverwrite = true)
152 if (!pdb)
153 return false;
154 if (fReadOnly)
155 assert(!"Write called on database in read-only mode");
157 // Key
158 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
159 ssKey.reserve(1000);
160 ssKey << key;
161 Dbt datKey(&ssKey[0], ssKey.size());
163 // Value
164 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
165 ssValue.reserve(10000);
166 ssValue << value;
167 Dbt datValue(&ssValue[0], ssValue.size());
169 // Write
170 int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
172 // Clear memory in case it was a private key
173 memset(datKey.get_data(), 0, datKey.get_size());
174 memset(datValue.get_data(), 0, datValue.get_size());
175 return (ret == 0);
178 template <typename K>
179 bool Erase(const K& key)
181 if (!pdb)
182 return false;
183 if (fReadOnly)
184 assert(!"Erase called on database in read-only mode");
186 // Key
187 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
188 ssKey.reserve(1000);
189 ssKey << key;
190 Dbt datKey(&ssKey[0], ssKey.size());
192 // Erase
193 int ret = pdb->del(activeTxn, &datKey, 0);
195 // Clear memory
196 memset(datKey.get_data(), 0, datKey.get_size());
197 return (ret == 0 || ret == DB_NOTFOUND);
200 template <typename K>
201 bool Exists(const K& key)
203 if (!pdb)
204 return false;
206 // Key
207 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
208 ssKey.reserve(1000);
209 ssKey << key;
210 Dbt datKey(&ssKey[0], ssKey.size());
212 // Exists
213 int ret = pdb->exists(activeTxn, &datKey, 0);
215 // Clear memory
216 memset(datKey.get_data(), 0, datKey.get_size());
217 return (ret == 0);
220 Dbc* GetCursor()
222 if (!pdb)
223 return NULL;
224 Dbc* pcursor = NULL;
225 int ret = pdb->cursor(NULL, &pcursor, 0);
226 if (ret != 0)
227 return NULL;
228 return pcursor;
231 int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT)
233 // Read at cursor
234 Dbt datKey;
235 if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
236 datKey.set_data(&ssKey[0]);
237 datKey.set_size(ssKey.size());
239 Dbt datValue;
240 if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
241 datValue.set_data(&ssValue[0]);
242 datValue.set_size(ssValue.size());
244 datKey.set_flags(DB_DBT_MALLOC);
245 datValue.set_flags(DB_DBT_MALLOC);
246 int ret = pcursor->get(&datKey, &datValue, fFlags);
247 if (ret != 0)
248 return ret;
249 else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
250 return 99999;
252 // Convert to streams
253 ssKey.SetType(SER_DISK);
254 ssKey.clear();
255 ssKey.write((char*)datKey.get_data(), datKey.get_size());
256 ssValue.SetType(SER_DISK);
257 ssValue.clear();
258 ssValue.write((char*)datValue.get_data(), datValue.get_size());
260 // Clear and free memory
261 memset(datKey.get_data(), 0, datKey.get_size());
262 memset(datValue.get_data(), 0, datValue.get_size());
263 free(datKey.get_data());
264 free(datValue.get_data());
265 return 0;
268 public:
269 bool TxnBegin()
271 if (!pdb || activeTxn)
272 return false;
273 DbTxn* ptxn = bitdb.TxnBegin();
274 if (!ptxn)
275 return false;
276 activeTxn = ptxn;
277 return true;
280 bool TxnCommit()
282 if (!pdb || !activeTxn)
283 return false;
284 int ret = activeTxn->commit(0);
285 activeTxn = NULL;
286 return (ret == 0);
289 bool TxnAbort()
291 if (!pdb || !activeTxn)
292 return false;
293 int ret = activeTxn->abort();
294 activeTxn = NULL;
295 return (ret == 0);
298 bool ReadVersion(int& nVersion)
300 nVersion = 0;
301 return Read(std::string("version"), nVersion);
304 bool WriteVersion(int nVersion)
306 return Write(std::string("version"), nVersion);
309 bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
312 #endif // BITCOIN_WALLET_DB_H