mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Implement CDBTransactionIterator
This iterator allows merged iteration of the key/values from the parent and the not-yet-committed key/values from the transaction. This also works for nested transactions (as used in CEvoDB). It's interface mimics CDBIterator.
This commit is contained in:
parent
6d1599bc68
commit
b67f6a0dc6
160
src/dbwrapper.h
160
src/dbwrapper.h
@ -159,9 +159,8 @@ public:
|
||||
void Next();
|
||||
|
||||
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);
|
||||
CDataStream ssKey = GetKey();
|
||||
ssKey >> key;
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
@ -169,6 +168,11 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
CDataStream GetKey() {
|
||||
leveldb::Slice slKey = piter->key();
|
||||
return CDataStream(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
|
||||
}
|
||||
|
||||
unsigned int GetKeySize() {
|
||||
return piter->key().size();
|
||||
}
|
||||
@ -389,8 +393,153 @@ public:
|
||||
|
||||
};
|
||||
|
||||
template<typename CDBTransaction>
|
||||
class CDBTransactionIterator
|
||||
{
|
||||
private:
|
||||
CDBTransaction& transaction;
|
||||
|
||||
typedef typename std::remove_pointer<decltype(transaction.parent.NewIterator())>::type ParentIterator;
|
||||
|
||||
// We maintain 2 iterators, one for the transaction and one for the parent
|
||||
// At all times, only one of both provides the current value. The decision is made by comparing the current keys
|
||||
// of both iterators, so that always the smaller key is the current one. On Next(), the previously chosen iterator
|
||||
// is advanced.
|
||||
typename CDBTransaction::WritesMap::iterator transactionIt;
|
||||
std::unique_ptr<ParentIterator> parentIt;
|
||||
CDataStream parentKey;
|
||||
bool curIsParent{false};
|
||||
|
||||
public:
|
||||
CDBTransactionIterator(CDBTransaction& _transaction) :
|
||||
transaction(_transaction),
|
||||
parentKey(SER_DISK, CLIENT_VERSION)
|
||||
{
|
||||
transactionIt = transaction.writes.end();
|
||||
parentIt = std::unique_ptr<ParentIterator>(transaction.parent.NewIterator());
|
||||
}
|
||||
|
||||
void SeekToFirst() {
|
||||
transactionIt = transaction.writes.begin();
|
||||
parentIt->SeekToFirst();
|
||||
SkipDeletedAndOverwritten();
|
||||
DecideCur();
|
||||
}
|
||||
|
||||
template<typename K>
|
||||
void Seek(const K& key) {
|
||||
Seek(CDBTransaction::KeyToDataStream(key));
|
||||
}
|
||||
|
||||
void Seek(const CDataStream& ssKey) {
|
||||
transactionIt = transaction.writes.lower_bound(ssKey);
|
||||
parentIt->Seek(ssKey);
|
||||
SkipDeletedAndOverwritten();
|
||||
DecideCur();
|
||||
}
|
||||
|
||||
bool Valid() {
|
||||
return transactionIt != transaction.writes.end() || parentIt->Valid();
|
||||
}
|
||||
|
||||
void Next() {
|
||||
if (transactionIt == transaction.writes.end() && !parentIt->Valid()) {
|
||||
return;
|
||||
}
|
||||
if (curIsParent) {
|
||||
assert(parentIt->Valid());
|
||||
parentIt->Next();
|
||||
SkipDeletedAndOverwritten();
|
||||
} else {
|
||||
assert(transactionIt != transaction.writes.end());
|
||||
++transactionIt;
|
||||
}
|
||||
DecideCur();
|
||||
}
|
||||
|
||||
template<typename K>
|
||||
bool GetKey(K& key) {
|
||||
if (!Valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (curIsParent) {
|
||||
return parentIt->GetKey(key);
|
||||
} else {
|
||||
try {
|
||||
// TODO try to avoid this copy (we need a stream that allows reading from external buffers)
|
||||
CDataStream ssKey = transactionIt->first;
|
||||
ssKey >> key;
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
CDataStream GetKey() {
|
||||
if (!Valid()) {
|
||||
return CDataStream(SER_DISK, CLIENT_VERSION);
|
||||
}
|
||||
if (curIsParent) {
|
||||
return parentIt->GetKey();
|
||||
} else {
|
||||
return transactionIt->first;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int GetKeySize() {
|
||||
if (!Valid()) {
|
||||
return 0;
|
||||
}
|
||||
if (curIsParent) {
|
||||
return parentIt->GetKeySize();
|
||||
} else {
|
||||
return transactionIt->first.vKey.size();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename V>
|
||||
bool GetValue(V& value) {
|
||||
if (!Valid()) {
|
||||
return false;
|
||||
}
|
||||
if (curIsParent) {
|
||||
return transaction.Read(parentKey, value);
|
||||
} else {
|
||||
return transaction.Read(transactionIt->first, value);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
void SkipDeletedAndOverwritten() {
|
||||
while (parentIt->Valid()) {
|
||||
parentKey = parentIt->GetKey();
|
||||
if (!transaction.deletes.count(parentKey) && !transaction.writes.count(parentKey)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DecideCur() {
|
||||
if (transactionIt != transaction.writes.end() && !parentIt->Valid()) {
|
||||
curIsParent = false;
|
||||
} else if (transactionIt == transaction.writes.end() && parentIt->Valid()) {
|
||||
curIsParent = true;
|
||||
} else if (transactionIt != transaction.writes.end() && parentIt->Valid()) {
|
||||
if (CDBTransaction::DataStreamCmp::less(transactionIt->first, parentKey)) {
|
||||
curIsParent = false;
|
||||
} else {
|
||||
curIsParent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Parent, typename CommitTarget>
|
||||
class CDBTransaction {
|
||||
friend class CDBTransactionIterator<CDBTransaction>;
|
||||
|
||||
protected:
|
||||
Parent &parent;
|
||||
CommitTarget &commitTarget;
|
||||
@ -520,6 +669,13 @@ public:
|
||||
bool IsClean() {
|
||||
return writes.empty() && deletes.empty();
|
||||
}
|
||||
|
||||
CDBTransactionIterator<CDBTransaction>* NewIterator() {
|
||||
return new CDBTransactionIterator<CDBTransaction>(*this);
|
||||
}
|
||||
std::unique_ptr<CDBTransactionIterator<CDBTransaction>> NewIteratorUniquePtr() {
|
||||
return std::make_unique<CDBTransactionIterator<CDBTransaction>>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Parent, typename CommitTarget>
|
||||
|
Loading…
Reference in New Issue
Block a user