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/shamap/SHAMap.h>
22 #include <ripple/shamap/SHAMapSyncFilter.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](SHAMapTreeNode& node) {
32  if (!node.isInner())
33  leafFunction(static_cast<SHAMapLeafNode&>(node).peekItem());
34  return true;
35  });
36 }
37 
38 void
39 SHAMap::visitNodes(std::function<bool(SHAMapTreeNode&)> const& function) const
40 {
41  if (!root_)
42  return;
43 
44  function(*root_);
45 
46  if (!root_->isInner())
47  return;
48 
51 
52  auto node = std::static_pointer_cast<SHAMapInnerNode>(root_);
53  int pos = 0;
54 
55  while (1)
56  {
57  while (pos < 16)
58  {
59  uint256 childHash;
60  if (!node->isEmptyBranch(pos))
61  {
63  descendNoStore(node, pos);
64  if (!function(*child))
65  return;
66 
67  if (child->isLeaf())
68  ++pos;
69  else
70  {
71  // If there are no more children, don't push this node
72  while ((pos != 15) && (node->isEmptyBranch(pos + 1)))
73  ++pos;
74 
75  if (pos != 15)
76  {
77  // save next position to resume at
78  stack.push(std::make_pair(pos + 1, std::move(node)));
79  }
80 
81  // descend to the child's first position
82  node = std::static_pointer_cast<SHAMapInnerNode>(child);
83  pos = 0;
84  }
85  }
86  else
87  {
88  ++pos; // move to next position
89  }
90  }
91 
92  if (stack.empty())
93  break;
94 
95  std::tie(pos, node) = stack.top();
96  stack.pop();
97  }
98 }
99 
100 void
102  SHAMap const* have,
103  std::function<bool(SHAMapTreeNode const&)> function) const
104 {
105  // Visit every node in this SHAMap that is not present
106  // in the specified SHAMap
107  if (!root_)
108  return;
109 
110  if (root_->getHash().isZero())
111  return;
112 
113  if (have && (root_->getHash() == have->root_->getHash()))
114  return;
115 
116  if (root_->isLeaf())
117  {
118  auto leaf = std::static_pointer_cast<SHAMapLeafNode>(root_);
119  if (!have ||
120  !have->hasLeafNode(leaf->peekItem()->key(), leaf->getHash()))
121  function(*root_);
122  return;
123  }
124  // contains unexplored non-matching inner node entries
127 
128  stack.push({static_cast<SHAMapInnerNode*>(root_.get()), SHAMapNodeID{}});
129 
130  while (!stack.empty())
131  {
132  auto const [node, nodeID] = stack.top();
133  stack.pop();
134 
135  // 1) Add this node to the pack
136  if (!function(*node))
137  return;
138 
139  // 2) push non-matching child inner nodes
140  for (int i = 0; i < 16; ++i)
141  {
142  if (!node->isEmptyBranch(i))
143  {
144  auto const& childHash = node->getChildHash(i);
145  SHAMapNodeID childID = nodeID.getChildNodeID(i);
146  auto next = descendThrow(node, i);
147 
148  if (next->isInner())
149  {
150  if (!have || !have->hasInnerNode(childID, childHash))
151  stack.push(
152  {static_cast<SHAMapInnerNode*>(next), childID});
153  }
154  else if (
155  !have ||
156  !have->hasLeafNode(
157  static_cast<SHAMapLeafNode*>(next)->peekItem()->key(),
158  childHash))
159  {
160  if (!function(*next))
161  return;
162  }
163  }
164  }
165  }
166 }
167 
168 // Starting at the position referred to by the specfied
169 // StackEntry, process that node and its first resident
170 // children, descending the SHAMap until we complete the
171 // processing of a node.
172 void
174 {
175  SHAMapInnerNode*& node = std::get<0>(se);
176  SHAMapNodeID& nodeID = std::get<1>(se);
177  int& firstChild = std::get<2>(se);
178  int& currentChild = std::get<3>(se);
179  bool& fullBelow = std::get<4>(se);
180 
181  while (currentChild < 16)
182  {
183  int branch = (firstChild + currentChild++) % 16;
184  if (node->isEmptyBranch(branch))
185  continue;
186 
187  auto const& childHash = node->getChildHash(branch);
188 
189  if (mn.missingHashes_.count(childHash) != 0)
190  {
191  // we already know this child node is missing
192  fullBelow = false;
193  }
194  else if (
195  !backed_ ||
197  ->touch_if_exists(childHash.as_uint256()))
198  {
199  bool pending = false;
200  auto d = descendAsync(
201  node,
202  branch,
203  mn.filter_,
204  pending,
205  [node, nodeID, branch, &mn](
207  // a read completed asynchronously
208  std::unique_lock<std::mutex> lock{mn.deferLock_};
209  mn.finishedReads_.emplace_back(
210  node, nodeID, branch, std::move(found));
212  });
213 
214  if (pending)
215  {
216  fullBelow = false;
217  ++mn.deferred_;
218  }
219  else if (!d)
220  {
221  // node is not in database
222 
223  fullBelow = false; // for now, not known full below
224  mn.missingHashes_.insert(childHash);
225  mn.missingNodes_.emplace_back(
226  nodeID.getChildNodeID(branch), childHash.as_uint256());
227 
228  if (--mn.max_ <= 0)
229  return;
230  }
231  else if (
232  d->isInner() &&
233  !static_cast<SHAMapInnerNode*>(d)->isFullBelow(mn.generation_))
234  {
235  mn.stack_.push(se);
236 
237  // Switch to processing the child node
238  node = static_cast<SHAMapInnerNode*>(d);
239  nodeID = nodeID.getChildNodeID(branch);
240  firstChild = rand_int(255);
241  currentChild = 0;
242  fullBelow = true;
243  }
244  }
245  }
246 
247  // We have finished processing an inner node
248  // and thus (for now) all its children
249 
250  if (fullBelow)
251  { // No partial node encountered below this node
252  node->setFullBelowGen(mn.generation_);
253  if (backed_)
254  {
255  f_.getFullBelowCache(ledgerSeq_)
256  ->insert(node->getHash().as_uint256());
257  }
258  }
259 
260  node = nullptr;
261 }
262 
263 // Wait for deferred reads to finish and
264 // process their results
265 void
266 SHAMap::gmn_ProcessDeferredReads(MissingNodes& mn)
267 {
268  // Process all deferred reads
269  int complete = 0;
270  while (complete != mn.deferred_)
271  {
272  std::tuple<
274  SHAMapNodeID,
275  int,
277  deferredNode;
278  {
280 
281  while (mn.finishedReads_.size() <= complete)
282  mn.deferCondVar_.wait(lock);
283  deferredNode = std::move(mn.finishedReads_[complete++]);
284  }
285 
286  auto parent = std::get<0>(deferredNode);
287  auto const& parentID = std::get<1>(deferredNode);
288  auto branch = std::get<2>(deferredNode);
289  auto nodePtr = std::get<3>(deferredNode);
290  auto const& nodeHash = parent->getChildHash(branch);
291 
292  if (nodePtr)
293  { // Got the node
294  nodePtr = parent->canonicalizeChild(branch, std::move(nodePtr));
295 
296  // When we finish this stack, we need to restart
297  // with the parent of this node
298  mn.resumes_[parent] = parentID;
299  }
300  else if ((mn.max_ > 0) && (mn.missingHashes_.insert(nodeHash).second))
301  {
302  mn.missingNodes_.emplace_back(
303  parentID.getChildNodeID(branch), nodeHash.as_uint256());
304  --mn.max_;
305  }
306  }
307 
308  mn.finishedReads_.clear();
309  mn.deferred_ = 0;
310 }
311 
317 SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter)
318 {
319  assert(root_->getHash().isNonZero());
320  assert(max > 0);
321 
322  MissingNodes mn(
323  max,
324  filter,
325  4096, // number of async reads per pass
326  f_.getFullBelowCache(ledgerSeq_)->getGeneration());
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.deferred_ <= mn.maxDefer_))
356  {
357  gmn_ProcessNodes(mn, pos);
358 
359  if (mn.max_ <= 0)
360  break;
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  if (mn.deferred_)
386  gmn_ProcessDeferredReads(mn);
387 
388  if (mn.max_ <= 0)
389  return std::move(mn.missingNodes_);
390 
391  if (node == nullptr)
392  { // We weren't in the middle of processing a node
393 
394  if (mn.stack_.empty() && !mn.resumes_.empty())
395  {
396  // Recheck nodes we could not finish before
397  for (auto const& [innerNode, nodeId] : mn.resumes_)
398  if (!innerNode->isFullBelow(mn.generation_))
399  mn.stack_.push(std::make_tuple(
400  innerNode, nodeId, rand_int(255), 0, true));
401 
402  mn.resumes_.clear();
403  }
404 
405  if (!mn.stack_.empty())
406  {
407  // Resume at the top of the stack
408  pos = mn.stack_.top();
409  mn.stack_.pop();
410  assert(node != nullptr);
411  }
412  }
413 
414  // node will only still be nullptr if
415  // we finished the current node, the stack is empty
416  // and we have no nodes to resume
417 
418  } while (node != nullptr);
419 
420  if (mn.missingNodes_.empty())
421  clearSynching();
422 
423  return std::move(mn.missingNodes_);
424 }
425 
426 bool
427 SHAMap::getNodeFat(
428  SHAMapNodeID const& wanted,
429  std::vector<SHAMapNodeID>& nodeIDs,
430  std::vector<Blob>& rawNodes,
431  bool fatLeaves,
432  std::uint32_t depth) const
433 {
434  // Gets a node and some of its children
435  // to a specified depth
436 
437  auto node = root_.get();
438  SHAMapNodeID nodeID;
439 
440  while (node && node->isInner() && (nodeID.getDepth() < wanted.getDepth()))
441  {
442  int branch = selectBranch(nodeID, wanted.getNodeID());
443  auto inner = static_cast<SHAMapInnerNode*>(node);
444  if (inner->isEmptyBranch(branch))
445  return false;
446 
447  node = descendThrow(inner, branch);
448  nodeID = nodeID.getChildNodeID(branch);
449  }
450 
451  if (node == nullptr || wanted != nodeID)
452  {
453  JLOG(journal_.warn()) << "peer requested node that is not in the map:\n"
454  << wanted << " but found\n"
455  << nodeID;
456  return false;
457  }
458 
459  if (node->isInner() && static_cast<SHAMapInnerNode*>(node)->isEmpty())
460  {
461  JLOG(journal_.warn()) << "peer requests empty node";
462  return false;
463  }
464 
466  stack.emplace(node, nodeID, depth);
467 
468  while (!stack.empty())
469  {
470  std::tie(node, nodeID, depth) = stack.top();
471  stack.pop();
472 
473  {
474  // Add this node to the reply
475  Serializer s;
476  node->serializeForWire(s);
477  nodeIDs.push_back(nodeID);
478  rawNodes.push_back(std::move(s.modData()));
479  }
480 
481  if (node->isInner())
482  {
483  // We descend inner nodes with only a single child
484  // without decrementing the depth
485  auto inner = static_cast<SHAMapInnerNode*>(node);
486  int bc = inner->getBranchCount();
487  if ((depth > 0) || (bc == 1))
488  {
489  // We need to process this node's children
490  for (int i = 0; i < 16; ++i)
491  {
492  if (!inner->isEmptyBranch(i))
493  {
494  auto const childNode = descendThrow(inner, i);
495  SHAMapNodeID const childID = nodeID.getChildNodeID(i);
496 
497  if (childNode->isInner() && ((depth > 1) || (bc == 1)))
498  {
499  // If there's more than one child, reduce the depth
500  // If only one child, follow the chain
501  stack.emplace(
502  childNode,
503  childID,
504  (bc > 1) ? (depth - 1) : depth);
505  }
506  else if (childNode->isInner() || fatLeaves)
507  {
508  // Just include this node
509  Serializer ns;
510  childNode->serializeForWire(ns);
511  nodeIDs.push_back(childID);
512  rawNodes.push_back(std::move(ns.modData()));
513  }
514  }
515  }
516  }
517  }
518  }
519 
520  return true;
521 }
522 
523 void
524 SHAMap::serializeRoot(Serializer& s) const
525 {
526  root_->serializeForWire(s);
527 }
528 
530 SHAMap::addRootNode(
531  SHAMapHash const& hash,
532  Slice const& rootNode,
533  SHAMapSyncFilter* filter)
534 {
535  // we already have a root_ node
536  if (root_->getHash().isNonZero())
537  {
538  JLOG(journal_.trace()) << "got root node, already have one";
539  assert(root_->getHash() == hash);
540  return SHAMapAddNode::duplicate();
541  }
542 
543  assert(cowid_ >= 1);
544  auto node = SHAMapTreeNode::makeFromWire(rootNode);
545  if (!node || node->getHash() != hash)
546  return SHAMapAddNode::invalid();
547 
548  if (backed_)
549  canonicalize(hash, node);
550 
551  root_ = node;
552 
553  if (root_->isLeaf())
554  clearSynching();
555 
556  if (filter)
557  {
558  Serializer s;
559  root_->serializeWithPrefix(s);
560  filter->gotNode(
561  false,
562  root_->getHash(),
563  ledgerSeq_,
564  std::move(s.modData()),
565  root_->getType());
566  }
567 
568  return SHAMapAddNode::useful();
569 }
570 
572 SHAMap::addKnownNode(
573  const SHAMapNodeID& node,
574  Slice const& rawNode,
575  SHAMapSyncFilter* filter)
576 {
577  assert(!node.isRoot());
578 
579  if (!isSynching())
580  {
581  JLOG(journal_.trace()) << "AddKnownNode while not synching";
582  return SHAMapAddNode::duplicate();
583  }
584 
585  auto const generation = f_.getFullBelowCache(ledgerSeq_)->getGeneration();
586  auto newNode = SHAMapTreeNode::makeFromWire(rawNode);
587  SHAMapNodeID iNodeID;
588  auto iNode = root_.get();
589 
590  while (iNode->isInner() &&
591  !static_cast<SHAMapInnerNode*>(iNode)->isFullBelow(generation) &&
592  (iNodeID.getDepth() < node.getDepth()))
593  {
594  int branch = selectBranch(iNodeID, node.getNodeID());
595  assert(branch >= 0);
596  auto inner = static_cast<SHAMapInnerNode*>(iNode);
597  if (inner->isEmptyBranch(branch))
598  {
599  JLOG(journal_.warn()) << "Add known node for empty branch" << node;
600  return SHAMapAddNode::invalid();
601  }
602 
603  auto childHash = inner->getChildHash(branch);
604  if (f_.getFullBelowCache(ledgerSeq_)
605  ->touch_if_exists(childHash.as_uint256()))
606  {
607  return SHAMapAddNode::duplicate();
608  }
609 
610  auto prevNode = inner;
611  std::tie(iNode, iNodeID) = descend(inner, iNodeID, branch, filter);
612 
613  if (iNode == nullptr)
614  {
615  if (!newNode || childHash != newNode->getHash())
616  {
617  JLOG(journal_.warn()) << "Corrupt node received";
618  return SHAMapAddNode::invalid();
619  }
620 
621  // Inner nodes must be at a level strictly less than 64
622  // but leaf nodes (while notionally at level 64) can be
623  // at any depth up to and including 64:
624  if ((iNodeID.getDepth() > leafDepth) ||
625  (newNode->isInner() && iNodeID.getDepth() == leafDepth))
626  {
627  // Map is provably invalid
628  state_ = SHAMapState::Invalid;
629  return SHAMapAddNode::useful();
630  }
631 
632  if (iNodeID != node)
633  {
634  // Either this node is broken or we didn't request it (yet)
635  JLOG(journal_.warn()) << "unable to hook node " << node;
636  JLOG(journal_.info()) << " stuck at " << iNodeID;
637  JLOG(journal_.info()) << "got depth=" << node.getDepth()
638  << ", walked to= " << iNodeID.getDepth();
639  return SHAMapAddNode::useful();
640  }
641 
642  if (backed_)
643  canonicalize(childHash, newNode);
644 
645  newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
646 
647  if (filter)
648  {
649  Serializer s;
650  newNode->serializeWithPrefix(s);
651  filter->gotNode(
652  false,
653  childHash,
654  ledgerSeq_,
655  std::move(s.modData()),
656  newNode->getType());
657  }
658 
659  return SHAMapAddNode::useful();
660  }
661  }
662 
663  JLOG(journal_.trace()) << "got node, already had it (late)";
664  return SHAMapAddNode::duplicate();
665 }
666 
667 bool
668 SHAMap::deepCompare(SHAMap& other) const
669 {
670  // Intended for debug/test only
672 
673  stack.push({root_.get(), other.root_.get()});
674 
675  while (!stack.empty())
676  {
677  auto const [node, otherNode] = stack.top();
678  stack.pop();
679 
680  if (!node || !otherNode)
681  {
682  JLOG(journal_.info()) << "unable to fetch node";
683  return false;
684  }
685  else if (otherNode->getHash() != node->getHash())
686  {
687  JLOG(journal_.warn()) << "node hash mismatch";
688  return false;
689  }
690 
691  if (node->isLeaf())
692  {
693  if (!otherNode->isLeaf())
694  return false;
695  auto& nodePeek = static_cast<SHAMapLeafNode*>(node)->peekItem();
696  auto& otherNodePeek =
697  static_cast<SHAMapLeafNode*>(otherNode)->peekItem();
698  if (nodePeek->key() != otherNodePeek->key())
699  return false;
700  if (nodePeek->peekData() != otherNodePeek->peekData())
701  return false;
702  }
703  else if (node->isInner())
704  {
705  if (!otherNode->isInner())
706  return false;
707  auto node_inner = static_cast<SHAMapInnerNode*>(node);
708  auto other_inner = static_cast<SHAMapInnerNode*>(otherNode);
709  for (int i = 0; i < 16; ++i)
710  {
711  if (node_inner->isEmptyBranch(i))
712  {
713  if (!other_inner->isEmptyBranch(i))
714  return false;
715  }
716  else
717  {
718  if (other_inner->isEmptyBranch(i))
719  return false;
720 
721  auto next = descend(node_inner, i);
722  auto otherNext = other.descend(other_inner, i);
723  if (!next || !otherNext)
724  {
725  JLOG(journal_.warn()) << "unable to fetch inner node";
726  return false;
727  }
728  stack.push({next, otherNext});
729  }
730  }
731  }
732  }
733 
734  return true;
735 }
736 
739 bool
740 SHAMap::hasInnerNode(
741  SHAMapNodeID const& targetNodeID,
742  SHAMapHash const& targetNodeHash) const
743 {
744  auto node = root_.get();
745  SHAMapNodeID nodeID;
746 
747  while (node->isInner() && (nodeID.getDepth() < targetNodeID.getDepth()))
748  {
749  int branch = selectBranch(nodeID, targetNodeID.getNodeID());
750  auto inner = static_cast<SHAMapInnerNode*>(node);
751  if (inner->isEmptyBranch(branch))
752  return false;
753 
754  node = descendThrow(inner, branch);
755  nodeID = nodeID.getChildNodeID(branch);
756  }
757 
758  return (node->isInner()) && (node->getHash() == targetNodeHash);
759 }
760 
763 bool
764 SHAMap::hasLeafNode(uint256 const& tag, SHAMapHash const& targetNodeHash) const
765 {
766  auto node = root_.get();
767  SHAMapNodeID nodeID;
768 
769  if (!node->isInner()) // only one leaf node in the tree
770  return node->getHash() == targetNodeHash;
771 
772  do
773  {
774  int branch = selectBranch(nodeID, tag);
775  auto inner = static_cast<SHAMapInnerNode*>(node);
776  if (inner->isEmptyBranch(branch))
777  return false; // Dead end, node must not be here
778 
779  if (inner->getChildHash(branch) ==
780  targetNodeHash) // Matching leaf, no need to retrieve it
781  return true;
782 
783  node = descendThrow(inner, branch);
784  nodeID = nodeID.getChildNodeID(branch);
785  } while (node->isInner());
786 
787  return false; // If this was a matching leaf, we would have caught it
788  // already
789 }
790 
791 } // namespace ripple
ripple::SHAMap::MissingNodes
Definition: SHAMap.h:443
ripple::SHAMapAddNode
Definition: SHAMapAddNode.h:28
ripple::SHAMap::visitDifferences
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.
Definition: SHAMapSync.cpp:101
std::make_tuple
T make_tuple(T... args)
ripple::SHAMap::descendNoStore
std::shared_ptr< SHAMapTreeNode > descendNoStore(std::shared_ptr< SHAMapInnerNode > const &, int branch) const
Definition: SHAMap.cpp:340
ripple::SHAMapNodeID::getChildNodeID
SHAMapNodeID getChildNodeID(unsigned int m) const
Definition: SHAMapNodeID.cpp:74
ripple::SHAMap::MissingNodes::deferLock_
std::mutex deferLock_
Definition: SHAMap.h:483
std::shared_ptr
STL class.
ripple::SHAMap::backed_
bool backed_
Definition: SHAMap.h:110
ripple::selectBranch
unsigned int selectBranch(SHAMapNodeID const &id, uint256 const &hash)
Returns the branch that would contain the given hash.
Definition: SHAMapNodeID.cpp:121
ripple::SHAMap::MissingNodes::stack_
std::stack< StackEntry, std::deque< StackEntry > > stack_
Definition: SHAMap.h:473
ripple::SHAMap::hasInnerNode
bool hasInnerNode(SHAMapNodeID const &nodeID, SHAMapHash const &hash) const
Does this map have this inner node?
Definition: SHAMapSync.cpp:740
ripple::SHAMap::MissingNodes::deferred_
int deferred_
Definition: SHAMap.h:482
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:176
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
std::pair
std::vector
STL class.
ripple::SHAMap::MissingNodes::maxDefer_
const int maxDefer_
Definition: SHAMap.h:453
ripple::SHAMap::MissingNodes::generation_
std::uint32_t generation_
Definition: SHAMap.h:454
std::stack
STL class.
ripple::SHAMap::peekItem
std::shared_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
Definition: SHAMap.cpp:561
std::stack::emplace
T emplace(T... args)
std::tuple
ripple::SHAMap::MissingNodes::finishedReads_
std::vector< DeferredNode > finishedReads_
Definition: SHAMap.h:485
std::function
ripple::Family::getFullBelowCache
virtual std::shared_ptr< FullBelowCache > getFullBelowCache(std::uint32_t ledgerSeq)=0
Return a pointer to the Family Full Below Cache.
ripple::SHAMapNodeID
Identifies a node inside a SHAMap.
Definition: SHAMapNodeID.h:33
ripple::SHAMap::MissingNodes::filter_
SHAMapSyncFilter * filter_
Definition: SHAMap.h:452
ripple::SHAMapTreeNode::isInner
virtual bool isInner() const =0
Determines if this is an inner node.
ripple::SHAMap::gmn_ProcessNodes
void gmn_ProcessNodes(MissingNodes &, MissingNodes::StackEntry &node)
Definition: SHAMapSync.cpp:173
ripple::SHAMapLeafNode
Definition: SHAMapLeafNode.h:32
ripple::SHAMapHash
Definition: SHAMapTreeNode.h:47
ripple::SHAMap::f_
Family & f_
Definition: SHAMap.h:98
std::tie
T tie(T... args)
std::vector::push_back
T push_back(T... args)
ripple::SHAMapInnerNode::isEmptyBranch
bool isEmptyBranch(int m) const
Definition: SHAMapInnerNode.h:195
ripple::base_uint< 256 >
ripple::SHAMap::MissingNodes::resumes_
std::map< SHAMapInnerNode *, SHAMapNodeID > resumes_
Definition: SHAMap.h:489
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::HashPrefix::innerNode
@ innerNode
inner node in V1 tree
ripple::SHAMapInnerNode::getChildHash
SHAMapHash const & getChildHash(int m) const
Definition: SHAMapInnerNode.cpp:353
ripple::SHAMap::hasLeafNode
bool hasLeafNode(uint256 const &tag, SHAMapHash const &hash) const
Does this map have this leaf node?
Definition: SHAMapSync.cpp:764
ripple::SHAMapInnerNode
Definition: SHAMapInnerNode.h:39
ripple::SHAMap::MissingNodes::max_
int max_
Definition: SHAMap.h:451
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: SHAMapInnerNode.h:201
ripple::SHAMapSyncFilter::gotNode
virtual void gotNode(bool fromFilter, SHAMapHash const &nodeHash, std::uint32_t ledgerSeq, Blob &&nodeData, SHAMapNodeType type) const =0
std::unique_lock
STL class.
ripple::SHAMap
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition: SHAMap.h:95
std::stack::pop
T pop(T... args)
std::stack::top
T top(T... args)
ripple::SHAMapTreeNode
Definition: SHAMapTreeNode.h:133
ripple::SHAMap::descendThrow
SHAMapTreeNode * descendThrow(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:283
ripple::SHAMap::MissingNodes::missingHashes_
std::set< SHAMapHash > missingHashes_
Definition: SHAMap.h:458
ripple::SHAMapNodeID::getDepth
unsigned int getDepth() const
Definition: SHAMapNodeID.h:58
ripple::SHAMapInnerNode::getBranchCount
int getBranchCount() const
Definition: SHAMapInnerNode.cpp:264
std::uint32_t
std::condition_variable::wait
T wait(T... args)
std::condition_variable::notify_one
T notify_one(T... args)
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::MissingNodes::deferCondVar_
std::condition_variable deferCondVar_
Definition: SHAMap.h:484
ripple::SHAMap::descendAsync
SHAMapTreeNode * descendAsync(SHAMapInnerNode *parent, int branch, SHAMapSyncFilter *filter, bool &pending, descendCallback &&) const
Definition: SHAMap.cpp:380
std::stack::empty
T empty(T... args)
std::stack::push
T push(T... args)
ripple::SHAMap::visitNodes
void visitNodes(std::function< bool(SHAMapTreeNode &)> const &function) const
Visit every node in this SHAMap.
Definition: SHAMapSync.cpp:39
std::make_pair
T make_pair(T... args)
ripple::SHAMapNodeID::getNodeID
uint256 const & getNodeID() const
Definition: SHAMapNodeID.h:64
ripple::SHAMapInnerNode::isEmpty
bool isEmpty() const
Definition: SHAMapInnerNode.cpp:258
ripple::SHAMapLeafNode::peekItem
std::shared_ptr< SHAMapItem const > const & peekItem() const
Definition: SHAMapLeafNode.cpp:44
ripple::SHAMap::descend
SHAMapTreeNode * descend(SHAMapInnerNode *, int branch) const
Definition: SHAMap.cpp:306
ripple::SHAMap::ledgerSeq_
std::uint32_t ledgerSeq_
The sequence of the ledger that this map references, if any.
Definition: SHAMap.h:105
ripple::SHAMapSyncFilter
Definition: SHAMapSyncFilter.h:30
ripple::SHAMap::MissingNodes::missingNodes_
std::vector< std::pair< SHAMapNodeID, uint256 > > missingNodes_
Definition: SHAMap.h:457
ripple::SHAMapNodeID::isRoot
bool isRoot() const
Definition: SHAMapNodeID.h:48
ripple::SHAMap::root_
std::shared_ptr< SHAMapTreeNode > root_
Definition: SHAMap.h:107