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