Remove unreachable or otherwise redundant code
[bitcoinplatinum.git] / src / wallet / db.h
blobba3785357218a082cfa94c9ed83bdabc4acb1126
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 <map>
17 #include <string>
18 #include <vector>
20 #include <db_cxx.h>
22 static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
23 static const bool DEFAULT_WALLET_PRIVDB = true;
25 class CDBEnv
27 private:
28 bool fDbEnvInit;
29 bool fMockDb;
30 // Don't change into fs::path, as that can result in
31 // shutdown problems/crashes caused by a static initialized internal pointer.
32 std::string strPath;
34 void EnvShutdown();
36 public:
37 mutable CCriticalSection cs_db;
38 DbEnv *dbenv;
39 std::map<std::string, int> mapFileUseCount;
40 std::map<std::string, Db*> mapDb;
42 CDBEnv();
43 ~CDBEnv();
44 void Reset();
46 void MakeMock();
47 bool IsMock() { return fMockDb; }
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.
55 enum VerifyResult { VERIFY_OK,
56 RECOVER_OK,
57 RECOVER_FAIL };
58 typedef bool (*recoverFunc_type)(const std::string& strFile, std::string& out_backup_filename);
59 VerifyResult Verify(const std::string& strFile, recoverFunc_type recoverFunc, std::string& out_backup_filename);
60 /**
61 * Salvage data from a file that Verify says is bad.
62 * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).
63 * Appends binary key/value pairs to vResult, returns true if successful.
64 * NOTE: reads the entire database into memory, so cannot be used
65 * for huge databases.
67 typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
68 bool Salvage(const std::string& strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
70 bool Open(const fs::path& path);
71 void Close();
72 void Flush(bool fShutdown);
73 void CheckpointLSN(const std::string& strFile);
75 void CloseDb(const std::string& strFile);
77 DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
79 DbTxn* ptxn = NULL;
80 int ret = dbenv->txn_begin(NULL, &ptxn, flags);
81 if (!ptxn || ret != 0)
82 return NULL;
83 return ptxn;
87 extern CDBEnv bitdb;
89 /** An instance of this class represents one database.
90 * For BerkeleyDB this is just a (env, strFile) tuple.
91 **/
92 class CWalletDBWrapper
94 friend class CDB;
95 public:
96 /** Create dummy DB handle */
97 CWalletDBWrapper() : nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(nullptr)
101 /** Create DB handle to real database */
102 CWalletDBWrapper(CDBEnv *env_in, const std::string &strFile_in) :
103 nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(env_in), strFile(strFile_in)
107 /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero
109 bool Rewrite(const char* pszSkip=nullptr);
111 /** Back up the entire database to a file.
113 bool Backup(const std::string& strDest);
115 /** Get a name for this database, for debugging etc.
117 std::string GetName() const { return strFile; }
119 /** Make sure all changes are flushed to disk.
121 void Flush(bool shutdown);
123 void IncrementUpdateCounter();
125 std::atomic<unsigned int> nUpdateCounter;
126 unsigned int nLastSeen;
127 unsigned int nLastFlushed;
128 int64_t nLastWalletUpdate;
130 private:
131 /** BerkeleyDB specific */
132 CDBEnv *env;
133 std::string strFile;
135 /** Return whether this database handle is a dummy for testing.
136 * Only to be used at a low level, application should ideally not care
137 * about this.
139 bool IsDummy() { return env == nullptr; }
143 /** RAII class that provides access to a Berkeley database */
144 class CDB
146 protected:
147 Db* pdb;
148 std::string strFile;
149 DbTxn* activeTxn;
150 bool fReadOnly;
151 bool fFlushOnClose;
152 CDBEnv *env;
154 public:
155 explicit CDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
156 ~CDB() { Close(); }
158 void Flush();
159 void Close();
160 static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
162 /* flush the wallet passively (TRY_LOCK)
163 ideal to be called periodically */
164 static bool PeriodicFlush(CWalletDBWrapper& dbw);
165 /* verifies the database environment */
166 static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr);
167 /* verifies the database file */
168 static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc);
170 private:
171 CDB(const CDB&);
172 void operator=(const CDB&);
174 public:
175 template <typename K, typename T>
176 bool Read(const K& key, T& value)
178 if (!pdb)
179 return false;
181 // Key
182 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
183 ssKey.reserve(1000);
184 ssKey << key;
185 Dbt datKey(ssKey.data(), ssKey.size());
187 // Read
188 Dbt datValue;
189 datValue.set_flags(DB_DBT_MALLOC);
190 int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
191 memory_cleanse(datKey.get_data(), datKey.get_size());
192 bool success = false;
193 if (datValue.get_data() != NULL) {
194 // Unserialize value
195 try {
196 CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
197 ssValue >> value;
198 success = true;
199 } catch (const std::exception&) {
200 // In this case success remains 'false'
203 // Clear and free memory
204 memory_cleanse(datValue.get_data(), datValue.get_size());
205 free(datValue.get_data());
207 return ret == 0 && success;
210 template <typename K, typename T>
211 bool Write(const K& key, const T& value, bool fOverwrite = true)
213 if (!pdb)
214 return true;
215 if (fReadOnly)
216 assert(!"Write called on database in read-only mode");
218 // Key
219 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
220 ssKey.reserve(1000);
221 ssKey << key;
222 Dbt datKey(ssKey.data(), ssKey.size());
224 // Value
225 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
226 ssValue.reserve(10000);
227 ssValue << value;
228 Dbt datValue(ssValue.data(), ssValue.size());
230 // Write
231 int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
233 // Clear memory in case it was a private key
234 memory_cleanse(datKey.get_data(), datKey.get_size());
235 memory_cleanse(datValue.get_data(), datValue.get_size());
236 return (ret == 0);
239 template <typename K>
240 bool Erase(const K& key)
242 if (!pdb)
243 return false;
244 if (fReadOnly)
245 assert(!"Erase called on database in read-only mode");
247 // Key
248 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
249 ssKey.reserve(1000);
250 ssKey << key;
251 Dbt datKey(ssKey.data(), ssKey.size());
253 // Erase
254 int ret = pdb->del(activeTxn, &datKey, 0);
256 // Clear memory
257 memory_cleanse(datKey.get_data(), datKey.get_size());
258 return (ret == 0 || ret == DB_NOTFOUND);
261 template <typename K>
262 bool Exists(const K& key)
264 if (!pdb)
265 return false;
267 // Key
268 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
269 ssKey.reserve(1000);
270 ssKey << key;
271 Dbt datKey(ssKey.data(), ssKey.size());
273 // Exists
274 int ret = pdb->exists(activeTxn, &datKey, 0);
276 // Clear memory
277 memory_cleanse(datKey.get_data(), datKey.get_size());
278 return (ret == 0);
281 Dbc* GetCursor()
283 if (!pdb)
284 return NULL;
285 Dbc* pcursor = NULL;
286 int ret = pdb->cursor(NULL, &pcursor, 0);
287 if (ret != 0)
288 return NULL;
289 return pcursor;
292 int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false)
294 // Read at cursor
295 Dbt datKey;
296 unsigned int fFlags = DB_NEXT;
297 if (setRange) {
298 datKey.set_data(ssKey.data());
299 datKey.set_size(ssKey.size());
300 fFlags = DB_SET_RANGE;
302 Dbt datValue;
303 datKey.set_flags(DB_DBT_MALLOC);
304 datValue.set_flags(DB_DBT_MALLOC);
305 int ret = pcursor->get(&datKey, &datValue, fFlags);
306 if (ret != 0)
307 return ret;
308 else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
309 return 99999;
311 // Convert to streams
312 ssKey.SetType(SER_DISK);
313 ssKey.clear();
314 ssKey.write((char*)datKey.get_data(), datKey.get_size());
315 ssValue.SetType(SER_DISK);
316 ssValue.clear();
317 ssValue.write((char*)datValue.get_data(), datValue.get_size());
319 // Clear and free memory
320 memory_cleanse(datKey.get_data(), datKey.get_size());
321 memory_cleanse(datValue.get_data(), datValue.get_size());
322 free(datKey.get_data());
323 free(datValue.get_data());
324 return 0;
327 public:
328 bool TxnBegin()
330 if (!pdb || activeTxn)
331 return false;
332 DbTxn* ptxn = bitdb.TxnBegin();
333 if (!ptxn)
334 return false;
335 activeTxn = ptxn;
336 return true;
339 bool TxnCommit()
341 if (!pdb || !activeTxn)
342 return false;
343 int ret = activeTxn->commit(0);
344 activeTxn = NULL;
345 return (ret == 0);
348 bool TxnAbort()
350 if (!pdb || !activeTxn)
351 return false;
352 int ret = activeTxn->abort();
353 activeTxn = NULL;
354 return (ret == 0);
357 bool ReadVersion(int& nVersion)
359 nVersion = 0;
360 return Read(std::string("version"), nVersion);
363 bool WriteVersion(int nVersion)
365 return Write(std::string("version"), nVersion);
368 bool static Rewrite(CWalletDBWrapper& dbw, const char* pszSkip = NULL);
371 #endif // BITCOIN_WALLET_DB_H