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