Skip to content

Commit 3499ce1

Browse files
sipajamesob
authored andcommitted
Encapsulate CLevelDB iterators cleanly
Conflicts: src/leveldb.cpp src/leveldb.h src/txdb.cpp
1 parent 4fac576 commit 3499ce1

File tree

3 files changed

+89
-44
lines changed

3 files changed

+89
-44
lines changed

src/leveldbwrapper.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ std::vector<unsigned char> CLevelDBWrapper::CreateObfuscateKey() const
131131

132132
bool CLevelDBWrapper::IsEmpty()
133133
{
134-
boost::scoped_ptr<leveldb::Iterator> it(NewIterator());
134+
boost::scoped_ptr<CLevelDBIterator> it(NewIterator());
135135
it->SeekToFirst();
136136
return !(it->Valid());
137137
}
@@ -145,3 +145,10 @@ std::string CLevelDBWrapper::GetObfuscateKeyHex() const
145145
{
146146
return HexStr(obfuscate_key);
147147
}
148+
149+
CLevelDBIterator::~CLevelDBIterator() { delete piter; }
150+
bool CLevelDBIterator::Valid() { return piter->Valid(); }
151+
void CLevelDBIterator::SeekToFirst() { piter->SeekToFirst(); }
152+
void CLevelDBIterator::SeekToLast() { piter->SeekToLast(); }
153+
void CLevelDBIterator::Next() { piter->Next(); }
154+
void CLevelDBIterator::Prev() { piter->Prev(); }

src/leveldbwrapper.h

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,65 @@ class CLevelDBBatch
6868
batch.Delete(slKey);
6969
}
7070
};
71+
72+
class CLevelDBIterator
73+
{
74+
private:
75+
leveldb::Iterator *piter;
76+
77+
public:
78+
CLevelDBIterator(leveldb::Iterator *piterIn) : piter(piterIn) {}
79+
~CLevelDBIterator();
80+
81+
bool Valid();
7182

83+
void SeekToFirst();
84+
void SeekToLast();
85+
86+
template<typename K> void Seek(const K& key) {
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+
piter->Seek(slKey);
92+
}
93+
94+
void Next();
95+
void Prev();
96+
97+
template<typename K> bool GetKey(K& key) {
98+
leveldb::Slice slKey = piter->key();
99+
try {
100+
CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
101+
ssKey >> key;
102+
} catch(std::exception &e) {
103+
return false;
104+
}
105+
return true;
106+
}
107+
108+
unsigned int GetKeySize() {
109+
return piter->key().size();
110+
}
111+
112+
template<typename V> bool GetValue(V& value) {
113+
leveldb::Slice slValue = piter->value();
114+
try {
115+
CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
116+
ssValue.Xor(db.GetObfuscateKey());
117+
ssValue >> value;
118+
} catch(std::exception &e) {
119+
return false;
120+
}
121+
return true;
122+
}
123+
124+
unsigned int GetValueSize() {
125+
return piter->value().size();
126+
}
127+
128+
};
129+
72130
class CLevelDBWrapper
73131
{
74132
private:
@@ -191,11 +249,10 @@ class CLevelDBWrapper
191249
return WriteBatch(batch, true);
192250
}
193251

194-
// not exactly clean encapsulation, but it's easiest for now
195-
leveldb::Iterator* NewIterator()
252+
CLevelDBIterator *NewIterator()
253+
{
254+
return new CLevelDBIterator(pdb->NewIterator(iteroptions));
196255
{
197-
return pdb->NewIterator(iteroptions);
198-
}
199256

200257
/**
201258
* Return true if the database managed by this class contains no entries.

src/txdb.cpp

Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -98,31 +98,19 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
9898
/* It seems that there are no "const iterators" for LevelDB. Since we
9999
only need read operations on it, use a const-cast to get around
100100
that restriction. */
101-
boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
102-
pcursor->SeekToFirst();
101+
boost::scoped_ptr<CLevelDBWrapper> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
102+
pcursor->Seek('c');
103103

104104
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
105105
stats.hashBlock = GetBestBlock();
106106
ss << stats.hashBlock;
107107
CAmount nTotalAmount = 0;
108108
while (pcursor->Valid()) {
109109
boost::this_thread::interruption_point();
110-
try {
111-
leveldb::Slice slKey = pcursor->key();
112-
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
113-
char chType;
114-
ssKey >> chType;
115-
if (chType == DB_COINS) {
116-
leveldb::Slice slValue = pcursor->value();
117-
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
118-
CCoins coins;
119-
ssValue >> coins;
120-
uint256 txhash;
121-
ssKey >> txhash;
122-
ss << txhash;
123-
ss << VARINT(coins.nVersion);
124-
ss << (coins.fCoinBase ? 'c' : 'n');
125-
ss << VARINT(coins.nHeight);
110+
std::pair<char, uint256> key;
111+
CCoins coins;
112+
if (pcursor->GetKey(key) && key.first == 'c') {
113+
if (pcursor->GetValue(coins)) {
126114
stats.nTransactions++;
127115
for (unsigned int i=0; i<coins.vout.size(); i++) {
128116
const CTxOut &out = coins.vout[i];
@@ -133,13 +121,15 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
133121
nTotalAmount += out.nValue;
134122
}
135123
}
136-
stats.nSerializedSize += 32 + slValue.size();
124+
stats.nSerializedSize += 32 + pcursor->GetKeySize();
137125
ss << VARINT(0);
126+
} else {
127+
return error("CCoinsViewDB::GetStats() : unable to read value");
138128
}
139-
pcursor->Next();
140-
} catch (const std::exception& e) {
141-
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
129+
} else {
130+
break;
142131
}
132+
pcursor->Next();
143133
}
144134
{
145135
LOCK(cs_main);
@@ -189,24 +179,15 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
189179
{
190180
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
191181

192-
CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
193-
ssKeySet << make_pair(DB_BLOCK_INDEX, uint256());
194-
pcursor->Seek(ssKeySet.str());
182+
pcursor->Seek(make_pair('b', uint256(0)));
195183

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

228209
pcursor->Next();
229210
} else {
230-
break; // if shutdown requested or finished loading block index
211+
return error("LoadBlockIndex() : failed to read value");
231212
}
232-
} catch (const std::exception& e) {
233-
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
213+
} else {
214+
break;
234215
}
235216
}
236217

0 commit comments

Comments
 (0)