mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 02:25:52 +00:00
Split SHAMapTreeNode into leaf and inner nodes.
* This reduces the memory requirements of both leaf and inner nodes. * The name SHAMapTreeNode is retained for leaf nodes so as to keep the public API of SHAMap stable.
This commit is contained in:
committed by
Nik Bougalis
parent
e95ab65396
commit
f875603525
@@ -235,16 +235,16 @@ public:
|
||||
if (!node.has_nodeid () || !node.has_nodedata ())
|
||||
return;
|
||||
|
||||
SHAMapTreeNode newNode(
|
||||
auto newNode = SHAMapAbstractNode::make(
|
||||
Blob (node.nodedata().begin(), node.nodedata().end()),
|
||||
0, snfWIRE, uZero, false);
|
||||
|
||||
s.erase();
|
||||
newNode.addRaw(s, snfPREFIX);
|
||||
newNode->addRaw(s, snfPREFIX);
|
||||
|
||||
auto blob = std::make_shared<Blob> (s.begin(), s.end());
|
||||
|
||||
getApp().getOPs().addFetchPack (newNode.getNodeHash(), blob);
|
||||
getApp().getOPs().addFetchPack (newNode->getNodeHash(), blob);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
|
||||
@@ -245,7 +245,7 @@ SHAMapStoreImp::onLedgerClosed (Ledger::pointer validatedLedger)
|
||||
|
||||
bool
|
||||
SHAMapStoreImp::copyNode (std::uint64_t& nodeCount,
|
||||
SHAMapTreeNode const& node)
|
||||
SHAMapAbstractNode const& node)
|
||||
{
|
||||
// Copy a single record from node to database_
|
||||
database_->fetchNode (node.getNodeHash());
|
||||
|
||||
@@ -159,7 +159,7 @@ public:
|
||||
|
||||
private:
|
||||
// callback for visitNodes
|
||||
bool copyNode (std::uint64_t& nodeCount, SHAMapTreeNode const &node);
|
||||
bool copyNode (std::uint64_t& nodeCount, SHAMapAbstractNode const &node);
|
||||
void run();
|
||||
void dbPaths();
|
||||
std::shared_ptr <NodeStore::Backend> makeBackendRotating (
|
||||
|
||||
@@ -83,7 +83,7 @@ private:
|
||||
beast::Journal journal_;
|
||||
std::uint32_t seq_;
|
||||
std::uint32_t ledgerSeq_; // sequence number of ledger this is part of
|
||||
std::shared_ptr<SHAMapTreeNode> root_;
|
||||
std::shared_ptr<SHAMapAbstractNode> root_;
|
||||
SHAMapState state_;
|
||||
SHAMapType type_;
|
||||
bool backed_ = true; // Map is backed by the database
|
||||
@@ -153,7 +153,7 @@ public:
|
||||
std::shared_ptr<SHAMapItem> peekNextItem (uint256 const& , SHAMapTreeNode::TNType & type) const;
|
||||
std::shared_ptr<SHAMapItem> peekPrevItem (uint256 const& ) const;
|
||||
|
||||
void visitNodes (std::function<bool (SHAMapTreeNode&)> const&) const;
|
||||
void visitNodes (std::function<bool (SHAMapAbstractNode&)> const&) const;
|
||||
void visitLeaves(std::function<void (std::shared_ptr<SHAMapItem> const&)> const&) const;
|
||||
|
||||
// comparison/sync functions
|
||||
@@ -192,7 +192,7 @@ public:
|
||||
|
||||
using fetchPackEntry_t = std::pair <uint256, Blob>;
|
||||
|
||||
void visitDifferences (SHAMap * have, std::function<bool (SHAMapTreeNode&)>) const;
|
||||
void visitDifferences(SHAMap* have, std::function<bool(SHAMapAbstractNode&)>) const;
|
||||
|
||||
void getFetchPack (SHAMap * have, bool includeLeaves, int max,
|
||||
std::function<void (uint256 const&, const Blob&)>) const;
|
||||
@@ -203,30 +203,30 @@ public:
|
||||
|
||||
private:
|
||||
using SharedPtrNodeStack =
|
||||
std::stack<std::pair<std::shared_ptr<SHAMapTreeNode>, SHAMapNodeID>>;
|
||||
std::stack<std::pair<std::shared_ptr<SHAMapAbstractNode>, SHAMapNodeID>>;
|
||||
using DeltaRef = std::pair<std::shared_ptr<SHAMapItem> const&,
|
||||
std::shared_ptr<SHAMapItem> const&>;
|
||||
|
||||
int unshare ();
|
||||
|
||||
// tree node cache operations
|
||||
std::shared_ptr<SHAMapTreeNode> getCache (uint256 const& hash) const;
|
||||
void canonicalize (uint256 const& hash, std::shared_ptr<SHAMapTreeNode>&) const;
|
||||
std::shared_ptr<SHAMapAbstractNode> getCache (uint256 const& hash) const;
|
||||
void canonicalize (uint256 const& hash, std::shared_ptr<SHAMapAbstractNode>&) const;
|
||||
|
||||
// database operations
|
||||
std::shared_ptr<SHAMapTreeNode> fetchNodeFromDB (uint256 const& hash) const;
|
||||
std::shared_ptr<SHAMapTreeNode> fetchNodeNT (uint256 const& hash) const;
|
||||
std::shared_ptr<SHAMapTreeNode> fetchNodeNT (
|
||||
std::shared_ptr<SHAMapAbstractNode> fetchNodeFromDB (uint256 const& hash) const;
|
||||
std::shared_ptr<SHAMapAbstractNode> fetchNodeNT (uint256 const& hash) const;
|
||||
std::shared_ptr<SHAMapAbstractNode> fetchNodeNT (
|
||||
SHAMapNodeID const& id,
|
||||
uint256 const& hash,
|
||||
SHAMapSyncFilter *filter) const;
|
||||
std::shared_ptr<SHAMapTreeNode> fetchNode (uint256 const& hash) const;
|
||||
std::shared_ptr<SHAMapTreeNode> checkFilter (uint256 const& hash, SHAMapNodeID const& id,
|
||||
SHAMapSyncFilter* filter) const;
|
||||
std::shared_ptr<SHAMapAbstractNode> fetchNode (uint256 const& hash) const;
|
||||
std::shared_ptr<SHAMapAbstractNode> checkFilter(uint256 const& hash,
|
||||
SHAMapNodeID const& id, SHAMapSyncFilter* filter) const;
|
||||
|
||||
/** Update hashes up to the root */
|
||||
void dirtyUp (SharedPtrNodeStack& stack,
|
||||
uint256 const& target, std::shared_ptr<SHAMapTreeNode> terminal);
|
||||
uint256 const& target, std::shared_ptr<SHAMapAbstractNode> terminal);
|
||||
|
||||
/** Get the path from the root to the specified node */
|
||||
SharedPtrNodeStack
|
||||
@@ -236,44 +236,50 @@ private:
|
||||
SHAMapTreeNode* walkToPointer (uint256 const& id) const;
|
||||
|
||||
/** Unshare the node, allowing it to be modified */
|
||||
void unshareNode (std::shared_ptr<SHAMapTreeNode>&, SHAMapNodeID const& nodeID);
|
||||
template <class Node>
|
||||
std::shared_ptr<Node>
|
||||
unshareNode(std::shared_ptr<Node>, SHAMapNodeID const& nodeID);
|
||||
|
||||
/** prepare a node to be modified before flushing */
|
||||
void preFlushNode (std::shared_ptr<SHAMapTreeNode>& node) const;
|
||||
template <class Node>
|
||||
std::shared_ptr<Node>
|
||||
preFlushNode(std::shared_ptr<Node> node) const;
|
||||
|
||||
/** write and canonicalize modified node */
|
||||
void writeNode (NodeObjectType t, std::uint32_t seq,
|
||||
std::shared_ptr<SHAMapTreeNode>& node) const;
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
writeNode(NodeObjectType t, std::uint32_t seq,
|
||||
std::shared_ptr<SHAMapAbstractNode> node) const;
|
||||
|
||||
SHAMapTreeNode* firstBelow (SHAMapTreeNode*) const;
|
||||
SHAMapTreeNode* lastBelow (SHAMapTreeNode*) const;
|
||||
SHAMapTreeNode* firstBelow (SHAMapAbstractNode*) const;
|
||||
SHAMapTreeNode* lastBelow (SHAMapAbstractNode*) const;
|
||||
|
||||
// Simple descent
|
||||
// Get a child of the specified node
|
||||
SHAMapTreeNode* descend (SHAMapTreeNode*, int branch) const;
|
||||
SHAMapTreeNode* descendThrow (SHAMapTreeNode*, int branch) const;
|
||||
std::shared_ptr<SHAMapTreeNode> descend (std::shared_ptr<SHAMapTreeNode> const&, int branch) const;
|
||||
std::shared_ptr<SHAMapTreeNode> descendThrow (std::shared_ptr<SHAMapTreeNode> const&, int branch) const;
|
||||
SHAMapAbstractNode* descend (SHAMapInnerNode*, int branch) const;
|
||||
SHAMapAbstractNode* descendThrow (SHAMapInnerNode*, int branch) const;
|
||||
std::shared_ptr<SHAMapAbstractNode> descend (std::shared_ptr<SHAMapInnerNode> const&, int branch) const;
|
||||
std::shared_ptr<SHAMapAbstractNode> descendThrow (std::shared_ptr<SHAMapInnerNode> const&, int branch) const;
|
||||
|
||||
// Descend with filter
|
||||
SHAMapTreeNode* descendAsync (SHAMapTreeNode* parent, int branch,
|
||||
SHAMapAbstractNode* descendAsync (SHAMapInnerNode* parent, int branch,
|
||||
SHAMapNodeID const& childID, SHAMapSyncFilter* filter, bool& pending) const;
|
||||
|
||||
std::pair <SHAMapTreeNode*, SHAMapNodeID>
|
||||
descend (SHAMapTreeNode* parent, SHAMapNodeID const& parentID,
|
||||
std::pair <SHAMapAbstractNode*, SHAMapNodeID>
|
||||
descend (SHAMapInnerNode* parent, SHAMapNodeID const& parentID,
|
||||
int branch, SHAMapSyncFilter* filter) const;
|
||||
|
||||
// Non-storing
|
||||
// Does not hook the returned node to its parent
|
||||
std::shared_ptr<SHAMapTreeNode> descendNoStore (std::shared_ptr<SHAMapTreeNode> const&, int branch) const;
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
descendNoStore (std::shared_ptr<SHAMapInnerNode> const&, int branch) const;
|
||||
|
||||
/** If there is only one leaf below this node, get its contents */
|
||||
std::shared_ptr<SHAMapItem> onlyBelow (SHAMapTreeNode*) const;
|
||||
std::shared_ptr<SHAMapItem> onlyBelow (SHAMapAbstractNode*) const;
|
||||
|
||||
bool hasInnerNode (SHAMapNodeID const& nodeID, uint256 const& hash) const;
|
||||
bool hasLeafNode (uint256 const& tag, uint256 const& hash) const;
|
||||
|
||||
bool walkBranch (SHAMapTreeNode* node,
|
||||
bool walkBranch (SHAMapAbstractNode* node,
|
||||
std::shared_ptr<SHAMapItem> const& otherMapItem, bool isFirstMap,
|
||||
Delta & differences, int & maxCount) const;
|
||||
int walkSubTree (bool doWrite, NodeObjectType t, std::uint32_t seq);
|
||||
|
||||
@@ -39,7 +39,7 @@ enum SHANodeFormat
|
||||
snfHASH = 3, // just the hash
|
||||
};
|
||||
|
||||
class SHAMapTreeNode
|
||||
class SHAMapAbstractNode
|
||||
{
|
||||
public:
|
||||
enum TNType
|
||||
@@ -51,112 +51,164 @@ public:
|
||||
tnACCOUNT_STATE = 4
|
||||
};
|
||||
|
||||
private:
|
||||
uint256 mHash;
|
||||
uint256 mHashes[16];
|
||||
std::shared_ptr<SHAMapTreeNode> mChildren[16];
|
||||
std::shared_ptr<SHAMapItem> mItem;
|
||||
std::uint32_t mSeq;
|
||||
protected:
|
||||
TNType mType;
|
||||
int mIsBranch;
|
||||
std::uint32_t mFullBelowGen;
|
||||
uint256 mHash;
|
||||
std::uint32_t mSeq;
|
||||
|
||||
protected:
|
||||
virtual ~SHAMapAbstractNode() = 0;
|
||||
SHAMapAbstractNode(SHAMapAbstractNode const&) = delete;
|
||||
SHAMapAbstractNode& operator=(SHAMapAbstractNode const&) = delete;
|
||||
|
||||
SHAMapAbstractNode(TNType type, std::uint32_t seq);
|
||||
SHAMapAbstractNode(TNType type, std::uint32_t seq, uint256 const& hash);
|
||||
|
||||
public:
|
||||
std::uint32_t getSeq () const;
|
||||
void setSeq (std::uint32_t s);
|
||||
uint256 const& getNodeHash () const;
|
||||
TNType getType () const;
|
||||
bool isLeaf () const;
|
||||
bool isInner () const;
|
||||
bool isValid () const;
|
||||
bool isInBounds (SHAMapNodeID const &id) const;
|
||||
|
||||
virtual bool updateHash () = 0;
|
||||
virtual void addRaw (Serializer&, SHANodeFormat format) = 0;
|
||||
virtual std::string getString (SHAMapNodeID const&) const;
|
||||
virtual std::shared_ptr<SHAMapAbstractNode> clone(std::uint32_t seq) const = 0;
|
||||
|
||||
static std::shared_ptr<SHAMapAbstractNode>
|
||||
make(Blob const& rawNode, std::uint32_t seq, SHANodeFormat format,
|
||||
uint256 const& hash, bool hashValid);
|
||||
|
||||
// debugging
|
||||
#ifdef BEAST_DEBUG
|
||||
static void dump (SHAMapNodeID const&, beast::Journal journal);
|
||||
#endif
|
||||
};
|
||||
|
||||
class SHAMapInnerNode
|
||||
: public SHAMapAbstractNode
|
||||
{
|
||||
uint256 mHashes[16];
|
||||
std::shared_ptr<SHAMapAbstractNode> mChildren[16];
|
||||
int mIsBranch = 0;
|
||||
std::uint32_t mFullBelowGen = 0;
|
||||
|
||||
static std::mutex childLock;
|
||||
public:
|
||||
SHAMapInnerNode(std::uint32_t seq = 0);
|
||||
std::shared_ptr<SHAMapAbstractNode> clone(std::uint32_t seq) const override;
|
||||
|
||||
bool isEmpty () const;
|
||||
bool isEmptyBranch (int m) const;
|
||||
int getBranchCount () const;
|
||||
uint256 const& getChildHash (int m) const;
|
||||
|
||||
void setChild(int m, std::shared_ptr<SHAMapAbstractNode> const& child);
|
||||
void shareChild (int m, std::shared_ptr<SHAMapAbstractNode> const& child);
|
||||
SHAMapAbstractNode* getChildPointer (int branch);
|
||||
std::shared_ptr<SHAMapAbstractNode> getChild (int branch);
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
canonicalizeChild (int branch, std::shared_ptr<SHAMapAbstractNode> node);
|
||||
|
||||
// sync functions
|
||||
bool isFullBelow (std::uint32_t generation) const;
|
||||
void setFullBelowGen (std::uint32_t gen);
|
||||
|
||||
bool updateHash () override;
|
||||
void updateHashDeep();
|
||||
void addRaw (Serializer&, SHANodeFormat format) override;
|
||||
std::string getString (SHAMapNodeID const&) const override;
|
||||
|
||||
friend std::shared_ptr<SHAMapAbstractNode>
|
||||
SHAMapAbstractNode::make(Blob const& rawNode, std::uint32_t seq,
|
||||
SHANodeFormat format, uint256 const& hash, bool hashValid);
|
||||
};
|
||||
|
||||
// SHAMapTreeNode represents a leaf, and may eventually be renamed to reflect that.
|
||||
class SHAMapTreeNode
|
||||
: public SHAMapAbstractNode
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<SHAMapItem> mItem;
|
||||
|
||||
public:
|
||||
SHAMapTreeNode (const SHAMapTreeNode&) = delete;
|
||||
SHAMapTreeNode& operator= (const SHAMapTreeNode&) = delete;
|
||||
|
||||
SHAMapTreeNode (std::uint32_t seq); // empty node
|
||||
SHAMapTreeNode (const SHAMapTreeNode & node, std::uint32_t seq); // copy node from older tree
|
||||
SHAMapTreeNode (std::shared_ptr<SHAMapItem> const& item, TNType type, std::uint32_t seq);
|
||||
SHAMapTreeNode (Blob const & data, std::uint32_t seq,
|
||||
SHANodeFormat format, uint256 const& hash, bool hashValid);
|
||||
SHAMapTreeNode(std::shared_ptr<SHAMapItem> const& item, TNType type,
|
||||
std::uint32_t seq, uint256 const& hash);
|
||||
std::shared_ptr<SHAMapAbstractNode> clone(std::uint32_t seq) const override;
|
||||
|
||||
void addRaw (Serializer&, SHANodeFormat format);
|
||||
uint256 const& getNodeHash () const;
|
||||
void addRaw (Serializer&, SHANodeFormat format) override;
|
||||
|
||||
public: // public only to SHAMap
|
||||
void setChild (int m, std::shared_ptr<SHAMapTreeNode> const& child);
|
||||
void shareChild (int m, std::shared_ptr<SHAMapTreeNode> const& child);
|
||||
|
||||
// node functions
|
||||
std::uint32_t getSeq () const;
|
||||
void setSeq (std::uint32_t s);
|
||||
TNType getType () const;
|
||||
|
||||
// type functions
|
||||
bool isLeaf () const;
|
||||
bool isInner () const;
|
||||
bool isInBounds (SHAMapNodeID const &id) const;
|
||||
bool isValid () const;
|
||||
|
||||
// inner node functions
|
||||
bool isInnerNode () const;
|
||||
bool isEmptyBranch (int m) const;
|
||||
bool isEmpty () const;
|
||||
int getBranchCount () const;
|
||||
void makeInner ();
|
||||
uint256 const& getChildHash (int m) const;
|
||||
|
||||
// item node function
|
||||
bool hasItem () const;
|
||||
std::shared_ptr<SHAMapItem> const& peekItem () const;
|
||||
bool setItem (std::shared_ptr<SHAMapItem> const& i, TNType type);
|
||||
|
||||
// sync functions
|
||||
bool isFullBelow (std::uint32_t generation) const;
|
||||
void setFullBelowGen (std::uint32_t gen);
|
||||
|
||||
SHAMapTreeNode* getChildPointer (int branch);
|
||||
std::shared_ptr<SHAMapTreeNode> getChild (int branch);
|
||||
void canonicalizeChild (int branch, std::shared_ptr<SHAMapTreeNode>& node);
|
||||
|
||||
// debugging
|
||||
#ifdef BEAST_DEBUG
|
||||
void dump (SHAMapNodeID const&, beast::Journal journal);
|
||||
#endif
|
||||
std::string getString (SHAMapNodeID const&) const;
|
||||
bool updateHash ();
|
||||
void updateHashDeep();
|
||||
|
||||
private:
|
||||
bool isTransaction () const;
|
||||
bool hasMetaData () const;
|
||||
bool isAccountState () const;
|
||||
std::string getString (SHAMapNodeID const&) const override;
|
||||
bool updateHash () override;
|
||||
};
|
||||
|
||||
// SHAMapAbstractNode
|
||||
|
||||
inline
|
||||
SHAMapAbstractNode::SHAMapAbstractNode(TNType type, std::uint32_t seq)
|
||||
: mType(type)
|
||||
, mSeq(seq)
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
SHAMapAbstractNode::SHAMapAbstractNode(TNType type, std::uint32_t seq,
|
||||
uint256 const& hash)
|
||||
: mType(type)
|
||||
, mHash(hash)
|
||||
, mSeq(seq)
|
||||
{
|
||||
}
|
||||
|
||||
inline
|
||||
std::uint32_t
|
||||
SHAMapTreeNode::getSeq () const
|
||||
SHAMapAbstractNode::getSeq () const
|
||||
{
|
||||
return mSeq;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
SHAMapTreeNode::setSeq (std::uint32_t s)
|
||||
SHAMapAbstractNode::setSeq (std::uint32_t s)
|
||||
{
|
||||
mSeq = s;
|
||||
}
|
||||
|
||||
inline
|
||||
uint256 const&
|
||||
SHAMapTreeNode::getNodeHash () const
|
||||
SHAMapAbstractNode::getNodeHash () const
|
||||
{
|
||||
return mHash;
|
||||
}
|
||||
|
||||
inline
|
||||
SHAMapTreeNode::TNType
|
||||
SHAMapTreeNode::getType () const
|
||||
SHAMapAbstractNode::TNType
|
||||
SHAMapAbstractNode::getType () const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapTreeNode::isLeaf () const
|
||||
SHAMapAbstractNode::isLeaf () const
|
||||
{
|
||||
return (mType == tnTRANSACTION_NM) || (mType == tnTRANSACTION_MD) ||
|
||||
(mType == tnACCOUNT_STATE);
|
||||
@@ -164,69 +216,72 @@ SHAMapTreeNode::isLeaf () const
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapTreeNode::isInner () const
|
||||
SHAMapAbstractNode::isInner () const
|
||||
{
|
||||
return mType == tnINNER;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapTreeNode::isInBounds (SHAMapNodeID const &id) const
|
||||
{
|
||||
// Nodes at depth 64 must be leaves
|
||||
return (!isInner() || (id.getDepth() < 64));
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapTreeNode::isValid () const
|
||||
SHAMapAbstractNode::isValid () const
|
||||
{
|
||||
return mType != tnERROR;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapTreeNode::isTransaction () const
|
||||
SHAMapAbstractNode::isInBounds (SHAMapNodeID const &id) const
|
||||
{
|
||||
// Nodes at depth 64 must be leaves
|
||||
return (!isInner() || (id.getDepth() < 64));
|
||||
}
|
||||
|
||||
// SHAMapInnerNode
|
||||
|
||||
inline
|
||||
SHAMapInnerNode::SHAMapInnerNode(std::uint32_t seq)
|
||||
: SHAMapAbstractNode(tnINNER, seq)
|
||||
{
|
||||
return (mType == tnTRANSACTION_NM) || (mType == tnTRANSACTION_MD);
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapTreeNode::hasMetaData () const
|
||||
{
|
||||
return mType == tnTRANSACTION_MD;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapTreeNode::isAccountState () const
|
||||
{
|
||||
return mType == tnACCOUNT_STATE;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapTreeNode::isInnerNode () const
|
||||
{
|
||||
return !mItem;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapTreeNode::isEmptyBranch (int m) const
|
||||
SHAMapInnerNode::isEmptyBranch (int m) const
|
||||
{
|
||||
return (mIsBranch & (1 << m)) == 0;
|
||||
}
|
||||
|
||||
inline
|
||||
uint256 const&
|
||||
SHAMapTreeNode::getChildHash (int m) const
|
||||
SHAMapInnerNode::getChildHash (int m) const
|
||||
{
|
||||
assert ((m >= 0) && (m < 16) && (mType == tnINNER));
|
||||
assert ((m >= 0) && (m < 16) && (getType() == tnINNER));
|
||||
return mHashes[m];
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapInnerNode::isFullBelow (std::uint32_t generation) const
|
||||
{
|
||||
return mFullBelowGen == generation;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
SHAMapInnerNode::setFullBelowGen (std::uint32_t gen)
|
||||
{
|
||||
mFullBelowGen = gen;
|
||||
}
|
||||
|
||||
// SHAMapTreeNode
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapTreeNode::isInnerNode () const
|
||||
{
|
||||
return !mItem;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapTreeNode::hasItem () const
|
||||
@@ -241,20 +296,6 @@ SHAMapTreeNode::peekItem () const
|
||||
return mItem;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
SHAMapTreeNode::isFullBelow (std::uint32_t generation) const
|
||||
{
|
||||
return mFullBelowGen == generation;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
SHAMapTreeNode::setFullBelowGen (std::uint32_t gen)
|
||||
{
|
||||
mFullBelowGen = gen;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class SHAMapTreeNode;
|
||||
class SHAMapAbstractNode;
|
||||
|
||||
using TreeNodeCache = TaggedCache <uint256, SHAMapTreeNode>;
|
||||
using TreeNodeCache = TaggedCache <uint256, SHAMapAbstractNode>;
|
||||
|
||||
} // ripple
|
||||
|
||||
|
||||
@@ -38,8 +38,7 @@ SHAMap::SHAMap (
|
||||
{
|
||||
assert (seq_ != 0);
|
||||
|
||||
root_ = std::make_shared<SHAMapTreeNode> (seq_);
|
||||
root_->makeInner ();
|
||||
root_ = std::make_shared<SHAMapInnerNode> (seq_);
|
||||
}
|
||||
|
||||
SHAMap::SHAMap (
|
||||
@@ -54,8 +53,7 @@ SHAMap::SHAMap (
|
||||
, state_ (SHAMapState::Synching)
|
||||
, type_ (t)
|
||||
{
|
||||
root_ = std::make_shared<SHAMapTreeNode> (seq_);
|
||||
root_->makeInner ();
|
||||
root_ = std::make_shared<SHAMapInnerNode> (seq_);
|
||||
}
|
||||
|
||||
SHAMap::~SHAMap ()
|
||||
@@ -91,7 +89,7 @@ SHAMap::getStack (uint256 const& id, bool include_nonmatching_leaf) const
|
||||
// produce a stack of nodes along the way, with the terminal node at the top
|
||||
SharedPtrNodeStack stack;
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> node = root_;
|
||||
std::shared_ptr<SHAMapAbstractNode> node = root_;
|
||||
SHAMapNodeID nodeID;
|
||||
|
||||
while (!node->isLeaf ())
|
||||
@@ -100,15 +98,16 @@ SHAMap::getStack (uint256 const& id, bool include_nonmatching_leaf) const
|
||||
|
||||
int branch = nodeID.selectBranch (id);
|
||||
assert (branch >= 0);
|
||||
|
||||
if (node->isEmptyBranch (branch))
|
||||
auto inner = std::static_pointer_cast<SHAMapInnerNode>(std::move(node));
|
||||
if (inner->isEmptyBranch (branch))
|
||||
return stack;
|
||||
|
||||
node = descendThrow (node, branch);
|
||||
node = descendThrow (inner, branch);
|
||||
nodeID = nodeID.getChildNodeID (branch);
|
||||
}
|
||||
|
||||
if (include_nonmatching_leaf || (node->peekItem ()->getTag () == id))
|
||||
if (include_nonmatching_leaf ||
|
||||
(std::static_pointer_cast<SHAMapTreeNode>(node)->peekItem()->getTag() == id))
|
||||
stack.push ({node, nodeID});
|
||||
|
||||
return stack;
|
||||
@@ -116,7 +115,7 @@ SHAMap::getStack (uint256 const& id, bool include_nonmatching_leaf) const
|
||||
|
||||
void
|
||||
SHAMap::dirtyUp (SharedPtrNodeStack& stack,
|
||||
uint256 const& target, std::shared_ptr<SHAMapTreeNode> child)
|
||||
uint256 const& target, std::shared_ptr<SHAMapAbstractNode> child)
|
||||
{
|
||||
// walk the tree up from through the inner nodes to the root_
|
||||
// update hashes and links
|
||||
@@ -128,15 +127,15 @@ SHAMap::dirtyUp (SharedPtrNodeStack& stack,
|
||||
|
||||
while (!stack.empty ())
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> node = stack.top ().first;
|
||||
auto node = std::dynamic_pointer_cast<SHAMapInnerNode>(stack.top ().first);
|
||||
SHAMapNodeID nodeID = stack.top ().second;
|
||||
stack.pop ();
|
||||
assert (node->isInnerNode ());
|
||||
assert (node != nullptr);
|
||||
|
||||
int branch = nodeID.selectBranch (target);
|
||||
assert (branch >= 0);
|
||||
|
||||
unshareNode (node, nodeID);
|
||||
node = unshareNode(std::move(node), nodeID);
|
||||
node->setChild (branch, child);
|
||||
|
||||
#ifdef ST_DEBUG
|
||||
@@ -149,28 +148,29 @@ SHAMap::dirtyUp (SharedPtrNodeStack& stack,
|
||||
|
||||
SHAMapTreeNode* SHAMap::walkToPointer (uint256 const& id) const
|
||||
{
|
||||
SHAMapTreeNode* inNode = root_.get ();
|
||||
auto inNode = root_.get();
|
||||
SHAMapNodeID nodeID;
|
||||
uint256 nodeHash;
|
||||
|
||||
while (inNode->isInner ())
|
||||
{
|
||||
int branch = nodeID.selectBranch (id);
|
||||
|
||||
if (inNode->isEmptyBranch (branch))
|
||||
auto inner = static_cast<SHAMapInnerNode*>(inNode);
|
||||
if (inner->isEmptyBranch (branch))
|
||||
return nullptr;
|
||||
|
||||
inNode = descendThrow (inNode, branch);
|
||||
inNode = descendThrow (inner, branch);
|
||||
nodeID = nodeID.getChildNodeID (branch);
|
||||
}
|
||||
|
||||
return (inNode->peekItem()->getTag () == id) ? inNode : nullptr;
|
||||
auto ret = static_cast<SHAMapTreeNode*>(inNode);
|
||||
return ret->peekItem()->getTag() == id ? ret : nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode>
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
SHAMap::fetchNodeFromDB (uint256 const& hash) const
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> node;
|
||||
std::shared_ptr<SHAMapAbstractNode> node;
|
||||
|
||||
if (backed_)
|
||||
{
|
||||
@@ -179,7 +179,7 @@ SHAMap::fetchNodeFromDB (uint256 const& hash) const
|
||||
{
|
||||
try
|
||||
{
|
||||
node = std::make_shared <SHAMapTreeNode> (obj->getData(),
|
||||
node = SHAMapAbstractNode::make(obj->getData(),
|
||||
0, snfPREFIX, hash, true);
|
||||
canonicalize (hash, node);
|
||||
}
|
||||
@@ -201,36 +201,30 @@ SHAMap::fetchNodeFromDB (uint256 const& hash) const
|
||||
}
|
||||
|
||||
// See if a sync filter has a node
|
||||
std::shared_ptr<SHAMapTreeNode> SHAMap::checkFilter (
|
||||
uint256 const& hash,
|
||||
SHAMapNodeID const& id,
|
||||
SHAMapSyncFilter* filter) const
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
SHAMap::checkFilter(uint256 const& hash, SHAMapNodeID const& id,
|
||||
SHAMapSyncFilter* filter) const
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> node;
|
||||
std::shared_ptr<SHAMapAbstractNode> node;
|
||||
Blob nodeData;
|
||||
|
||||
if (filter->haveNode (id, hash, nodeData))
|
||||
{
|
||||
node = std::make_shared <SHAMapTreeNode> (
|
||||
nodeData, 0, snfPREFIX, hash, true);
|
||||
|
||||
filter->gotNode (true, id, hash, nodeData, node->getType ());
|
||||
|
||||
if (backed_)
|
||||
canonicalize (hash, node);
|
||||
node = SHAMapAbstractNode::make(nodeData, 0, snfPREFIX, hash, true);
|
||||
filter->gotNode (true, id, hash, nodeData, node->getType ());
|
||||
if (backed_)
|
||||
canonicalize (hash, node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// Get a node without throwing
|
||||
// Used on maps where missing nodes are expected
|
||||
std::shared_ptr<SHAMapTreeNode> SHAMap::fetchNodeNT(
|
||||
std::shared_ptr<SHAMapAbstractNode> SHAMap::fetchNodeNT(
|
||||
SHAMapNodeID const& id,
|
||||
uint256 const& hash,
|
||||
SHAMapSyncFilter* filter) const
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> node = getCache (hash);
|
||||
std::shared_ptr<SHAMapAbstractNode> node = getCache (hash);
|
||||
if (node)
|
||||
return node;
|
||||
|
||||
@@ -250,9 +244,9 @@ std::shared_ptr<SHAMapTreeNode> SHAMap::fetchNodeNT(
|
||||
return node;
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> SHAMap::fetchNodeNT (uint256 const& hash) const
|
||||
std::shared_ptr<SHAMapAbstractNode> SHAMap::fetchNodeNT (uint256 const& hash) const
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> node = getCache (hash);
|
||||
auto node = getCache (hash);
|
||||
|
||||
if (!node && backed_)
|
||||
node = fetchNodeFromDB (hash);
|
||||
@@ -261,9 +255,9 @@ std::shared_ptr<SHAMapTreeNode> SHAMap::fetchNodeNT (uint256 const& hash) const
|
||||
}
|
||||
|
||||
// Throw if the node is missing
|
||||
std::shared_ptr<SHAMapTreeNode> SHAMap::fetchNode (uint256 const& hash) const
|
||||
std::shared_ptr<SHAMapAbstractNode> SHAMap::fetchNode (uint256 const& hash) const
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> node = fetchNodeNT (hash);
|
||||
auto node = fetchNodeNT (hash);
|
||||
|
||||
if (!node)
|
||||
throw SHAMapMissingNode (type_, hash);
|
||||
@@ -271,9 +265,9 @@ std::shared_ptr<SHAMapTreeNode> SHAMap::fetchNode (uint256 const& hash) const
|
||||
return node;
|
||||
}
|
||||
|
||||
SHAMapTreeNode* SHAMap::descendThrow (SHAMapTreeNode* parent, int branch) const
|
||||
SHAMapAbstractNode* SHAMap::descendThrow (SHAMapInnerNode* parent, int branch) const
|
||||
{
|
||||
SHAMapTreeNode* ret = descend (parent, branch);
|
||||
SHAMapAbstractNode* ret = descend (parent, branch);
|
||||
|
||||
if (! ret && ! parent->isEmptyBranch (branch))
|
||||
throw SHAMapMissingNode (type_, parent->getChildHash (branch));
|
||||
@@ -281,10 +275,10 @@ SHAMapTreeNode* SHAMap::descendThrow (SHAMapTreeNode* parent, int branch) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode>
|
||||
SHAMap::descendThrow (std::shared_ptr<SHAMapTreeNode> const& parent, int branch) const
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
SHAMap::descendThrow (std::shared_ptr<SHAMapInnerNode> const& parent, int branch) const
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> ret = descend (parent, branch);
|
||||
std::shared_ptr<SHAMapAbstractNode> ret = descend (parent, branch);
|
||||
|
||||
if (! ret && ! parent->isEmptyBranch (branch))
|
||||
throw SHAMapMissingNode (type_, parent->getChildHash (branch));
|
||||
@@ -292,24 +286,24 @@ SHAMap::descendThrow (std::shared_ptr<SHAMapTreeNode> const& parent, int branch)
|
||||
return ret;
|
||||
}
|
||||
|
||||
SHAMapTreeNode* SHAMap::descend (SHAMapTreeNode* parent, int branch) const
|
||||
SHAMapAbstractNode* SHAMap::descend (SHAMapInnerNode* parent, int branch) const
|
||||
{
|
||||
SHAMapTreeNode* ret = parent->getChildPointer (branch);
|
||||
SHAMapAbstractNode* ret = parent->getChildPointer (branch);
|
||||
if (ret || !backed_)
|
||||
return ret;
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> node = fetchNodeNT (parent->getChildHash (branch));
|
||||
std::shared_ptr<SHAMapAbstractNode> node = fetchNodeNT (parent->getChildHash (branch));
|
||||
if (!node)
|
||||
return nullptr;
|
||||
|
||||
parent->canonicalizeChild (branch, node);
|
||||
node = parent->canonicalizeChild (branch, std::move(node));
|
||||
return node.get ();
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode>
|
||||
SHAMap::descend (std::shared_ptr<SHAMapTreeNode> const& parent, int branch) const
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
SHAMap::descend (std::shared_ptr<SHAMapInnerNode> const& parent, int branch) const
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> node = parent->getChild (branch);
|
||||
std::shared_ptr<SHAMapAbstractNode> node = parent->getChild (branch);
|
||||
if (node || !backed_)
|
||||
return node;
|
||||
|
||||
@@ -317,23 +311,23 @@ SHAMap::descend (std::shared_ptr<SHAMapTreeNode> const& parent, int branch) cons
|
||||
if (!node)
|
||||
return nullptr;
|
||||
|
||||
parent->canonicalizeChild (branch, node);
|
||||
node = parent->canonicalizeChild (branch, std::move(node));
|
||||
return node;
|
||||
}
|
||||
|
||||
// Gets the node that would be hooked to this branch,
|
||||
// but doesn't hook it up.
|
||||
std::shared_ptr<SHAMapTreeNode>
|
||||
SHAMap::descendNoStore (std::shared_ptr<SHAMapTreeNode> const& parent, int branch) const
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
SHAMap::descendNoStore (std::shared_ptr<SHAMapInnerNode> const& parent, int branch) const
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> ret = parent->getChild (branch);
|
||||
std::shared_ptr<SHAMapAbstractNode> ret = parent->getChild (branch);
|
||||
if (!ret && backed_)
|
||||
ret = fetchNode (parent->getChildHash (branch));
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::pair <SHAMapTreeNode*, SHAMapNodeID>
|
||||
SHAMap::descend (SHAMapTreeNode * parent, SHAMapNodeID const& parentID,
|
||||
std::pair <SHAMapAbstractNode*, SHAMapNodeID>
|
||||
SHAMap::descend (SHAMapInnerNode * parent, SHAMapNodeID const& parentID,
|
||||
int branch, SHAMapSyncFilter * filter) const
|
||||
{
|
||||
assert (parent->isInner ());
|
||||
@@ -341,16 +335,16 @@ SHAMap::descend (SHAMapTreeNode * parent, SHAMapNodeID const& parentID,
|
||||
assert (!parent->isEmptyBranch (branch));
|
||||
|
||||
SHAMapNodeID childID = parentID.getChildNodeID (branch);
|
||||
SHAMapTreeNode* child = parent->getChildPointer (branch);
|
||||
SHAMapAbstractNode* child = parent->getChildPointer (branch);
|
||||
uint256 const& childHash = parent->getChildHash (branch);
|
||||
|
||||
if (!child)
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> childNode = fetchNodeNT (childID, childHash, filter);
|
||||
std::shared_ptr<SHAMapAbstractNode> childNode = fetchNodeNT (childID, childHash, filter);
|
||||
|
||||
if (childNode)
|
||||
{
|
||||
parent->canonicalizeChild (branch, childNode);
|
||||
childNode = parent->canonicalizeChild (branch, std::move(childNode));
|
||||
child = childNode.get ();
|
||||
}
|
||||
}
|
||||
@@ -358,18 +352,19 @@ SHAMap::descend (SHAMapTreeNode * parent, SHAMapNodeID const& parentID,
|
||||
return std::make_pair (child, childID);
|
||||
}
|
||||
|
||||
SHAMapTreeNode* SHAMap::descendAsync (SHAMapTreeNode* parent, int branch,
|
||||
SHAMapAbstractNode*
|
||||
SHAMap::descendAsync (SHAMapInnerNode* parent, int branch,
|
||||
SHAMapNodeID const& childID, SHAMapSyncFilter * filter, bool & pending) const
|
||||
{
|
||||
pending = false;
|
||||
|
||||
SHAMapTreeNode* ret = parent->getChildPointer (branch);
|
||||
SHAMapAbstractNode* ret = parent->getChildPointer (branch);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uint256 const& hash = parent->getChildHash (branch);
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> ptr = getCache (hash);
|
||||
std::shared_ptr<SHAMapAbstractNode> ptr = getCache (hash);
|
||||
if (!ptr)
|
||||
{
|
||||
if (filter)
|
||||
@@ -386,7 +381,7 @@ SHAMapTreeNode* SHAMap::descendAsync (SHAMapTreeNode* parent, int branch,
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
ptr = std::make_shared <SHAMapTreeNode> (obj->getData(), 0, snfPREFIX, hash, true);
|
||||
ptr = SHAMapAbstractNode::make(obj->getData(), 0, snfPREFIX, hash, true);
|
||||
|
||||
if (backed_)
|
||||
canonicalize (hash, ptr);
|
||||
@@ -394,49 +389,49 @@ SHAMapTreeNode* SHAMap::descendAsync (SHAMapTreeNode* parent, int branch,
|
||||
}
|
||||
|
||||
if (ptr)
|
||||
parent->canonicalizeChild (branch, ptr);
|
||||
ptr = parent->canonicalizeChild (branch, std::move(ptr));
|
||||
|
||||
return ptr.get ();
|
||||
}
|
||||
|
||||
void
|
||||
SHAMap::unshareNode (std::shared_ptr<SHAMapTreeNode>& node, SHAMapNodeID const& nodeID)
|
||||
template <class Node>
|
||||
std::shared_ptr<Node>
|
||||
SHAMap::unshareNode (std::shared_ptr<Node> node, SHAMapNodeID const& nodeID)
|
||||
{
|
||||
// make sure the node is suitable for the intended operation (copy on write)
|
||||
assert (node->isValid ());
|
||||
assert (node->getSeq () <= seq_);
|
||||
|
||||
if (node->getSeq () != seq_)
|
||||
{
|
||||
// have a CoW
|
||||
assert (state_ != SHAMapState::Immutable);
|
||||
|
||||
node = std::make_shared<SHAMapTreeNode> (*node, seq_); // here's to the new node, same as the old node
|
||||
node = std::static_pointer_cast<Node>(node->clone(seq_));
|
||||
assert (node->isValid ());
|
||||
|
||||
if (nodeID.isRoot ())
|
||||
root_ = node;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
SHAMapTreeNode*
|
||||
SHAMap::firstBelow (SHAMapTreeNode* node) const
|
||||
SHAMap::firstBelow (SHAMapAbstractNode* node) const
|
||||
{
|
||||
// Return the first item below this node
|
||||
do
|
||||
{
|
||||
assert(node != nullptr);
|
||||
|
||||
if (node->hasItem ())
|
||||
return node;
|
||||
if (node->isLeaf ())
|
||||
return static_cast<SHAMapTreeNode*>(node);
|
||||
|
||||
// Walk down the tree
|
||||
bool foundNode = false;
|
||||
auto inner = static_cast<SHAMapInnerNode*>(node);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
if (!node->isEmptyBranch (i))
|
||||
if (!inner->isEmptyBranch (i))
|
||||
{
|
||||
node = descendThrow (node, i);
|
||||
node = descendThrow (inner, i);
|
||||
foundNode = true;
|
||||
break;
|
||||
}
|
||||
@@ -448,20 +443,21 @@ SHAMap::firstBelow (SHAMapTreeNode* node) const
|
||||
}
|
||||
|
||||
SHAMapTreeNode*
|
||||
SHAMap::lastBelow (SHAMapTreeNode* node) const
|
||||
SHAMap::lastBelow (SHAMapAbstractNode* node) const
|
||||
{
|
||||
do
|
||||
{
|
||||
if (node->hasItem ())
|
||||
return node;
|
||||
if (node->isLeaf ())
|
||||
return static_cast<SHAMapTreeNode*>(node);
|
||||
|
||||
// Walk down the tree
|
||||
bool foundNode = false;
|
||||
auto inner = static_cast<SHAMapInnerNode*>(node);
|
||||
for (int i = 15; i >= 0; --i)
|
||||
{
|
||||
if (!node->isEmptyBranch (i))
|
||||
if (!inner->isEmptyBranch (i))
|
||||
{
|
||||
node = descendThrow (node, i);
|
||||
node = descendThrow (inner, i);
|
||||
foundNode = true;
|
||||
break;
|
||||
}
|
||||
@@ -473,21 +469,22 @@ SHAMap::lastBelow (SHAMapTreeNode* node) const
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAMapItem>
|
||||
SHAMap::onlyBelow (SHAMapTreeNode* node) const
|
||||
SHAMap::onlyBelow (SHAMapAbstractNode* node) const
|
||||
{
|
||||
// If there is only one item below this node, return it
|
||||
|
||||
while (!node->isLeaf ())
|
||||
{
|
||||
SHAMapTreeNode* nextNode = nullptr;
|
||||
SHAMapAbstractNode* nextNode = nullptr;
|
||||
auto inner = static_cast<SHAMapInnerNode*>(node);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
if (!node->isEmptyBranch (i))
|
||||
if (!inner->isEmptyBranch (i))
|
||||
{
|
||||
if (nextNode)
|
||||
return std::shared_ptr<SHAMapItem> ();
|
||||
|
||||
nextNode = descendThrow (node, i);
|
||||
nextNode = descendThrow (inner, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,9 +499,10 @@ SHAMap::onlyBelow (SHAMapTreeNode* node) const
|
||||
|
||||
// An inner node must have at least one leaf
|
||||
// below it, unless it's the root_
|
||||
assert (node->hasItem () || (node == root_.get ()));
|
||||
auto leaf = static_cast<SHAMapTreeNode*>(node);
|
||||
assert (leaf->hasItem () || (leaf == root_.get ()));
|
||||
|
||||
return node->peekItem ();
|
||||
return leaf->peekItem ();
|
||||
}
|
||||
|
||||
static std::shared_ptr<
|
||||
@@ -559,7 +557,8 @@ std::shared_ptr<SHAMapItem> SHAMap::peekNextItem (uint256 const& id) const
|
||||
return peekNextItem (id, type);
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAMapItem> SHAMap::peekNextItem (uint256 const& id, SHAMapTreeNode::TNType& type) const
|
||||
std::shared_ptr<SHAMapItem>
|
||||
SHAMap::peekNextItem (uint256 const& id, SHAMapTreeNode::TNType& type) const
|
||||
{
|
||||
// Get a pointer to the next item in the tree after a given item - item need not be in tree
|
||||
|
||||
@@ -567,32 +566,34 @@ std::shared_ptr<SHAMapItem> SHAMap::peekNextItem (uint256 const& id, SHAMapTreeN
|
||||
|
||||
while (!stack.empty ())
|
||||
{
|
||||
SHAMapTreeNode* node = stack.top().first.get();
|
||||
SHAMapNodeID nodeID = stack.top().second;
|
||||
auto node = stack.top().first.get();
|
||||
auto nodeID = stack.top().second;
|
||||
stack.pop ();
|
||||
|
||||
if (node->isLeaf ())
|
||||
{
|
||||
if (node->peekItem ()->getTag () > id)
|
||||
auto leaf = static_cast<SHAMapTreeNode*>(node);
|
||||
if (leaf->peekItem ()->getTag () > id)
|
||||
{
|
||||
type = node->getType ();
|
||||
return node->peekItem ();
|
||||
type = leaf->getType ();
|
||||
return leaf->peekItem ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// breadth-first
|
||||
auto inner = static_cast<SHAMapInnerNode*>(node);
|
||||
for (int i = nodeID.selectBranch (id) + 1; i < 16; ++i)
|
||||
if (!node->isEmptyBranch (i))
|
||||
if (!inner->isEmptyBranch (i))
|
||||
{
|
||||
node = descendThrow (node, i);
|
||||
node = firstBelow (node);
|
||||
node = descendThrow (inner, i);
|
||||
auto leaf = firstBelow (node);
|
||||
|
||||
if (!node || node->isInner ())
|
||||
if (!leaf)
|
||||
throw (std::runtime_error ("missing/corrupt node"));
|
||||
|
||||
type = node->getType ();
|
||||
return node->peekItem ();
|
||||
type = leaf->getType ();
|
||||
return leaf->peekItem ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -602,30 +603,33 @@ std::shared_ptr<SHAMapItem> SHAMap::peekNextItem (uint256 const& id, SHAMapTreeN
|
||||
}
|
||||
|
||||
// Get a pointer to the previous item in the tree after a given item - item need not be in tree
|
||||
std::shared_ptr<SHAMapItem> SHAMap::peekPrevItem (uint256 const& id) const
|
||||
std::shared_ptr<SHAMapItem>
|
||||
SHAMap::peekPrevItem (uint256 const& id) const
|
||||
{
|
||||
auto stack = getStack (id, true);
|
||||
|
||||
while (!stack.empty ())
|
||||
{
|
||||
SHAMapTreeNode* node = stack.top ().first.get();
|
||||
SHAMapNodeID nodeID = stack.top ().second;
|
||||
auto node = stack.top ().first.get();
|
||||
auto nodeID = stack.top ().second;
|
||||
stack.pop ();
|
||||
|
||||
if (node->isLeaf ())
|
||||
{
|
||||
if (node->peekItem ()->getTag () < id)
|
||||
return node->peekItem ();
|
||||
auto leaf = static_cast<SHAMapTreeNode*>(node);
|
||||
if (leaf->peekItem ()->getTag () < id)
|
||||
return leaf->peekItem ();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto inner = static_cast<SHAMapInnerNode*>(node);
|
||||
for (int i = nodeID.selectBranch (id) - 1; i >= 0; --i)
|
||||
{
|
||||
if (!node->isEmptyBranch (i))
|
||||
if (!inner->isEmptyBranch (i))
|
||||
{
|
||||
node = descendThrow (node, i);
|
||||
node = lastBelow (node);
|
||||
return node->peekItem ();
|
||||
node = descendThrow (inner, i);
|
||||
auto leaf = lastBelow (node);
|
||||
return leaf->peekItem ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -685,10 +689,10 @@ bool SHAMap::delItem (uint256 const& id)
|
||||
if (stack.empty ())
|
||||
throw (std::runtime_error ("missing node"));
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> leaf = stack.top ().first;
|
||||
auto leaf = std::dynamic_pointer_cast<SHAMapTreeNode>(stack.top ().first);
|
||||
stack.pop ();
|
||||
|
||||
if (!leaf || !leaf->hasItem () || (leaf->peekItem ()->getTag () != id))
|
||||
if (!leaf || (leaf->peekItem ()->getTag () != id))
|
||||
return false;
|
||||
|
||||
SHAMapTreeNode::TNType type = leaf->getType ();
|
||||
@@ -696,17 +700,17 @@ bool SHAMap::delItem (uint256 const& id)
|
||||
// What gets attached to the end of the chain
|
||||
// (For now, nothing, since we deleted the leaf)
|
||||
uint256 prevHash;
|
||||
std::shared_ptr<SHAMapTreeNode> prevNode;
|
||||
std::shared_ptr<SHAMapAbstractNode> prevNode;
|
||||
|
||||
while (!stack.empty ())
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> node = stack.top ().first;
|
||||
auto node = std::dynamic_pointer_cast<SHAMapInnerNode>(stack.top ().first);
|
||||
SHAMapNodeID nodeID = stack.top ().second;
|
||||
stack.pop ();
|
||||
|
||||
assert (node->isInner ());
|
||||
assert (node);
|
||||
|
||||
unshareNode (node, nodeID);
|
||||
node = unshareNode(std::move(node), nodeID);
|
||||
node->setChild (nodeID.selectBranch (id), prevNode);
|
||||
|
||||
if (!nodeID.isRoot ())
|
||||
@@ -736,11 +740,14 @@ bool SHAMap::delItem (uint256 const& id)
|
||||
break;
|
||||
}
|
||||
}
|
||||
node->setItem (item, type);
|
||||
prevNode = std::make_shared<SHAMapTreeNode>(item, type, node->getSeq());
|
||||
prevHash = prevNode->getNodeHash();
|
||||
}
|
||||
else
|
||||
{
|
||||
prevHash = node->getNodeHash ();
|
||||
prevNode = std::move (node);
|
||||
}
|
||||
|
||||
prevHash = node->getNodeHash ();
|
||||
prevNode = std::move (node);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -770,29 +777,34 @@ SHAMap::addGiveItem (std::shared_ptr<SHAMapItem> const& item,
|
||||
if (stack.empty ())
|
||||
throw (std::runtime_error ("missing node"));
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> node = stack.top ().first;
|
||||
SHAMapNodeID nodeID = stack.top ().second;
|
||||
auto node = stack.top ().first;
|
||||
auto nodeID = stack.top ().second;
|
||||
stack.pop ();
|
||||
|
||||
if (node->isLeaf () && (node->peekItem ()->getTag () == tag))
|
||||
return false;
|
||||
|
||||
unshareNode (node, nodeID);
|
||||
if (node->isLeaf())
|
||||
{
|
||||
auto leaf = std::static_pointer_cast<SHAMapTreeNode>(node);
|
||||
if (leaf->peekItem()->getTag() == tag)
|
||||
return false;
|
||||
}
|
||||
node = unshareNode(std::move(node), nodeID);
|
||||
if (node->isInner ())
|
||||
{
|
||||
// easy case, we end on an inner node
|
||||
auto inner = std::static_pointer_cast<SHAMapInnerNode>(node);
|
||||
int branch = nodeID.selectBranch (tag);
|
||||
assert (node->isEmptyBranch (branch));
|
||||
assert (inner->isEmptyBranch (branch));
|
||||
auto newNode = std::make_shared<SHAMapTreeNode> (item, type, seq_);
|
||||
node->setChild (branch, newNode);
|
||||
inner->setChild (branch, newNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a leaf node that has to be made an inner node holding two items
|
||||
std::shared_ptr<SHAMapItem> otherItem = node->peekItem ();
|
||||
auto leaf = std::static_pointer_cast<SHAMapTreeNode>(node);
|
||||
std::shared_ptr<SHAMapItem> otherItem = leaf->peekItem ();
|
||||
assert (otherItem && (tag != otherItem->getTag ()));
|
||||
|
||||
node->makeInner ();
|
||||
node = std::make_shared<SHAMapInnerNode>(node->getSeq());
|
||||
|
||||
int b1, b2;
|
||||
|
||||
@@ -803,8 +815,7 @@ SHAMap::addGiveItem (std::shared_ptr<SHAMapItem> const& item,
|
||||
|
||||
// we need a new inner node, since both go on same branch at this level
|
||||
nodeID = nodeID.getChildNodeID (b1);
|
||||
node = std::make_shared<SHAMapTreeNode> (seq_);
|
||||
node->makeInner ();
|
||||
node = std::make_shared<SHAMapInnerNode> (seq_);
|
||||
}
|
||||
|
||||
// we can add the two leaf nodes here
|
||||
@@ -813,11 +824,12 @@ SHAMap::addGiveItem (std::shared_ptr<SHAMapItem> const& item,
|
||||
std::shared_ptr<SHAMapTreeNode> newNode =
|
||||
std::make_shared<SHAMapTreeNode> (item, type, seq_);
|
||||
assert (newNode->isValid () && newNode->isLeaf ());
|
||||
node->setChild (b1, newNode);
|
||||
auto inner = std::static_pointer_cast<SHAMapInnerNode>(node);
|
||||
inner->setChild (b1, newNode);
|
||||
|
||||
newNode = std::make_shared<SHAMapTreeNode> (otherItem, type, seq_);
|
||||
assert (newNode->isValid () && newNode->isLeaf ());
|
||||
node->setChild (b2, newNode);
|
||||
inner->setChild (b2, newNode);
|
||||
}
|
||||
|
||||
dirtyUp (stack, tag, node);
|
||||
@@ -855,17 +867,17 @@ SHAMap::updateGiveItem (std::shared_ptr<SHAMapItem> const& item,
|
||||
if (stack.empty ())
|
||||
throw (std::runtime_error ("missing node"));
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> node = stack.top ().first;
|
||||
SHAMapNodeID nodeID = stack.top ().second;
|
||||
auto node = std::dynamic_pointer_cast<SHAMapTreeNode>(stack.top().first);
|
||||
auto nodeID = stack.top ().second;
|
||||
stack.pop ();
|
||||
|
||||
if (!node->isLeaf () || (node->peekItem ()->getTag () != tag))
|
||||
if (!node || (node->peekItem ()->getTag () != tag))
|
||||
{
|
||||
assert (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
unshareNode (node, nodeID);
|
||||
node = unshareNode(std::move(node), nodeID);
|
||||
|
||||
if (!node->setItem (item, !isTransaction ? SHAMapTreeNode::tnACCOUNT_STATE :
|
||||
(hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD : SHAMapTreeNode::tnTRANSACTION_NM)))
|
||||
@@ -903,7 +915,7 @@ bool SHAMap::fetchRoot (uint256 const& hash, SHAMapSyncFilter* filter)
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> newRoot = fetchNodeNT (SHAMapNodeID(), hash, filter);
|
||||
auto newRoot = fetchNodeNT (SHAMapNodeID(), hash, filter);
|
||||
|
||||
if (newRoot)
|
||||
{
|
||||
@@ -924,8 +936,9 @@ bool SHAMap::fetchRoot (uint256 const& hash, SHAMapSyncFilter* filter)
|
||||
//
|
||||
// 2) An unshareable node is shared. This happens when you make
|
||||
// a mutable snapshot of a mutable SHAMap.
|
||||
void SHAMap::writeNode (
|
||||
NodeObjectType t, std::uint32_t seq, std::shared_ptr<SHAMapTreeNode>& node) const
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
SHAMap::writeNode (
|
||||
NodeObjectType t, std::uint32_t seq, std::shared_ptr<SHAMapAbstractNode> node) const
|
||||
{
|
||||
// Node is ours, so we can just make it shareable
|
||||
assert (node->getSeq() == seq_);
|
||||
@@ -938,12 +951,15 @@ void SHAMap::writeNode (
|
||||
node->addRaw (s, snfPREFIX);
|
||||
f_.db().store (t,
|
||||
std::move (s.modData ()), node->getNodeHash ());
|
||||
return node;
|
||||
}
|
||||
|
||||
// We can't modify an inner node someone else might have a
|
||||
// pointer to because flushing modifies inner nodes -- it
|
||||
// makes them point to canonical/shared nodes.
|
||||
void SHAMap::preFlushNode (std::shared_ptr<SHAMapTreeNode>& node) const
|
||||
template <class Node>
|
||||
std::shared_ptr<Node>
|
||||
SHAMap::preFlushNode (std::shared_ptr<Node> node) const
|
||||
{
|
||||
// A shared node should never need to be flushed
|
||||
// because that would imply someone modified it
|
||||
@@ -953,8 +969,9 @@ void SHAMap::preFlushNode (std::shared_ptr<SHAMapTreeNode>& node) const
|
||||
{
|
||||
// Node is not uniquely ours, so unshare it before
|
||||
// possibly modifying it
|
||||
node = std::make_shared <SHAMapTreeNode> (*node, seq_);
|
||||
node = std::static_pointer_cast<Node>(node->clone(seq_));
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
int SHAMap::unshare ()
|
||||
@@ -975,24 +992,26 @@ SHAMap::walkSubTree (bool doWrite, NodeObjectType t, std::uint32_t seq)
|
||||
int flushed = 0;
|
||||
Serializer s;
|
||||
|
||||
if (!root_ || (root_->getSeq() == 0) || root_->isEmpty ())
|
||||
if (!root_ || (root_->getSeq() == 0))
|
||||
return flushed;
|
||||
|
||||
if (root_->isLeaf())
|
||||
{ // special case -- root_ is leaf
|
||||
preFlushNode (root_);
|
||||
root_ = preFlushNode (std::move(root_));
|
||||
if (doWrite && backed_)
|
||||
writeNode (t, seq, root_);
|
||||
root_ = writeNode(t, seq, std::move(root_));
|
||||
return 1;
|
||||
}
|
||||
auto node = std::static_pointer_cast<SHAMapInnerNode>(root_);
|
||||
if (node->isEmpty())
|
||||
return flushed;
|
||||
|
||||
// Stack of {parent,index,child} pointers representing
|
||||
// inner nodes we are in the process of flushing
|
||||
using StackEntry = std::pair <std::shared_ptr<SHAMapTreeNode>, int>;
|
||||
using StackEntry = std::pair <std::shared_ptr<SHAMapInnerNode>, int>;
|
||||
std::stack <StackEntry, std::vector<StackEntry>> stack;
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> node = root_;
|
||||
preFlushNode (node);
|
||||
node = preFlushNode(std::move(node));
|
||||
|
||||
int pos = 0;
|
||||
|
||||
@@ -1010,7 +1029,7 @@ SHAMap::walkSubTree (bool doWrite, NodeObjectType t, std::uint32_t seq)
|
||||
// No need to do I/O. If the node isn't linked,
|
||||
// it can't need to be flushed
|
||||
int branch = pos;
|
||||
std::shared_ptr<SHAMapTreeNode> child = node->getChild (pos++);
|
||||
auto child = node->getChild(pos++);
|
||||
|
||||
if (child && (child->getSeq() != 0))
|
||||
{
|
||||
@@ -1019,11 +1038,11 @@ SHAMap::walkSubTree (bool doWrite, NodeObjectType t, std::uint32_t seq)
|
||||
if (child->isInner ())
|
||||
{
|
||||
// save our place and work on this node
|
||||
preFlushNode (child);
|
||||
child = preFlushNode(std::move(child));
|
||||
|
||||
stack.emplace (std::move (node), branch);
|
||||
|
||||
node = std::move (child);
|
||||
node = std::static_pointer_cast<SHAMapInnerNode>(std::move(child));
|
||||
pos = 0;
|
||||
}
|
||||
else
|
||||
@@ -1031,13 +1050,13 @@ SHAMap::walkSubTree (bool doWrite, NodeObjectType t, std::uint32_t seq)
|
||||
// flush this leaf
|
||||
++flushed;
|
||||
|
||||
preFlushNode (child);
|
||||
child = preFlushNode(std::move(child));
|
||||
|
||||
assert (node->getSeq() == seq_);
|
||||
child->updateHash();
|
||||
|
||||
if (doWrite && backed_)
|
||||
writeNode (t, seq, child);
|
||||
child = writeNode(t, seq, std::move(child));
|
||||
|
||||
node->shareChild (branch, child);
|
||||
}
|
||||
@@ -1050,14 +1069,15 @@ SHAMap::walkSubTree (bool doWrite, NodeObjectType t, std::uint32_t seq)
|
||||
|
||||
// This inner node can now be shared
|
||||
if (doWrite && backed_)
|
||||
writeNode (t, seq, node);
|
||||
node = std::static_pointer_cast<SHAMapInnerNode>(writeNode(t, seq,
|
||||
std::move(node)));
|
||||
|
||||
++flushed;
|
||||
|
||||
if (stack.empty ())
|
||||
break;
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> parent = std::move (stack.top().first);
|
||||
auto parent = std::move (stack.top().first);
|
||||
pos = stack.top().second;
|
||||
stack.pop();
|
||||
|
||||
@@ -1082,13 +1102,13 @@ void SHAMap::dump (bool hash) const
|
||||
if (journal_.info) journal_.info <<
|
||||
" MAP Contains";
|
||||
|
||||
std::stack <std::pair <SHAMapTreeNode*, SHAMapNodeID> > stack;
|
||||
std::stack <std::pair <SHAMapAbstractNode*, SHAMapNodeID> > stack;
|
||||
stack.push ({root_.get (), SHAMapNodeID ()});
|
||||
|
||||
do
|
||||
{
|
||||
SHAMapTreeNode* node = stack.top().first;
|
||||
SHAMapNodeID nodeID = stack.top().second;
|
||||
auto node = stack.top().first;
|
||||
auto nodeID = stack.top().second;
|
||||
stack.pop();
|
||||
|
||||
if (journal_.info) journal_.info <<
|
||||
@@ -1099,14 +1119,15 @@ void SHAMap::dump (bool hash) const
|
||||
|
||||
if (node->isInner ())
|
||||
{
|
||||
auto inner = static_cast<SHAMapInnerNode*>(node);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
if (!node->isEmptyBranch (i))
|
||||
if (!inner->isEmptyBranch (i))
|
||||
{
|
||||
SHAMapTreeNode* child = node->getChildPointer (i);
|
||||
auto child = inner->getChildPointer (i);
|
||||
if (child)
|
||||
{
|
||||
assert (child->getNodeHash() == node->getChildHash (i));
|
||||
assert (child->getNodeHash() == inner->getChildHash (i));
|
||||
stack.push ({child, nodeID.getChildNodeID (i)});
|
||||
}
|
||||
}
|
||||
@@ -1121,14 +1142,15 @@ void SHAMap::dump (bool hash) const
|
||||
leafCount << " resident leaves";
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> SHAMap::getCache (uint256 const& hash) const
|
||||
std::shared_ptr<SHAMapAbstractNode> SHAMap::getCache (uint256 const& hash) const
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> ret = f_.treecache().fetch (hash);
|
||||
auto ret = f_.treecache().fetch (hash);
|
||||
assert (!ret || !ret->getSeq());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SHAMap::canonicalize (uint256 const& hash, std::shared_ptr<SHAMapTreeNode>& node) const
|
||||
void
|
||||
SHAMap::canonicalize(uint256 const& hash, std::shared_ptr<SHAMapAbstractNode>& node) const
|
||||
{
|
||||
assert (backed_);
|
||||
assert (node->getSeq() == 0);
|
||||
|
||||
@@ -30,13 +30,13 @@ namespace ripple {
|
||||
// makes no sense at all. (And our sync algorithm will avoid
|
||||
// synchronizing matching branches too.)
|
||||
|
||||
bool SHAMap::walkBranch (SHAMapTreeNode* node,
|
||||
bool SHAMap::walkBranch (SHAMapAbstractNode* node,
|
||||
std::shared_ptr<SHAMapItem> const& otherMapItem, bool isFirstMap,
|
||||
Delta& differences, int& maxCount) const
|
||||
{
|
||||
// Walk a branch of a SHAMap that's matched by an empty branch or single item in the other map
|
||||
std::stack <SHAMapTreeNode*, std::vector<SHAMapTreeNode*>> nodeStack;
|
||||
nodeStack.push ({node});
|
||||
std::stack <SHAMapAbstractNode*, std::vector<SHAMapAbstractNode*>> nodeStack;
|
||||
nodeStack.push (node);
|
||||
|
||||
bool emptyBranch = !otherMapItem;
|
||||
|
||||
@@ -48,14 +48,15 @@ bool SHAMap::walkBranch (SHAMapTreeNode* node,
|
||||
if (node->isInner ())
|
||||
{
|
||||
// This is an inner node, add all non-empty branches
|
||||
auto inner = static_cast<SHAMapInnerNode*>(node);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
if (!node->isEmptyBranch (i))
|
||||
nodeStack.push ({descendThrow (node, i)});
|
||||
if (!inner->isEmptyBranch (i))
|
||||
nodeStack.push ({descendThrow (inner, i)});
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a leaf node, process its item
|
||||
std::shared_ptr<SHAMapItem> item = node->peekItem ();
|
||||
auto item = static_cast<SHAMapTreeNode*>(node)->peekItem();
|
||||
|
||||
if (emptyBranch || (item->getTag () != otherMapItem->getTag ()))
|
||||
{
|
||||
@@ -126,14 +127,14 @@ SHAMap::compare (std::shared_ptr<SHAMap> const& otherMap,
|
||||
if (getHash () == otherMap->getHash ())
|
||||
return true;
|
||||
|
||||
using StackEntry = std::pair <SHAMapTreeNode*, SHAMapTreeNode*>;
|
||||
using StackEntry = std::pair <SHAMapAbstractNode*, SHAMapAbstractNode*>;
|
||||
std::stack <StackEntry, std::vector<StackEntry>> nodeStack; // track nodes we've pushed
|
||||
|
||||
nodeStack.push ({root_.get(), otherMap->root_.get()});
|
||||
while (!nodeStack.empty ())
|
||||
{
|
||||
SHAMapTreeNode* ourNode = nodeStack.top().first;
|
||||
SHAMapTreeNode* otherNode = nodeStack.top().second;
|
||||
SHAMapAbstractNode* ourNode = nodeStack.top().first;
|
||||
SHAMapAbstractNode* otherNode = nodeStack.top().second;
|
||||
nodeStack.pop ();
|
||||
|
||||
if (!ourNode || !otherNode)
|
||||
@@ -145,71 +146,79 @@ SHAMap::compare (std::shared_ptr<SHAMap> const& otherMap,
|
||||
if (ourNode->isLeaf () && otherNode->isLeaf ())
|
||||
{
|
||||
// two leaves
|
||||
if (ourNode->peekItem()->getTag () == otherNode->peekItem()->getTag ())
|
||||
auto ours = static_cast<SHAMapTreeNode*>(ourNode);
|
||||
auto other = static_cast<SHAMapTreeNode*>(otherNode);
|
||||
if (ours->peekItem()->getTag () == other->peekItem()->getTag ())
|
||||
{
|
||||
if (ourNode->peekItem()->peekData () != otherNode->peekItem()->peekData ())
|
||||
if (ours->peekItem()->peekData () != other->peekItem()->peekData ())
|
||||
{
|
||||
differences.insert (std::make_pair (ourNode->peekItem()->getTag (),
|
||||
DeltaRef (ourNode->peekItem (),
|
||||
otherNode->peekItem ())));
|
||||
differences.insert (std::make_pair (ours->peekItem()->getTag (),
|
||||
DeltaRef (ours->peekItem (),
|
||||
other->peekItem ())));
|
||||
if (--maxCount <= 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
differences.insert (std::make_pair(ourNode->peekItem()->getTag (),
|
||||
DeltaRef(ourNode->peekItem(),
|
||||
differences.insert (std::make_pair(ours->peekItem()->getTag (),
|
||||
DeltaRef(ours->peekItem(),
|
||||
std::shared_ptr<SHAMapItem> ())));
|
||||
if (--maxCount <= 0)
|
||||
return false;
|
||||
|
||||
differences.insert(std::make_pair(otherNode->peekItem()->getTag (),
|
||||
differences.insert(std::make_pair(other->peekItem()->getTag (),
|
||||
DeltaRef(std::shared_ptr<SHAMapItem>(),
|
||||
otherNode->peekItem ())));
|
||||
other->peekItem ())));
|
||||
if (--maxCount <= 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (ourNode->isInner () && otherNode->isLeaf ())
|
||||
{
|
||||
if (!walkBranch (ourNode, otherNode->peekItem (),
|
||||
auto ours = static_cast<SHAMapInnerNode*>(ourNode);
|
||||
auto other = static_cast<SHAMapTreeNode*>(otherNode);
|
||||
if (!walkBranch (ours, other->peekItem (),
|
||||
true, differences, maxCount))
|
||||
return false;
|
||||
}
|
||||
else if (ourNode->isLeaf () && otherNode->isInner ())
|
||||
{
|
||||
if (!otherMap->walkBranch (otherNode, ourNode->peekItem (),
|
||||
auto ours = static_cast<SHAMapTreeNode*>(ourNode);
|
||||
auto other = static_cast<SHAMapInnerNode*>(otherNode);
|
||||
if (!otherMap->walkBranch (other, ours->peekItem (),
|
||||
false, differences, maxCount))
|
||||
return false;
|
||||
}
|
||||
else if (ourNode->isInner () && otherNode->isInner ())
|
||||
{
|
||||
auto ours = static_cast<SHAMapInnerNode*>(ourNode);
|
||||
auto other = static_cast<SHAMapInnerNode*>(otherNode);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
if (ourNode->getChildHash (i) != otherNode->getChildHash (i))
|
||||
if (ours->getChildHash (i) != other->getChildHash (i))
|
||||
{
|
||||
if (otherNode->isEmptyBranch (i))
|
||||
if (other->isEmptyBranch (i))
|
||||
{
|
||||
// We have a branch, the other tree does not
|
||||
SHAMapTreeNode* iNode = descendThrow (ourNode, i);
|
||||
SHAMapAbstractNode* iNode = descendThrow (ours, i);
|
||||
if (!walkBranch (iNode,
|
||||
std::shared_ptr<SHAMapItem> (), true,
|
||||
differences, maxCount))
|
||||
return false;
|
||||
}
|
||||
else if (ourNode->isEmptyBranch (i))
|
||||
else if (ours->isEmptyBranch (i))
|
||||
{
|
||||
// The other tree has a branch, we do not
|
||||
SHAMapTreeNode* iNode =
|
||||
otherMap->descendThrow(otherNode, i);
|
||||
SHAMapAbstractNode* iNode =
|
||||
otherMap->descendThrow(other, i);
|
||||
if (!otherMap->walkBranch (iNode,
|
||||
std::shared_ptr<SHAMapItem>(),
|
||||
false, differences, maxCount))
|
||||
return false;
|
||||
}
|
||||
else // The two trees have different non-empty branches
|
||||
nodeStack.push ({descendThrow (ourNode, i),
|
||||
otherMap->descendThrow (otherNode, i)});
|
||||
nodeStack.push ({descendThrow (ours, i),
|
||||
otherMap->descendThrow (other, i)});
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -224,26 +233,27 @@ void SHAMap::walkMap (std::vector<SHAMapMissingNode>& missingNodes, int maxMissi
|
||||
if (!root_->isInner ()) // root_ is only node, and we have it
|
||||
return;
|
||||
|
||||
using StackEntry = std::shared_ptr<SHAMapTreeNode>;
|
||||
using StackEntry = std::shared_ptr<SHAMapInnerNode>;
|
||||
std::stack <StackEntry, std::vector <StackEntry>> nodeStack;
|
||||
|
||||
nodeStack.push (root_);
|
||||
nodeStack.push (std::static_pointer_cast<SHAMapInnerNode>(root_));
|
||||
|
||||
while (!nodeStack.empty ())
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> node = std::move (nodeStack.top());
|
||||
std::shared_ptr<SHAMapInnerNode> node = std::move (nodeStack.top());
|
||||
nodeStack.pop ();
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
if (!node->isEmptyBranch (i))
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> nextNode = descendNoStore (node, i);
|
||||
std::shared_ptr<SHAMapAbstractNode> nextNode = descendNoStore (node, i);
|
||||
|
||||
if (nextNode)
|
||||
{
|
||||
if (nextNode->isInner ())
|
||||
nodeStack.push (std::move (nextNode));
|
||||
nodeStack.push(
|
||||
std::static_pointer_cast<SHAMapInnerNode>(nextNode));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -30,27 +30,29 @@ static const uint256 uZero;
|
||||
|
||||
static bool visitLeavesHelper (
|
||||
std::function <void (std::shared_ptr<SHAMapItem> const&)> const& function,
|
||||
SHAMapTreeNode& node)
|
||||
SHAMapAbstractNode& node)
|
||||
{
|
||||
// Adapt visitNodes to visitLeaves
|
||||
if (!node.isInner ())
|
||||
function (node.peekItem ());
|
||||
function (static_cast<SHAMapTreeNode&>(node).peekItem ());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SHAMap::visitLeaves (std::function<void (std::shared_ptr<SHAMapItem> const& item)> const& leafFunction) const
|
||||
void
|
||||
SHAMap::visitLeaves(
|
||||
std::function<void(std::shared_ptr<SHAMapItem> const& item)> const& leafFunction) const
|
||||
{
|
||||
visitNodes (std::bind (visitLeavesHelper,
|
||||
std::cref (leafFunction), std::placeholders::_1));
|
||||
}
|
||||
|
||||
void SHAMap::visitNodes(std::function<bool (SHAMapTreeNode&)> const& function) const
|
||||
void SHAMap::visitNodes(std::function<bool (SHAMapAbstractNode&)> const& function) const
|
||||
{
|
||||
// Visit every node in a SHAMap
|
||||
assert (root_->isValid ());
|
||||
|
||||
if (!root_ || root_->isEmpty ())
|
||||
if (!root_)
|
||||
return;
|
||||
|
||||
function (*root_);
|
||||
@@ -58,10 +60,10 @@ void SHAMap::visitNodes(std::function<bool (SHAMapTreeNode&)> const& function) c
|
||||
if (!root_->isInner ())
|
||||
return;
|
||||
|
||||
using StackEntry = std::pair <int, std::shared_ptr<SHAMapTreeNode>>;
|
||||
using StackEntry = std::pair <int, std::shared_ptr<SHAMapInnerNode>>;
|
||||
std::stack <StackEntry, std::vector <StackEntry>> stack;
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> node = root_;
|
||||
auto node = std::static_pointer_cast<SHAMapInnerNode>(root_);
|
||||
int pos = 0;
|
||||
|
||||
while (1)
|
||||
@@ -71,7 +73,7 @@ void SHAMap::visitNodes(std::function<bool (SHAMapTreeNode&)> const& function) c
|
||||
uint256 childHash;
|
||||
if (!node->isEmptyBranch (pos))
|
||||
{
|
||||
std::shared_ptr<SHAMapTreeNode> child = descendNoStore (node, pos);
|
||||
std::shared_ptr<SHAMapAbstractNode> child = descendNoStore (node, pos);
|
||||
if (function (*child))
|
||||
return;
|
||||
|
||||
@@ -90,7 +92,7 @@ void SHAMap::visitNodes(std::function<bool (SHAMapTreeNode&)> const& function) c
|
||||
}
|
||||
|
||||
// descend to the child's first position
|
||||
node = child;
|
||||
node = std::static_pointer_cast<SHAMapInnerNode>(child);
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
@@ -112,26 +114,30 @@ void SHAMap::visitNodes(std::function<bool (SHAMapTreeNode&)> const& function) c
|
||||
but not available locally. The filter can hold alternate sources of
|
||||
nodes that are not permanently stored locally
|
||||
*/
|
||||
void SHAMap::getMissingNodes (std::vector<SHAMapNodeID>& nodeIDs, std::vector<uint256>& hashes, int max,
|
||||
SHAMapSyncFilter* filter)
|
||||
void
|
||||
SHAMap::getMissingNodes(std::vector<SHAMapNodeID>& nodeIDs, std::vector<uint256>& hashes,
|
||||
int max, SHAMapSyncFilter* filter)
|
||||
{
|
||||
assert (root_->isValid ());
|
||||
assert (root_->getNodeHash().isNonZero ());
|
||||
|
||||
std::uint32_t generation = f_.fullbelow().getGeneration();
|
||||
if (root_->isFullBelow (generation))
|
||||
{
|
||||
clearSynching ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!root_->isInner ())
|
||||
{
|
||||
if (journal_.warning) journal_.warning <<
|
||||
if (generation == 0)
|
||||
clearSynching();
|
||||
else if (journal_.warning) journal_.warning <<
|
||||
"synching empty tree";
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::static_pointer_cast<SHAMapInnerNode>(root_)->isFullBelow (generation))
|
||||
{
|
||||
clearSynching ();
|
||||
return;
|
||||
}
|
||||
|
||||
int const maxDefer = f_.db().getDesiredAsyncReadCount ();
|
||||
|
||||
// Track the missing hashes we have found so far
|
||||
@@ -140,15 +146,15 @@ void SHAMap::getMissingNodes (std::vector<SHAMapNodeID>& nodeIDs, std::vector<ui
|
||||
|
||||
while (1)
|
||||
{
|
||||
std::vector <std::tuple <SHAMapTreeNode*, int, SHAMapNodeID>> deferredReads;
|
||||
std::vector <std::tuple <SHAMapInnerNode*, int, SHAMapNodeID>> deferredReads;
|
||||
deferredReads.reserve (maxDefer + 16);
|
||||
|
||||
using StackEntry = std::tuple<SHAMapTreeNode*, SHAMapNodeID, int, int, bool>;
|
||||
using StackEntry = std::tuple<SHAMapInnerNode*, SHAMapNodeID, int, int, bool>;
|
||||
std::stack <StackEntry, std::vector<StackEntry>> stack;
|
||||
|
||||
// Traverse the map without blocking
|
||||
|
||||
SHAMapTreeNode *node = root_.get ();
|
||||
auto node = static_cast<SHAMapInnerNode*>(root_.get());
|
||||
SHAMapNodeID nodeID;
|
||||
|
||||
// The firstChild value is selected randomly so if multiple threads
|
||||
@@ -177,7 +183,7 @@ void SHAMap::getMissingNodes (std::vector<SHAMapNodeID>& nodeIDs, std::vector<ui
|
||||
{
|
||||
SHAMapNodeID childID = nodeID.getChildNodeID (branch);
|
||||
bool pending = false;
|
||||
SHAMapTreeNode* d = descendAsync (node, branch, childID, filter, pending);
|
||||
auto d = descendAsync (node, branch, childID, filter, pending);
|
||||
|
||||
if (!d)
|
||||
{
|
||||
@@ -197,13 +203,14 @@ void SHAMap::getMissingNodes (std::vector<SHAMapNodeID>& nodeIDs, std::vector<ui
|
||||
|
||||
fullBelow = false; // This node is not known full below
|
||||
}
|
||||
else if (d->isInner () && !d->isFullBelow (generation))
|
||||
else if (d->isInner() &&
|
||||
!static_cast<SHAMapInnerNode*>(d)->isFullBelow(generation))
|
||||
{
|
||||
stack.push (std::make_tuple (node, nodeID,
|
||||
firstChild, currentChild, fullBelow));
|
||||
|
||||
// Switch to processing the child node
|
||||
node = d;
|
||||
node = static_cast<SHAMapInnerNode*>(d);
|
||||
nodeID = childID;
|
||||
firstChild = rand() % 256;
|
||||
currentChild = 0;
|
||||
@@ -256,13 +263,13 @@ void SHAMap::getMissingNodes (std::vector<SHAMapNodeID>& nodeIDs, std::vector<ui
|
||||
auto const& nodeID = std::get<2>(node);
|
||||
auto const& nodeHash = parent->getChildHash (branch);
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> nodePtr = fetchNodeNT (nodeID, nodeHash, filter);
|
||||
auto nodePtr = fetchNodeNT(nodeID, nodeHash, filter);
|
||||
if (nodePtr)
|
||||
{
|
||||
++hits;
|
||||
if (backed_)
|
||||
canonicalize (nodeHash, nodePtr);
|
||||
parent->canonicalizeChild (branch, nodePtr);
|
||||
nodePtr = parent->canonicalizeChild (branch, std::move(nodePtr));
|
||||
}
|
||||
else if ((max > 0) && (missingHashes.insert (nodeHash).second))
|
||||
{
|
||||
@@ -310,17 +317,17 @@ bool SHAMap::getNodeFat (SHAMapNodeID wanted,
|
||||
// Gets a node and some of its children
|
||||
// to a specified depth
|
||||
|
||||
SHAMapTreeNode* node = root_.get ();
|
||||
auto node = root_.get();
|
||||
SHAMapNodeID nodeID;
|
||||
|
||||
while (node && node->isInner () && (nodeID.getDepth() < wanted.getDepth()))
|
||||
{
|
||||
int branch = nodeID.selectBranch (wanted.getNodeID());
|
||||
|
||||
if (node->isEmptyBranch (branch))
|
||||
auto inner = static_cast<SHAMapInnerNode*>(node);
|
||||
if (inner->isEmptyBranch (branch))
|
||||
return false;
|
||||
|
||||
node = descendThrow (node, branch);
|
||||
node = descendThrow(inner, branch);
|
||||
nodeID = nodeID.getChildNodeID (branch);
|
||||
}
|
||||
|
||||
@@ -331,14 +338,14 @@ bool SHAMap::getNodeFat (SHAMapNodeID wanted,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node->isInner () && node->isEmpty ())
|
||||
if (node->isInner() && static_cast<SHAMapInnerNode*>(node)->isEmpty())
|
||||
{
|
||||
if (journal_.warning) journal_.warning <<
|
||||
"peer requests empty node";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::stack<std::tuple <SHAMapTreeNode*, SHAMapNodeID, int>> stack;
|
||||
std::stack<std::tuple <SHAMapAbstractNode*, SHAMapNodeID, int>> stack;
|
||||
stack.emplace (node, nodeID, depth);
|
||||
|
||||
while (! stack.empty ())
|
||||
@@ -356,16 +363,17 @@ bool SHAMap::getNodeFat (SHAMapNodeID wanted,
|
||||
{
|
||||
// We descend inner nodes with only a single child
|
||||
// without decrementing the depth
|
||||
int bc = node->getBranchCount();
|
||||
auto inner = static_cast<SHAMapInnerNode*>(node);
|
||||
int bc = inner->getBranchCount();
|
||||
if ((depth > 0) || (bc == 1))
|
||||
{
|
||||
// We need to process this node's children
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
if (! node->isEmptyBranch (i))
|
||||
if (! inner->isEmptyBranch (i))
|
||||
{
|
||||
SHAMapNodeID childID = nodeID.getChildNodeID (i);
|
||||
SHAMapTreeNode* childNode = descendThrow (node, i);
|
||||
auto childID = nodeID.getChildNodeID (i);
|
||||
auto childNode = descendThrow (inner, i);
|
||||
|
||||
if (childNode->isInner () &&
|
||||
((depth > 1) || (bc == 1)))
|
||||
@@ -410,9 +418,7 @@ SHAMapAddNode SHAMap::addRootNode (Blob const& rootNode,
|
||||
}
|
||||
|
||||
assert (seq_ >= 1);
|
||||
auto node = std::make_shared<SHAMapTreeNode> (rootNode, 0,
|
||||
format, uZero, false);
|
||||
|
||||
auto node = SHAMapAbstractNode::make(rootNode, 0, format, uZero, false);
|
||||
if (!node)
|
||||
return SHAMapAddNode::invalid ();
|
||||
|
||||
@@ -452,10 +458,7 @@ SHAMapAddNode SHAMap::addRootNode (uint256 const& hash, Blob const& rootNode, SH
|
||||
}
|
||||
|
||||
assert (seq_ >= 1);
|
||||
std::shared_ptr<SHAMapTreeNode> node =
|
||||
std::make_shared<SHAMapTreeNode> (rootNode, 0,
|
||||
format, uZero, false);
|
||||
|
||||
auto node = SHAMapAbstractNode::make(rootNode, 0, format, uZero, false);
|
||||
if (!node || node->getNodeHash () != hash)
|
||||
return SHAMapAddNode::invalid ();
|
||||
|
||||
@@ -494,27 +497,28 @@ SHAMap::addKnownNode (const SHAMapNodeID& node, Blob const& rawNode,
|
||||
|
||||
std::uint32_t generation = f_.fullbelow().getGeneration();
|
||||
SHAMapNodeID iNodeID;
|
||||
SHAMapTreeNode* iNode = root_.get ();
|
||||
auto iNode = root_.get();
|
||||
|
||||
while (iNode->isInner () && !iNode->isFullBelow (generation) &&
|
||||
while (iNode->isInner () &&
|
||||
!static_cast<SHAMapInnerNode*>(iNode)->isFullBelow(generation) &&
|
||||
(iNodeID.getDepth () < node.getDepth ()))
|
||||
{
|
||||
int branch = iNodeID.selectBranch (node.getNodeID ());
|
||||
assert (branch >= 0);
|
||||
|
||||
if (iNode->isEmptyBranch (branch))
|
||||
auto inner = static_cast<SHAMapInnerNode*>(iNode);
|
||||
if (inner->isEmptyBranch (branch))
|
||||
{
|
||||
if (journal_.warning) journal_.warning <<
|
||||
"Add known node for empty branch" << node;
|
||||
return SHAMapAddNode::invalid ();
|
||||
}
|
||||
|
||||
uint256 childHash = iNode->getChildHash (branch);
|
||||
uint256 childHash = inner->getChildHash (branch);
|
||||
if (f_.fullbelow().touch_if_exists (childHash))
|
||||
return SHAMapAddNode::duplicate ();
|
||||
|
||||
SHAMapTreeNode* prevNode = iNode;
|
||||
std::tie (iNode, iNodeID) = descend (iNode, iNodeID, branch, filter);
|
||||
auto prevNode = inner;
|
||||
std::tie(iNode, iNodeID) = descend(inner, iNodeID, branch, filter);
|
||||
|
||||
if (!iNode)
|
||||
{
|
||||
@@ -531,8 +535,7 @@ SHAMap::addKnownNode (const SHAMapNodeID& node, Blob const& rawNode,
|
||||
return SHAMapAddNode::invalid ();
|
||||
}
|
||||
|
||||
auto newNode = std::make_shared<SHAMapTreeNode>(rawNode, 0, snfWIRE,
|
||||
uZero, false);
|
||||
auto newNode = SHAMapAbstractNode::make(rawNode, 0, snfWIRE, uZero, false);
|
||||
|
||||
if (!newNode->isInBounds (iNodeID))
|
||||
{
|
||||
@@ -551,7 +554,7 @@ SHAMap::addKnownNode (const SHAMapNodeID& node, Blob const& rawNode,
|
||||
if (backed_)
|
||||
canonicalize (childHash, newNode);
|
||||
|
||||
prevNode->canonicalizeChild (branch, newNode);
|
||||
newNode = prevNode->canonicalizeChild (branch, std::move(newNode));
|
||||
|
||||
if (filter)
|
||||
{
|
||||
@@ -573,13 +576,14 @@ SHAMap::addKnownNode (const SHAMapNodeID& node, Blob const& rawNode,
|
||||
bool SHAMap::deepCompare (SHAMap& other) const
|
||||
{
|
||||
// Intended for debug/test only
|
||||
std::stack <std::pair <SHAMapTreeNode*, SHAMapTreeNode*> > stack;
|
||||
std::stack <std::pair <SHAMapAbstractNode*, SHAMapAbstractNode*> > stack;
|
||||
|
||||
stack.push ({root_.get(), other.root_.get()});
|
||||
|
||||
while (!stack.empty ())
|
||||
{
|
||||
SHAMapTreeNode *node, *otherNode;
|
||||
SHAMapAbstractNode* node;
|
||||
SHAMapAbstractNode* otherNode;
|
||||
std::tie(node, otherNode) = stack.top ();
|
||||
stack.pop ();
|
||||
|
||||
@@ -600,8 +604,8 @@ bool SHAMap::deepCompare (SHAMap& other) const
|
||||
{
|
||||
if (!otherNode->isLeaf ())
|
||||
return false;
|
||||
auto nodePeek = node->peekItem();
|
||||
auto otherNodePeek = otherNode->peekItem();
|
||||
auto& nodePeek = static_cast<SHAMapTreeNode*>(node)->peekItem();
|
||||
auto& otherNodePeek = static_cast<SHAMapTreeNode*>(otherNode)->peekItem();
|
||||
if (nodePeek->getTag() != otherNodePeek->getTag())
|
||||
return false;
|
||||
if (nodePeek->peekData() != otherNodePeek->peekData())
|
||||
@@ -611,21 +615,22 @@ bool SHAMap::deepCompare (SHAMap& other) const
|
||||
{
|
||||
if (!otherNode->isInner ())
|
||||
return false;
|
||||
|
||||
auto node_inner = static_cast<SHAMapInnerNode*>(node);
|
||||
auto other_inner = static_cast<SHAMapInnerNode*>(otherNode);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
if (node->isEmptyBranch (i))
|
||||
if (node_inner->isEmptyBranch (i))
|
||||
{
|
||||
if (!otherNode->isEmptyBranch (i))
|
||||
if (!other_inner->isEmptyBranch (i))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (otherNode->isEmptyBranch (i))
|
||||
if (other_inner->isEmptyBranch (i))
|
||||
return false;
|
||||
|
||||
SHAMapTreeNode *next = descend (node, i);
|
||||
SHAMapTreeNode *otherNext = other.descend (otherNode, i);
|
||||
auto next = descend(node_inner, i);
|
||||
auto otherNext = other.descend(other_inner, i);
|
||||
if (!next || !otherNext)
|
||||
{
|
||||
if (journal_.warning) journal_.warning <<
|
||||
@@ -647,17 +652,17 @@ bool
|
||||
SHAMap::hasInnerNode (SHAMapNodeID const& targetNodeID,
|
||||
uint256 const& targetNodeHash) const
|
||||
{
|
||||
SHAMapTreeNode* node = root_.get ();
|
||||
auto node = root_.get();
|
||||
SHAMapNodeID nodeID;
|
||||
|
||||
while (node->isInner () && (nodeID.getDepth () < targetNodeID.getDepth ()))
|
||||
{
|
||||
int branch = nodeID.selectBranch (targetNodeID.getNodeID ());
|
||||
|
||||
if (node->isEmptyBranch (branch))
|
||||
auto inner = static_cast<SHAMapInnerNode*>(node);
|
||||
if (inner->isEmptyBranch (branch))
|
||||
return false;
|
||||
|
||||
node = descendThrow (node, branch);
|
||||
node = descendThrow (inner, branch);
|
||||
nodeID = nodeID.getChildNodeID (branch);
|
||||
}
|
||||
|
||||
@@ -669,7 +674,7 @@ SHAMap::hasInnerNode (SHAMapNodeID const& targetNodeID,
|
||||
bool
|
||||
SHAMap::hasLeafNode (uint256 const& tag, uint256 const& targetNodeHash) const
|
||||
{
|
||||
SHAMapTreeNode* node = root_.get ();
|
||||
auto node = root_.get();
|
||||
SHAMapNodeID nodeID;
|
||||
|
||||
if (!node->isInner()) // only one leaf node in the tree
|
||||
@@ -678,14 +683,14 @@ SHAMap::hasLeafNode (uint256 const& tag, uint256 const& targetNodeHash) const
|
||||
do
|
||||
{
|
||||
int branch = nodeID.selectBranch (tag);
|
||||
|
||||
if (node->isEmptyBranch (branch))
|
||||
auto inner = static_cast<SHAMapInnerNode*>(node);
|
||||
if (inner->isEmptyBranch (branch))
|
||||
return false; // Dead end, node must not be here
|
||||
|
||||
if (node->getChildHash (branch) == targetNodeHash) // Matching leaf, no need to retrieve it
|
||||
if (inner->getChildHash (branch) == targetNodeHash) // Matching leaf, no need to retrieve it
|
||||
return true;
|
||||
|
||||
node = descendThrow (node, branch);
|
||||
node = descendThrow(inner, branch);
|
||||
nodeID = nodeID.getChildNodeID (branch);
|
||||
}
|
||||
while (node->isInner());
|
||||
@@ -706,7 +711,7 @@ void SHAMap::getFetchPack (SHAMap* have, bool includeLeaves, int max,
|
||||
std::function<void (uint256 const&, const Blob&)> func) const
|
||||
{
|
||||
visitDifferences (have,
|
||||
[includeLeaves, &max, &func] (SHAMapTreeNode& smn) -> bool
|
||||
[includeLeaves, &max, &func] (SHAMapAbstractNode& smn) -> bool
|
||||
{
|
||||
if (includeLeaves || smn.isInner ())
|
||||
{
|
||||
@@ -721,7 +726,9 @@ void SHAMap::getFetchPack (SHAMap* have, bool includeLeaves, int max,
|
||||
});
|
||||
}
|
||||
|
||||
void SHAMap::visitDifferences (SHAMap* have, std::function <bool (SHAMapTreeNode&)> func) const
|
||||
void
|
||||
SHAMap::visitDifferences(SHAMap* have,
|
||||
std::function<bool (SHAMapAbstractNode&)> func) const
|
||||
{
|
||||
// Visit every node in this SHAMap that is not present
|
||||
// in the specified SHAMap
|
||||
@@ -734,20 +741,21 @@ void SHAMap::visitDifferences (SHAMap* have, std::function <bool (SHAMapTreeNode
|
||||
|
||||
if (root_->isLeaf ())
|
||||
{
|
||||
if (! have || ! have->hasLeafNode (root_->peekItem()->getTag (), root_->getNodeHash ()))
|
||||
auto leaf = std::static_pointer_cast<SHAMapTreeNode>(root_);
|
||||
if (!have || !have->hasLeafNode(leaf->peekItem()->getTag(), leaf->getNodeHash()))
|
||||
func (*root_);
|
||||
|
||||
return;
|
||||
}
|
||||
// contains unexplored non-matching inner node entries
|
||||
using StackEntry = std::pair <SHAMapTreeNode*, SHAMapNodeID>;
|
||||
using StackEntry = std::pair <SHAMapInnerNode*, SHAMapNodeID>;
|
||||
std::stack <StackEntry, std::vector<StackEntry>> stack;
|
||||
|
||||
stack.push ({root_.get(), SHAMapNodeID{}});
|
||||
stack.push ({static_cast<SHAMapInnerNode*>(root_.get()), SHAMapNodeID{}});
|
||||
|
||||
while (!stack.empty())
|
||||
{
|
||||
SHAMapTreeNode* node;
|
||||
SHAMapInnerNode* node;
|
||||
SHAMapNodeID nodeID;
|
||||
std::tie (node, nodeID) = stack.top ();
|
||||
stack.pop ();
|
||||
@@ -763,14 +771,16 @@ void SHAMap::visitDifferences (SHAMap* have, std::function <bool (SHAMapTreeNode
|
||||
{
|
||||
uint256 const& childHash = node->getChildHash (i);
|
||||
SHAMapNodeID childID = nodeID.getChildNodeID (i);
|
||||
SHAMapTreeNode* next = descendThrow (node, i);
|
||||
auto next = descendThrow(node, i);
|
||||
|
||||
if (next->isInner ())
|
||||
{
|
||||
if (! have || ! have->hasInnerNode (childID, childHash))
|
||||
stack.push ({next, childID});
|
||||
if (!have || !have->hasInnerNode(childID, childHash))
|
||||
stack.push ({static_cast<SHAMapInnerNode*>(next), childID});
|
||||
}
|
||||
else if (! have || ! have->hasLeafNode (next->peekItem()->getTag(), childHash))
|
||||
else if (!have || !have->hasLeafNode(
|
||||
static_cast<SHAMapTreeNode*>(next)->peekItem()->getTag(),
|
||||
childHash))
|
||||
{
|
||||
if (! func (*next))
|
||||
return;
|
||||
|
||||
@@ -31,55 +31,50 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::mutex SHAMapTreeNode::childLock;
|
||||
std::mutex SHAMapInnerNode::childLock;
|
||||
|
||||
SHAMapTreeNode::SHAMapTreeNode (std::uint32_t seq)
|
||||
: mSeq (seq)
|
||||
, mType (tnERROR)
|
||||
, mIsBranch (0)
|
||||
, mFullBelowGen (0)
|
||||
SHAMapAbstractNode::~SHAMapAbstractNode() = default;
|
||||
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
SHAMapInnerNode::clone(std::uint32_t seq) const
|
||||
{
|
||||
auto p = std::make_shared<SHAMapInnerNode>(seq);
|
||||
p->mHash = mHash;
|
||||
p->mIsBranch = mIsBranch;
|
||||
p->mFullBelowGen = mFullBelowGen;
|
||||
std::memcpy(p->mHashes, mHashes, sizeof(mHashes));
|
||||
std::unique_lock <std::mutex> lock(childLock);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
p->mChildren[i] = mChildren[i];
|
||||
return std::move(p);
|
||||
}
|
||||
|
||||
SHAMapTreeNode::SHAMapTreeNode (const SHAMapTreeNode& node, std::uint32_t seq)
|
||||
: mHash (node.mHash)
|
||||
, mSeq (seq)
|
||||
, mType (node.mType)
|
||||
, mIsBranch (node.mIsBranch)
|
||||
, mFullBelowGen (0)
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
SHAMapTreeNode::clone(std::uint32_t seq) const
|
||||
{
|
||||
if (node.mItem)
|
||||
mItem = node.mItem;
|
||||
else
|
||||
{
|
||||
memcpy (mHashes, node.mHashes, sizeof (mHashes));
|
||||
|
||||
std::unique_lock <std::mutex> lock (childLock);
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
mChildren[i] = node.mChildren[i];
|
||||
}
|
||||
return std::make_shared<SHAMapTreeNode>(mItem, mType, seq, mHash);
|
||||
}
|
||||
|
||||
SHAMapTreeNode::SHAMapTreeNode (std::shared_ptr<SHAMapItem> const& item,
|
||||
TNType type, std::uint32_t seq)
|
||||
: mItem (item)
|
||||
, mSeq (seq)
|
||||
, mType (type)
|
||||
, mIsBranch (0)
|
||||
, mFullBelowGen (0)
|
||||
: SHAMapAbstractNode(type, seq)
|
||||
, mItem (item)
|
||||
{
|
||||
assert (item->peekData ().size () >= 12);
|
||||
updateHash ();
|
||||
updateHash();
|
||||
}
|
||||
|
||||
SHAMapTreeNode::SHAMapTreeNode (Blob const& rawNode,
|
||||
std::uint32_t seq, SHANodeFormat format,
|
||||
uint256 const& hash, bool hashValid)
|
||||
: mSeq (seq)
|
||||
, mType (tnERROR)
|
||||
, mIsBranch (0)
|
||||
, mFullBelowGen (0)
|
||||
SHAMapTreeNode::SHAMapTreeNode (std::shared_ptr<SHAMapItem> const& item,
|
||||
TNType type, std::uint32_t seq, uint256 const& hash)
|
||||
: SHAMapAbstractNode(type, seq, hash)
|
||||
, mItem (item)
|
||||
{
|
||||
assert (item->peekData ().size () >= 12);
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
SHAMapAbstractNode::make(Blob const& rawNode, std::uint32_t seq, SHANodeFormat format,
|
||||
uint256 const& hash, bool hashValid)
|
||||
{
|
||||
if (format == snfWIRE)
|
||||
{
|
||||
@@ -110,11 +105,13 @@ SHAMapTreeNode::SHAMapTreeNode (Blob const& rawNode,
|
||||
if (type == 0)
|
||||
{
|
||||
// transaction
|
||||
mItem = std::make_shared<SHAMapItem>(
|
||||
auto item = std::make_shared<SHAMapItem>(
|
||||
sha512Half(HashPrefix::transactionID,
|
||||
Slice(s.data(), s.size())),
|
||||
s.peekData());
|
||||
mType = tnTRANSACTION_NM;
|
||||
if (hashValid)
|
||||
return std::make_shared<SHAMapTreeNode>(item, tnTRANSACTION_NM, seq, hash);
|
||||
return std::make_shared<SHAMapTreeNode>(item, tnTRANSACTION_NM, seq);
|
||||
}
|
||||
else if (type == 1)
|
||||
{
|
||||
@@ -128,8 +125,10 @@ SHAMapTreeNode::SHAMapTreeNode (Blob const& rawNode,
|
||||
|
||||
if (u.isZero ()) throw std::runtime_error ("invalid AS node");
|
||||
|
||||
mItem = std::make_shared<SHAMapItem> (u, s.peekData ());
|
||||
mType = tnACCOUNT_STATE;
|
||||
auto item = std::make_shared<SHAMapItem> (u, s.peekData ());
|
||||
if (hashValid)
|
||||
return std::make_shared<SHAMapTreeNode>(item, tnACCOUNT_STATE, seq, hash);
|
||||
return std::make_shared<SHAMapTreeNode>(item, tnACCOUNT_STATE, seq);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
@@ -137,18 +136,23 @@ SHAMapTreeNode::SHAMapTreeNode (Blob const& rawNode,
|
||||
if (len != 512)
|
||||
throw std::runtime_error ("invalid FI node");
|
||||
|
||||
auto ret = std::make_shared<SHAMapInnerNode>(seq);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
s.get256 (mHashes[i], i * 32);
|
||||
s.get256 (ret->mHashes[i], i * 32);
|
||||
|
||||
if (mHashes[i].isNonZero ())
|
||||
mIsBranch |= (1 << i);
|
||||
if (ret->mHashes[i].isNonZero ())
|
||||
ret->mIsBranch |= (1 << i);
|
||||
}
|
||||
|
||||
mType = tnINNER;
|
||||
if (hashValid)
|
||||
ret->mHash = hash;
|
||||
else
|
||||
ret->updateHash();
|
||||
return ret;
|
||||
}
|
||||
else if (type == 3)
|
||||
{
|
||||
auto ret = std::make_shared<SHAMapInnerNode>(seq);
|
||||
// compressed inner
|
||||
for (int i = 0; i < (len / 33); ++i)
|
||||
{
|
||||
@@ -157,13 +161,16 @@ SHAMapTreeNode::SHAMapTreeNode (Blob const& rawNode,
|
||||
|
||||
if ((pos < 0) || (pos >= 16)) throw std::runtime_error ("invalid CI node");
|
||||
|
||||
s.get256 (mHashes[pos], i * 33);
|
||||
s.get256 (ret->mHashes[pos], i * 33);
|
||||
|
||||
if (mHashes[pos].isNonZero ())
|
||||
mIsBranch |= (1 << pos);
|
||||
if (ret->mHashes[pos].isNonZero ())
|
||||
ret->mIsBranch |= (1 << pos);
|
||||
}
|
||||
|
||||
mType = tnINNER;
|
||||
if (hashValid)
|
||||
ret->mHash = hash;
|
||||
else
|
||||
ret->updateHash();
|
||||
return ret;
|
||||
}
|
||||
else if (type == 4)
|
||||
{
|
||||
@@ -178,8 +185,10 @@ SHAMapTreeNode::SHAMapTreeNode (Blob const& rawNode,
|
||||
if (u.isZero ())
|
||||
throw std::runtime_error ("invalid TM node");
|
||||
|
||||
mItem = std::make_shared<SHAMapItem> (u, s.peekData ());
|
||||
mType = tnTRANSACTION_MD;
|
||||
auto item = std::make_shared<SHAMapItem> (u, s.peekData ());
|
||||
if (hashValid)
|
||||
return std::make_shared<SHAMapTreeNode>(item, tnTRANSACTION_MD, seq, hash);
|
||||
return std::make_shared<SHAMapTreeNode>(item, tnTRANSACTION_MD, seq);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,10 +211,12 @@ SHAMapTreeNode::SHAMapTreeNode (Blob const& rawNode,
|
||||
|
||||
if (prefix == HashPrefix::transactionID)
|
||||
{
|
||||
mItem = std::make_shared<SHAMapItem>(
|
||||
auto item = std::make_shared<SHAMapItem>(
|
||||
sha512Half(make_Slice(rawNode)),
|
||||
s.peekData ());
|
||||
mType = tnTRANSACTION_NM;
|
||||
if (hashValid)
|
||||
return std::make_shared<SHAMapTreeNode>(item, tnTRANSACTION_NM, seq, hash);
|
||||
return std::make_shared<SHAMapTreeNode>(item, tnTRANSACTION_NM, seq);
|
||||
}
|
||||
else if (prefix == HashPrefix::leafNode)
|
||||
{
|
||||
@@ -222,23 +233,28 @@ SHAMapTreeNode::SHAMapTreeNode (Blob const& rawNode,
|
||||
throw std::runtime_error ("invalid PLN node");
|
||||
}
|
||||
|
||||
mItem = std::make_shared<SHAMapItem> (u, s.peekData ());
|
||||
mType = tnACCOUNT_STATE;
|
||||
auto item = std::make_shared<SHAMapItem> (u, s.peekData ());
|
||||
if (hashValid)
|
||||
return std::make_shared<SHAMapTreeNode>(item, tnACCOUNT_STATE, seq, hash);
|
||||
return std::make_shared<SHAMapTreeNode>(item, tnACCOUNT_STATE, seq);
|
||||
}
|
||||
else if (prefix == HashPrefix::innerNode)
|
||||
{
|
||||
if (s.getLength () != 512)
|
||||
throw std::runtime_error ("invalid PIN node");
|
||||
|
||||
auto ret = std::make_shared<SHAMapInnerNode>(seq);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
s.get256 (mHashes[i], i * 32);
|
||||
s.get256 (ret->mHashes[i], i * 32);
|
||||
|
||||
if (mHashes[i].isNonZero ())
|
||||
mIsBranch |= (1 << i);
|
||||
if (ret->mHashes[i].isNonZero ())
|
||||
ret->mIsBranch |= (1 << i);
|
||||
}
|
||||
|
||||
mType = tnINNER;
|
||||
if (hashValid)
|
||||
ret->mHash = hash;
|
||||
else
|
||||
ret->updateHash();
|
||||
return ret;
|
||||
}
|
||||
else if (prefix == HashPrefix::txNode)
|
||||
{
|
||||
@@ -249,8 +265,10 @@ SHAMapTreeNode::SHAMapTreeNode (Blob const& rawNode,
|
||||
uint256 txID;
|
||||
s.get256 (txID, s.getLength () - 32);
|
||||
s.chop (32);
|
||||
mItem = std::make_shared<SHAMapItem> (txID, s.peekData ());
|
||||
mType = tnTRANSACTION_MD;
|
||||
auto item = std::make_shared<SHAMapItem> (txID, s.peekData ());
|
||||
if (hashValid)
|
||||
return std::make_shared<SHAMapTreeNode>(item, tnTRANSACTION_MD, seq, hash);
|
||||
return std::make_shared<SHAMapTreeNode>(item, tnTRANSACTION_MD, seq);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -258,49 +276,50 @@ SHAMapTreeNode::SHAMapTreeNode (Blob const& rawNode,
|
||||
throw std::runtime_error ("invalid node prefix");
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
assert (false);
|
||||
throw std::runtime_error ("Unknown format");
|
||||
}
|
||||
|
||||
if (hashValid)
|
||||
{
|
||||
mHash = hash;
|
||||
#if RIPPLE_VERIFY_NODEOBJECT_KEYS
|
||||
updateHash ();
|
||||
assert (mHash == hash);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
updateHash ();
|
||||
assert (false);
|
||||
throw std::runtime_error ("Unknown format");
|
||||
}
|
||||
|
||||
bool SHAMapTreeNode::updateHash ()
|
||||
bool
|
||||
SHAMapInnerNode::updateHash()
|
||||
{
|
||||
uint256 nh;
|
||||
|
||||
if (mType == tnINNER)
|
||||
if (mIsBranch != 0)
|
||||
{
|
||||
if (mIsBranch != 0)
|
||||
{
|
||||
// VFALCO This code assumes the layout of a base_uint
|
||||
nh = sha512Half(HashPrefix::innerNode,
|
||||
Slice(reinterpret_cast<unsigned char const*>(mHashes),
|
||||
sizeof (mHashes)));
|
||||
// VFALCO This code assumes the layout of a base_uint
|
||||
nh = sha512Half(HashPrefix::innerNode,
|
||||
Slice(reinterpret_cast<unsigned char const*>(mHashes),
|
||||
sizeof (mHashes)));
|
||||
#if RIPPLE_VERIFY_NODEOBJECT_KEYS
|
||||
SHA512HalfHasher h;
|
||||
using beast::hash_append;
|
||||
hash_append(h, HashPrefix::innerNode, mHashes);
|
||||
assert (nh == sha512Half(
|
||||
static_cast<uint256>(h)));
|
||||
SHA512HalfHasher h;
|
||||
using beast::hash_append;
|
||||
hash_append(h, HashPrefix::innerNode, mHashes);
|
||||
assert (nh == sha512Half(
|
||||
static_cast<uint256>(h)));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
nh.zero ();
|
||||
}
|
||||
else if (mType == tnTRANSACTION_NM)
|
||||
if (nh == mHash)
|
||||
return false;
|
||||
mHash = nh;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SHAMapInnerNode::updateHashDeep()
|
||||
{
|
||||
for (auto pos = 0; pos < 16; ++pos)
|
||||
{
|
||||
if (mChildren[pos] != nullptr)
|
||||
mHashes[pos] = mChildren[pos]->getNodeHash();
|
||||
}
|
||||
updateHash();
|
||||
}
|
||||
|
||||
bool
|
||||
SHAMapTreeNode::updateHash()
|
||||
{
|
||||
uint256 nh;
|
||||
if (mType == tnTRANSACTION_NM)
|
||||
{
|
||||
nh = sha512Half(HashPrefix::transactionID,
|
||||
make_Slice(mItem->peekData()));
|
||||
@@ -328,17 +347,7 @@ bool SHAMapTreeNode::updateHash ()
|
||||
}
|
||||
|
||||
void
|
||||
SHAMapTreeNode::updateHashDeep()
|
||||
{
|
||||
for (auto pos = 0; pos < 16; ++pos)
|
||||
{
|
||||
if (mChildren[pos] != nullptr)
|
||||
mHashes[pos] = mChildren[pos]->mHash;
|
||||
}
|
||||
updateHash();
|
||||
}
|
||||
|
||||
void SHAMapTreeNode::addRaw (Serializer& s, SHANodeFormat format)
|
||||
SHAMapInnerNode::addRaw(Serializer& s, SHANodeFormat format)
|
||||
{
|
||||
assert ((format == snfPREFIX) || (format == snfWIRE) || (format == snfHASH));
|
||||
|
||||
@@ -383,6 +392,22 @@ void SHAMapTreeNode::addRaw (Serializer& s, SHANodeFormat format)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
assert (false);
|
||||
}
|
||||
|
||||
void
|
||||
SHAMapTreeNode::addRaw(Serializer& s, SHANodeFormat format)
|
||||
{
|
||||
assert ((format == snfPREFIX) || (format == snfWIRE) || (format == snfHASH));
|
||||
|
||||
if (mType == tnERROR)
|
||||
throw std::runtime_error ("invalid I node type");
|
||||
|
||||
if (format == snfHASH)
|
||||
{
|
||||
s.add256 (getNodeHash ());
|
||||
}
|
||||
else if (mType == tnACCOUNT_STATE)
|
||||
{
|
||||
if (format == snfPREFIX)
|
||||
@@ -439,12 +464,12 @@ bool SHAMapTreeNode::setItem (std::shared_ptr<SHAMapItem> const& i, TNType type)
|
||||
return updateHash ();
|
||||
}
|
||||
|
||||
bool SHAMapTreeNode::isEmpty () const
|
||||
bool SHAMapInnerNode::isEmpty () const
|
||||
{
|
||||
return mIsBranch == 0;
|
||||
}
|
||||
|
||||
int SHAMapTreeNode::getBranchCount () const
|
||||
int SHAMapInnerNode::getBranchCount () const
|
||||
{
|
||||
assert (isInner ());
|
||||
int count = 0;
|
||||
@@ -456,18 +481,10 @@ int SHAMapTreeNode::getBranchCount () const
|
||||
return count;
|
||||
}
|
||||
|
||||
void SHAMapTreeNode::makeInner ()
|
||||
{
|
||||
mItem.reset ();
|
||||
mIsBranch = 0;
|
||||
memset (mHashes, 0, sizeof (mHashes));
|
||||
mType = tnINNER;
|
||||
mHash.zero ();
|
||||
}
|
||||
|
||||
#ifdef BEAST_DEBUG
|
||||
|
||||
void SHAMapTreeNode::dump (const SHAMapNodeID & id, beast::Journal journal)
|
||||
void
|
||||
SHAMapAbstractNode::dump(const SHAMapNodeID & id, beast::Journal journal)
|
||||
{
|
||||
if (journal.debug) journal.debug <<
|
||||
"SHAMapTreeNode(" << id.getNodeID () << ")";
|
||||
@@ -475,51 +492,59 @@ void SHAMapTreeNode::dump (const SHAMapNodeID & id, beast::Journal journal)
|
||||
|
||||
#endif // BEAST_DEBUG
|
||||
|
||||
std::string SHAMapTreeNode::getString (const SHAMapNodeID & id) const
|
||||
std::string
|
||||
SHAMapAbstractNode::getString(const SHAMapNodeID & id) const
|
||||
{
|
||||
std::string ret = "NodeID(";
|
||||
ret += beast::lexicalCastThrow <std::string> (id.getDepth ());
|
||||
ret += ",";
|
||||
ret += to_string (id.getNodeID ());
|
||||
ret += ")";
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (isInner ())
|
||||
std::string
|
||||
SHAMapInnerNode::getString(const SHAMapNodeID & id) const
|
||||
{
|
||||
std::string ret = SHAMapAbstractNode::getString(id);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
if (!isEmptyBranch (i))
|
||||
{
|
||||
ret += "\nb";
|
||||
ret += beast::lexicalCastThrow <std::string> (i);
|
||||
ret += " = ";
|
||||
ret += to_string (mHashes[i]);
|
||||
}
|
||||
if (!isEmptyBranch (i))
|
||||
{
|
||||
ret += "\nb";
|
||||
ret += beast::lexicalCastThrow <std::string> (i);
|
||||
ret += " = ";
|
||||
ret += to_string (mHashes[i]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (isLeaf ())
|
||||
{
|
||||
if (mType == tnTRANSACTION_NM)
|
||||
ret += ",txn\n";
|
||||
else if (mType == tnTRANSACTION_MD)
|
||||
ret += ",txn+md\n";
|
||||
else if (mType == tnACCOUNT_STATE)
|
||||
ret += ",as\n";
|
||||
else
|
||||
ret += ",leaf\n";
|
||||
|
||||
ret += " Tag=";
|
||||
ret += to_string (peekItem()->getTag ());
|
||||
ret += "\n Hash=";
|
||||
ret += to_string (mHash);
|
||||
ret += "/";
|
||||
ret += beast::lexicalCast <std::string> (mItem->size());
|
||||
}
|
||||
std::string
|
||||
SHAMapTreeNode::getString(const SHAMapNodeID & id) const
|
||||
{
|
||||
std::string ret = SHAMapAbstractNode::getString(id);
|
||||
if (mType == tnTRANSACTION_NM)
|
||||
ret += ",txn\n";
|
||||
else if (mType == tnTRANSACTION_MD)
|
||||
ret += ",txn+md\n";
|
||||
else if (mType == tnACCOUNT_STATE)
|
||||
ret += ",as\n";
|
||||
else
|
||||
ret += ",leaf\n";
|
||||
|
||||
ret += " Tag=";
|
||||
ret += to_string (peekItem()->getTag ());
|
||||
ret += "\n Hash=";
|
||||
ret += to_string (mHash);
|
||||
ret += "/";
|
||||
ret += beast::lexicalCast <std::string> (mItem->size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
// We are modifying an inner node
|
||||
void
|
||||
SHAMapTreeNode::setChild (int m, std::shared_ptr<SHAMapTreeNode> const& child)
|
||||
SHAMapInnerNode::setChild(int m, std::shared_ptr<SHAMapAbstractNode> const& child)
|
||||
{
|
||||
assert ((m >= 0) && (m < 16));
|
||||
assert (mType == tnINNER);
|
||||
@@ -535,7 +560,7 @@ SHAMapTreeNode::setChild (int m, std::shared_ptr<SHAMapTreeNode> const& child)
|
||||
}
|
||||
|
||||
// finished modifying, now make shareable
|
||||
void SHAMapTreeNode::shareChild (int m, std::shared_ptr<SHAMapTreeNode> const& child)
|
||||
void SHAMapInnerNode::shareChild (int m, std::shared_ptr<SHAMapAbstractNode> const& child)
|
||||
{
|
||||
assert ((m >= 0) && (m < 16));
|
||||
assert (mType == tnINNER);
|
||||
@@ -546,28 +571,31 @@ void SHAMapTreeNode::shareChild (int m, std::shared_ptr<SHAMapTreeNode> const& c
|
||||
mChildren[m] = child;
|
||||
}
|
||||
|
||||
SHAMapTreeNode* SHAMapTreeNode::getChildPointer (int branch)
|
||||
SHAMapAbstractNode*
|
||||
SHAMapInnerNode::getChildPointer (int branch)
|
||||
{
|
||||
assert (branch >= 0 && branch < 16);
|
||||
assert (isInnerNode ());
|
||||
assert (isInner());
|
||||
|
||||
std::unique_lock <std::mutex> lock (childLock);
|
||||
return mChildren[branch].get ();
|
||||
}
|
||||
|
||||
std::shared_ptr<SHAMapTreeNode> SHAMapTreeNode::getChild (int branch)
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
SHAMapInnerNode::getChild (int branch)
|
||||
{
|
||||
assert (branch >= 0 && branch < 16);
|
||||
assert (isInnerNode ());
|
||||
assert (isInner());
|
||||
|
||||
std::unique_lock <std::mutex> lock (childLock);
|
||||
return mChildren[branch];
|
||||
}
|
||||
|
||||
void SHAMapTreeNode::canonicalizeChild (int branch, std::shared_ptr<SHAMapTreeNode>& node)
|
||||
std::shared_ptr<SHAMapAbstractNode>
|
||||
SHAMapInnerNode::canonicalizeChild(int branch, std::shared_ptr<SHAMapAbstractNode> node)
|
||||
{
|
||||
assert (branch >= 0 && branch < 16);
|
||||
assert (isInnerNode ());
|
||||
assert (isInner());
|
||||
assert (node);
|
||||
assert (node->getNodeHash() == mHashes[branch]);
|
||||
|
||||
@@ -582,6 +610,7 @@ void SHAMapTreeNode::canonicalizeChild (int branch, std::shared_ptr<SHAMapTreeNo
|
||||
// Hook this node up
|
||||
mChildren[branch] = node;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -95,6 +95,45 @@ public:
|
||||
unexpected (!sMap.delItem (sMap.peekFirstItem ()->getTag ()), "bad mod");
|
||||
unexpected (sMap.getHash () == mapHash, "bad snapshot");
|
||||
unexpected (map2->getHash () != mapHash, "bad snapshot");
|
||||
|
||||
testcase ("build/tear");
|
||||
{
|
||||
std::vector<uint256> keys(8);
|
||||
keys[0].SetHex ("b92891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6ca8");
|
||||
keys[1].SetHex ("b92881fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6ca8");
|
||||
keys[2].SetHex ("b92691fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6ca8");
|
||||
keys[3].SetHex ("b92791fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6ca8");
|
||||
keys[4].SetHex ("b91891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6ca8");
|
||||
keys[5].SetHex ("b99891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6ca8");
|
||||
keys[6].SetHex ("f22891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6ca8");
|
||||
keys[7].SetHex ("292891fe4ef6cee585fdc6fda1e09eb4d386363158ec3321b8123e5a772c6ca8");
|
||||
|
||||
std::vector<uint256> hashes(8);
|
||||
hashes[0].SetHex ("B7387CFEA0465759ADC718E8C42B52D2309D179B326E239EB5075C64B6281F7F");
|
||||
hashes[1].SetHex ("FBC195A9592A54AB44010274163CB6BA95F497EC5BA0A8831845467FB2ECE266");
|
||||
hashes[2].SetHex ("4E7D2684B65DFD48937FFB775E20175C43AF0C94066F7D5679F51AE756795B75");
|
||||
hashes[3].SetHex ("7A2F312EB203695FFD164E038E281839EEF06A1B99BFC263F3CECC6C74F93E07");
|
||||
hashes[4].SetHex ("395A6691A372387A703FB0F2C6D2C405DAF307D0817F8F0E207596462B0E3A3E");
|
||||
hashes[5].SetHex ("D044C0A696DE3169CC70AE216A1564D69DE96582865796142CE7D98A84D9DDE4");
|
||||
hashes[6].SetHex ("76DCC77C4027309B5A91AD164083264D70B77B5E43E08AEDA5EBF94361143615");
|
||||
hashes[7].SetHex ("DF4220E93ADC6F5569063A01B4DC79F8DB9553B6A3222ADE23DEA02BBE7230E5");
|
||||
|
||||
SHAMap map (SHAMapType::FREE, f, beast::Journal());
|
||||
|
||||
expect (map.getHash() == uint256(), "bad initial empty map hash");
|
||||
for (int i = 0; i < keys.size(); ++i)
|
||||
{
|
||||
SHAMapItem item (keys[i], IntToVUC (i));
|
||||
map.addItem (item, true, false);
|
||||
expect (map.getHash() == hashes[i], "bad buildup map hash");
|
||||
}
|
||||
for (int i = keys.size() - 1; i >= 0; --i)
|
||||
{
|
||||
expect (map.getHash() == hashes[i], "bad teardown hash");
|
||||
map.delItem (keys[i]);
|
||||
}
|
||||
expect (map.getHash() == uint256(), "bad final empty map hash");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user