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
;
58 * @param[in] _parent CDBWrapper that this batch is to be submitted to
60 CDBBatch(const CDBWrapper
&_parent
) : parent(_parent
) { };
62 template <typename K
, typename V
>
63 void Write(const K
& key
, const V
& value
)
65 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
66 ssKey
.reserve(DBWRAPPER_PREALLOC_KEY_SIZE
);
68 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
70 CDataStream
ssValue(SER_DISK
, CLIENT_VERSION
);
71 ssValue
.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE
);
73 ssValue
.Xor(dbwrapper_private::GetObfuscateKey(parent
));
74 leveldb::Slice
slValue(&ssValue
[0], ssValue
.size());
76 batch
.Put(slKey
, slValue
);
80 void Erase(const K
& key
)
82 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
83 ssKey
.reserve(DBWRAPPER_PREALLOC_KEY_SIZE
);
85 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
94 const CDBWrapper
&parent
;
95 leveldb::Iterator
*piter
;
100 * @param[in] _parent Parent CDBWrapper instance.
101 * @param[in] _piter The original leveldb iterator.
103 CDBIterator(const CDBWrapper
&_parent
, leveldb::Iterator
*_piter
) :
104 parent(_parent
), piter(_piter
) { };
111 template<typename K
> void Seek(const K
& key
) {
112 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
113 ssKey
.reserve(DBWRAPPER_PREALLOC_KEY_SIZE
);
115 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
121 template<typename K
> bool GetKey(K
& key
) {
122 leveldb::Slice slKey
= piter
->key();
124 CDataStream
ssKey(slKey
.data(), slKey
.data() + slKey
.size(), SER_DISK
, CLIENT_VERSION
);
126 } catch (const std::exception
&) {
132 unsigned int GetKeySize() {
133 return piter
->key().size();
136 template<typename V
> bool GetValue(V
& value
) {
137 leveldb::Slice slValue
= piter
->value();
139 CDataStream
ssValue(slValue
.data(), slValue
.data() + slValue
.size(), SER_DISK
, CLIENT_VERSION
);
140 ssValue
.Xor(dbwrapper_private::GetObfuscateKey(parent
));
142 } catch (const std::exception
&) {
148 unsigned int GetValueSize() {
149 return piter
->value().size();
156 friend const std::vector
<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper
&w
);
158 //! custom environment this database is using (may be NULL in case of default environment)
161 //! database options used
162 leveldb::Options options
;
164 //! options used when reading from the database
165 leveldb::ReadOptions readoptions
;
167 //! options used when iterating over values of the database
168 leveldb::ReadOptions iteroptions
;
170 //! options used when writing to the database
171 leveldb::WriteOptions writeoptions
;
173 //! options used when sync writing to the database
174 leveldb::WriteOptions syncoptions
;
176 //! the database itself
179 //! a key used for optional XOR-obfuscation of the database
180 std::vector
<unsigned char> obfuscate_key
;
182 //! the key under which the obfuscation key is stored
183 static const std::string OBFUSCATE_KEY_KEY
;
185 //! the length of the obfuscate key in number of bytes
186 static const unsigned int OBFUSCATE_KEY_NUM_BYTES
;
188 std::vector
<unsigned char> CreateObfuscateKey() const;
192 * @param[in] path Location in the filesystem where leveldb data will be stored.
193 * @param[in] nCacheSize Configures various leveldb cache settings.
194 * @param[in] fMemory If true, use leveldb's memory environment.
195 * @param[in] fWipe If true, remove all existing data.
196 * @param[in] obfuscate If true, store data obfuscated via simple XOR. If false, XOR
197 * with a zero'd byte array.
199 CDBWrapper(const boost::filesystem::path
& path
, size_t nCacheSize
, bool fMemory
= false, bool fWipe
= false, bool obfuscate
= false);
202 template <typename K
, typename V
>
203 bool Read(const K
& key
, V
& value
) const
205 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
206 ssKey
.reserve(DBWRAPPER_PREALLOC_KEY_SIZE
);
208 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
210 std::string strValue
;
211 leveldb::Status status
= pdb
->Get(readoptions
, slKey
, &strValue
);
213 if (status
.IsNotFound())
215 LogPrintf("LevelDB read failure: %s\n", status
.ToString());
216 dbwrapper_private::HandleError(status
);
219 CDataStream
ssValue(strValue
.data(), strValue
.data() + strValue
.size(), SER_DISK
, CLIENT_VERSION
);
220 ssValue
.Xor(obfuscate_key
);
222 } catch (const std::exception
&) {
228 template <typename K
, typename V
>
229 bool Write(const K
& key
, const V
& value
, bool fSync
= false)
231 CDBBatch
batch(*this);
232 batch
.Write(key
, value
);
233 return WriteBatch(batch
, fSync
);
236 template <typename K
>
237 bool Exists(const K
& key
) const
239 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
240 ssKey
.reserve(DBWRAPPER_PREALLOC_KEY_SIZE
);
242 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
244 std::string strValue
;
245 leveldb::Status status
= pdb
->Get(readoptions
, slKey
, &strValue
);
247 if (status
.IsNotFound())
249 LogPrintf("LevelDB read failure: %s\n", status
.ToString());
250 dbwrapper_private::HandleError(status
);
255 template <typename K
>
256 bool Erase(const K
& key
, bool fSync
= false)
258 CDBBatch
batch(*this);
260 return WriteBatch(batch
, fSync
);
263 bool WriteBatch(CDBBatch
& batch
, bool fSync
= false);
265 // not available for LevelDB; provide for compatibility with BDB
273 CDBBatch
batch(*this);
274 return WriteBatch(batch
, true);
277 CDBIterator
*NewIterator()
279 return new CDBIterator(*this, pdb
->NewIterator(iteroptions
));
283 * Return true if the database managed by this class contains no entries.
288 #endif // BITCOIN_DBWRAPPER_H