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