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"
19 #include <boost/filesystem/path.hpp>
23 static const unsigned int DEFAULT_WALLET_DBLOGSIZE
= 100;
24 static const bool DEFAULT_WALLET_PRIVDB
= true;
26 extern unsigned int nWalletDBUpdated
;
33 // Don't change into boost::filesystem::path, as that can result in
34 // shutdown problems/crashes caused by a static initialized internal pointer.
40 mutable CCriticalSection cs_db
;
42 std::map
<std::string
, int> mapFileUseCount
;
43 std::map
<std::string
, Db
*> mapDb
;
50 bool IsMock() { return fMockDb
; }
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
,
61 VerifyResult
Verify(const std::string
& strFile
, bool (*recoverFunc
)(CDBEnv
& dbenv
, const std::string
& strFile
));
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
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
);
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
)
83 int ret
= dbenv
->txn_begin(NULL
, &ptxn
, flags
);
84 if (!ptxn
|| ret
!= 0)
93 /** RAII class that provides access to a Berkeley database */
103 explicit CDB(const std::string
& strFilename
, const char* pszMode
= "r+", bool fFlushOnCloseIn
=true);
112 void operator=(const CDB
&);
115 template <typename K
, typename T
>
116 bool Read(const K
& key
, T
& value
)
122 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
125 Dbt
datKey(&ssKey
[0], ssKey
.size());
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
)
137 CDataStream
ssValue((char*)datValue
.get_data(), (char*)datValue
.get_data() + datValue
.get_size(), SER_DISK
, CLIENT_VERSION
);
139 } catch (const std::exception
&) {
143 // Clear and free memory
144 memset(datValue
.get_data(), 0, datValue
.get_size());
145 free(datValue
.get_data());
149 template <typename K
, typename T
>
150 bool Write(const K
& key
, const T
& value
, bool fOverwrite
= true)
155 assert(!"Write called on database in read-only mode");
158 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
161 Dbt
datKey(&ssKey
[0], ssKey
.size());
164 CDataStream
ssValue(SER_DISK
, CLIENT_VERSION
);
165 ssValue
.reserve(10000);
167 Dbt
datValue(&ssValue
[0], ssValue
.size());
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());
178 template <typename K
>
179 bool Erase(const K
& key
)
184 assert(!"Erase called on database in read-only mode");
187 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
190 Dbt
datKey(&ssKey
[0], ssKey
.size());
193 int ret
= pdb
->del(activeTxn
, &datKey
, 0);
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
)
207 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
210 Dbt
datKey(&ssKey
[0], ssKey
.size());
213 int ret
= pdb
->exists(activeTxn
, &datKey
, 0);
216 memset(datKey
.get_data(), 0, datKey
.get_size());
225 int ret
= pdb
->cursor(NULL
, &pcursor
, 0);
231 int ReadAtCursor(Dbc
* pcursor
, CDataStream
& ssKey
, CDataStream
& ssValue
, unsigned int fFlags
= DB_NEXT
)
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());
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
);
249 else if (datKey
.get_data() == NULL
|| datValue
.get_data() == NULL
)
252 // Convert to streams
253 ssKey
.SetType(SER_DISK
);
255 ssKey
.write((char*)datKey
.get_data(), datKey
.get_size());
256 ssValue
.SetType(SER_DISK
);
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());
271 if (!pdb
|| activeTxn
)
273 DbTxn
* ptxn
= bitdb
.TxnBegin();
282 if (!pdb
|| !activeTxn
)
284 int ret
= activeTxn
->commit(0);
291 if (!pdb
|| !activeTxn
)
293 int ret
= activeTxn
->abort();
298 bool ReadVersion(int& nVersion
)
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