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