Convert COrphanTx to keep a CTransactionRef
[bitcoinplatinum.git] / src / dbwrapper.h
blob08c72c25ddb71d9135883b79a3975d76d7b329c9
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"
9 #include "serialize.h"
10 #include "streams.h"
11 #include "util.h"
12 #include "utilstrencodings.h"
13 #include "version.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
25 public:
26 dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
29 class CDBWrapper;
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
41 * specific database.
43 const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w);
47 /** Batch of changes queued to be written to a CDBWrapper */
48 class CDBBatch
50 friend class CDBWrapper;
52 private:
53 const CDBWrapper &parent;
54 leveldb::WriteBatch batch;
56 CDataStream ssKey;
57 CDataStream ssValue;
59 public:
60 /**
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);
69 ssKey << key;
70 leveldb::Slice slKey(&ssKey[0], ssKey.size());
72 ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
73 ssValue << value;
74 ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
75 leveldb::Slice slValue(&ssValue[0], ssValue.size());
77 batch.Put(slKey, slValue);
78 ssKey.clear();
79 ssValue.clear();
82 template <typename K>
83 void Erase(const K& key)
85 ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
86 ssKey << key;
87 leveldb::Slice slKey(&ssKey[0], ssKey.size());
89 batch.Delete(slKey);
90 ssKey.clear();
94 class CDBIterator
96 private:
97 const CDBWrapper &parent;
98 leveldb::Iterator *piter;
100 public:
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) { };
108 ~CDBIterator();
110 bool Valid();
112 void SeekToFirst();
114 template<typename K> void Seek(const K& key) {
115 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
116 ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
117 ssKey << key;
118 leveldb::Slice slKey(&ssKey[0], ssKey.size());
119 piter->Seek(slKey);
122 void Next();
124 template<typename K> bool GetKey(K& key) {
125 leveldb::Slice slKey = piter->key();
126 try {
127 CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
128 ssKey >> key;
129 } catch (const std::exception&) {
130 return false;
132 return true;
135 unsigned int GetKeySize() {
136 return piter->key().size();
139 template<typename V> bool GetValue(V& value) {
140 leveldb::Slice slValue = piter->value();
141 try {
142 CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
143 ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
144 ssValue >> value;
145 } catch (const std::exception&) {
146 return false;
148 return true;
151 unsigned int GetValueSize() {
152 return piter->value().size();
157 class CDBWrapper
159 friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w);
160 private:
161 //! custom environment this database is using (may be NULL in case of default environment)
162 leveldb::Env* penv;
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
180 leveldb::DB* pdb;
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;
193 public:
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);
203 ~CDBWrapper();
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);
210 ssKey << key;
211 leveldb::Slice slKey(&ssKey[0], ssKey.size());
213 std::string strValue;
214 leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
215 if (!status.ok()) {
216 if (status.IsNotFound())
217 return false;
218 LogPrintf("LevelDB read failure: %s\n", status.ToString());
219 dbwrapper_private::HandleError(status);
221 try {
222 CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
223 ssValue.Xor(obfuscate_key);
224 ssValue >> value;
225 } catch (const std::exception&) {
226 return false;
228 return true;
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);
244 ssKey << key;
245 leveldb::Slice slKey(&ssKey[0], ssKey.size());
247 std::string strValue;
248 leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
249 if (!status.ok()) {
250 if (status.IsNotFound())
251 return false;
252 LogPrintf("LevelDB read failure: %s\n", status.ToString());
253 dbwrapper_private::HandleError(status);
255 return true;
258 template <typename K>
259 bool Erase(const K& key, bool fSync = false)
261 CDBBatch batch(*this);
262 batch.Erase(key);
263 return WriteBatch(batch, fSync);
266 bool WriteBatch(CDBBatch& batch, bool fSync = false);
268 // not available for LevelDB; provide for compatibility with BDB
269 bool Flush()
271 return true;
274 bool Sync()
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.
288 bool IsEmpty();
291 #endif // BITCOIN_DBWRAPPER_H