1 // Copyright (c) 2012-2015 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #ifndef BITCOIN_DBWRAPPER_H
6 #define BITCOIN_DBWRAPPER_H
8 #include "clientversion.h"
12 #include "utilstrencodings.h"
15 #include <boost/filesystem/path.hpp>
17 #include <leveldb/db.h>
18 #include <leveldb/write_batch.h>
20 static const size_t DBWRAPPER_PREALLOC_KEY_SIZE
= 64;
21 static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE
= 1024;
23 class dbwrapper_error
: public std::runtime_error
26 dbwrapper_error(const std::string
& msg
) : std::runtime_error(msg
) {}
31 /** These should be considered an implementation detail of the specific database.
33 namespace dbwrapper_private
{
35 /** Handle database error by throwing dbwrapper_error exception.
37 void HandleError(const leveldb::Status
& status
);
39 /** Work around circular dependency, as well as for testing in dbwrapper_tests.
40 * Database obfuscation should be considered an implementation detail of the
43 const std::vector
<unsigned char>& GetObfuscateKey(const CDBWrapper
&w
);
47 /** Batch of changes queued to be written to a CDBWrapper */
50 friend class CDBWrapper
;
53 const CDBWrapper
&parent
;
54 leveldb::WriteBatch batch
;
61 * @param[in] _parent CDBWrapper that this batch is to be submitted to
63 CDBBatch(const CDBWrapper
&_parent
) : parent(_parent
), ssKey(SER_DISK
, CLIENT_VERSION
), ssValue(SER_DISK
, CLIENT_VERSION
) { };
65 template <typename K
, typename V
>
66 void Write(const K
& key
, const V
& value
)
68 ssKey
.reserve(DBWRAPPER_PREALLOC_KEY_SIZE
);
70 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
72 ssValue
.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE
);
74 ssValue
.Xor(dbwrapper_private::GetObfuscateKey(parent
));
75 leveldb::Slice
slValue(&ssValue
[0], ssValue
.size());
77 batch
.Put(slKey
, slValue
);
83 void Erase(const K
& key
)
85 ssKey
.reserve(DBWRAPPER_PREALLOC_KEY_SIZE
);
87 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
97 const CDBWrapper
&parent
;
98 leveldb::Iterator
*piter
;
103 * @param[in] _parent Parent CDBWrapper instance.
104 * @param[in] _piter The original leveldb iterator.
106 CDBIterator(const CDBWrapper
&_parent
, leveldb::Iterator
*_piter
) :
107 parent(_parent
), piter(_piter
) { };
114 template<typename K
> void Seek(const K
& key
) {
115 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
116 ssKey
.reserve(DBWRAPPER_PREALLOC_KEY_SIZE
);
118 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
124 template<typename K
> bool GetKey(K
& key
) {
125 leveldb::Slice slKey
= piter
->key();
127 CDataStream
ssKey(slKey
.data(), slKey
.data() + slKey
.size(), SER_DISK
, CLIENT_VERSION
);
129 } catch (const std::exception
&) {
135 unsigned int GetKeySize() {
136 return piter
->key().size();
139 template<typename V
> bool GetValue(V
& value
) {
140 leveldb::Slice slValue
= piter
->value();
142 CDataStream
ssValue(slValue
.data(), slValue
.data() + slValue
.size(), SER_DISK
, CLIENT_VERSION
);
143 ssValue
.Xor(dbwrapper_private::GetObfuscateKey(parent
));
145 } catch (const std::exception
&) {
151 unsigned int GetValueSize() {
152 return piter
->value().size();
159 friend const std::vector
<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper
&w
);
161 //! custom environment this database is using (may be NULL in case of default environment)
164 //! database options used
165 leveldb::Options options
;
167 //! options used when reading from the database
168 leveldb::ReadOptions readoptions
;
170 //! options used when iterating over values of the database
171 leveldb::ReadOptions iteroptions
;
173 //! options used when writing to the database
174 leveldb::WriteOptions writeoptions
;
176 //! options used when sync writing to the database
177 leveldb::WriteOptions syncoptions
;
179 //! the database itself
182 //! a key used for optional XOR-obfuscation of the database
183 std::vector
<unsigned char> obfuscate_key
;
185 //! the key under which the obfuscation key is stored
186 static const std::string OBFUSCATE_KEY_KEY
;
188 //! the length of the obfuscate key in number of bytes
189 static const unsigned int OBFUSCATE_KEY_NUM_BYTES
;
191 std::vector
<unsigned char> CreateObfuscateKey() const;
195 * @param[in] path Location in the filesystem where leveldb data will be stored.
196 * @param[in] nCacheSize Configures various leveldb cache settings.
197 * @param[in] fMemory If true, use leveldb's memory environment.
198 * @param[in] fWipe If true, remove all existing data.
199 * @param[in] obfuscate If true, store data obfuscated via simple XOR. If false, XOR
200 * with a zero'd byte array.
202 CDBWrapper(const boost::filesystem::path
& path
, size_t nCacheSize
, bool fMemory
= false, bool fWipe
= false, bool obfuscate
= false);
205 template <typename K
, typename V
>
206 bool Read(const K
& key
, V
& value
) const
208 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
209 ssKey
.reserve(DBWRAPPER_PREALLOC_KEY_SIZE
);
211 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
213 std::string strValue
;
214 leveldb::Status status
= pdb
->Get(readoptions
, slKey
, &strValue
);
216 if (status
.IsNotFound())
218 LogPrintf("LevelDB read failure: %s\n", status
.ToString());
219 dbwrapper_private::HandleError(status
);
222 CDataStream
ssValue(strValue
.data(), strValue
.data() + strValue
.size(), SER_DISK
, CLIENT_VERSION
);
223 ssValue
.Xor(obfuscate_key
);
225 } catch (const std::exception
&) {
231 template <typename K
, typename V
>
232 bool Write(const K
& key
, const V
& value
, bool fSync
= false)
234 CDBBatch
batch(*this);
235 batch
.Write(key
, value
);
236 return WriteBatch(batch
, fSync
);
239 template <typename K
>
240 bool Exists(const K
& key
) const
242 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
243 ssKey
.reserve(DBWRAPPER_PREALLOC_KEY_SIZE
);
245 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
247 std::string strValue
;
248 leveldb::Status status
= pdb
->Get(readoptions
, slKey
, &strValue
);
250 if (status
.IsNotFound())
252 LogPrintf("LevelDB read failure: %s\n", status
.ToString());
253 dbwrapper_private::HandleError(status
);
258 template <typename K
>
259 bool Erase(const K
& key
, bool fSync
= false)
261 CDBBatch
batch(*this);
263 return WriteBatch(batch
, fSync
);
266 bool WriteBatch(CDBBatch
& batch
, bool fSync
= false);
268 // not available for LevelDB; provide for compatibility with BDB
276 CDBBatch
batch(*this);
277 return WriteBatch(batch
, true);
280 CDBIterator
*NewIterator()
282 return new CDBIterator(*this, pdb
->NewIterator(iteroptions
));
286 * Return true if the database managed by this class contains no entries.
291 #endif // BITCOIN_DBWRAPPER_H