20 #include <ripple/basics/random.h>
21 #include <ripple/nodestore/Database.h>
22 #include <ripple/shamap/SHAMap.h>
43 assert(
root_->isValid());
50 if (!
root_->isInner())
56 auto node = std::static_pointer_cast<SHAMapInnerNode>(
root_);
64 if (!node->isEmptyBranch(pos))
68 if (!
function(*child))
76 while ((pos != 15) && (node->isEmptyBranch(pos + 1)))
86 node = std::static_pointer_cast<SHAMapInnerNode>(child);
111 assert(
root_->isValid());
116 if (
root_->getNodeHash().isZero())
119 if (have && (
root_->getNodeHash() == have->
root_->getNodeHash()))
124 auto leaf = std::static_pointer_cast<SHAMapTreeNode>(
root_);
126 !have->
hasLeafNode(leaf->peekItem()->key(), leaf->getNodeHash()))
136 while (!stack.
empty())
138 auto const [node, nodeID] = stack.
top();
142 if (!
function(*node))
146 for (
int i = 0; i < 16; ++i)
148 if (!node->isEmptyBranch(i))
150 auto const& childHash = node->getChildHash(i);
166 if (!
function(*next))
183 int& firstChild = std::get<2>(se);
184 int& currentChild = std::get<3>(se);
185 bool& fullBelow = std::get<4>(se);
187 while (currentChild < 16)
189 int branch = (firstChild + currentChild++) % 16;
203 ->touch_if_exists(childHash.as_uint256()))
206 bool pending =
false;
217 childID, childHash.as_uint256());
268 std::chrono::duration_cast<std::chrono::milliseconds>(
after - before);
275 auto parent = std::get<0>(deferredNode);
276 auto const& parentID = std::get<1>(deferredNode);
277 auto branch = std::get<2>(deferredNode);
278 auto const& nodeHash = parent->getChildHash(branch);
286 nodePtr = parent->canonicalizeChild(branch, std::move(nodePtr));
295 parentID.getChildNodeID(branch), nodeHash.as_uint256());
302 auto const process_time =
303 std::chrono::duration_cast<std::chrono::milliseconds>(
306 using namespace std::chrono_literals;
307 if ((count > 50) || (elapsed > 50ms))
310 <<
"getMissingNodes reads " << count <<
" nodes (" << hits
311 <<
" hits) in " << elapsed.count() <<
" + " << process_time.count()
323 assert(
root_->isValid());
324 assert(
root_->getNodeHash().isNonZero());
333 if (!
root_->isInner() ||
334 std::static_pointer_cast<SHAMapInnerNode>(
root_)->isFullBelow(
353 auto& node = std::get<0>(pos);
354 auto& nextChild = std::get<3>(pos);
355 auto& fullBelow = std::get<4>(pos);
367 if ((node ==
nullptr) && !mn.
stack_.empty())
370 bool was = fullBelow;
382 fullBelow = fullBelow && was;
416 assert(node !=
nullptr);
424 }
while (node !=
nullptr);
440 for (
auto const& n : ret)
457 auto node =
root_.get();
464 if (inner->isEmptyBranch(branch))
471 if (node ==
nullptr || wanted != nodeID)
473 JLOG(
journal_.
warn()) <<
"peer requested node that is not in the map:\n"
474 << wanted <<
" but found\n"
486 stack.
emplace(node, nodeID, depth);
488 while (!stack.
empty())
507 if ((depth > 0) || (bc == 1))
510 for (
int i = 0; i < 16; ++i)
512 if (!inner->isEmptyBranch(i))
517 if (childNode->isInner() && ((depth > 1) || (bc == 1)))
524 (bc > 1) ? (depth - 1) : depth);
526 else if (childNode->isInner() || fatLeaves)
546 root_->addRaw(s, format);
553 Slice const& rootNode,
557 if (
root_->getNodeHash().isNonZero())
560 assert(
root_->getNodeHash() == hash);
566 if (!node || !node->isValid() || node->getNodeHash() != hash)
583 root_->getNodeHash(),
595 Slice const& rawNode,
610 auto iNode =
root_.get();
612 while (iNode->isInner() &&
619 if (inner->isEmptyBranch(branch))
621 JLOG(
journal_.
warn()) <<
"Add known node for empty branch" << node;
625 auto childHash = inner->getChildHash(branch);
627 ->touch_if_exists(childHash.as_uint256()))
632 auto prevNode = inner;
635 if (iNode ==
nullptr)
637 if (!newNode || !newNode->isValid() ||
638 childHash != newNode->getNodeHash())
644 if (!newNode->isInBounds(iNodeID))
654 JLOG(
journal_.
warn()) <<
"unable to hook node " << node;
657 <<
", walked to= " << iNodeID.
getDepth();
664 newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
694 while (!stack.
empty())
696 auto const [node, otherNode] = stack.
top();
699 if (!node || !otherNode)
704 else if (otherNode->getNodeHash() != node->getNodeHash())
712 if (!otherNode->isLeaf())
715 auto& otherNodePeek =
717 if (nodePeek->key() != otherNodePeek->key())
719 if (nodePeek->peekData() != otherNodePeek->peekData())
722 else if (node->isInner())
724 if (!otherNode->isInner())
728 for (
int i = 0; i < 16; ++i)
730 if (node_inner->isEmptyBranch(i))
732 if (!other_inner->isEmptyBranch(i))
737 if (other_inner->isEmptyBranch(i))
740 auto next =
descend(node_inner, i);
741 auto otherNext = other.
descend(other_inner, i);
742 if (!next || !otherNext)
747 stack.
push({next, otherNext});
763 auto node =
root_.get();
770 if (inner->isEmptyBranch(branch))
777 return (node->isInner()) && (node->getNodeHash() == targetNodeHash);
785 auto node =
root_.get();
788 if (!node->isInner())
789 return node->getNodeHash() == targetNodeHash;
795 if (inner->isEmptyBranch(branch))
798 if (inner->getChildHash(branch) ==
804 }
while (node->isInner());
828 if (includeLeaves || smn.
isInner())
831 smn.addRaw(s, snfPREFIX);
832 func(smn.getNodeHash(), s.peekData());
int selectBranch(uint256 const &hash) const
Stream trace() const
Severity stream access functions.
uint256 const & getNodeID() const
bool deepCompare(SHAMap &other) const
std::stack< StackEntry, std::deque< StackEntry > > stack_
bool hasInnerNode(SHAMapNodeID const &nodeID, SHAMapHash const &hash) const
Does this map have this inner node?
void canonicalize(SHAMapHash const &hash, std::shared_ptr< SHAMapAbstractNode > &) const
An immutable linear range of bytes.
SHAMapNodeID getChildNodeID(int m) const
SHAMapAbstractNode * descendThrow(SHAMapInnerNode *, int branch) const
bool getNodeFat(SHAMapNodeID node, std::vector< SHAMapNodeID > &nodeIDs, std::vector< Blob > &rawNode, bool fatLeaves, std::uint32_t depth) const
void getFetchPack(SHAMap const *have, bool includeLeaves, int max, std::function< void(SHAMapHash const &, const Blob &)>) const
void visitNodes(std::function< bool(SHAMapAbstractNode &)> const &function) const
Visit every node in this SHAMap.
std::uint32_t generation_
std::shared_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
virtual std::shared_ptr< FullBelowCache > getFullBelowCache(std::uint32_t ledgerSeq)=0
Return a pointer to the Family Full Below Cache.
SHAMapSyncFilter * filter_
void gmn_ProcessNodes(MissingNodes &, MissingNodes::StackEntry &node)
virtual NodeStore::Database & db()=0
std::shared_ptr< SHAMapAbstractNode > fetchNodeNT(SHAMapHash const &hash) const
std::vector< uint256 > getNeededHashes(int max, SHAMapSyncFilter *filter)
static SHAMapAddNode duplicate()
bool getRootNode(Serializer &s, SHANodeFormat format) const
static SHAMapAddNode useful()
bool isEmptyBranch(int m) const
virtual void gotNode(bool fromFilter, SHAMapHash const &nodeHash, std::uint32_t ledgerSeq, Blob &&nodeData, SHAMapTreeNode::TNType type) const =0
SHAMapAbstractNode * descendAsync(SHAMapInnerNode *parent, int branch, SHAMapSyncFilter *filter, bool &pending) const
std::map< SHAMapInnerNode *, SHAMapNodeID > resumes_
std::vector< std::tuple< SHAMapInnerNode *, SHAMapNodeID, int > > deferredReads_
std::enable_if_t< std::is_integral< Integral >::value &&detail::is_engine< Engine >::value, Integral > rand_int(Engine &engine, Integral min, Integral max)
Return a uniformly distributed random integer.
@ innerNode
inner node in V1 tree
SHAMapHash const & getChildHash(int m) const
bool hasLeafNode(uint256 const &tag, SHAMapHash const &hash) const
Does this map have this leaf node?
void visitDifferences(SHAMap const *have, std::function< bool(SHAMapAbstractNode &)>) const
Visit every node in this SHAMap that is not present in the specified SHAMap.
void visitLeaves(std::function< void(std::shared_ptr< SHAMapItem const > const &)> const &) const
Visit every leaf node in this SHAMap.
bool isFullBelow(std::uint32_t generation) const
SHAMapHash const & getNodeHash() const
static SHAMapAddNode invalid()
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
int addRaw(Blob const &vector)
void waitReads()
Wait for all currently pending async reads to complete.
std::set< SHAMapHash > missingHashes_
int getBranchCount() const
std::vector< std::pair< SHAMapNodeID, uint256 > > getMissingNodes(int maxNodes, SHAMapSyncFilter *filter)
Check for nodes in the SHAMap not available.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
SHAMapAbstractNode * descend(SHAMapInnerNode *, int branch) const
static std::shared_ptr< SHAMapAbstractNode > makeFromWire(Slice rawNode)
std::shared_ptr< SHAMapAbstractNode > descendNoStore(std::shared_ptr< SHAMapInnerNode > const &, int branch) const
std::shared_ptr< SHAMapAbstractNode > root_
void gmn_ProcessDeferredReads(MissingNodes &)
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
SHAMapAddNode addKnownNode(SHAMapNodeID const &nodeID, Slice const &rawNode, SHAMapSyncFilter *filter)
uint256 const & as_uint256() const
SHAMapAddNode addRootNode(SHAMapHash const &hash, Slice const &rootNode, SHAMapSyncFilter *filter)
void setFullBelowGen(std::uint32_t gen)
std::vector< std::pair< SHAMapNodeID, uint256 > > missingNodes_
virtual int getDesiredAsyncReadCount(std::uint32_t seq)=0
Get the maximum number of async reads the node store prefers.
std::shared_ptr< SHAMapItem const > const & peekItem() const