rippled
SHAMapSync.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/random.h>
21 #include <ripple/nodestore/Database.h>
22 #include <ripple/shamap/SHAMap.h>
23 
24 namespace ripple {
25 
26 void
28  std::function<void(std::shared_ptr<SHAMapItem const> const& item)> const&
29  leafFunction) const
30 {
31  visitNodes([&leafFunction](SHAMapAbstractNode& node) {
32  if (!node.isInner())
33  leafFunction(static_cast<SHAMapTreeNode&>(node).peekItem());
34  return true;
35  });
36 }
37 
38 void
40  std::function<bool(SHAMapAbstractNode&)> const& function) const
41 {
42  // Visit every node in a SHAMap
43  assert(root_->isValid());
44 
45  if (!root_)
46  return;
47 
48  function(*root_);
49 
50  if (!root_->isInner())
51  return;
52 
55 
56  auto node = std::static_pointer_cast<SHAMapInnerNode>(root_);
57  int pos = 0;
58 
59  while (1)
60  {
61  while (pos < 16)
62  {
63  uint256 childHash;
64  if (!node->isEmptyBranch(pos))
65  {
67  descendNoStore(node, pos);
68  if (!function(*child))
69  return;
70 
71  if (child->isLeaf())
72  ++pos;
73  else
74  {
75  // If there are no more children, don't push this node
76  while ((pos != 15) && (node->isEmptyBranch(pos + 1)))
77  ++pos;
78 
79  if (pos != 15)
80  {
81  // save next position to resume at
82  stack.push(std::make_pair(pos + 1, std::move(node)));
83  }
84 
85  // descend to the child's first position
86  node = std::static_pointer_cast<SHAMapInnerNode>(child);
87  pos = 0;
88  }
89  }
90  else
91  {
92  ++pos; // move to next position
93  }
94  }
95 
96  if (stack.empty())
97  break;
98 
99  std::tie(pos, node) = stack.top();
100  stack.pop();
101  }
102 }
103 
104 void
106  SHAMap const* have,
107  std::function<bool(SHAMapAbstractNode&)> function) const
108 {
109  // Visit every node in this SHAMap that is not present
110  // in the specified SHAMap
111  assert(root_->isValid());
112 
113  if (!root_)
114  return;
115 
116  if (root_->getNodeHash().isZero())
117  return;
118 
119  if (have && (root_->getNodeHash() == have->root_->getNodeHash()))
120  return;
121 
122  if (root_->isLeaf())
123  {
124  auto leaf = std::static_pointer_cast<SHAMapTreeNode>(root_);
125  if (!have ||
126  !have->hasLeafNode(leaf->peekItem()->key(), leaf->getNodeHash()))
127  function(*root_);
128  return;
129  }
130  // contains unexplored non-matching inner node entries
133 
134  stack.push({static_cast<SHAMapInnerNode*>(root_.get()), SHAMapNodeID{}});
135 
136  while (!stack.empty())
137  {
138  auto const [node, nodeID] = stack.top();
139  stack.pop();
140 
141  // 1) Add this node to the pack
142  if (!function(*node))
143  return;
144 
145  // 2) push non-matching child inner nodes
146  for (int i = 0; i < 16; ++i)
147  {
148  if (!node->isEmptyBranch(i))
149  {
150  auto const& childHash = node->getChildHash(i);
151  SHAMapNodeID childID = nodeID.getChildNodeID(i);
152  auto next = descendThrow(node, i);
153 
154  if (next->isInner())
155  {
156  if (!have || !have->hasInnerNode(childID, childHash))
157  stack.push(
158  {static_cast<SHAMapInnerNode*>(next), childID});
159  }
160  else if (
161  !have ||
162  !have->hasLeafNode(
163  static_cast<SHAMapTreeNode*>(next)->peekItem()->key(),
164  childHash))
165  {
166  if (!function(*next))
167  return;
168  }
169  }
170  }
171  }
172 }
173 
174 // Starting at the position referred to by the specfied
175 // StackEntry, process that node and its first resident
176 // children, descending the SHAMap until we complete the
177 // processing of a node.
178 void
180 {
181  SHAMapInnerNode*& node = std::get<0>(se);
182  SHAMapNodeID& nodeID = std::get<1>(se);
183  int& firstChild = std::get<2>(se);
184  int& currentChild = std::get<3>(se);
185  bool& fullBelow = std::get<4>(se);
186 
187  while (currentChild < 16)
188  {
189  int branch = (firstChild + currentChild++) % 16;
190  if (node->isEmptyBranch(branch))
191  continue;
192 
193  auto const& childHash = node->getChildHash(branch);
194 
195  if (mn.missingHashes_.count(childHash) != 0)
196  {
197  // we already know this child node is missing
198  fullBelow = false;
199  }
200  else if (
201  !backed_ || !f_.fullbelow().touch_if_exists(childHash.as_uint256()))
202  {
203  SHAMapNodeID childID = nodeID.getChildNodeID(branch);
204  bool pending = false;
205  auto d = descendAsync(node, branch, mn.filter_, pending);
206 
207  if (!d)
208  {
209  fullBelow = false; // for now, not known full below
210 
211  if (!pending)
212  { // node is not in the database
213  mn.missingHashes_.insert(childHash);
214  mn.missingNodes_.emplace_back(
215  childID, childHash.as_uint256());
216 
217  if (--mn.max_ <= 0)
218  return;
219  }
220  else
221  mn.deferredReads_.emplace_back(node, nodeID, branch);
222  }
223  else if (
224  d->isInner() &&
225  !static_cast<SHAMapInnerNode*>(d)->isFullBelow(mn.generation_))
226  {
227  mn.stack_.push(se);
228 
229  // Switch to processing the child node
230  node = static_cast<SHAMapInnerNode*>(d);
231  nodeID = childID;
232  firstChild = rand_int(255);
233  currentChild = 0;
234  fullBelow = true;
235  }
236  }
237  }
238 
239  // We have finished processing an inner node
240  // and thus (for now) all its children
241 
242  if (fullBelow)
243  { // No partial node encountered below this node
244  node->setFullBelowGen(mn.generation_);
245  if (backed_)
247  }
248 
249  node = nullptr;
250 }
251 
252 // Wait for deferred reads to finish and
253 // process their results
254 void
256 {
257  // Wait for our deferred reads to finish
258  auto const before = std::chrono::steady_clock::now();
259  f_.db().waitReads();
260  auto const after = std::chrono::steady_clock::now();
261 
262  auto const elapsed =
263  std::chrono::duration_cast<std::chrono::milliseconds>(after - before);
264  auto const count = mn.deferredReads_.size();
265 
266  // Process all deferred reads
267  int hits = 0;
268  for (auto const& deferredNode : mn.deferredReads_)
269  {
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);
274 
275  auto nodePtr = fetchNodeNT(nodeHash, mn.filter_);
276  if (nodePtr)
277  { // Got the node
278  ++hits;
279  if (backed_)
280  canonicalize(nodeHash, nodePtr);
281  nodePtr = parent->canonicalizeChild(branch, std::move(nodePtr));
282 
283  // When we finish this stack, we need to restart
284  // with the parent of this node
285  mn.resumes_[parent] = parentID;
286  }
287  else if ((mn.max_ > 0) && (mn.missingHashes_.insert(nodeHash).second))
288  {
289  mn.missingNodes_.emplace_back(
290  parentID.getChildNodeID(branch), nodeHash.as_uint256());
291 
292  --mn.max_;
293  }
294  }
295  mn.deferredReads_.clear();
296 
297  auto const process_time =
298  std::chrono::duration_cast<std::chrono::milliseconds>(
300 
301  using namespace std::chrono_literals;
302  if ((count > 50) || (elapsed > 50ms))
303  {
304  JLOG(journal_.debug())
305  << "getMissingNodes reads " << count << " nodes (" << hits
306  << " hits) in " << elapsed.count() << " + " << process_time.count()
307  << " ms";
308  }
309 }
310 
317 {
318  assert(root_->isValid());
319  assert(root_->getNodeHash().isNonZero());
320  assert(max > 0);
321 
322  MissingNodes mn(
323  max,
324  filter,
327 
328  if (!root_->isInner() ||
329  std::static_pointer_cast<SHAMapInnerNode>(root_)->isFullBelow(
330  mn.generation_))
331  {
332  clearSynching();
333  return std::move(mn.missingNodes_);
334  }
335 
336  // Start at the root.
337  // The firstChild value is selected randomly so if multiple threads
338  // are traversing the map, each thread will start at a different
339  // (randomly selected) inner node. This increases the likelihood
340  // that the two threads will produce different request sets (which is
341  // more efficient than sending identical requests).
343  static_cast<SHAMapInnerNode*>(root_.get()),
344  SHAMapNodeID(),
345  rand_int(255),
346  0,
347  true};
348  auto& node = std::get<0>(pos);
349  auto& nextChild = std::get<3>(pos);
350  auto& fullBelow = std::get<4>(pos);
351 
352  // Traverse the map without blocking
353  do
354  {
355  while ((node != nullptr) && (mn.deferredReads_.size() <= mn.maxDefer_))
356  {
357  gmn_ProcessNodes(mn, pos);
358 
359  if (mn.max_ <= 0)
360  return std::move(mn.missingNodes_);
361 
362  if ((node == nullptr) && !mn.stack_.empty())
363  {
364  // Pick up where we left off with this node's parent
365  bool was = fullBelow; // was full below
366 
367  pos = mn.stack_.top();
368  mn.stack_.pop();
369  if (nextChild == 0)
370  {
371  // This is a node we are processing for the first time
372  fullBelow = true;
373  }
374  else
375  {
376  // This is a node we are continuing to process
377  fullBelow = fullBelow && was; // was and still is
378  }
379  assert(node);
380  }
381  }
382 
383  // We have either emptied the stack or
384  // posted as many deferred reads as we can
385 
386  if (!mn.deferredReads_.empty())
388 
389  if (mn.max_ <= 0)
390  return std::move(mn.missingNodes_);
391 
392  if (node == nullptr)
393  { // We weren't in the middle of processing a node
394 
395  if (mn.stack_.empty() && !mn.resumes_.empty())
396  {
397  // Recheck nodes we could not finish before
398  for (auto const& [innerNode, nodeId] : mn.resumes_)
399  if (!innerNode->isFullBelow(mn.generation_))
400  mn.stack_.push(std::make_tuple(
401  innerNode, nodeId, rand_int(255), 0, true));
402 
403  mn.resumes_.clear();
404  }
405 
406  if (!mn.stack_.empty())
407  {
408  // Resume at the top of the stack
409  pos = mn.stack_.top();
410  mn.stack_.pop();
411  assert(node != nullptr);
412  }
413  }
414 
415  // node will only still be nullptr if
416  // we finished the current node, the stack is empty
417  // and we have no nodes to resume
418 
419  } while (node != nullptr);
420 
421  if (mn.missingNodes_.empty())
422  clearSynching();
423 
424  return std::move(mn.missingNodes_);
425 }
426 
429 {
430  auto ret = getMissingNodes(max, filter);
431 
432  std::vector<uint256> hashes;
433  hashes.reserve(ret.size());
434 
435  for (auto const& n : ret)
436  hashes.push_back(n.second);
437 
438  return hashes;
439 }
440 
441 bool
443  SHAMapNodeID wanted,
444  std::vector<SHAMapNodeID>& nodeIDs,
445  std::vector<Blob>& rawNodes,
446  bool fatLeaves,
447  std::uint32_t depth) const
448 {
449  // Gets a node and some of its children
450  // to a specified depth
451 
452  auto node = root_.get();
453  SHAMapNodeID nodeID;
454 
455  while (node && node->isInner() && (nodeID.getDepth() < wanted.getDepth()))
456  {
457  int branch = nodeID.selectBranch(wanted.getNodeID());
458  auto inner = static_cast<SHAMapInnerNode*>(node);
459  if (inner->isEmptyBranch(branch))
460  return false;
461 
462  node = descendThrow(inner, branch);
463  nodeID = nodeID.getChildNodeID(branch);
464  }
465 
466  if (node == nullptr || wanted != nodeID)
467  {
468  JLOG(journal_.warn()) << "peer requested node that is not in the map:\n"
469  << wanted << " but found\n"
470  << nodeID;
471  return false;
472  }
473 
474  if (node->isInner() && static_cast<SHAMapInnerNode*>(node)->isEmpty())
475  {
476  JLOG(journal_.warn()) << "peer requests empty node";
477  return false;
478  }
479 
481  stack.emplace(node, nodeID, depth);
482 
483  while (!stack.empty())
484  {
485  std::tie(node, nodeID, depth) = stack.top();
486  stack.pop();
487 
488  {
489  // Add this node to the reply
490  Serializer s;
491  node->addRaw(s, snfWIRE);
492  nodeIDs.push_back(nodeID);
493  rawNodes.push_back(std::move(s.modData()));
494  }
495 
496  if (node->isInner())
497  {
498  // We descend inner nodes with only a single child
499  // without decrementing the depth
500  auto inner = static_cast<SHAMapInnerNode*>(node);
501  int bc = inner->getBranchCount();
502  if ((depth > 0) || (bc == 1))
503  {
504  // We need to process this node's children
505  for (int i = 0; i < 16; ++i)
506  {
507  if (!inner->isEmptyBranch(i))
508  {
509  auto const childNode = descendThrow(inner, i);
510  SHAMapNodeID const childID = nodeID.getChildNodeID(i);
511 
512  if (childNode->isInner() && ((depth > 1) || (bc == 1)))
513  {
514  // If there's more than one child, reduce the depth
515  // If only one child, follow the chain
516  stack.emplace(
517  childNode,
518  childID,
519  (bc > 1) ? (depth - 1) : depth);
520  }
521  else if (childNode->isInner() || fatLeaves)
522  {
523  // Just include this node
524  Serializer ns;
525  childNode->addRaw(ns, snfWIRE);
526  nodeIDs.push_back(childID);
527  rawNodes.push_back(std::move(ns.modData()));
528  }
529  }
530  }
531  }
532  }
533  }
534 
535  return true;
536 }
537 
538 bool
540 {
541  root_->addRaw(s, format);
542  return true;
543 }
544 
547  SHAMapHash const& hash,
548  Slice const& rootNode,
549  SHANodeFormat format,
550  SHAMapSyncFilter* filter)
551 {
552  // we already have a root_ node
553  if (root_->getNodeHash().isNonZero())
554  {
555  JLOG(journal_.trace()) << "got root node, already have one";
556  assert(root_->getNodeHash() == hash);
557  return SHAMapAddNode::duplicate();
558  }
559 
560  assert(seq_ >= 1);
561  auto node = SHAMapAbstractNode::make(
562  rootNode, 0, format, SHAMapHash{}, false, f_.journal());
563  if (!node || !node->isValid() || node->getNodeHash() != hash)
564  return SHAMapAddNode::invalid();
565 
566  if (backed_)
567  canonicalize(hash, node);
568 
569  root_ = node;
570 
571  if (root_->isLeaf())
572  clearSynching();
573 
574  if (filter)
575  {
576  Serializer s;
577  root_->addRaw(s, snfPREFIX);
578  filter->gotNode(
579  false,
580  root_->getNodeHash(),
581  ledgerSeq_,
582  std::move(s.modData()),
583  root_->getType());
584  }
585 
586  return SHAMapAddNode::useful();
587 }
588 
591  const SHAMapNodeID& node,
592  Slice const& rawNode,
593  SHAMapSyncFilter* filter)
594 {
595  // return value: true=okay, false=error
596  assert(!node.isRoot());
597 
598  if (!isSynching())
599  {
600  JLOG(journal_.trace()) << "AddKnownNode while not synching";
601  return SHAMapAddNode::duplicate();
602  }
603 
604  std::uint32_t generation = f_.fullbelow().getGeneration();
605  auto newNode = SHAMapAbstractNode::make(
606  rawNode, 0, snfWIRE, SHAMapHash{}, false, f_.journal(), node);
607  SHAMapNodeID iNodeID;
608  auto iNode = root_.get();
609 
610  while (iNode->isInner() &&
611  !static_cast<SHAMapInnerNode*>(iNode)->isFullBelow(generation) &&
612  (iNodeID.getDepth() < node.getDepth()))
613  {
614  int branch = iNodeID.selectBranch(node.getNodeID());
615  assert(branch >= 0);
616  auto inner = static_cast<SHAMapInnerNode*>(iNode);
617  if (inner->isEmptyBranch(branch))
618  {
619  JLOG(journal_.warn()) << "Add known node for empty branch" << node;
620  return SHAMapAddNode::invalid();
621  }
622 
623  auto childHash = inner->getChildHash(branch);
624  if (f_.fullbelow().touch_if_exists(childHash.as_uint256()))
625  return SHAMapAddNode::duplicate();
626 
627  auto prevNode = inner;
628  std::tie(iNode, iNodeID) = descend(inner, iNodeID, branch, filter);
629 
630  if (iNode == nullptr)
631  {
632  if (!newNode || !newNode->isValid() ||
633  childHash != newNode->getNodeHash())
634  {
635  JLOG(journal_.warn()) << "Corrupt node received";
636  return SHAMapAddNode::invalid();
637  }
638 
639  if (!newNode->isInBounds(iNodeID))
640  {
641  // Map is provably invalid
643  return SHAMapAddNode::useful();
644  }
645 
646  if (iNodeID != node)
647  {
648  // Either this node is broken or we didn't request it (yet)
649  JLOG(journal_.warn()) << "unable to hook node " << node;
650  JLOG(journal_.info()) << " stuck at " << iNodeID;
651  JLOG(journal_.info()) << "got depth=" << node.getDepth()
652  << ", walked to= " << iNodeID.getDepth();
653  return SHAMapAddNode::useful();
654  }
655 
656  if (backed_)
657  canonicalize(childHash, newNode);
658 
659  newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
660 
661  if (filter)
662  {
663  Serializer s;
664  newNode->addRaw(s, snfPREFIX);
665  filter->gotNode(
666  false,
667  childHash,
668  ledgerSeq_,
669  std::move(s.modData()),
670  newNode->getType());
671  }
672 
673  return SHAMapAddNode::useful();
674  }
675  }
676 
677  JLOG(journal_.trace()) << "got node, already had it (late)";
678  return SHAMapAddNode::duplicate();
679 }
680 
681 bool
683 {
684  // Intended for debug/test only
686 
687  stack.push({root_.get(), other.root_.get()});
688 
689  while (!stack.empty())
690  {
691  auto const [node, otherNode] = stack.top();
692  stack.pop();
693 
694  if (!node || !otherNode)
695  {
696  JLOG(journal_.info()) << "unable to fetch node";
697  return false;
698  }
699  else if (otherNode->getNodeHash() != node->getNodeHash())
700  {
701  JLOG(journal_.warn()) << "node hash mismatch";
702  return false;
703  }
704 
705  if (node->isLeaf())
706  {
707  if (!otherNode->isLeaf())
708  return false;
709  auto& nodePeek = static_cast<SHAMapTreeNode*>(node)->peekItem();
710  auto& otherNodePeek =
711  static_cast<SHAMapTreeNode*>(otherNode)->peekItem();
712  if (nodePeek->key() != otherNodePeek->key())
713  return false;
714  if (nodePeek->peekData() != otherNodePeek->peekData())
715  return false;
716  }
717  else if (node->isInner())
718  {
719  if (!otherNode->isInner())
720  return false;
721  auto node_inner = static_cast<SHAMapInnerNode*>(node);
722  auto other_inner = static_cast<SHAMapInnerNode*>(otherNode);
723  for (int i = 0; i < 16; ++i)
724  {
725  if (node_inner->isEmptyBranch(i))
726  {
727  if (!other_inner->isEmptyBranch(i))
728  return false;
729  }
730  else
731  {
732  if (other_inner->isEmptyBranch(i))
733  return false;
734 
735  auto next = descend(node_inner, i);
736  auto otherNext = other.descend(other_inner, i);
737  if (!next || !otherNext)
738  {
739  JLOG(journal_.warn()) << "unable to fetch inner node";
740  return false;
741  }
742  stack.push({next, otherNext});
743  }
744  }
745  }
746  }
747 
748  return true;
749 }
750 
753 bool
755  SHAMapNodeID const& targetNodeID,
756  SHAMapHash const& targetNodeHash) const
757 {
758  auto node = root_.get();
759  SHAMapNodeID nodeID;
760 
761  while (node->isInner() && (nodeID.getDepth() < targetNodeID.getDepth()))
762  {
763  int branch = nodeID.selectBranch(targetNodeID.getNodeID());
764  auto inner = static_cast<SHAMapInnerNode*>(node);
765  if (inner->isEmptyBranch(branch))
766  return false;
767 
768  node = descendThrow(inner, branch);
769  nodeID = nodeID.getChildNodeID(branch);
770  }
771 
772  return (node->isInner()) && (node->getNodeHash() == targetNodeHash);
773 }
774 
777 bool
778 SHAMap::hasLeafNode(uint256 const& tag, SHAMapHash const& targetNodeHash) const
779 {
780  auto node = root_.get();
781  SHAMapNodeID nodeID;
782 
783  if (!node->isInner()) // only one leaf node in the tree
784  return node->getNodeHash() == targetNodeHash;
785 
786  do
787  {
788  int branch = nodeID.selectBranch(tag);
789  auto inner = static_cast<SHAMapInnerNode*>(node);
790  if (inner->isEmptyBranch(branch))
791  return false; // Dead end, node must not be here
792 
793  if (inner->getChildHash(branch) ==
794  targetNodeHash) // Matching leaf, no need to retrieve it
795  return true;
796 
797  node = descendThrow(inner, branch);
798  nodeID = nodeID.getChildNodeID(branch);
799  } while (node->isInner());
800 
801  return false; // If this was a matching leaf, we would have caught it
802  // already
803 }
804 
814 void
816  SHAMap const* have,
817  bool includeLeaves,
818  int max,
819  std::function<void(SHAMapHash const&, const Blob&)> func) const
820 {
822  have, [includeLeaves, &max, &func](SHAMapAbstractNode& smn) -> bool {
823  if (includeLeaves || smn.isInner())
824  {
825  Serializer s;
826  smn.addRaw(s, snfPREFIX);
827  func(smn.getNodeHash(), s.peekData());
828 
829  if (--max <= 0)
830  return false;
831  }
832  return true;
833  });
834 }
835 
836 } // namespace ripple
ripple::SHAMap::MissingNodes
Definition: SHAMap.h:422
ripple::SHAMapAddNode
Definition: SHAMapAddNode.h:28
ripple::SHAMap::clearSynching
void clearSynching()
Definition: SHAMap.h:517
std::make_tuple
T make_tuple(T... args)
ripple::SHAMapNodeID::selectBranch
int selectBranch(uint256 const &hash) const
Definition: SHAMapNodeID.cpp:114
std::shared_ptr
STL class.
ripple::SHAMap::backed_
bool backed_
Definition: SHAMap.h:91
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::SHAMapNodeID::getNodeID
uint256 const & getNodeID() const
Definition: SHAMapNodeID.h:112
ripple::SHAMap::deepCompare
bool deepCompare(SHAMap &other) const
Definition: SHAMapSync.cpp:682
ripple::SHAMap::MissingNodes::stack_
std::stack< StackEntry, std::deque< StackEntry > > stack_
Definition: SHAMap.h:452
ripple::SHAMap::hasInnerNode
bool hasInnerNode(SHAMapNodeID const &nodeID, SHAMapHash const &hash) const
Does this map have this inner node?
Definition: SHAMapSync.cpp:754
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:176
ripple::SHAMap::canonicalize
void canonicalize(SHAMapHash const &hash, std::shared_ptr< SHAMapAbstractNode > &) const
Definition: SHAMap.cpp:1122
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:43
ripple::SHAMapAbstractNode::make
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{})
Definition: SHAMapTreeNode.cpp:79
ripple::SHAMap::seq_
std::uint32_t seq_
Definition: SHAMap.h:86
std::pair
std::vector::reserve
T reserve(T... args)
ripple::SHAMapNodeID::getDepth
int getDepth() const
Definition: SHAMapNodeID.h:106
ripple::SHAMapNodeID::getChildNodeID
SHAMapNodeID getChildNodeID(int m) const
Definition: SHAMapNodeID.cpp:101
ripple::SHAMap::descendThrow
SHAMapAbstractNode * descendThrow(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:249
ripple::SHAMap::getNodeFat
bool getNodeFat(SHAMapNodeID node, std::vector< SHAMapNodeID > &nodeIDs, std::vector< Blob > &rawNode, bool fatLeaves, std::uint32_t depth) const
Definition: SHAMapSync.cpp:442
ripple::SHAMap::getFetchPack
void getFetchPack(SHAMap const *have, bool includeLeaves, int max, std::function< void(SHAMapHash const &, const Blob &)>) const
Definition: SHAMapSync.cpp:815
std::vector
STL class.
ripple::SHAMap::visitNodes
void visitNodes(std::function< bool(SHAMapAbstractNode &)> const &function) const
Visit every node in this SHAMap.
Definition: SHAMapSync.cpp:39
ripple::SHAMap::MissingNodes::maxDefer_
const int maxDefer_
Definition: SHAMap.h:432
ripple::SHAMap::MissingNodes::generation_
std::uint32_t generation_
Definition: SHAMap.h:433
ripple::snfPREFIX
@ snfPREFIX
Definition: SHAMapTreeNode.h:36
std::stack
STL class.
ripple::SHAMap::peekItem
std::shared_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
Definition: SHAMap.cpp:539
std::stack::emplace
T emplace(T... args)
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
std::tuple
std::function
ripple::SHAMapNodeID
Definition: SHAMapNodeID.h:33
ripple::SHAMap::MissingNodes::filter_
SHAMapSyncFilter * filter_
Definition: SHAMap.h:431
ripple::SHAMap::gmn_ProcessNodes
void gmn_ProcessNodes(MissingNodes &, MissingNodes::StackEntry &node)
Definition: SHAMapSync.cpp:179
ripple::Family::db
virtual NodeStore::Database & db()=0
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:43
ripple::SHAMap::fetchNodeNT
std::shared_ptr< SHAMapAbstractNode > fetchNodeNT(SHAMapHash const &hash) const
Definition: SHAMap.cpp:226
ripple::SHAMap::getNeededHashes
std::vector< uint256 > getNeededHashes(int max, SHAMapSyncFilter *filter)
Definition: SHAMapSync.cpp:428
ripple::SHAMapAddNode::duplicate
static SHAMapAddNode duplicate()
Definition: SHAMapAddNode.h:138
ripple::SHAMap::getRootNode
bool getRootNode(Serializer &s, SHANodeFormat format) const
Definition: SHAMapSync.cpp:539
ripple::SHAMap::f_
Family & f_
Definition: SHAMap.h:84
ripple::SHAMapAddNode::useful
static SHAMapAddNode useful()
Definition: SHAMapAddNode.h:144
std::tie
T tie(T... args)
std::vector::push_back
T push_back(T... args)
ripple::SHAMapInnerNode::isEmptyBranch
bool isEmptyBranch(int m) const
Definition: SHAMapTreeNode.h:376
ripple::detail::BasicFullBelowCache::touch_if_exists
bool touch_if_exists(key_type const &key)
Refresh the last access time of an item, if it exists.
Definition: FullBelowCache.h:101
ripple::SHAMapSyncFilter::gotNode
virtual void gotNode(bool fromFilter, SHAMapHash const &nodeHash, std::uint32_t ledgerSeq, Blob &&nodeData, SHAMapTreeNode::TNType type) const =0
ripple::base_uint< 256 >
ripple::SHAMap::descendAsync
SHAMapAbstractNode * descendAsync(SHAMapInnerNode *parent, int branch, SHAMapSyncFilter *filter, bool &pending) const
Definition: SHAMap.cpp:346
ripple::SHAMap::MissingNodes::resumes_
std::map< SHAMapInnerNode *, SHAMapNodeID > resumes_
Definition: SHAMap.h:460
ripple::SHAMap::MissingNodes::deferredReads_
std::vector< std::tuple< SHAMapInnerNode *, SHAMapNodeID, int > > deferredReads_
Definition: SHAMap.h:456
ripple::rand_int
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.
Definition: ripple/basics/random.h:115
ripple::SHAMapAbstractNode::isInner
bool isInner() const
Definition: SHAMapTreeNode.h:350
ripple::HashPrefix::innerNode
@ innerNode
inner node in V1 tree
ripple::SHAMapInnerNode::getChildHash
SHAMapHash const & getChildHash(int m) const
Definition: SHAMapTreeNode.h:382
ripple::SHAMap::hasLeafNode
bool hasLeafNode(uint256 const &tag, SHAMapHash const &hash) const
Does this map have this leaf node?
Definition: SHAMapSync.cpp:778
ripple::SHAMap::visitDifferences
void visitDifferences(SHAMap const *have, std::function< bool(SHAMapAbstractNode &)>) const
Visit every node in this SHAMap that is not present in the specified SHAMap.
Definition: SHAMapSync.cpp:105
ripple::SHAMapInnerNode
Definition: SHAMapTreeNode.h:189
ripple::SHAMap::MissingNodes::max_
int max_
Definition: SHAMap.h:430
ripple::SHAMap::visitLeaves
void visitLeaves(std::function< void(std::shared_ptr< SHAMapItem const > const &)> const &) const
Visit every leaf node in this SHAMap.
Definition: SHAMapSync.cpp:27
ripple::SHAMapInnerNode::isFullBelow
bool isFullBelow(std::uint32_t generation) const
Definition: SHAMapTreeNode.h:389
ripple::SHAMapAbstractNode::getNodeHash
SHAMapHash const & getNodeHash() const
Definition: SHAMapTreeNode.h:331
ripple::SHAMapAddNode::invalid
static SHAMapAddNode invalid()
Definition: SHAMapAddNode.h:150
ripple::SHAMap::isSynching
bool isSynching() const
Definition: SHAMap.h:504
ripple::SHAMap
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition: SHAMap.h:81
std::stack::pop
T pop(T... args)
std::stack::top
T top(T... args)
ripple::Serializer::addRaw
int addRaw(Blob const &vector)
Definition: Serializer.cpp:100
ripple::SHAMapTreeNode
Definition: SHAMapTreeNode.h:255
ripple::NodeStore::Database::waitReads
void waitReads()
Wait for all currently pending async reads to complete.
Definition: Database.cpp:61
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::SHAMap::journal_
beast::Journal journal_
Definition: SHAMap.h:85
ripple::SHAMap::MissingNodes::missingHashes_
std::set< SHAMapHash > missingHashes_
Definition: SHAMap.h:437
ripple::SHAMapInnerNode::getBranchCount
int getBranchCount() const
Definition: SHAMapTreeNode.cpp:480
std::uint32_t
ripple::SHAMap::addRootNode
SHAMapAddNode addRootNode(SHAMapHash const &hash, Slice const &rootNode, SHANodeFormat format, SHAMapSyncFilter *filter)
Definition: SHAMapSync.cpp:546
ripple::SHAMap::getMissingNodes
std::vector< std::pair< SHAMapNodeID, uint256 > > getMissingNodes(int maxNodes, SHAMapSyncFilter *filter)
Check for nodes in the SHAMap not available.
Definition: SHAMapSync.cpp:316
ripple::Serializer
Definition: Serializer.h:39
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::SHAMap::descend
SHAMapAbstractNode * descend(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:272
ripple::SHAMap::descendNoStore
std::shared_ptr< SHAMapAbstractNode > descendNoStore(std::shared_ptr< SHAMapInnerNode > const &, int branch) const
Definition: SHAMap.cpp:306
ripple::detail::BasicFullBelowCache::getGeneration
std::uint32_t getGeneration(void) const
generation determines whether cached entry is valid
Definition: FullBelowCache.h:121
ripple::snfWIRE
@ snfWIRE
Definition: SHAMapTreeNode.h:37
ripple::SHAMap::root_
std::shared_ptr< SHAMapAbstractNode > root_
Definition: SHAMap.h:88
ripple::SHAMapAbstractNode
Definition: SHAMapTreeNode.h:122
std::stack::empty
T empty(T... args)
std::stack::push
T push(T... args)
ripple::SHAMap::gmn_ProcessDeferredReads
void gmn_ProcessDeferredReads(MissingNodes &)
Definition: SHAMapSync.cpp:255
ripple::detail::BasicFullBelowCache::insert
void insert(key_type const &key)
Insert a key into the cache.
Definition: FullBelowCache.h:114
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::after
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition: Escrow.cpp:88
ripple::SHAMapState::Invalid
@ Invalid
ripple::Family::fullbelow
virtual FullBelowCache & fullbelow()=0
std::make_pair
T make_pair(T... args)
ripple::SHAMapInnerNode::isEmpty
bool isEmpty() const
Definition: SHAMapTreeNode.cpp:474
ripple::SHAMap::addKnownNode
SHAMapAddNode addKnownNode(SHAMapNodeID const &nodeID, Slice const &rawNode, SHAMapSyncFilter *filter)
Definition: SHAMapSync.cpp:590
ripple::Family::journal
virtual beast::Journal const & journal()=0
ripple::SHAMapHash::as_uint256
uint256 const & as_uint256() const
Definition: SHAMapTreeNode.h:54
ripple::SHAMapInnerNode::setFullBelowGen
void setFullBelowGen(std::uint32_t gen)
Definition: SHAMapTreeNode.h:395
ripple::SHAMap::ledgerSeq_
std::uint32_t ledgerSeq_
Definition: SHAMap.h:87
ripple::SHAMapSyncFilter
Definition: SHAMapSyncFilter.h:30
ripple::SHAMap::MissingNodes::missingNodes_
std::vector< std::pair< SHAMapNodeID, uint256 > > missingNodes_
Definition: SHAMap.h:436
ripple::SHAMap::state_
SHAMapState state_
Definition: SHAMap.h:89
ripple::SHAMapNodeID::isRoot
bool isRoot() const
Definition: SHAMapNodeID.h:124
ripple::SHANodeFormat
SHANodeFormat
Definition: SHAMapTreeNode.h:35
ripple::NodeStore::Database::getDesiredAsyncReadCount
virtual int getDesiredAsyncReadCount(std::uint32_t seq)=0
Get the maximum number of async reads the node store prefers.
ripple::SHAMapTreeNode::peekItem
std::shared_ptr< SHAMapItem const > const & peekItem() const
Definition: SHAMapTreeNode.h:415
std::chrono::steady_clock::now
T now(T... args)