Fix uninitialized atomic variables
[bitcoinplatinum.git] / src / wallet / db.h
blob4f3ad0c42dee66bbf90fc0a6adb7e858c95ed7b1
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 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 "fs.h"
11 #include "serialize.h"
12 #include "streams.h"
13 #include "sync.h"
14 #include "version.h"
16 #include <atomic>
17 #include <map>
18 #include <string>
19 #include <vector>
21 #include <db_cxx.h>
23 static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
24 static const bool DEFAULT_WALLET_PRIVDB = true;
26 class CDBEnv
28 private:
29 bool fDbEnvInit;
30 bool fMockDb;
31 // Don't change into fs::path, as that can result in
32 // shutdown problems/crashes caused by a static initialized internal pointer.
33 std::string strPath;
35 void EnvShutdown();
37 public:
38 mutable CCriticalSection cs_db;
39 DbEnv *dbenv;
40 std::map<std::string, int> mapFileUseCount;
41 std::map<std::string, Db*> mapDb;
43 CDBEnv();
44 ~CDBEnv();
45 void Reset();
47 void MakeMock();
48 bool IsMock() { return fMockDb; }
50 /**
51 * Verify that database file strFile is OK. If it is not,
52 * call the callback to try to recover.
53 * This must be called BEFORE strFile is opened.
54 * Returns true if strFile is OK.
56 enum VerifyResult { VERIFY_OK,
57 RECOVER_OK,
58 RECOVER_FAIL };
59 typedef bool (*recoverFunc_type)(const std::string& strFile, std::string& out_backup_filename);
60 VerifyResult Verify(const std::string& strFile, recoverFunc_type recoverFunc, std::string& out_backup_filename);
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 fs::path& path);
72 void Close();
73 void Flush(bool fShutdown);
74 void CheckpointLSN(const std::string& strFile);
76 void CloseDb(const std::string& strFile);
78 DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
80 DbTxn* ptxn = NULL;
81 int ret = dbenv->txn_begin(NULL, &ptxn, flags);
82 if (!ptxn || ret != 0)
83 return NULL;
84 return ptxn;
88 extern CDBEnv bitdb;
90 /** An instance of this class represents one database.
91 * For BerkeleyDB this is just a (env, strFile) tuple.
92 **/
93 class CWalletDBWrapper
95 friend class CDB;
96 public:
97 /** Create dummy DB handle */
98 CWalletDBWrapper() : nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(nullptr)
102 /** Create DB handle to real database */
103 CWalletDBWrapper(CDBEnv *env_in, const std::string &strFile_in) :
104 nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(env_in), strFile(strFile_in)
108 /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero
110 bool Rewrite(const char* pszSkip=nullptr);
112 /** Back up the entire database to a file.
114 bool Backup(const std::string& strDest);
116 /** Get a name for this database, for debugging etc.
118 std::string GetName() const { return strFile; }
120 /** Make sure all changes are flushed to disk.
122 void Flush(bool shutdown);
124 void IncrementUpdateCounter();
126 std::atomic<unsigned int> nUpdateCounter;
127 unsigned int nLastSeen;
128 unsigned int nLastFlushed;
129 int64_t nLastWalletUpdate;
131 private:
132 /** BerkeleyDB specific */
133 CDBEnv *env;
134 std::string strFile;
136 /** Return whether this database handle is a dummy for testing.
137 * Only to be used at a low level, application should ideally not care
138 * about this.
140 bool IsDummy() { return env == nullptr; }
144 /** RAII class that provides access to a Berkeley database */
145 class CDB
147 protected:
148 Db* pdb;
149 std::string strFile;
150 DbTxn* activeTxn;
151 bool fReadOnly;
152 bool fFlushOnClose;
153 CDBEnv *env;
155 public:
156 explicit CDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
157 ~CDB() { Close(); }
159 void Flush();
160 void Close();
161 static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
163 /* flush the wallet passively (TRY_LOCK)
164 ideal to be called periodically */
165 static bool PeriodicFlush(CWalletDBWrapper& dbw);
166 /* verifies the database environment */
167 static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr);
168 /* verifies the database file */
169 static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc);
171 private:
172 CDB(const CDB&);
173 void operator=(const CDB&);
175 public:
176 template <typename K, typename T>
177 bool Read(const K& key, T& value)
179 if (!pdb)
180 return false;
182 // Key
183 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
184 ssKey.reserve(1000);
185 ssKey << key;
186 Dbt datKey(ssKey.data(), ssKey.size());
188 // Read
189 Dbt datValue;
190 datValue.set_flags(DB_DBT_MALLOC);
191 int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
192 memory_cleanse(datKey.get_data(), datKey.get_size());
193 bool success = false;
194 if (datValue.get_data() != NULL) {
195 // Unserialize value
196 try {
197 CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
198 ssValue >> value;
199 success = true;
200 } catch (const std::exception&) {
201 // In this case success remains 'false'
204 // Clear and free memory
205 memory_cleanse(datValue.get_data(), datValue.get_size());
206 free(datValue.get_data());
208 return ret == 0 && success;
211 template <typename K, typename T>
212 bool Write(const K& key, const T& value, bool fOverwrite = true)
214 if (!pdb)
215 return true;
216 if (fReadOnly)
217 assert(!"Write called on database in read-only mode");
219 // Key
220 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
221 ssKey.reserve(1000);
222 ssKey << key;
223 Dbt datKey(ssKey.data(), ssKey.size());
225 // Value
226 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
227 ssValue.reserve(10000);
228 ssValue << value;
229 Dbt datValue(ssValue.data(), ssValue.size());
231 // Write
232 int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
234 // Clear memory in case it was a private key
235 memory_cleanse(datKey.get_data(), datKey.get_size());
236 memory_cleanse(datValue.get_data(), datValue.get_size());
237 return (ret == 0);
240 template <typename K>
241 bool Erase(const K& key)
243 if (!pdb)
244 return false;
245 if (fReadOnly)
246 assert(!"Erase called on database in read-only mode");
248 // Key
249 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
250 ssKey.reserve(1000);
251 ssKey << key;
252 Dbt datKey(ssKey.data(), ssKey.size());
254 // Erase
255 int ret = pdb->del(activeTxn, &datKey, 0);
257 // Clear memory
258 memory_cleanse(datKey.get_data(), datKey.get_size());
259 return (ret == 0 || ret == DB_NOTFOUND);
262 template <typename K>
263 bool Exists(const K& key)
265 if (!pdb)
266 return false;
268 // Key
269 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
270 ssKey.reserve(1000);
271 ssKey << key;
272 Dbt datKey(ssKey.data(), ssKey.size());
274 // Exists
275 int ret = pdb->exists(activeTxn, &datKey, 0);
277 // Clear memory
278 memory_cleanse(datKey.get_data(), datKey.get_size());
279 return (ret == 0);
282 Dbc* GetCursor()
284 if (!pdb)
285 return NULL;
286 Dbc* pcursor = NULL;
287 int ret = pdb->cursor(NULL, &pcursor, 0);
288 if (ret != 0)
289 return NULL;
290 return pcursor;
293 int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false)
295 // Read at cursor
296 Dbt datKey;
297 unsigned int fFlags = DB_NEXT;
298 if (setRange) {
299 datKey.set_data(ssKey.data());
300 datKey.set_size(ssKey.size());
301 fFlags = DB_SET_RANGE;
303 Dbt datValue;
304 datKey.set_flags(DB_DBT_MALLOC);
305 datValue.set_flags(DB_DBT_MALLOC);
306 int ret = pcursor->get(&datKey, &datValue, fFlags);
307 if (ret != 0)
308 return ret;
309 else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
310 return 99999;
312 // Convert to streams
313 ssKey.SetType(SER_DISK);
314 ssKey.clear();
315 ssKey.write((char*)datKey.get_data(), datKey.get_size());
316 ssValue.SetType(SER_DISK);
317 ssValue.clear();
318 ssValue.write((char*)datValue.get_data(), datValue.get_size());
320 // Clear and free memory
321 memory_cleanse(datKey.get_data(), datKey.get_size());
322 memory_cleanse(datValue.get_data(), datValue.get_size());
323 free(datKey.get_data());
324 free(datValue.get_data());
325 return 0;
328 public:
329 bool TxnBegin()
331 if (!pdb || activeTxn)
332 return false;
333 DbTxn* ptxn = bitdb.TxnBegin();
334 if (!ptxn)
335 return false;
336 activeTxn = ptxn;
337 return true;
340 bool TxnCommit()
342 if (!pdb || !activeTxn)
343 return false;
344 int ret = activeTxn->commit(0);
345 activeTxn = NULL;
346 return (ret == 0);
349 bool TxnAbort()
351 if (!pdb || !activeTxn)
352 return false;
353 int ret = activeTxn->abort();
354 activeTxn = NULL;
355 return (ret == 0);
358 bool ReadVersion(int& nVersion)
360 nVersion = 0;
361 return Read(std::string("version"), nVersion);
364 bool WriteVersion(int nVersion)
366 return Write(std::string("version"), nVersion);
369 bool static Rewrite(CWalletDBWrapper& dbw, const char* pszSkip = NULL);
372 #endif // BITCOIN_WALLET_DB_H