-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathtxdb-leveldb.h
More file actions
206 lines (179 loc) · 6.4 KB
/
txdb-leveldb.h
File metadata and controls
206 lines (179 loc) · 6.4 KB
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// Copyright (c) 2009-2012 The Bitcoin Developers.
// Authored by Google, Inc.
// 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 "main.h"
#include <map>
#include <string>
#include <vector>
#include <leveldb/db.h>
#include <leveldb/write_batch.h>
// Class that provides access to a LevelDB. Note that this class is frequently
// instantiated on the stack and then destroyed again, so instantiation has to
// be very cheap. Unfortunately that means, a CTxDB instance is actually just a
// wrapper around some global state.
//
// A LevelDB is a key/value store that is optimized for fast usage on hard
// disks. It prefers long read/writes to seeks and is based on a series of
// sorted key/value mapping files that are stacked on top of each other, with
// newer files overriding older files. A background thread compacts them
// together when too many files stack up.
//
// Learn more: http://code.google.com/p/leveldb/
class CTxDB
{
public:
CTxDB(const char* pszMode="r+");
~CTxDB() {
// Note that this is not the same as Close() because it deletes only
// data scoped to this TxDB object.
delete activeBatch;
}
// Destroys the underlying shared global state accessed by this TxDB.
void Close();
private:
leveldb::DB *pdb; // Points to the global instance.
// A batch stores up writes and deletes for atomic application. When this
// field is non-NULL, writes/deletes go there instead of directly to disk.
leveldb::WriteBatch *activeBatch;
leveldb::Options options;
bool fReadOnly;
int nVersion;
protected:
// Returns true and sets (value,false) if activeBatch contains the given key
// or leaves value alone and sets deleted = true if activeBatch contains a
// delete for it.
bool ScanBatch(const CDataStream &key, std::string *value, bool *deleted) const;
template<typename K, typename T>
bool Read(const K& key, T& value)
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
std::string strValue;
bool readFromDb = true;
if (activeBatch) {
// First we must search for it in the currently pending set of
// changes to the db. If not found in the batch, go on to read disk.
bool deleted = false;
readFromDb = ScanBatch(ssKey, &strValue, &deleted) == false;
if (deleted) {
return false;
}
}
if (readFromDb) {
leveldb::Status status = pdb->Get(leveldb::ReadOptions(),
ssKey.str(), &strValue);
if (!status.ok()) {
if (status.IsNotFound())
return false;
// Some unexpected error.
LogPrintf("LevelDB read failure: %s\n", status.ToString());
return false;
}
}
// Unserialize value
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 T>
bool Write(const K& key, const T& value)
{
if (fReadOnly)
assert(!"Write called on database in read-only mode");
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
ssValue.reserve(10000);
ssValue << value;
if (activeBatch) {
activeBatch->Put(ssKey.str(), ssValue.str());
return true;
}
leveldb::Status status = pdb->Put(leveldb::WriteOptions(), ssKey.str(), ssValue.str());
if (!status.ok()) {
LogPrintf("LevelDB write failure: %s\n", status.ToString());
return false;
}
return true;
}
template<typename K>
bool Erase(const K& key)
{
if (!pdb)
return false;
if (fReadOnly)
assert(!"Erase called on database in read-only mode");
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
if (activeBatch) {
activeBatch->Delete(ssKey.str());
return true;
}
leveldb::Status status = pdb->Delete(leveldb::WriteOptions(), ssKey.str());
return (status.ok() || status.IsNotFound());
}
template<typename K>
bool Exists(const K& key)
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
std::string unused;
if (activeBatch) {
bool deleted;
if (ScanBatch(ssKey, &unused, &deleted) && !deleted) {
return true;
}
}
leveldb::Status status = pdb->Get(leveldb::ReadOptions(), ssKey.str(), &unused);
return status.IsNotFound() == false;
}
public:
bool TxnBegin();
bool TxnCommit();
bool TxnAbort()
{
delete activeBatch;
activeBatch = NULL;
return true;
}
bool ReadVersion(int& nVersion)
{
nVersion = 0;
return Read(std::string("version"), nVersion);
}
bool WriteVersion(int nVersion)
{
return Write(std::string("version"), nVersion);
}
bool ReadTxIndex(uint256 hash, CTxIndex& txindex);
bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex);
bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
bool EraseTxIndex(const CTransaction& tx);
bool ContainsTx(uint256 hash);
bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
bool ReadDiskTx(uint256 hash, CTransaction& tx);
bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);
bool ReadDiskTx(COutPoint outpoint, CTransaction& tx);
bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
bool ReadHashBestChain(uint256& hashBestChain);
bool WriteHashBestChain(uint256 hashBestChain);
bool ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust);
bool WriteBestInvalidTrust(CBigNum bnBestInvalidTrust);
bool LoadBlockIndex();
private:
bool LoadBlockIndexGuts();
};
#endif // BITCOIN_DB_H