Optimize and clean up SHAMap::iterator:

* Remove dependence on boost::iterator_facade.
* Rename iterator to const_iterator.
* Change value_type from shared_ptr<SHAMapItem const> to SHAMapItem.
* Install a stack-path to the current SHAMapItem in the const_iterator.
This commit is contained in:
Howard Hinnant
2015-06-30 12:15:47 -04:00
committed by Vinnie Falco
parent 30e068ae17
commit 361f1da5b8
8 changed files with 186 additions and 71 deletions

View File

@@ -35,7 +35,7 @@ AcceptedLedger::AcceptedLedger (Ledger::ref ledger) : mLedger (ledger)
{ {
for (auto const& item : ledger->txMap()) for (auto const& item : ledger->txMap())
{ {
SerialIter sit (item->slice()); SerialIter sit (item.slice());
insert (std::make_shared<AcceptedLedgerTx>( insert (std::make_shared<AcceptedLedgerTx>(
ledger, std::ref (sit))); ledger, std::ref (sit)));
} }

View File

@@ -59,7 +59,7 @@ class Ledger::txs_iter_impl
private: private:
bool metadata_; bool metadata_;
ReadView const* view_; ReadView const* view_;
SHAMap::iterator iter_; SHAMap::const_iterator iter_;
public: public:
txs_iter_impl() = delete; txs_iter_impl() = delete;
@@ -68,7 +68,7 @@ public:
txs_iter_impl (txs_iter_impl const&) = default; txs_iter_impl (txs_iter_impl const&) = default;
txs_iter_impl (bool metadata, txs_iter_impl (bool metadata,
SHAMap::iterator iter, SHAMap::const_iterator iter,
ReadView const& view) ReadView const& view)
: metadata_ (metadata) : metadata_ (metadata)
, view_ (&view) , view_ (&view)
@@ -102,8 +102,8 @@ public:
{ {
auto const item = *iter_; auto const item = *iter_;
if (metadata_) if (metadata_)
return deserializeTxPlusMeta(*item); return deserializeTxPlusMeta(item);
return { deserializeTx(*item), nullptr }; return { deserializeTx(item), nullptr };
} }
}; };

View File

@@ -275,16 +275,14 @@ log_metadata_difference(Ledger::pointer builtLedger, Ledger::pointer validLedger
// Return list of leaves sorted by key // Return list of leaves sorted by key
static static
std::vector<std::shared_ptr<SHAMapItem const>> std::vector<SHAMapItem const*>
leaves (SHAMap const& sm) leaves (SHAMap const& sm)
{ {
std::vector<std::shared_ptr< std::vector<SHAMapItem const*> v;
SHAMapItem const>> v;
for (auto const& item : sm) for (auto const& item : sm)
v.push_back(item); v.push_back(&item);
std::sort(v.begin(), v.end(), std::sort(v.begin(), v.end(),
[](std::shared_ptr<SHAMapItem const> const& lhs, [](SHAMapItem const* lhs, SHAMapItem const* rhs)
std::shared_ptr<SHAMapItem const> const& rhs)
{ return lhs->key() < rhs->key(); }); { return lhs->key() < rhs->key(); });
return v; return v;
} }

View File

@@ -1812,20 +1812,19 @@ void applyTransactions (
{ {
if (set) if (set)
{ {
for (auto const item : *set) for (auto const& item : *set)
{ {
if (checkLedger->txExists (item->key())) if (checkLedger->txExists (item.key()))
continue; continue;
// The transaction isn't in the check ledger, try to apply it // The transaction isn't in the check ledger, try to apply it
WriteLog (lsDEBUG, LedgerConsensus) << WriteLog (lsDEBUG, LedgerConsensus) <<
"Processing candidate transaction: " << item->key(); "Processing candidate transaction: " << item.key();
std::shared_ptr<STTx const> txn; std::shared_ptr<STTx const> txn;
try try
{ {
SerialIter sit (item->slice()); txn = std::make_shared<STTx const>(SerialIter{item.slice()});
txn = std::make_shared<STTx const>(sit);
} }
catch (...) catch (...)
{ {

View File

@@ -207,7 +207,7 @@ debugTostr (SHAMap const& set)
{ {
try try
{ {
SerialIter sit(item->slice()); SerialIter sit(item.slice());
auto const tx = std::make_shared< auto const tx = std::make_shared<
STTx const>(sit); STTx const>(sit);
ss << debugTxstr(tx) << ", "; ss << debugTxstr(tx) << ", ";

View File

@@ -1334,16 +1334,16 @@ bool ApplicationImp::loadOldLedger (
for (auto const& item : txns) for (auto const& item : txns)
{ {
auto const txn = auto const txn =
getTransaction(*replayLedger, item->key(), getTransaction(*replayLedger, item.key(),
getApp().getMasterTransaction()); getApp().getMasterTransaction());
if (m_journal.info) m_journal.info << if (m_journal.info) m_journal.info <<
txn->getJson(0); txn->getJson(0);
Serializer s; Serializer s;
txn->getSTransaction()->add(s); txn->getSTransaction()->add(s);
cur->rawTxInsert(item->key(), cur->rawTxInsert(item.key(),
std::make_shared<Serializer const>( std::make_shared<Serializer const>(
std::move(s)), nullptr); std::move(s)), nullptr);
getApp().getHashRouter().setFlag (item->key(), SF_SIGGOOD); getApp().getHashRouter().setFlag (item.key(), SF_SIGGOOD);
} }
// Switch to the mutable snapshot // Switch to the mutable snapshot

View File

@@ -33,12 +33,12 @@
#include <ripple/nodestore/Database.h> #include <ripple/nodestore/Database.h>
#include <ripple/nodestore/NodeObject.h> #include <ripple/nodestore/NodeObject.h>
#include <beast/utility/Journal.h> #include <beast/utility/Journal.h>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/shared_lock_guard.hpp> #include <boost/thread/shared_lock_guard.hpp>
#include <boost/thread/shared_mutex.hpp> #include <boost/thread/shared_mutex.hpp>
#include <cassert> #include <cassert>
#include <stack> #include <stack>
#include <vector>
namespace ripple { namespace ripple {
@@ -80,6 +80,8 @@ class SHAMap
{ {
private: private:
using Family = shamap::Family; using Family = shamap::Family;
using NodeStack = std::stack<std::pair<SHAMapAbstractNode*, SHAMapNodeID>,
std::vector<std::pair<SHAMapAbstractNode*, SHAMapNodeID>>>;
Family& f_; Family& f_;
beast::Journal journal_; beast::Journal journal_;
@@ -119,10 +121,10 @@ public:
This is always a const iterator. This is always a const iterator.
Meets the requirements of ForwardRange. Meets the requirements of ForwardRange.
*/ */
class iterator; class const_iterator;
iterator begin() const; const_iterator begin() const;
iterator end() const; const_iterator end() const;
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@@ -166,10 +168,12 @@ public:
std::shared_ptr<SHAMapItem const> const& peekFirstItem () const; std::shared_ptr<SHAMapItem const> const& peekFirstItem () const;
std::shared_ptr<SHAMapItem const> const& std::shared_ptr<SHAMapItem const> const&
peekFirstItem (SHAMapTreeNode::TNType & type) const; peekFirstItem (SHAMapTreeNode::TNType & type) const;
SHAMapItem const* peekFirstItem(NodeStack& stack) const;
std::shared_ptr<SHAMapItem const> const& peekLastItem () const; std::shared_ptr<SHAMapItem const> const& peekLastItem () const;
std::shared_ptr<SHAMapItem const> const& peekNextItem (uint256 const& ) const; std::shared_ptr<SHAMapItem const> const& peekNextItem (uint256 const& ) const;
std::shared_ptr<SHAMapItem const> const& std::shared_ptr<SHAMapItem const> const&
peekNextItem (uint256 const& , SHAMapTreeNode::TNType & type) const; peekNextItem (uint256 const& , SHAMapTreeNode::TNType & type) const;
SHAMapItem const* peekNextItem(uint256 const& id, NodeStack& stack) const;
std::shared_ptr<SHAMapItem const> const& peekPrevItem (uint256 const& ) const; std::shared_ptr<SHAMapItem const> const& peekPrevItem (uint256 const& ) const;
void visitNodes (std::function<bool (SHAMapAbstractNode&)> const&) const; void visitNodes (std::function<bool (SHAMapAbstractNode&)> const&) const;
@@ -272,6 +276,7 @@ private:
std::shared_ptr<SHAMapAbstractNode> node) const; std::shared_ptr<SHAMapAbstractNode> node) const;
SHAMapTreeNode* firstBelow (SHAMapAbstractNode*) const; SHAMapTreeNode* firstBelow (SHAMapAbstractNode*) const;
SHAMapTreeNode* firstBelow (SHAMapAbstractNode*, NodeStack& stack) const;
SHAMapTreeNode* lastBelow (SHAMapAbstractNode*) const; SHAMapTreeNode* lastBelow (SHAMapAbstractNode*) const;
// Simple descent // Simple descent
@@ -358,66 +363,109 @@ SHAMap::setUnbacked ()
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
class SHAMap::iterator class SHAMap::const_iterator
: public boost::iterator_facade<
SHAMap::iterator,
std::shared_ptr<SHAMapItem const> const,
std::forward_iterator_tag>
{ {
private: public:
friend class boost::iterator_core_access; using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = SHAMapItem;
using reference = value_type const&;
using pointer = value_type const*;
SHAMap const* map_ = nullptr; private:
std::shared_ptr< NodeStack stack_;
SHAMapItem const> item_; SHAMap const* map_ = nullptr;
pointer item_ = nullptr;
public: public:
iterator() = default; const_iterator() = default;
iterator (iterator const&) = default;
iterator& operator= (iterator const&) = default;
iterator (SHAMap const& map, reference operator*() const;
std::shared_ptr<SHAMapItem const> const& item) pointer operator->() const;
: map_(&map)
, item_(item) const_iterator& operator++();
{ const_iterator operator++(int);
}
private: private:
void explicit const_iterator(SHAMap const* map);
increment() const_iterator(SHAMap const* map, pointer item);
{
item_ = map_->peekNextItem(
item_->key());
}
bool friend bool operator==(const_iterator const& x, const_iterator const& y);
equal (iterator const& other) const friend class SHAMap;
{
assert(map_ == other.map_);
return item_ == other.item_;
}
std::shared_ptr<
SHAMapItem const> const&
dereference() const
{
return item_;
}
}; };
inline inline
SHAMap::iterator SHAMap::const_iterator::const_iterator(SHAMap const* map)
SHAMap::begin() const : map_(map)
, item_(map_->peekFirstItem(stack_))
{ {
return iterator(*this, peekFirstItem());
} }
inline inline
SHAMap::iterator SHAMap::const_iterator::const_iterator(SHAMap const* map, pointer item)
: map_(map)
, item_(item)
{
}
inline
SHAMap::const_iterator::reference
SHAMap::const_iterator::operator*() const
{
return *item_;
}
inline
SHAMap::const_iterator::pointer
SHAMap::const_iterator::operator->() const
{
return item_;
}
inline
SHAMap::const_iterator&
SHAMap::const_iterator::operator++()
{
item_ = map_->peekNextItem(item_->key(), stack_);
return *this;
}
inline
SHAMap::const_iterator
SHAMap::const_iterator::operator++(int)
{
auto tmp = *this;
++(*this);
return tmp;
}
inline
bool
operator==(SHAMap::const_iterator const& x, SHAMap::const_iterator const& y)
{
assert(x.map_ == y.map_);
return x.item_ == y.item_;
}
inline
bool
operator!=(SHAMap::const_iterator const& x, SHAMap::const_iterator const& y)
{
return !(x == y);
}
inline
SHAMap::const_iterator
SHAMap::begin() const
{
return const_iterator(this);
}
inline
SHAMap::const_iterator
SHAMap::end() const SHAMap::end() const
{ {
return iterator(*this, nullptr); return const_iterator(this, nullptr);
} }
} }

View File

@@ -445,6 +445,33 @@ SHAMap::firstBelow (SHAMapAbstractNode* node) const
while (true); while (true);
} }
SHAMapTreeNode*
SHAMap::firstBelow(SHAMapAbstractNode* node, NodeStack& stack) const
{
// Return the first item below this node
while (true)
{
assert(node != nullptr);
if (node->isLeaf())
return static_cast<SHAMapTreeNode*>(node);
bool foundNode = false;
auto inner = static_cast<SHAMapInnerNode*>(node);
for (int i = 0; i < 16; ++i)
{
if (!inner->isEmptyBranch(i))
{
node = descendThrow(inner, i);
assert(!stack.empty());
stack.push({node, stack.top().second.getChildNodeID(i)});
foundNode = true;
break;
}
}
if (!foundNode)
return nullptr;
}
}
SHAMapTreeNode* SHAMapTreeNode*
SHAMap::lastBelow (SHAMapAbstractNode* node) const SHAMap::lastBelow (SHAMapAbstractNode* node) const
{ {
@@ -534,6 +561,17 @@ SHAMap::peekFirstItem () const
return node->peekItem (); return node->peekItem ();
} }
SHAMapItem const*
SHAMap::peekFirstItem(NodeStack& stack) const
{
assert(stack.empty());
stack.push({root_.get(), SHAMapNodeID{}});
SHAMapTreeNode* node = firstBelow(root_.get(), stack);
if (!node)
return nullptr;
return node->peekItem().get();
}
std::shared_ptr<SHAMapItem const> const& std::shared_ptr<SHAMapItem const> const&
SHAMap::peekFirstItem (SHAMapTreeNode::TNType& type) const SHAMap::peekFirstItem (SHAMapTreeNode::TNType& type) const
{ {
@@ -597,7 +635,7 @@ SHAMap::peekNextItem (uint256 const& id, SHAMapTreeNode::TNType& type) const
auto leaf = firstBelow (node); auto leaf = firstBelow (node);
if (!leaf) if (!leaf)
throw (std::runtime_error ("missing/corrupt node")); throw SHAMapMissingNode(type_, id);
type = leaf->getType (); type = leaf->getType ();
return leaf->peekItem (); return leaf->peekItem ();
@@ -609,6 +647,38 @@ SHAMap::peekNextItem (uint256 const& id, SHAMapTreeNode::TNType& type) const
return no_item; return no_item;
} }
SHAMapItem const*
SHAMap::peekNextItem(uint256 const& id, NodeStack& stack) const
{
assert(!stack.empty());
assert(stack.top().first->isLeaf());
stack.pop();
while (!stack.empty())
{
auto node = stack.top().first;
auto nodeID = stack.top().second;
assert(!node->isLeaf());
auto inner = static_cast<SHAMapInnerNode*>(node);
for (auto i = nodeID.selectBranch(id) + 1; i < 16; ++i)
{
if (!inner->isEmptyBranch(i))
{
node = descendThrow(inner, i);
nodeID = nodeID.getChildNodeID(i);
stack.push({node, nodeID});
auto leaf = firstBelow(node, stack);
if (!leaf)
throw SHAMapMissingNode(type_, id);
assert(leaf->isLeaf());
return leaf->peekItem().get();
}
}
stack.pop();
}
// must be last item
return nullptr;
}
// Get a pointer to the previous item in the tree after a given item - item need not be in tree // Get a pointer to the previous item in the tree after a given item - item need not be in tree
std::shared_ptr<SHAMapItem const> const& std::shared_ptr<SHAMapItem const> const&
SHAMap::peekPrevItem (uint256 const& id) const SHAMap::peekPrevItem (uint256 const& id) const
@@ -697,7 +767,7 @@ bool SHAMap::delItem (uint256 const& id)
auto stack = getStack (id, true); auto stack = getStack (id, true);
if (stack.empty ()) if (stack.empty ())
throw (std::runtime_error ("missing node")); throw SHAMapMissingNode(type_, id);
auto leaf = std::dynamic_pointer_cast<SHAMapTreeNode>(stack.top ().first); auto leaf = std::dynamic_pointer_cast<SHAMapTreeNode>(stack.top ().first);
stack.pop (); stack.pop ();
@@ -785,7 +855,7 @@ SHAMap::addGiveItem (std::shared_ptr<SHAMapItem const> const& item,
auto stack = getStack (tag, true); auto stack = getStack (tag, true);
if (stack.empty ()) if (stack.empty ())
throw (std::runtime_error ("missing node")); throw SHAMapMissingNode(type_, tag);
auto node = stack.top ().first; auto node = stack.top ().first;
auto nodeID = stack.top ().second; auto nodeID = stack.top ().second;
@@ -875,7 +945,7 @@ SHAMap::updateGiveItem (std::shared_ptr<SHAMapItem const> const& item,
auto stack = getStack (tag, true); auto stack = getStack (tag, true);
if (stack.empty ()) if (stack.empty ())
throw (std::runtime_error ("missing node")); throw SHAMapMissingNode(type_, tag);
auto node = std::dynamic_pointer_cast<SHAMapTreeNode>(stack.top().first); auto node = std::dynamic_pointer_cast<SHAMapTreeNode>(stack.top().first);
auto nodeID = stack.top ().second; auto nodeID = stack.top ().second;