20#include <xrpld/shamap/SHAMap.h>
22#include <xrpl/basics/contract.h>
41 boost::intrusive_ptr<SHAMapItem const>
const& otherMapItem,
51 bool emptyBranch = !otherMapItem;
53 while (!nodeStack.
empty())
55 node = nodeStack.
top();
62 for (
int i = 0; i < 16; ++i)
63 if (!inner->isEmptyBranch(i))
71 if (emptyBranch || (item->key() != otherMapItem->key()))
84 else if (item->slice() != otherMapItem->slice())
89 item->key(),
DeltaRef(item, otherMapItem)));
92 item->key(),
DeltaRef(otherMapItem, item)));
112 otherMapItem->key(), DeltaRef(
nullptr, otherMapItem)));
115 otherMapItem->key(), DeltaRef(otherMapItem,
nullptr)));
125SHAMap::compare(
SHAMap const& otherMap,
Delta& differences,
int maxCount)
const
133 isValid() && otherMap.
isValid(),
134 "ripple::SHAMap::compare : valid state and valid input");
136 if (getHash() == otherMap.
getHash())
143 nodeStack.
push({root_.get(), otherMap.
root_.get()});
144 while (!nodeStack.
empty())
146 auto [ourNode, otherNode] = nodeStack.
top();
149 if (!ourNode || !otherNode)
151 UNREACHABLE(
"ripple::SHAMap::compare : missing a node");
152 Throw<SHAMapMissingNode>(type_,
uint256());
155 if (ourNode->isLeaf() && otherNode->isLeaf())
160 if (ours->peekItem()->key() == other->peekItem()->key())
162 if (ours->peekItem()->slice() != other->peekItem()->slice())
165 ours->peekItem()->key(),
166 DeltaRef(ours->peekItem(), other->peekItem())));
174 ours->peekItem()->key(),
175 DeltaRef(ours->peekItem(),
nullptr)));
180 other->peekItem()->key(),
181 DeltaRef(
nullptr, other->peekItem())));
186 else if (ourNode->isInner() && otherNode->isLeaf())
191 ours, other->peekItem(),
true, differences, maxCount))
194 else if (ourNode->isLeaf() && otherNode->isInner())
199 other, ours->peekItem(),
false, differences, maxCount))
202 else if (ourNode->isInner() && otherNode->isInner())
206 for (
int i = 0; i < 16; ++i)
207 if (ours->getChildHash(i) != other->getChildHash(i))
209 if (other->isEmptyBranch(i))
214 iNode,
nullptr,
true, differences, maxCount))
217 else if (ours->isEmptyBranch(i))
222 iNode,
nullptr,
false, differences, maxCount))
227 {descendThrow(ours, i),
232 UNREACHABLE(
"ripple::SHAMap::compare : invalid node");
242 if (!root_->isInner())
248 nodeStack.
push(std::static_pointer_cast<SHAMapInnerNode>(root_));
250 while (!nodeStack.
empty())
255 for (
int i = 0; i < 16; ++i)
257 if (!node->isEmptyBranch(i))
260 descendNoStore(node, i);
264 if (nextNode->isInner())
266 std::static_pointer_cast<SHAMapInnerNode>(
271 missingNodes.
emplace_back(type_, node->getChildHash(i));
272 if (--maxMissing <= 0)
281SHAMap::walkMapParallel(
283 int maxMissing)
const
285 if (!root_->isInner())
291 auto const& innerRoot =
292 std::static_pointer_cast<SHAMapInnerNode>(root_);
293 for (
int i = 0; i < 16; ++i)
295 if (!innerRoot->isEmptyBranch(i))
296 topChildren[i] = descendNoStore(innerRoot, i);
310 for (
int rootChildIndex = 0; rootChildIndex < 16; ++rootChildIndex)
312 auto const& child = topChildren[rootChildIndex];
313 if (!child || !child->isInner())
316 nodeStacks[rootChildIndex].push(
317 std::static_pointer_cast<SHAMapInnerNode>(child));
319 JLOG(journal_.debug()) <<
"starting worker " << rootChildIndex;
321 [&m, &missingNodes, &maxMissing, &exceptions,
this](
325 while (!nodeStack.empty())
327 std::shared_ptr<SHAMapInnerNode> node =
328 std::move(nodeStack.top());
331 "ripple::SHAMap::walkMapParallel : non-null node");
334 for (int i = 0; i < 16; ++i)
336 if (node->isEmptyBranch(i))
338 std::shared_ptr<SHAMapTreeNode> nextNode =
339 descendNoStore(node, i);
343 if (nextNode->isInner())
344 nodeStack.push(std::static_pointer_cast<
345 SHAMapInnerNode>(nextNode));
349 std::lock_guard l{m};
350 missingNodes.emplace_back(
351 type_, node->getChildHash(i));
352 if (--maxMissing <= 0)
364 std::move(nodeStacks[rootChildIndex])));
371 if (exceptions.empty())
374 ss <<
"Exception(s) in ledger load: ";
375 for (
auto const& e : exceptions)
376 ss << e.what() <<
", ";
377 JLOG(journal_.error()) << ss.
str();
virtual bool isInner() const =0
Determines if this is an inner node.
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
SHAMapTreeNode * descendThrow(SHAMapInnerNode *, int branch) const
boost::intrusive_ptr< SHAMapItem const > const & peekItem(uint256 const &id) const
std::pair< boost::intrusive_ptr< SHAMapItem const >, boost::intrusive_ptr< SHAMapItem const > > DeltaRef
std::shared_ptr< SHAMapTreeNode > root_
SHAMapHash getHash() const
bool walkBranch(SHAMapTreeNode *node, boost::intrusive_ptr< SHAMapItem const > const &otherMapItem, bool isFirstMap, Delta &differences, int &maxCount) const
T emplace_back(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.