Browse Source

Started implementing namespace association.

views
Just Wonder 5 years ago
parent
commit
76c50bc850
  1. 30
      src/coins.cpp
  2. 5
      src/coins.h
  3. 71
      src/keva/common.cpp
  4. 32
      src/keva/common.h
  5. 2
      src/rpc/rpckeva_nonwallet.cpp
  6. 25
      src/txdb.cpp
  7. 1
      src/txdb.h

30
src/coins.cpp

@ -14,6 +14,7 @@ bool CCoinsView::GetNamespace(const valtype &nameSpace, CKevaData &data) const { @@ -14,6 +14,7 @@ bool CCoinsView::GetNamespace(const valtype &nameSpace, CKevaData &data) const {
bool CCoinsView::GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const { return false; }
bool CCoinsView::GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const { return false; }
CKevaIterator* CCoinsView::IterateKeys(const valtype& nameSpace) const { assert (false); }
CKevaIterator* CCoinsView::IterateAssociatedNamespaces(const valtype& nameSpace) const { assert (false); }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) { return false; }
CCoinsViewCursor *CCoinsView::Cursor() const { return nullptr; }
bool CCoinsView::ValidateKevaDB() const {
@ -43,6 +44,7 @@ bool CCoinsViewBacked::GetNamesForHeight(unsigned nHeight, std::set<valtype>& na @@ -43,6 +44,7 @@ bool CCoinsViewBacked::GetNamesForHeight(unsigned nHeight, std::set<valtype>& na
return base->GetNamesForHeight(nHeight, names);
}
CKevaIterator* CCoinsViewBacked::IterateKeys(const valtype& nameSpace) const { return base->IterateKeys(nameSpace); }
CKevaIterator* CCoinsViewBacked::IterateAssociatedNamespaces(const valtype& nameSpace) const { return base->IterateAssociatedNamespaces(nameSpace); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) {
return base->BatchWrite(mapCoins, hashBlock, names);
@ -198,6 +200,10 @@ CKevaIterator* CCoinsViewCache::IterateKeys(const valtype& nameSpace) const { @@ -198,6 +200,10 @@ CKevaIterator* CCoinsViewCache::IterateKeys(const valtype& nameSpace) const {
return cacheNames.iterateKeys(base->IterateKeys(nameSpace));
}
CKevaIterator* CCoinsViewCache::IterateAssociatedNamespaces(const valtype& nameSpace) const {
return cacheNames.IterateAssociatedNamespaces(base->IterateAssociatedNamespaces(nameSpace));
}
/* undo is set if the change is due to disconnecting blocks / going back in
time. The ordinary case (!undo) means that we update the name normally,
going forward in time. This is important for keeping track of the
@ -210,6 +216,18 @@ void CCoinsViewCache::SetName(const valtype &nameSpace, const valtype &key, cons @@ -210,6 +216,18 @@ void CCoinsViewCache::SetName(const valtype &nameSpace, const valtype &key, cons
cacheNames.setNamespace(nameSpace, namespaceData);
}
cacheNames.set(nameSpace, key, data);
// Handle namespace association.
valtype associdateNamespace;
if (!cacheNames.getAssociateNamespaces(data.getValue(), associdateNamespace)) {
return;
}
CKevaData dummyData;
if (!GetNamespace(associdateNamespace, dummyData)) {
return;
}
cacheNames.associateNamespaces(nameSpace, associdateNamespace);
}
void CCoinsViewCache::DeleteName(const valtype &nameSpace, const valtype &key) {
@ -218,6 +236,18 @@ void CCoinsViewCache::DeleteName(const valtype &nameSpace, const valtype &key) { @@ -218,6 +236,18 @@ void CCoinsViewCache::DeleteName(const valtype &nameSpace, const valtype &key) {
assert(false);
}
cacheNames.remove(nameSpace, key);
// Handle namespace association.
valtype associdateNamespace;
if (!cacheNames.getAssociateNamespaces(oldData.getValue(), associdateNamespace)) {
return;
}
CKevaData dummyData;
if (!GetNamespace(associdateNamespace, dummyData)) {
return;
}
cacheNames.disassociateNamespaces(nameSpace, associdateNamespace);
}
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn, const CKevaCache &names) {

5
src/coins.h

@ -176,6 +176,9 @@ public: @@ -176,6 +176,9 @@ public:
// Get a key iterator.
virtual CKevaIterator* IterateKeys(const valtype& nameSpace) const;
// Get the associated namespace iterator.
virtual CKevaIterator* IterateAssociatedNamespaces(const valtype& nameSpace) const;
//! Do a bulk modification (multiple Coin changes + BestBlock change).
//! The passed mapCoins can be modified.
virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names);
@ -210,6 +213,7 @@ public: @@ -210,6 +213,7 @@ public:
bool GetName(const valtype& nameSpace, const valtype& key, CKevaData& data) const override;
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
CKevaIterator* IterateKeys(const valtype& nameSpace) const override;
virtual CKevaIterator* IterateAssociatedNamespaces(const valtype& nameSpace) const override;
void SetBackend(CCoinsView &viewIn);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override;
CCoinsViewCursor *Cursor() const override;
@ -252,6 +256,7 @@ public: @@ -252,6 +256,7 @@ public:
bool GetName(const valtype &nameSpace, const valtype &key, CKevaData& data) const override;
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
CKevaIterator* IterateKeys(const valtype& nameSpace) const override;
CKevaIterator* IterateAssociatedNamespaces(const valtype& nameSpace) const override;
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override;
CCoinsViewCursor* Cursor() const override {
throw std::logic_error("CCoinsViewCache cursor iteration not supported.");

71
src/keva/common.cpp

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <keva/common.h>
#include <base58.h>
#include <script/keva.h>
@ -55,6 +55,9 @@ private: @@ -55,6 +55,9 @@ private:
/** Base iterator to combine with the cache. */
CKevaIterator* base;
/** Whether or not it is for namespace association. */
bool isAssociation;
/** Whether or not the base iterator has more entries. */
bool baseHasMore;
@ -79,7 +82,7 @@ public: @@ -79,7 +82,7 @@ public:
* @param c The cache object to use.
* @param b The base iterator.
*/
CCacheKeyIterator(const CKevaCache& c, CKevaIterator* b);
CCacheKeyIterator(const CKevaCache& c, CKevaIterator* b, bool association=false);
/* Destruct, this deletes also the base iterator. */
~CCacheKeyIterator();
@ -90,8 +93,8 @@ public: @@ -90,8 +93,8 @@ public:
};
CCacheKeyIterator::CCacheKeyIterator(const CKevaCache& c, CKevaIterator* b)
: CKevaIterator(b->getNamespace()), cache(c), base(b)
CCacheKeyIterator::CCacheKeyIterator(const CKevaCache& c, CKevaIterator* b, bool association)
: CKevaIterator(b->getNamespace()), cache(c), base(b), isAssociation(association)
{
/* Add a seek-to-start to ensure that everything is consistent. This call
may be superfluous if we seek to another position afterwards anyway,
@ -116,7 +119,8 @@ CCacheKeyIterator::advanceBaseIterator() @@ -116,7 +119,8 @@ CCacheKeyIterator::advanceBaseIterator()
void
CCacheKeyIterator::seek(const valtype& start)
{
cacheIter = cache.entries.lower_bound(std::make_tuple(nameSpace, start));
auto &entries = isAssociation ? cache.associations : cache.entries;
cacheIter = entries.lower_bound(std::make_tuple(nameSpace, start));
base->seek(start);
baseHasMore = true;
@ -127,15 +131,15 @@ bool CCacheKeyIterator::next(valtype& key, CKevaData& data) @@ -127,15 +131,15 @@ bool CCacheKeyIterator::next(valtype& key, CKevaData& data)
{
/* Exit early if no more data is available in either the cache
nor the base iterator. */
auto &entries = isAssociation ? cache.associations : cache.entries;
bool endOfCacheNamespace = false;
if (cacheIter != cache.entries.end()) {
if (cacheIter != entries.end()) {
valtype curNameSpace = std::get<0>(cacheIter->first);
if (curNameSpace != nameSpace) {
endOfCacheNamespace = true;
}
}
bool noMoreCache = (cacheIter == cache.entries.end()) || endOfCacheNamespace;
bool noMoreCache = (cacheIter == entries.end()) || endOfCacheNamespace;
if (!baseHasMore && noMoreCache) {
return false;
}
@ -144,7 +148,7 @@ bool CCacheKeyIterator::next(valtype& key, CKevaData& data) @@ -144,7 +148,7 @@ bool CCacheKeyIterator::next(valtype& key, CKevaData& data)
bool useBase = false;
if (!baseHasMore) {
useBase = false;
} else if (cacheIter == cache.entries.end()) {
} else if (cacheIter == entries.end()) {
useBase = true;
} else {
if (baseKey == std::get<1>(cacheIter->first)) {
@ -182,6 +186,8 @@ bool CCacheKeyIterator::next(valtype& key, CKevaData& data) @@ -182,6 +186,8 @@ bool CCacheKeyIterator::next(valtype& key, CKevaData& data)
/* ************************************************************************** */
/* CKevaCache. */
const std::string CKevaCache::associatePrefix = "_A_";
bool
CKevaCache::get(const valtype& nameSpace, const valtype& key, CKevaData& data) const
{
@ -233,12 +239,55 @@ CKevaCache::remove(const valtype& nameSpace, const valtype& key) @@ -233,12 +239,55 @@ CKevaCache::remove(const valtype& nameSpace, const valtype& key)
deleted.insert(name);
}
/* If the value is an associated namespace (_A_N...), return the namespace */
bool
CKevaCache::getAssociateNamespaces(const valtype& value, valtype& nameSpace)
{
std::string valueStr = ValtypeToString(value);
if (valueStr.rfind(associatePrefix, 0) != 0) {
return false;
}
valueStr.erase(0, associatePrefix.length());
if (!DecodeKevaNamespace(valueStr, Params(), nameSpace)) {
return false;
}
return true;
}
void
CKevaCache::associateNamespaces(const valtype& nameSpace, const valtype& nameSpaceOther)
{
auto name = std::make_tuple(nameSpaceOther, nameSpace);
const NamespaceMap::iterator ei = associations.find(name);
CKevaData data;
if (ei != entries.end())
ei->second = data;
else
associations.insert(std::make_pair(name, data));
}
void
CKevaCache::disassociateNamespaces(const valtype& nameSpace, const valtype& nameSpaceOther)
{
auto name = std::make_tuple(nameSpaceOther, nameSpace);
const NamespaceMap::iterator ei = entries.find(name);
if (ei != entries.end()) {
associations.erase(ei);
}
}
CKevaIterator*
CKevaCache::iterateKeys(CKevaIterator* base) const
{
return new CCacheKeyIterator(*this, base);
}
CKevaIterator*
CKevaCache::IterateAssociatedNamespaces(CKevaIterator* base) const
{
return new CCacheKeyIterator(*this, base, true);
}
void
CKevaCache::updateNamesForHeight (unsigned nHeight,
std::set<valtype>& names) const
@ -253,6 +302,10 @@ void CKevaCache::apply(const CKevaCache& cache) @@ -253,6 +302,10 @@ void CKevaCache::apply(const CKevaCache& cache)
set(std::get<0>(i->first), std::get<1>(i->first), i->second);
}
for (NamespaceMap::const_iterator i = associations.begin(); i != associations.end(); ++i) {
set(std::get<0>(i->first), std::get<1>(i->first), i->second);
}
for (std::set<NamespaceKeyType>::const_iterator i = cache.deleted.begin(); i != cache.deleted.end(); ++i) {
remove(std::get<0>(*i), std::get<1>(*i));
}

32
src/keva/common.h

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// Copyright (c) 2018
// Copyright (c) 2018-2020 The Kevacoin Core Developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -298,6 +298,8 @@ class CKevaCache @@ -298,6 +298,8 @@ class CKevaCache
private:
const static std::string associatePrefix;
/**
* Special comparator class for names that compares by length first.
* This is used to sort the cache entry map in the same way as the
@ -336,6 +338,8 @@ public: @@ -336,6 +338,8 @@ public:
typedef std::tuple<valtype, valtype> NamespaceKeyType;
typedef std::map<std::tuple<valtype, valtype>, CKevaData, KeyComparator> NamespaceMap;
private:
/** New or updated names. */
@ -344,15 +348,19 @@ private: @@ -344,15 +348,19 @@ private:
/** Deleted names. */
std::set<NamespaceKeyType> deleted;
/** Namespace association. */
NamespaceMap associations;
friend class CCacheKeyIterator;
public:
inline void
clear ()
clear()
{
entries.clear ();
deleted.clear ();
entries.clear();
deleted.clear();
associations.clear();
}
/**
@ -362,9 +370,9 @@ public: @@ -362,9 +370,9 @@ public:
* @return True iff no changes are cached.
*/
inline bool
empty () const
empty() const
{
if (entries.empty() && deleted.empty()) {
if (entries.empty() && deleted.empty() && associations.empty()) {
return true;
}
@ -394,11 +402,23 @@ public: @@ -394,11 +402,23 @@ public:
/* Delete a name. If it is in the "entries" set also, remove it there. */
void remove(const valtype& nameSpace, const valtype& key);
/* If the value is an associated namespace (_A_N...), return the namespace */
bool getAssociateNamespaces(const valtype& value, valtype& nameSpace);
/* Associate nameSpace with nameSpaceOther */
void associateNamespaces(const valtype& nameSpace, const valtype& nameSpaceOther);
/* Disassociate nameSpace with nameSpaceOther */
void disassociateNamespaces(const valtype& nameSpace, const valtype& nameSpaceOther);
/* Return a name iterator that combines a "base" iterator with the changes
made to it according to the cache. The base iterator is taken
ownership of. */
CKevaIterator* iterateKeys(CKevaIterator* base) const;
// Get the associated namespace iterator.
CKevaIterator* IterateAssociatedNamespaces(CKevaIterator* base) const;
/* Query the cached changes to the expire index. In particular,
for a given height and a given set of names that were indexed to
this update height, apply possible changes to the set that

2
src/rpc/rpckeva_nonwallet.cpp

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// Copyright (c) 2018 the Kevacoin Core Developers
// Copyright (c) 2018-2020 the Kevacoin Core Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

25
src/txdb.cpp

@ -26,6 +26,7 @@ static const char DB_TXINDEX = 't'; @@ -26,6 +26,7 @@ static const char DB_TXINDEX = 't';
static const char DB_BLOCK_INDEX = 'b';
static const char DB_NAME = 'n';
static const char DB_NS_ASSOC = 'a';
static const char DB_BEST_BLOCK = 'B';
static const char DB_HEAD_BLOCKS = 'H';
@ -92,6 +93,9 @@ private: @@ -92,6 +93,9 @@ private:
/* The backing LevelDB iterator. */
CDBIterator* iter;
/* This iterator is for namespace association search. */
bool isAssociation;
public:
~CDbKeyIterator();
@ -100,7 +104,7 @@ public: @@ -100,7 +104,7 @@ public:
* Construct a new name iterator for the database.
* @param db The database to create the iterator for.
*/
CDbKeyIterator(const CDBWrapper& db, const valtype& nameSpace);
CDbKeyIterator(const CDBWrapper& db, const valtype& nameSpace, bool association=false);
/* Implement iterator methods. */
void seek(const valtype& start);
@ -112,22 +116,24 @@ CDbKeyIterator::~CDbKeyIterator() { @@ -112,22 +116,24 @@ CDbKeyIterator::~CDbKeyIterator() {
delete iter;
}
CDbKeyIterator::CDbKeyIterator(const CDBWrapper& db, const valtype& ns)
: CKevaIterator(ns), iter(const_cast<CDBWrapper*>(&db)->NewIterator())
CDbKeyIterator::CDbKeyIterator(const CDBWrapper& db, const valtype& ns, bool association)
: CKevaIterator(ns), iter(const_cast<CDBWrapper*>(&db)->NewIterator()), isAssociation(association)
{
seek(valtype());
}
void CDbKeyIterator::seek(const valtype& start) {
iter->Seek(std::make_pair(DB_NAME, std::make_pair(nameSpace, start)));
auto &prefix = isAssociation ? DB_NS_ASSOC : DB_NAME;
iter->Seek(std::make_pair(prefix, std::make_pair(nameSpace, start)));
}
bool CDbKeyIterator::next(valtype& key, CKevaData& data) {
if (!iter->Valid())
return false;
auto &prefix = isAssociation ? DB_NS_ASSOC : DB_NAME;
std::pair<char, std::pair<valtype, valtype>> curKey;
if (!iter->GetKey(curKey) || curKey.first != DB_NAME)
if (!iter->GetKey(curKey) || curKey.first != prefix)
return false;
valtype curNameSpace = std::get<0>(curKey.second);
@ -148,6 +154,10 @@ CKevaIterator* CCoinsViewDB::IterateKeys(const valtype& nameSpace) const { @@ -148,6 +154,10 @@ CKevaIterator* CCoinsViewDB::IterateKeys(const valtype& nameSpace) const {
return new CDbKeyIterator(db, nameSpace);
}
CKevaIterator* CCoinsViewDB::IterateAssociatedNamespaces(const valtype& nameSpace) const {
return new CDbKeyIterator(db, nameSpace, true);
}
bool CCoinsViewDB::GetNamespace(const valtype &nameSpace, CKevaData &data) const {
return db.Read(std::make_pair(DB_NAME, std::make_pair(nameSpace, CKevaScript::KEVA_DISPLAY_NAME_KEY)), data);
}
@ -324,6 +334,11 @@ void CKevaCache::writeBatch (CDBBatch& batch) const @@ -324,6 +334,11 @@ void CKevaCache::writeBatch (CDBBatch& batch) const
batch.Write(std::make_pair(DB_NAME, name), i->second);
}
for (NamespaceMap::const_iterator i = associations.begin(); i != associations.end(); ++i) {
std::pair<valtype, valtype> name = std::make_pair(std::get<0>(i->first), std::get<1>(i->first));
batch.Write(std::make_pair(DB_NS_ASSOC, name), i->second);
}
for (std::set<NamespaceKeyType>::const_iterator i = deleted.begin(); i != deleted.end(); ++i) {
std::pair<valtype, valtype> name = std::make_pair(std::get<0>(*i), std::get<1>(*i));
batch.Erase(std::make_pair(DB_NAME, name));

1
src/txdb.h

@ -80,6 +80,7 @@ public: @@ -80,6 +80,7 @@ public:
bool GetName(const valtype &nameSpace, const valtype &key, CKevaData &data) const override;
bool GetNamesForHeight(unsigned nHeight, std::set<valtype>& names) const override;
CKevaIterator* IterateKeys(const valtype& nameSpace) const override;
CKevaIterator* IterateAssociatedNamespaces(const valtype& nameSpace) const override;
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const CKevaCache &names) override;
CCoinsViewCursor *Cursor() const override;

Loading…
Cancel
Save