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 class dbwrapper_error
: public std::runtime_error
23 dbwrapper_error(const std::string
& msg
) : std::runtime_error(msg
) {}
28 /** These should be considered an implementation detail of the specific database.
30 namespace dbwrapper_private
{
32 /** Handle database error by throwing dbwrapper_error exception.
34 void HandleError(const leveldb::Status
& status
);
36 /** Work around circular dependency, as well as for testing in dbwrapper_tests.
37 * Database obfuscation should be considered an implementation detail of the
40 const std::vector
<unsigned char>& GetObfuscateKey(const CDBWrapper
&w
);
44 /** Batch of changes queued to be written to a CDBWrapper */
47 friend class CDBWrapper
;
50 const CDBWrapper
&parent
;
51 leveldb::WriteBatch batch
;
55 * @param[in] _parent CDBWrapper that this batch is to be submitted to
57 CDBBatch(const CDBWrapper
&_parent
) : parent(_parent
) { };
59 template <typename K
, typename V
>
60 void Write(const K
& key
, const V
& value
)
62 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
63 ssKey
.reserve(ssKey
.GetSerializeSize(key
));
65 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
67 CDataStream
ssValue(SER_DISK
, CLIENT_VERSION
);
68 ssValue
.reserve(ssValue
.GetSerializeSize(value
));
70 ssValue
.Xor(dbwrapper_private::GetObfuscateKey(parent
));
71 leveldb::Slice
slValue(&ssValue
[0], ssValue
.size());
73 batch
.Put(slKey
, slValue
);
77 void Erase(const K
& key
)
79 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
80 ssKey
.reserve(ssKey
.GetSerializeSize(key
));
82 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
91 const CDBWrapper
&parent
;
92 leveldb::Iterator
*piter
;
97 * @param[in] _parent Parent CDBWrapper instance.
98 * @param[in] _piter The original leveldb iterator.
100 CDBIterator(const CDBWrapper
&_parent
, leveldb::Iterator
*_piter
) :
101 parent(_parent
), piter(_piter
) { };
108 template<typename K
> void Seek(const K
& key
) {
109 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
110 ssKey
.reserve(ssKey
.GetSerializeSize(key
));
112 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
118 template<typename K
> bool GetKey(K
& key
) {
119 leveldb::Slice slKey
= piter
->key();
121 CDataStream
ssKey(slKey
.data(), slKey
.data() + slKey
.size(), SER_DISK
, CLIENT_VERSION
);
123 } catch (const std::exception
&) {
129 unsigned int GetKeySize() {
130 return piter
->key().size();
133 template<typename V
> bool GetValue(V
& value
) {
134 leveldb::Slice slValue
= piter
->value();
136 CDataStream
ssValue(slValue
.data(), slValue
.data() + slValue
.size(), SER_DISK
, CLIENT_VERSION
);
137 ssValue
.Xor(dbwrapper_private::GetObfuscateKey(parent
));
139 } catch (const std::exception
&) {
145 unsigned int GetValueSize() {
146 return piter
->value().size();
153 friend const std::vector
<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper
&w
);
155 //! custom environment this database is using (may be NULL in case of default environment)
158 //! database options used
159 leveldb::Options options
;
161 //! options used when reading from the database
162 leveldb::ReadOptions readoptions
;
164 //! options used when iterating over values of the database
165 leveldb::ReadOptions iteroptions
;
167 //! options used when writing to the database
168 leveldb::WriteOptions writeoptions
;
170 //! options used when sync writing to the database
171 leveldb::WriteOptions syncoptions
;
173 //! the database itself
176 //! a key used for optional XOR-obfuscation of the database
177 std::vector
<unsigned char> obfuscate_key
;
179 //! the key under which the obfuscation key is stored
180 static const std::string OBFUSCATE_KEY_KEY
;
182 //! the length of the obfuscate key in number of bytes
183 static const unsigned int OBFUSCATE_KEY_NUM_BYTES
;
185 std::vector
<unsigned char> CreateObfuscateKey() const;
189 * @param[in] path Location in the filesystem where leveldb data will be stored.
190 * @param[in] nCacheSize Configures various leveldb cache settings.
191 * @param[in] fMemory If true, use leveldb's memory environment.
192 * @param[in] fWipe If true, remove all existing data.
193 * @param[in] obfuscate If true, store data obfuscated via simple XOR. If false, XOR
194 * with a zero'd byte array.
196 CDBWrapper(const boost::filesystem::path
& path
, size_t nCacheSize
, bool fMemory
= false, bool fWipe
= false, bool obfuscate
= false);
199 template <typename K
, typename V
>
200 bool Read(const K
& key
, V
& value
) const
202 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
203 ssKey
.reserve(ssKey
.GetSerializeSize(key
));
205 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
207 std::string strValue
;
208 leveldb::Status status
= pdb
->Get(readoptions
, slKey
, &strValue
);
210 if (status
.IsNotFound())
212 LogPrintf("LevelDB read failure: %s\n", status
.ToString());
213 dbwrapper_private::HandleError(status
);
216 CDataStream
ssValue(strValue
.data(), strValue
.data() + strValue
.size(), SER_DISK
, CLIENT_VERSION
);
217 ssValue
.Xor(obfuscate_key
);
219 } catch (const std::exception
&) {
225 template <typename K
, typename V
>
226 bool Write(const K
& key
, const V
& value
, bool fSync
= false)
228 CDBBatch
batch(*this);
229 batch
.Write(key
, value
);
230 return WriteBatch(batch
, fSync
);
233 template <typename K
>
234 bool Exists(const K
& key
) const
236 CDataStream
ssKey(SER_DISK
, CLIENT_VERSION
);
237 ssKey
.reserve(ssKey
.GetSerializeSize(key
));
239 leveldb::Slice
slKey(&ssKey
[0], ssKey
.size());
241 std::string strValue
;
242 leveldb::Status status
= pdb
->Get(readoptions
, slKey
, &strValue
);
244 if (status
.IsNotFound())
246 LogPrintf("LevelDB read failure: %s\n", status
.ToString());
247 dbwrapper_private::HandleError(status
);
252 template <typename K
>
253 bool Erase(const K
& key
, bool fSync
= false)
255 CDBBatch
batch(*this);
257 return WriteBatch(batch
, fSync
);
260 bool WriteBatch(CDBBatch
& batch
, bool fSync
= false);
262 // not available for LevelDB; provide for compatibility with BDB
270 CDBBatch
batch(*this);
271 return WriteBatch(batch
, true);
274 CDBIterator
*NewIterator()
276 return new CDBIterator(*this, pdb
->NewIterator(iteroptions
));
280 * Return true if the database managed by this class contains no entries.
285 #endif // BITCOIN_DBWRAPPER_H