20 #include <ripple/basics/random.h>
21 #include <ripple/shamap/SHAMap.h>
22 #include <ripple/shamap/SHAMapSyncFilter.h>
46 if (!
root_->isInner())
52 auto node = std::static_pointer_cast<SHAMapInnerNode>(
root_);
60 if (!node->isEmptyBranch(pos))
64 if (!
function(*child))
72 while ((pos != 15) && (node->isEmptyBranch(pos + 1)))
82 node = std::static_pointer_cast<SHAMapInnerNode>(child);
110 if (
root_->getHash().isZero())
113 if (have && (
root_->getHash() == have->
root_->getHash()))
118 auto leaf = std::static_pointer_cast<SHAMapLeafNode>(
root_);
120 !have->
hasLeafNode(leaf->peekItem()->key(), leaf->getHash()))
130 while (!stack.
empty())
132 auto const [node, nodeID] = stack.
top();
136 if (!
function(*node))
140 for (
int i = 0; i < 16; ++i)
142 if (!node->isEmptyBranch(i))
144 auto const& childHash = node->getChildHash(i);
160 if (!
function(*next))
177 int& firstChild = std::get<2>(se);
178 int& currentChild = std::get<3>(se);
179 bool& fullBelow = std::get<4>(se);
181 while (currentChild < 16)
183 int branch = (firstChild + currentChild++) % 16;
197 ->touch_if_exists(childHash.as_uint256()))
200 bool pending =
false;
211 childID, childHash.as_uint256());
262 std::chrono::duration_cast<std::chrono::milliseconds>(
after - before);
269 auto parent = std::get<0>(deferredNode);
270 auto const& parentID = std::get<1>(deferredNode);
271 auto branch = std::get<2>(deferredNode);
272 auto const& nodeHash = parent->getChildHash(branch);
280 nodePtr = parent->canonicalizeChild(branch, std::move(nodePtr));
289 parentID.getChildNodeID(branch), nodeHash.as_uint256());
296 auto const process_time =
297 std::chrono::duration_cast<std::chrono::milliseconds>(
300 using namespace std::chrono_literals;
301 if ((count > 50) || (elapsed > 50ms))
304 <<
"getMissingNodes reads " << count <<
" nodes (" << hits
305 <<
" hits) in " << elapsed.count() <<
" + " << process_time.count()
317 assert(
root_->getHash().isNonZero());
326 if (!
root_->isInner() ||
327 std::static_pointer_cast<SHAMapInnerNode>(
root_)->isFullBelow(
346 auto& node = std::get<0>(pos);
347 auto& nextChild = std::get<3>(pos);
348 auto& fullBelow = std::get<4>(pos);
360 if ((node ==
nullptr) && !mn.
stack_.empty())
363 bool was = fullBelow;
375 fullBelow = fullBelow && was;
409 assert(node !=
nullptr);
417 }
while (node !=
nullptr);
436 auto node =
root_.get();
443 if (inner->isEmptyBranch(branch))
450 if (node ==
nullptr || wanted != nodeID)
452 JLOG(
journal_.
warn()) <<
"peer requested node that is not in the map:\n"
453 << wanted <<
" but found\n"
465 stack.
emplace(node, nodeID, depth);
467 while (!stack.
empty())
475 node->serializeForWire(s);
486 if ((depth > 0) || (bc == 1))
489 for (
int i = 0; i < 16; ++i)
491 if (!inner->isEmptyBranch(i))
496 if (childNode->isInner() && ((depth > 1) || (bc == 1)))
503 (bc > 1) ? (depth - 1) : depth);
505 else if (childNode->isInner() || fatLeaves)
509 childNode->serializeForWire(ns);
525 root_->serializeForWire(s);
531 Slice const& rootNode,
535 if (
root_->getHash().isNonZero())
538 assert(
root_->getHash() == hash);
544 if (!node || node->getHash() != hash)
558 root_->serializeWithPrefix(s);
573 Slice const& rawNode,
587 auto iNode =
root_.get();
589 while (iNode->isInner() &&
596 if (inner->isEmptyBranch(branch))
598 JLOG(
journal_.
warn()) <<
"Add known node for empty branch" << node;
602 auto childHash = inner->getChildHash(branch);
604 ->touch_if_exists(childHash.as_uint256()))
609 auto prevNode = inner;
612 if (iNode ==
nullptr)
614 if (!newNode || childHash != newNode->getHash())
634 JLOG(
journal_.
warn()) <<
"unable to hook node " << node;
637 <<
", walked to= " << iNodeID.
getDepth();
644 newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
649 newNode->serializeWithPrefix(s);
674 while (!stack.
empty())
676 auto const [node, otherNode] = stack.
top();
679 if (!node || !otherNode)
684 else if (otherNode->getHash() != node->getHash())
692 if (!otherNode->isLeaf())
695 auto& otherNodePeek =
697 if (nodePeek->key() != otherNodePeek->key())
699 if (nodePeek->peekData() != otherNodePeek->peekData())
702 else if (node->isInner())
704 if (!otherNode->isInner())
708 for (
int i = 0; i < 16; ++i)
710 if (node_inner->isEmptyBranch(i))
712 if (!other_inner->isEmptyBranch(i))
717 if (other_inner->isEmptyBranch(i))
720 auto next =
descend(node_inner, i);
721 auto otherNext = other.
descend(other_inner, i);
722 if (!next || !otherNext)
727 stack.
push({next, otherNext});
743 auto node =
root_.get();
750 if (inner->isEmptyBranch(branch))
757 return (node->isInner()) && (node->getHash() == targetNodeHash);
765 auto node =
root_.get();
768 if (!node->isInner())
769 return node->getHash() == targetNodeHash;
775 if (inner->isEmptyBranch(branch))
778 if (inner->getChildHash(branch) ==
784 }
while (node->isInner());
void visitDifferences(SHAMap const *have, std::function< bool(SHAMapTreeNode const &)>) const
Visit every node in this SHAMap that is not present in the specified SHAMap.
std::shared_ptr< SHAMapTreeNode > descendNoStore(std::shared_ptr< SHAMapInnerNode > const &, int branch) const
SHAMapNodeID getChildNodeID(unsigned int m) const
Stream trace() const
Severity stream access functions.
unsigned int selectBranch(SHAMapNodeID const &id, uint256 const &hash)
Returns the branch that would contain the given hash.
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?
An immutable linear range of bytes.
std::uint32_t generation_
std::shared_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
void serializeRoot(Serializer &s) const
Serializes the root in a format appropriate for sending over the wire.
std::shared_ptr< SHAMapTreeNode > fetchNodeNT(SHAMapHash const &hash) const
virtual std::shared_ptr< FullBelowCache > getFullBelowCache(std::uint32_t ledgerSeq)=0
Return a pointer to the Family Full Below Cache.
static std::shared_ptr< SHAMapTreeNode > makeFromWire(Slice rawNode)
Identifies a node inside a SHAMap.
SHAMapSyncFilter * filter_
virtual bool isInner() const =0
Determines if this is an inner node.
void gmn_ProcessNodes(MissingNodes &, MissingNodes::StackEntry &node)
virtual NodeStore::Database & db()=0
static SHAMapAddNode duplicate()
static SHAMapAddNode useful()
SHAMapTreeNode * descendAsync(SHAMapInnerNode *parent, int branch, SHAMapSyncFilter *filter, bool &pending) const
bool isEmptyBranch(int m) 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 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
static SHAMapAddNode invalid()
virtual void gotNode(bool fromFilter, SHAMapHash const &nodeHash, std::uint32_t ledgerSeq, Blob &&nodeData, SHAMapNodeType type) const =0
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
SHAMapTreeNode * descendThrow(SHAMapInnerNode *, int branch) const
void waitReads()
Wait for all currently pending async reads to complete.
void canonicalize(SHAMapHash const &hash, std::shared_ptr< SHAMapTreeNode > &) const
std::set< SHAMapHash > missingHashes_
unsigned int getDepth() const
int getBranchCount() const
std::vector< std::pair< SHAMapNodeID, uint256 > > getMissingNodes(int maxNodes, SHAMapSyncFilter *filter)
Check for nodes in the SHAMap not available.
SHAMapHash const & getHash() const
Return the hash of this node.
virtual int getDesiredAsyncReadCount(std::uint32_t ledgerSeq)=0
Get the maximum number of async reads the node store prefers.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
static constexpr unsigned int leafDepth
The depth of the hash map: data is only present in the leaves.
void visitNodes(std::function< bool(SHAMapTreeNode &)> const &function) const
Visit every node in this SHAMap.
void gmn_ProcessDeferredReads(MissingNodes &)
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
@ Invalid
The map is known to not be valid.
uint256 const & getNodeID() const
SHAMapAddNode addKnownNode(SHAMapNodeID const &nodeID, Slice const &rawNode, SHAMapSyncFilter *filter)
std::shared_ptr< SHAMapItem const > const & peekItem() const
uint256 const & as_uint256() const
SHAMapTreeNode * descend(SHAMapInnerNode *, int branch) const
SHAMapAddNode addRootNode(SHAMapHash const &hash, Slice const &rootNode, SHAMapSyncFilter *filter)
void setFullBelowGen(std::uint32_t gen)
std::uint32_t ledgerSeq_
The sequence of the ledger that this map references, if any.
bool getNodeFat(SHAMapNodeID const &wanted, std::vector< SHAMapNodeID > &nodeIDs, std::vector< Blob > &rawNodes, bool fatLeaves, std::uint32_t depth) const
std::vector< std::pair< SHAMapNodeID, uint256 > > missingNodes_
std::uint32_t cowid_
ID to distinguish this map for all others we're sharing nodes with.
std::shared_ptr< SHAMapTreeNode > root_