]>
Commit | Line | Data |
---|---|---|
b64187d0 | 1 | // Copyright (c) 2012-2013 The Bitcoin developers |
43b7905e PW |
2 | // Distributed under the MIT/X11 software license, see the accompanying |
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
b64187d0 BD |
4 | |
5 | #ifndef BITCOIN_LEVELDBWRAPPER_H | |
6 | #define BITCOIN_LEVELDBWRAPPER_H | |
43b7905e PW |
7 | |
8 | #include "serialize.h" | |
881a85a2 | 9 | #include "util.h" |
51ed9ec9 | 10 | #include "version.h" |
43b7905e | 11 | |
51ed9ec9 | 12 | #include <boost/filesystem/path.hpp> |
611116d4 | 13 | |
43b7905e PW |
14 | #include <leveldb/db.h> |
15 | #include <leveldb/write_batch.h> | |
16 | ||
421218d3 PW |
17 | class leveldb_error : public std::runtime_error |
18 | { | |
19 | public: | |
20 | leveldb_error(const std::string &msg) : std::runtime_error(msg) {} | |
21 | }; | |
22 | ||
23 | void HandleError(const leveldb::Status &status) throw(leveldb_error); | |
24 | ||
b64187d0 | 25 | // Batch of changes queued to be written to a CLevelDBWrapper |
43b7905e PW |
26 | class CLevelDBBatch |
27 | { | |
b64187d0 | 28 | friend class CLevelDBWrapper; |
43b7905e PW |
29 | |
30 | private: | |
31 | leveldb::WriteBatch batch; | |
32 | ||
33 | public: | |
34 | template<typename K, typename V> void Write(const K& key, const V& value) { | |
35 | CDataStream ssKey(SER_DISK, CLIENT_VERSION); | |
36 | ssKey.reserve(ssKey.GetSerializeSize(key)); | |
37 | ssKey << key; | |
38 | leveldb::Slice slKey(&ssKey[0], ssKey.size()); | |
39 | ||
40 | CDataStream ssValue(SER_DISK, CLIENT_VERSION); | |
41 | ssValue.reserve(ssValue.GetSerializeSize(value)); | |
42 | ssValue << value; | |
43 | leveldb::Slice slValue(&ssValue[0], ssValue.size()); | |
44 | ||
45 | batch.Put(slKey, slValue); | |
46 | } | |
47 | ||
48 | template<typename K> void Erase(const K& key) { | |
49 | CDataStream ssKey(SER_DISK, CLIENT_VERSION); | |
50 | ssKey.reserve(ssKey.GetSerializeSize(key)); | |
51 | ssKey << key; | |
52 | leveldb::Slice slKey(&ssKey[0], ssKey.size()); | |
53 | ||
54 | batch.Delete(slKey); | |
55 | } | |
56 | }; | |
57 | ||
b64187d0 | 58 | class CLevelDBWrapper |
43b7905e PW |
59 | { |
60 | private: | |
61 | // custom environment this database is using (may be NULL in case of default environment) | |
62 | leveldb::Env *penv; | |
63 | ||
64 | // database options used | |
65 | leveldb::Options options; | |
66 | ||
67 | // options used when reading from the database | |
68 | leveldb::ReadOptions readoptions; | |
69 | ||
70 | // options used when iterating over values of the database | |
71 | leveldb::ReadOptions iteroptions; | |
72 | ||
73 | // options used when writing to the database | |
74 | leveldb::WriteOptions writeoptions; | |
75 | ||
76 | // options used when sync writing to the database | |
77 | leveldb::WriteOptions syncoptions; | |
78 | ||
79 | // the database itself | |
80 | leveldb::DB *pdb; | |
81 | ||
82 | public: | |
b64187d0 BD |
83 | CLevelDBWrapper(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory = false, bool fWipe = false); |
84 | ~CLevelDBWrapper(); | |
43b7905e | 85 | |
ffb4c210 | 86 | template<typename K, typename V> bool Read(const K& key, V& value) const throw(leveldb_error) { |
43b7905e PW |
87 | CDataStream ssKey(SER_DISK, CLIENT_VERSION); |
88 | ssKey.reserve(ssKey.GetSerializeSize(key)); | |
89 | ssKey << key; | |
90 | leveldb::Slice slKey(&ssKey[0], ssKey.size()); | |
91 | ||
92 | std::string strValue; | |
93 | leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); | |
94 | if (!status.ok()) { | |
95 | if (status.IsNotFound()) | |
96 | return false; | |
79d06dc6 | 97 | LogPrintf("LevelDB read failure: %s\n", status.ToString()); |
421218d3 | 98 | HandleError(status); |
43b7905e PW |
99 | } |
100 | try { | |
101 | CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); | |
102 | ssValue >> value; | |
ec91092d | 103 | } catch(const std::exception &) { |
43b7905e PW |
104 | return false; |
105 | } | |
106 | return true; | |
107 | } | |
108 | ||
421218d3 | 109 | template<typename K, typename V> bool Write(const K& key, const V& value, bool fSync = false) throw(leveldb_error) { |
43b7905e PW |
110 | CLevelDBBatch batch; |
111 | batch.Write(key, value); | |
112 | return WriteBatch(batch, fSync); | |
113 | } | |
114 | ||
ffb4c210 | 115 | template<typename K> bool Exists(const K& key) const throw(leveldb_error) { |
43b7905e PW |
116 | CDataStream ssKey(SER_DISK, CLIENT_VERSION); |
117 | ssKey.reserve(ssKey.GetSerializeSize(key)); | |
118 | ssKey << key; | |
119 | leveldb::Slice slKey(&ssKey[0], ssKey.size()); | |
120 | ||
121 | std::string strValue; | |
122 | leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); | |
123 | if (!status.ok()) { | |
124 | if (status.IsNotFound()) | |
125 | return false; | |
79d06dc6 | 126 | LogPrintf("LevelDB read failure: %s\n", status.ToString()); |
421218d3 | 127 | HandleError(status); |
43b7905e PW |
128 | } |
129 | return true; | |
130 | } | |
131 | ||
421218d3 | 132 | template<typename K> bool Erase(const K& key, bool fSync = false) throw(leveldb_error) { |
43b7905e PW |
133 | CLevelDBBatch batch; |
134 | batch.Erase(key); | |
135 | return WriteBatch(batch, fSync); | |
136 | } | |
137 | ||
421218d3 | 138 | bool WriteBatch(CLevelDBBatch &batch, bool fSync = false) throw(leveldb_error); |
43b7905e PW |
139 | |
140 | // not available for LevelDB; provide for compatibility with BDB | |
141 | bool Flush() { | |
142 | return true; | |
143 | } | |
144 | ||
421218d3 | 145 | bool Sync() throw(leveldb_error) { |
43b7905e PW |
146 | CLevelDBBatch batch; |
147 | return WriteBatch(batch, true); | |
148 | } | |
149 | ||
150 | // not exactly clean encapsulation, but it's easiest for now | |
151 | leveldb::Iterator *NewIterator() { | |
152 | return pdb->NewIterator(iteroptions); | |
153 | } | |
154 | }; | |
155 | ||
b64187d0 | 156 | #endif // BITCOIN_LEVELDBWRAPPER_H |