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  // Add this node to the reply
489  Serializer s;
490  node->addRaw(s, snfWIRE);
491  nodeIDs.push_back(nodeID);
492  rawNodes.push_back(std::move(s.peekData()));
493 
494  if (node->isInner())
495  {
496  // We descend inner nodes with only a single child
497  // without decrementing the depth
498  auto inner = static_cast<SHAMapInnerNode*>(node);
499  int bc = inner->getBranchCount();
500  if ((depth > 0) || (bc == 1))
501  {
502  // We need to process this node's children
503  for (int i = 0; i < 16; ++i)
504  {
505  if (!inner->isEmptyBranch(i))
506  {
507  auto const childNode = descendThrow(inner, i);
508  SHAMapNodeID const childID = nodeID.getChildNodeID(i);
509 
510  if (childNode->isInner() && ((depth > 1) || (bc == 1)))
511  {
512  // If there's more than one child, reduce the depth
513  // If only one child, follow the chain
514  stack.emplace(
515  childNode,
516  childID,
517  (bc > 1) ? (depth - 1) : depth);
518  }
519  else if (childNode->isInner() || fatLeaves)
520  {
521  // Just include this node
522  Serializer ns;
523  childNode->addRaw(ns, snfWIRE);
524  nodeIDs.push_back(childID);
525  rawNodes.push_back(std::move(ns.peekData()));
526  }
527  }
528  }
529  }
530  }
531  }
532 
533  return true;
534 }
535 
536 bool
538 {
539  root_->addRaw(s, format);
540  return true;
541 }
542 
545  SHAMapHash const& hash,
546  Slice const& rootNode,
547  SHANodeFormat format,
548  SHAMapSyncFilter* filter)
549 {
550  // we already have a root_ node
551  if (root_->getNodeHash().isNonZero())
552  {
553  JLOG(journal_.trace()) << "got root node, already have one";
554  assert(root_->getNodeHash() == hash);
555  return SHAMapAddNode::duplicate();
556  }
557 
558  assert(seq_ >= 1);
559  auto node = SHAMapAbstractNode::make(
560  rootNode, 0, format, SHAMapHash{}, false, f_.journal());
561  if (!node || !node->isValid() || node->getNodeHash() != hash)
562  return SHAMapAddNode::invalid();
563 
564  if (backed_)
565  canonicalize(hash, node);
566 
567  root_ = node;
568 
569  if (root_->isLeaf())
570  clearSynching();
571 
572  if (filter)
573  {
574  Serializer s;
575  root_->addRaw(s, snfPREFIX);
576  filter->gotNode(
577  false,
578  root_->getNodeHash(),
579  ledgerSeq_,
580  std::move(s.modData()),
581  root_->getType());
582  }
583 
584  return SHAMapAddNode::useful();
585 }
586 
589  const SHAMapNodeID& node,
590  Slice const& rawNode,
591  SHAMapSyncFilter* filter)
592 {
593  // return value: true=okay, false=error
594  assert(!node.isRoot());
595 
596  if (!isSynching())
597  {
598  JLOG(journal_.trace()) << "AddKnownNode while not synching";
599  return SHAMapAddNode::duplicate();
600  }
601 
602  std::uint32_t generation = f_.fullbelow().getGeneration();
603  auto newNode = SHAMapAbstractNode::make(
604  rawNode, 0, snfWIRE, SHAMapHash{}, false, f_.journal(), node);
605  SHAMapNodeID iNodeID;
606  auto iNode = root_.get();
607 
608  while (iNode->isInner() &&
609  !static_cast<SHAMapInnerNode*>(iNode)->isFullBelow(generation) &&
610  (iNodeID.getDepth() < node.getDepth()))
611  {
612  int branch = iNodeID.selectBranch(node.getNodeID());
613  assert(branch >= 0);
614  auto inner = static_cast<SHAMapInnerNode*>(iNode);
615  if (inner->isEmptyBranch(branch))
616  {
617  JLOG(journal_.warn()) << "Add known node for empty branch" << node;
618  return SHAMapAddNode::invalid();
619  }
620 
621  auto childHash = inner->getChildHash(branch);
622  if (f_.fullbelow().touch_if_exists(childHash.as_uint256()))
623  return SHAMapAddNode::duplicate();
624 
625  auto prevNode = inner;
626  std::tie(iNode, iNodeID) = descend(inner, iNodeID, branch, filter);
627 
628  if (iNode == nullptr)
629  {
630  if (!newNode || !newNode->isValid() ||
631  childHash != newNode->getNodeHash())
632  {
633  JLOG(journal_.warn()) << "Corrupt node received";
634  return SHAMapAddNode::invalid();
635  }
636 
637  if (!newNode->isInBounds(iNodeID))
638  {
639  // Map is provably invalid
641  return SHAMapAddNode::useful();
642  }
643 
644  if (iNodeID != node)
645  {
646  // Either this node is broken or we didn't request it (yet)
647  JLOG(journal_.warn()) << "unable to hook node " << node;
648  JLOG(journal_.info()) << " stuck at " << iNodeID;
649  JLOG(journal_.info()) << "got depth=" << node.getDepth()
650  << ", walked to= " << iNodeID.getDepth();
651  return SHAMapAddNode::useful();
652  }
653 
654  if (backed_)
655  canonicalize(childHash, newNode);
656 
657  newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
658 
659  if (filter)
660  {
661  Serializer s;
662  newNode->addRaw(s, snfPREFIX);
663  filter->gotNode(
664  false,
665  childHash,
666  ledgerSeq_,
667  std::move(s.modData()),
668  newNode->getType());
669  }
670 
671  return SHAMapAddNode::useful();
672  }
673  }
674 
675  JLOG(journal_.trace()) << "got node, already had it (late)";
676  return SHAMapAddNode::duplicate();
677 }
678 
679 bool
681 {
682  // Intended for debug/test only
684 
685  stack.push({root_.get(), other.root_.get()});
686 
687  while (!stack.empty())
688  {
689  auto const [node, otherNode] = stack.top();
690  stack.pop();
691 
692  if (!node || !otherNode)
693  {
694  JLOG(journal_.info()) << "unable to fetch node";
695  return false;
696  }
697  else if (otherNode->getNodeHash() != node->getNodeHash())
698  {
699  JLOG(journal_.warn()) << "node hash mismatch";
700  return false;
701  }
702 
703  if (node->isLeaf())
704  {
705  if (!otherNode->isLeaf())
706  return false;
707  auto& nodePeek = static_cast<SHAMapTreeNode*>(node)->peekItem();
708  auto& otherNodePeek =
709  static_cast<SHAMapTreeNode*>(otherNode)->peekItem();
710  if (nodePeek->key() != otherNodePeek->key())
711  return false;
712  if (nodePeek->peekData() != otherNodePeek->peekData())
713  return false;
714  }
715  else if (node->isInner())
716  {
717  if (!otherNode->isInner())
718  return false;
719  auto node_inner = static_cast<SHAMapInnerNode*>(node);
720  auto other_inner = static_cast<SHAMapInnerNode*>(otherNode);
721  for (int i = 0; i < 16; ++i)
722  {
723  if (node_inner->isEmptyBranch(i))
724  {
725  if (!other_inner->isEmptyBranch(i))
726  return false;
727  }
728  else
729  {
730  if (other_inner->isEmptyBranch(i))
731  return false;
732 
733  auto next = descend(node_inner, i);
734  auto otherNext = other.descend(other_inner, i);
735  if (!next || !otherNext)
736  {
737  JLOG(journal_.warn()) << "unable to fetch inner node";
738  return false;
739  }
740  stack.push({next, otherNext});
741  }
742  }
743  }
744  }
745 
746  return true;
747 }
748 
751 bool
753  SHAMapNodeID const& targetNodeID,
754  SHAMapHash const& targetNodeHash) const
755 {
756  auto node = root_.get();
757  SHAMapNodeID nodeID;
758 
759  while (node->isInner() && (nodeID.getDepth() < targetNodeID.getDepth()))
760  {
761  int branch = nodeID.selectBranch(targetNodeID.getNodeID());
762  auto inner = static_cast<SHAMapInnerNode*>(node);
763  if (inner->isEmptyBranch(branch))
764  return false;
765 
766  node = descendThrow(inner, branch);
767  nodeID = nodeID.getChildNodeID(branch);
768  }
769 
770  return (node->isInner()) && (node->getNodeHash() == targetNodeHash);
771 }
772 
775 bool
776 SHAMap::hasLeafNode(uint256 const& tag, SHAMapHash const& targetNodeHash) const
777 {
778  auto node = root_.get();
779  SHAMapNodeID nodeID;
780 
781  if (!node->isInner()) // only one leaf node in the tree
782  return node->getNodeHash() == targetNodeHash;
783 
784  do
785  {
786  int branch = nodeID.selectBranch(tag);
787  auto inner = static_cast<SHAMapInnerNode*>(node);
788  if (inner->isEmptyBranch(branch))
789  return false; // Dead end, node must not be here
790 
791  if (inner->getChildHash(branch) ==
792  targetNodeHash) // Matching leaf, no need to retrieve it
793  return true;
794 
795  node = descendThrow(inner, branch);
796  nodeID = nodeID.getChildNodeID(branch);
797  } while (node->isInner());
798 
799  return false; // If this was a matching leaf, we would have caught it
800  // already
801 }
802 
812 void
814  SHAMap const* have,
815  bool includeLeaves,
816  int max,
817  std::function<void(SHAMapHash const&, const Blob&)> func) const
818 {
820  have, [includeLeaves, &max, &func](SHAMapAbstractNode& smn) -> bool {
821  if (includeLeaves || smn.isInner())
822  {
823  Serializer s;
824  smn.addRaw(s, snfPREFIX);
825  func(smn.getNodeHash(), s.peekData());
826 
827  if (--max <= 0)
828  return false;
829  }
830  return true;
831  });
832 }
833 
834 } // 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:680
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:752
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:212
ripple::SHAMap::canonicalize
void canonicalize(SHAMapHash const &hash, std::shared_ptr< SHAMapAbstractNode > &) const
Definition: SHAMap.cpp:1118
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:813
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:537
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:776
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:127
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:478
std::uint32_t
ripple::SHAMap::addRootNode
SHAMapAddNode addRootNode(SHAMapHash const &hash, Slice const &rootNode, SHANodeFormat format, SHAMapSyncFilter *filter)
Definition: SHAMapSync.cpp:544
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:43
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::Serializer::peekData
Blob const & peekData() const
Definition: Serializer.h:202
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:472
ripple::SHAMap::addKnownNode
SHAMapAddNode addKnownNode(SHAMapNodeID const &nodeID, Slice const &rawNode, SHAMapSyncFilter *filter)
Definition: SHAMapSync.cpp:588
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)