Remove unused C++ code not covered by unit tests
[bitcoinplatinum.git] / src / wallet / db.h
blob1a46448cc752955068da599859f961b5bba386a8
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 VerifyResult Verify(const std::string& strFile, bool (*recoverFunc)(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.
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);
69 bool Open(const fs::path& path);
70 void Close();
71 void Flush(bool fShutdown);
72 void CheckpointLSN(const std::string& strFile);
74 void CloseDb(const std::string& strFile);
76 DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
78 DbTxn* ptxn = NULL;
79 int ret = dbenv->txn_begin(NULL, &ptxn, flags);
80 if (!ptxn || ret != 0)
81 return NULL;
82 return ptxn;
86 extern CDBEnv bitdb;
88 /** An instance of this class represents one database.
89 * For BerkeleyDB this is just a (env, strFile) tuple.
90 **/
91 class CWalletDBWrapper
93 friend class CDB;
94 public:
95 /** Create dummy DB handle */
96 CWalletDBWrapper(): env(nullptr)
100 /** Create DB handle to real database */
101 CWalletDBWrapper(CDBEnv *env_in, const std::string &strFile_in):
102 env(env_in), strFile(strFile_in)
106 /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero
108 bool Rewrite(const char* pszSkip=nullptr);
110 /** Back up the entire database to a file.
112 bool Backup(const std::string& strDest);
114 /** Get a name for this database, for debugging etc.
116 std::string GetName() const { return strFile; }
118 /** Make sure all changes are flushed to disk.
120 void Flush(bool shutdown);
122 private:
123 /** BerkeleyDB specific */
124 CDBEnv *env;
125 std::string strFile;
127 /** Return whether this database handle is a dummy for testing.
128 * Only to be used at a low level, application should ideally not care
129 * about this.
131 bool IsDummy() { return env == nullptr; }
135 /** RAII class that provides access to a Berkeley database */
136 class CDB
138 protected:
139 Db* pdb;
140 std::string strFile;
141 DbTxn* activeTxn;
142 bool fReadOnly;
143 bool fFlushOnClose;
144 CDBEnv *env;
146 public:
147 explicit CDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
148 ~CDB() { Close(); }
150 void Flush();
151 void Close();
152 static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue));
154 /* flush the wallet passively (TRY_LOCK)
155 ideal to be called periodically */
156 static bool PeriodicFlush(CWalletDBWrapper& dbw);
157 /* verifies the database environment */
158 static bool VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr);
159 /* verifies the database file */
160 static bool VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, bool (*recoverFunc)(const std::string& strFile));
162 private:
163 CDB(const CDB&);
164 void operator=(const CDB&);
166 public:
167 template <typename K, typename T>
168 bool Read(const K& key, T& value)
170 if (!pdb)
171 return false;
173 // Key
174 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
175 ssKey.reserve(1000);
176 ssKey << key;
177 Dbt datKey(ssKey.data(), ssKey.size());
179 // Read
180 Dbt datValue;
181 datValue.set_flags(DB_DBT_MALLOC);
182 int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
183 memset(datKey.get_data(), 0, datKey.get_size());
184 if (datValue.get_data() == NULL)
185 return false;
187 // Unserialize value
188 try {
189 CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
190 ssValue >> value;
191 } catch (const std::exception&) {
192 return false;
195 // Clear and free memory
196 memset(datValue.get_data(), 0, datValue.get_size());
197 free(datValue.get_data());
198 return (ret == 0);
201 template <typename K, typename T>
202 bool Write(const K& key, const T& value, bool fOverwrite = true)
204 if (!pdb)
205 return true;
206 if (fReadOnly)
207 assert(!"Write called on database in read-only mode");
209 // Key
210 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
211 ssKey.reserve(1000);
212 ssKey << key;
213 Dbt datKey(ssKey.data(), ssKey.size());
215 // Value
216 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
217 ssValue.reserve(10000);
218 ssValue << value;
219 Dbt datValue(ssValue.data(), ssValue.size());
221 // Write
222 int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
224 // Clear memory in case it was a private key
225 memset(datKey.get_data(), 0, datKey.get_size());
226 memset(datValue.get_data(), 0, datValue.get_size());
227 return (ret == 0);
230 template <typename K>
231 bool Erase(const K& key)
233 if (!pdb)
234 return false;
235 if (fReadOnly)
236 assert(!"Erase called on database in read-only mode");
238 // Key
239 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
240 ssKey.reserve(1000);
241 ssKey << key;
242 Dbt datKey(ssKey.data(), ssKey.size());
244 // Erase
245 int ret = pdb->del(activeTxn, &datKey, 0);
247 // Clear memory
248 memset(datKey.get_data(), 0, datKey.get_size());
249 return (ret == 0 || ret == DB_NOTFOUND);
252 template <typename K>
253 bool Exists(const K& key)
255 if (!pdb)
256 return false;
258 // Key
259 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
260 ssKey.reserve(1000);
261 ssKey << key;
262 Dbt datKey(ssKey.data(), ssKey.size());
264 // Exists
265 int ret = pdb->exists(activeTxn, &datKey, 0);
267 // Clear memory
268 memset(datKey.get_data(), 0, datKey.get_size());
269 return (ret == 0);
272 Dbc* GetCursor()
274 if (!pdb)
275 return NULL;
276 Dbc* pcursor = NULL;
277 int ret = pdb->cursor(NULL, &pcursor, 0);
278 if (ret != 0)
279 return NULL;
280 return pcursor;
283 int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false)
285 // Read at cursor
286 Dbt datKey;
287 unsigned int fFlags = DB_NEXT;
288 if (setRange) {
289 datKey.set_data(ssKey.data());
290 datKey.set_size(ssKey.size());
291 fFlags = DB_SET_RANGE;
293 Dbt datValue;
294 datKey.set_flags(DB_DBT_MALLOC);
295 datValue.set_flags(DB_DBT_MALLOC);
296 int ret = pcursor->get(&datKey, &datValue, fFlags);
297 if (ret != 0)
298 return ret;
299 else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
300 return 99999;
302 // Convert to streams
303 ssKey.SetType(SER_DISK);
304 ssKey.clear();
305 ssKey.write((char*)datKey.get_data(), datKey.get_size());
306 ssValue.SetType(SER_DISK);
307 ssValue.clear();
308 ssValue.write((char*)datValue.get_data(), datValue.get_size());
310 // Clear and free memory
311 memset(datKey.get_data(), 0, datKey.get_size());
312 memset(datValue.get_data(), 0, datValue.get_size());
313 free(datKey.get_data());
314 free(datValue.get_data());
315 return 0;
318 public:
319 bool TxnBegin()
321 if (!pdb || activeTxn)
322 return false;
323 DbTxn* ptxn = bitdb.TxnBegin();
324 if (!ptxn)
325 return false;
326 activeTxn = ptxn;
327 return true;
330 bool TxnCommit()
332 if (!pdb || !activeTxn)
333 return false;
334 int ret = activeTxn->commit(0);
335 activeTxn = NULL;
336 return (ret == 0);
339 bool TxnAbort()
341 if (!pdb || !activeTxn)
342 return false;
343 int ret = activeTxn->abort();
344 activeTxn = NULL;
345 return (ret == 0);
348 bool ReadVersion(int& nVersion)
350 nVersion = 0;
351 return Read(std::string("version"), nVersion);
354 bool WriteVersion(int nVersion)
356 return Write(std::string("version"), nVersion);
359 bool static Rewrite(CWalletDBWrapper& dbw, const char* pszSkip = NULL);
362 #endif // BITCOIN_WALLET_DB_H