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;
204 bool pending =
false;
215 childID, childHash.as_uint256());
263 std::chrono::duration_cast<std::chrono::milliseconds>(
after - before);
270 auto parent = std::get<0>(deferredNode);
271 auto const& parentID = std::get<1>(deferredNode);
272 auto branch = std::get<2>(deferredNode);
273 auto const& nodeHash = parent->getChildHash(branch);
281 nodePtr = parent->canonicalizeChild(branch, std::move(nodePtr));
290 parentID.getChildNodeID(branch), nodeHash.as_uint256());
297 auto const process_time =
298 std::chrono::duration_cast<std::chrono::milliseconds>(
301 using namespace std::chrono_literals;
302 if ((count > 50) || (elapsed > 50ms))
305 <<
"getMissingNodes reads " << count <<
" nodes (" << hits
306 <<
" hits) in " << elapsed.count() <<
" + " << process_time.count()
318 assert(
root_->isValid());
319 assert(
root_->getNodeHash().isNonZero());
328 if (!
root_->isInner() ||
329 std::static_pointer_cast<SHAMapInnerNode>(
root_)->isFullBelow(
348 auto& node = std::get<0>(pos);
349 auto& nextChild = std::get<3>(pos);
350 auto& fullBelow = std::get<4>(pos);
362 if ((node ==
nullptr) && !mn.
stack_.empty())
365 bool was = fullBelow;
377 fullBelow = fullBelow && was;
411 assert(node !=
nullptr);
419 }
while (node !=
nullptr);
435 for (
auto const& n : ret)
452 auto node =
root_.get();
459 if (inner->isEmptyBranch(branch))
466 if (node ==
nullptr || wanted != nodeID)
468 JLOG(
journal_.
warn()) <<
"peer requested node that is not in the map:\n"
469 << wanted <<
" but found\n"
481 stack.
emplace(node, nodeID, depth);
483 while (!stack.
empty())
502 if ((depth > 0) || (bc == 1))
505 for (
int i = 0; i < 16; ++i)
507 if (!inner->isEmptyBranch(i))
512 if (childNode->isInner() && ((depth > 1) || (bc == 1)))
519 (bc > 1) ? (depth - 1) : depth);
521 else if (childNode->isInner() || fatLeaves)
541 root_->addRaw(s, format);
548 Slice const& rootNode,
553 if (
root_->getNodeHash().isNonZero())
556 assert(
root_->getNodeHash() == hash);
563 if (!node || !node->isValid() || node->getNodeHash() != hash)
580 root_->getNodeHash(),
592 Slice const& rawNode,
608 auto iNode =
root_.get();
610 while (iNode->isInner() &&
617 if (inner->isEmptyBranch(branch))
619 JLOG(
journal_.
warn()) <<
"Add known node for empty branch" << node;
623 auto childHash = inner->getChildHash(branch);
627 auto prevNode = inner;
630 if (iNode ==
nullptr)
632 if (!newNode || !newNode->isValid() ||
633 childHash != newNode->getNodeHash())
639 if (!newNode->isInBounds(iNodeID))
649 JLOG(
journal_.
warn()) <<
"unable to hook node " << node;
652 <<
", walked to= " << iNodeID.
getDepth();
659 newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
689 while (!stack.
empty())
691 auto const [node, otherNode] = stack.
top();
694 if (!node || !otherNode)
699 else if (otherNode->getNodeHash() != node->getNodeHash())
707 if (!otherNode->isLeaf())
710 auto& otherNodePeek =
712 if (nodePeek->key() != otherNodePeek->key())
714 if (nodePeek->peekData() != otherNodePeek->peekData())
717 else if (node->isInner())
719 if (!otherNode->isInner())
723 for (
int i = 0; i < 16; ++i)
725 if (node_inner->isEmptyBranch(i))
727 if (!other_inner->isEmptyBranch(i))
732 if (other_inner->isEmptyBranch(i))
735 auto next =
descend(node_inner, i);
736 auto otherNext = other.
descend(other_inner, i);
737 if (!next || !otherNext)
742 stack.
push({next, otherNext});
758 auto node =
root_.get();
765 if (inner->isEmptyBranch(branch))
772 return (node->isInner()) && (node->getNodeHash() == targetNodeHash);
780 auto node =
root_.get();
783 if (!node->isInner())
784 return node->getNodeHash() == targetNodeHash;
790 if (inner->isEmptyBranch(branch))
793 if (inner->getChildHash(branch) ==
799 }
while (node->isInner());
823 if (includeLeaves || smn.
isInner())
826 smn.addRaw(s, snfPREFIX);
827 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.
static std::shared_ptr< SHAMapAbstractNode > make(Slice const &rawNode, std::uint32_t seq, SHANodeFormat format, SHAMapHash const &hash, bool hashValid, beast::Journal j, SHAMapNodeID const &id=SHAMapNodeID{})
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
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
bool touch_if_exists(key_type const &key)
Refresh the last access time of an item, if it exists.
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
SHAMapAddNode addRootNode(SHAMapHash const &hash, Slice const &rootNode, SHANodeFormat format, SHAMapSyncFilter *filter)
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
std::shared_ptr< SHAMapAbstractNode > descendNoStore(std::shared_ptr< SHAMapInnerNode > const &, int branch) const
std::uint32_t getGeneration(void) const
generation determines whether cached entry is valid
std::shared_ptr< SHAMapAbstractNode > root_
void gmn_ProcessDeferredReads(MissingNodes &)
void insert(key_type const &key)
Insert a key into the cache.
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
virtual FullBelowCache & fullbelow()=0
SHAMapAddNode addKnownNode(SHAMapNodeID const &nodeID, Slice const &rawNode, SHAMapSyncFilter *filter)
virtual beast::Journal const & journal()=0
uint256 const & as_uint256() const
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