aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2015-10-07 17:12:24 -0700
committerJames O'Beirne <james.obeirne@gmail.com>2015-10-08 09:32:27 -0700
commit3499ce1e1ad87a86598d00b7124072c91ddad833 (patch)
treea85dd4fc69ca25aad28bf5bead2097d9688abece /src
parent4fac576c619f450da8ca09ac8790063b3dea4364 (diff)
downloadbitcoin-3499ce1e1ad87a86598d00b7124072c91ddad833.tar.xz
Encapsulate CLevelDB iterators cleanly
Conflicts: src/leveldb.cpp src/leveldb.h src/txdb.cpp
Diffstat (limited to 'src')
-rw-r--r--src/leveldbwrapper.cpp9
-rw-r--r--src/leveldbwrapper.h65
-rw-r--r--src/txdb.cpp59
3 files changed, 89 insertions, 44 deletions
diff --git a/src/leveldbwrapper.cpp b/src/leveldbwrapper.cpp
index ce96b5c8aa..a94cfd8a30 100644
--- a/src/leveldbwrapper.cpp
+++ b/src/leveldbwrapper.cpp
@@ -131,7 +131,7 @@ std::vector<unsigned char> CLevelDBWrapper::CreateObfuscateKey() const
bool CLevelDBWrapper::IsEmpty()
{
- boost::scoped_ptr<leveldb::Iterator> it(NewIterator());
+ boost::scoped_ptr<CLevelDBIterator> it(NewIterator());
it->SeekToFirst();
return !(it->Valid());
}
@@ -145,3 +145,10 @@ std::string CLevelDBWrapper::GetObfuscateKeyHex() const
{
return HexStr(obfuscate_key);
}
+
+CLevelDBIterator::~CLevelDBIterator() { delete piter; }
+bool CLevelDBIterator::Valid() { return piter->Valid(); }
+void CLevelDBIterator::SeekToFirst() { piter->SeekToFirst(); }
+void CLevelDBIterator::SeekToLast() { piter->SeekToLast(); }
+void CLevelDBIterator::Next() { piter->Next(); }
+void CLevelDBIterator::Prev() { piter->Prev(); }
diff --git a/src/leveldbwrapper.h b/src/leveldbwrapper.h
index f5c463830c..ece4e49694 100644
--- a/src/leveldbwrapper.h
+++ b/src/leveldbwrapper.h
@@ -68,7 +68,65 @@ public:
batch.Delete(slKey);
}
};
+
+class CLevelDBIterator
+{
+private:
+ leveldb::Iterator *piter;
+
+public:
+ CLevelDBIterator(leveldb::Iterator *piterIn) : piter(piterIn) {}
+ ~CLevelDBIterator();
+
+ bool Valid();
+ void SeekToFirst();
+ void SeekToLast();
+
+ template<typename K> void Seek(const K& key) {
+ CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+ ssKey.reserve(ssKey.GetSerializeSize(key));
+ ssKey << key;
+ leveldb::Slice slKey(&ssKey[0], ssKey.size());
+ piter->Seek(slKey);
+ }
+
+ void Next();
+ void Prev();
+
+ template<typename K> bool GetKey(K& key) {
+ leveldb::Slice slKey = piter->key();
+ try {
+ CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
+ ssKey >> key;
+ } catch(std::exception &e) {
+ return false;
+ }
+ return true;
+ }
+
+ unsigned int GetKeySize() {
+ return piter->key().size();
+ }
+
+ template<typename V> bool GetValue(V& value) {
+ leveldb::Slice slValue = piter->value();
+ try {
+ CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
+ ssValue.Xor(db.GetObfuscateKey());
+ ssValue >> value;
+ } catch(std::exception &e) {
+ return false;
+ }
+ return true;
+ }
+
+ unsigned int GetValueSize() {
+ return piter->value().size();
+ }
+
+};
+
class CLevelDBWrapper
{
private:
@@ -191,11 +249,10 @@ public:
return WriteBatch(batch, true);
}
- // not exactly clean encapsulation, but it's easiest for now
- leveldb::Iterator* NewIterator()
+ CLevelDBIterator *NewIterator()
+ {
+ return new CLevelDBIterator(pdb->NewIterator(iteroptions));
{
- return pdb->NewIterator(iteroptions);
- }
/**
* Return true if the database managed by this class contains no entries.
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 9738dea03d..3d20508912 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -98,8 +98,8 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
/* It seems that there are no "const iterators" for LevelDB. Since we
only need read operations on it, use a const-cast to get around
that restriction. */
- boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
- pcursor->SeekToFirst();
+ boost::scoped_ptr<CLevelDBWrapper> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
+ pcursor->Seek('c');
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
stats.hashBlock = GetBestBlock();
@@ -107,22 +107,10 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
CAmount nTotalAmount = 0;
while (pcursor->Valid()) {
boost::this_thread::interruption_point();
- try {
- leveldb::Slice slKey = pcursor->key();
- CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
- char chType;
- ssKey >> chType;
- if (chType == DB_COINS) {
- leveldb::Slice slValue = pcursor->value();
- CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
- CCoins coins;
- ssValue >> coins;
- uint256 txhash;
- ssKey >> txhash;
- ss << txhash;
- ss << VARINT(coins.nVersion);
- ss << (coins.fCoinBase ? 'c' : 'n');
- ss << VARINT(coins.nHeight);
+ std::pair<char, uint256> key;
+ CCoins coins;
+ if (pcursor->GetKey(key) && key.first == 'c') {
+ if (pcursor->GetValue(coins)) {
stats.nTransactions++;
for (unsigned int i=0; i<coins.vout.size(); i++) {
const CTxOut &out = coins.vout[i];
@@ -133,13 +121,15 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
nTotalAmount += out.nValue;
}
}
- stats.nSerializedSize += 32 + slValue.size();
+ stats.nSerializedSize += 32 + pcursor->GetKeySize();
ss << VARINT(0);
+ } else {
+ return error("CCoinsViewDB::GetStats() : unable to read value");
}
- pcursor->Next();
- } catch (const std::exception& e) {
- return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ } else {
+ break;
}
+ pcursor->Next();
}
{
LOCK(cs_main);
@@ -189,24 +179,15 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
{
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
- CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
- ssKeySet << make_pair(DB_BLOCK_INDEX, uint256());
- pcursor->Seek(ssKeySet.str());
+ pcursor->Seek(make_pair('b', uint256(0)));
// Load mapBlockIndex
while (pcursor->Valid()) {
boost::this_thread::interruption_point();
- try {
- leveldb::Slice slKey = pcursor->key();
- CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
- char chType;
- ssKey >> chType;
- if (chType == DB_BLOCK_INDEX) {
- leveldb::Slice slValue = pcursor->value();
- CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
- CDiskBlockIndex diskindex;
- ssValue >> diskindex;
-
+ std::pair<char, uint256> key;
+ if (pcursor->GetKey(key) && key.first == 'b') {
+ CDiskBlockIndex diskindex;
+ if (pcursor->GetValue(diskindex)) {
// Construct block index object
CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
@@ -227,10 +208,10 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
pcursor->Next();
} else {
- break; // if shutdown requested or finished loading block index
+ return error("LoadBlockIndex() : failed to read value");
}
- } catch (const std::exception& e) {
- return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ } else {
+ break;
}
}