Skip to content

Commit fd867c7

Browse files
committed
Encapsulate CLevelDB iterators cleanly
1 parent 4eab2dc commit fd867c7

File tree

3 files changed

+87
-43
lines changed

3 files changed

+87
-43
lines changed

src/leveldb.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ static leveldb::Options GetOptions(size_t nCacheSize) {
3434
return options;
3535
}
3636

37+
CLevelDBIterator::~CLevelDBIterator() { delete piter; }
38+
bool CLevelDBIterator::Valid() { return piter->Valid(); }
39+
void CLevelDBIterator::SeekToFirst() { piter->SeekToFirst(); }
40+
void CLevelDBIterator::SeekToLast() { piter->SeekToLast(); }
41+
void CLevelDBIterator::Next() { piter->Next(); }
42+
void CLevelDBIterator::Prev() { piter->Prev(); }
43+
3744
CLevelDB::CLevelDB(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory, bool fWipe) {
3845
penv = NULL;
3946
readoptions.verify_checksums = true;

src/leveldb.h

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,63 @@ class CLevelDBBatch
5252
}
5353
};
5454

55+
class CLevelDBIterator
56+
{
57+
private:
58+
leveldb::Iterator *piter;
59+
60+
public:
61+
CLevelDBIterator(leveldb::Iterator *piterIn) : piter(piterIn) {}
62+
~CLevelDBIterator();
63+
64+
bool Valid();
65+
66+
void SeekToFirst();
67+
void SeekToLast();
68+
69+
template<typename K> void Seek(const K& key) {
70+
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
71+
ssKey.reserve(ssKey.GetSerializeSize(key));
72+
ssKey << key;
73+
leveldb::Slice slKey(&ssKey[0], ssKey.size());
74+
piter->Seek(slKey);
75+
}
76+
77+
void Next();
78+
void Prev();
79+
80+
template<typename K> bool GetKey(K& key) {
81+
leveldb::Slice slKey = piter->key();
82+
try {
83+
CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
84+
ssKey >> key;
85+
} catch(std::exception &e) {
86+
return false;
87+
}
88+
return true;
89+
}
90+
91+
unsigned int GetKeySize() {
92+
return piter->key().size();
93+
}
94+
95+
template<typename V> bool GetValue(V& value) {
96+
leveldb::Slice slValue = piter->value();
97+
try {
98+
CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
99+
ssValue >> value;
100+
} catch(std::exception &e) {
101+
return false;
102+
}
103+
return true;
104+
}
105+
106+
unsigned int GetValueSize() {
107+
return piter->value().size();
108+
}
109+
110+
};
111+
55112
class CLevelDB
56113
{
57114
private:
@@ -144,9 +201,8 @@ class CLevelDB
144201
return WriteBatch(batch, true);
145202
}
146203

147-
// not exactly clean encapsulation, but it's easiest for now
148-
leveldb::Iterator *NewIterator() {
149-
return pdb->NewIterator(iteroptions);
204+
CLevelDBIterator *NewIterator() {
205+
return new CLevelDBIterator(pdb->NewIterator(iteroptions));
150206
}
151207
};
152208

src/txdb.cpp

Lines changed: 21 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -113,31 +113,19 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
113113
}
114114

115115
bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
116-
leveldb::Iterator *pcursor = db.NewIterator();
117-
pcursor->SeekToFirst();
116+
CLevelDBIterator *pcursor = db.NewIterator();
117+
pcursor->Seek('c');
118118

119119
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
120120
stats.hashBlock = GetBestBlock()->GetBlockHash();
121121
ss << stats.hashBlock;
122122
int64 nTotalAmount = 0;
123123
while (pcursor->Valid()) {
124124
boost::this_thread::interruption_point();
125-
try {
126-
leveldb::Slice slKey = pcursor->key();
127-
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
128-
char chType;
129-
ssKey >> chType;
130-
if (chType == 'c') {
131-
leveldb::Slice slValue = pcursor->value();
132-
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
133-
CCoins coins;
134-
ssValue >> coins;
135-
uint256 txhash;
136-
ssKey >> txhash;
137-
ss << txhash;
138-
ss << VARINT(coins.nVersion);
139-
ss << (coins.fCoinBase ? 'c' : 'n');
140-
ss << VARINT(coins.nHeight);
125+
std::pair<char, uint256> key;
126+
CCoins coins;
127+
if (pcursor->GetKey(key) && key.first == 'c') {
128+
if (pcursor->GetValue(coins)) {
141129
stats.nTransactions++;
142130
for (unsigned int i=0; i<coins.vout.size(); i++) {
143131
const CTxOut &out = coins.vout[i];
@@ -148,13 +136,15 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
148136
nTotalAmount += out.nValue;
149137
}
150138
}
151-
stats.nSerializedSize += 32 + slValue.size();
139+
stats.nSerializedSize += 32 + pcursor->GetKeySize();
152140
ss << VARINT(0);
141+
} else {
142+
return error("CCoinsViewDB::GetStats() : unable to read value");
153143
}
154-
pcursor->Next();
155-
} catch (std::exception &e) {
156-
return error("%s() : deserialize error", __PRETTY_FUNCTION__);
144+
} else {
145+
break;
157146
}
147+
pcursor->Next();
158148
}
159149
delete pcursor;
160150
stats.nHeight = GetBestBlock()->nHeight;
@@ -188,26 +178,17 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
188178

189179
bool CBlockTreeDB::LoadBlockIndexGuts()
190180
{
191-
leveldb::Iterator *pcursor = NewIterator();
181+
CLevelDBIterator *pcursor = NewIterator();
192182

193-
CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
194-
ssKeySet << make_pair('b', uint256(0));
195-
pcursor->Seek(ssKeySet.str());
183+
pcursor->Seek(make_pair('b', uint256(0)));
196184

197185
// Load mapBlockIndex
198186
while (pcursor->Valid()) {
199187
boost::this_thread::interruption_point();
200-
try {
201-
leveldb::Slice slKey = pcursor->key();
202-
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
203-
char chType;
204-
ssKey >> chType;
205-
if (chType == 'b') {
206-
leveldb::Slice slValue = pcursor->value();
207-
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
208-
CDiskBlockIndex diskindex;
209-
ssValue >> diskindex;
210-
188+
std::pair<char, uint256> key;
189+
if (pcursor->GetKey(key) && key.first == 'b') {
190+
CDiskBlockIndex diskindex;
191+
if (pcursor->GetValue(diskindex)) {
211192
// Construct block index object
212193
CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
213194
pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
@@ -232,10 +213,10 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
232213

233214
pcursor->Next();
234215
} else {
235-
break; // if shutdown requested or finished loading block index
216+
return error("LoadBlockIndex() : failed to read value");
236217
}
237-
} catch (std::exception &e) {
238-
return error("%s() : deserialize error", __PRETTY_FUNCTION__);
218+
} else {
219+
break;
239220
}
240221
}
241222
delete pcursor;

0 commit comments

Comments
 (0)