From b993c6ee329d35471c6caecd3662b4d455db4209 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 19 Apr 2013 14:22:52 -0700 Subject: [PATCH] Cache the hashes of nodes known to be full below. Remove the TNByID entries for those nodes in state trees. This reduces the memory and I/O neded during ledger fetching and prevents ledger fetching from crushing other caches. --- src/cpp/ripple/Application.cpp | 1 + src/cpp/ripple/SHAMap.cpp | 8 +++ src/cpp/ripple/SHAMap.h | 5 ++ src/cpp/ripple/SHAMapSync.cpp | 106 ++++++++++++++++++++------------- 4 files changed, 78 insertions(+), 42 deletions(-) diff --git a/src/cpp/ripple/Application.cpp b/src/cpp/ripple/Application.cpp index 7a20af6aa..31809985c 100644 --- a/src/cpp/ripple/Application.cpp +++ b/src/cpp/ripple/Application.cpp @@ -359,6 +359,7 @@ void Application::sweep() getMasterLedgerAcquire().sweep(); mSLECache.sweep(); AcceptedLedger::sweep(); + SHAMap::sweep(); mSweepTimer.expires_from_now(boost::posix_time::seconds(theConfig.getSize(siSweepInterval))); mSweepTimer.async_wait(boost::bind(&Application::sweep, this)); } diff --git a/src/cpp/ripple/SHAMap.cpp b/src/cpp/ripple/SHAMap.cpp index a08028047..c0191f6c4 100644 --- a/src/cpp/ripple/SHAMap.cpp +++ b/src/cpp/ripple/SHAMap.cpp @@ -853,6 +853,14 @@ void SHAMap::dropCache() mTNByID[*root] = root; } +void SHAMap::dropBelow(SHAMapTreeNode* d) +{ + if (d->isInner()) + for (int i = 0 ; i < 16; ++i) + if (!d->isEmptyBranch(i)) + mTNByID.erase(d->getChildNodeID(i)); +} + void SHAMap::dump(bool hash) { cLog(lsINFO) << " MAP Contains"; diff --git a/src/cpp/ripple/SHAMap.h b/src/cpp/ripple/SHAMap.h index d241f1843..68db98473 100644 --- a/src/cpp/ripple/SHAMap.h +++ b/src/cpp/ripple/SHAMap.h @@ -354,6 +354,8 @@ private: SHAMapType mType; + static KeyCache fullBelowCache; + protected: void dirtyUp(std::stack& stack, const uint256& target, uint256 prevHash); @@ -372,6 +374,7 @@ protected: SHAMapItem::pointer onlyBelow(SHAMapTreeNode*); void eraseChildren(SHAMapTreeNode::pointer); + void dropBelow(SHAMapTreeNode*); bool walkBranch(SHAMapTreeNode* node, SHAMapItem::ref otherMapItem, bool isFirstMap, SHAMapDiff& differences, int& maxCount); @@ -472,6 +475,8 @@ public: bool deepCompare(SHAMap& other); virtual void dump(bool withHashes = false); + + static void sweep() { fullBelowCache.sweep(); } }; #endif diff --git a/src/cpp/ripple/SHAMapSync.cpp b/src/cpp/ripple/SHAMapSync.cpp index 86ec7d3eb..2cd5e1c14 100644 --- a/src/cpp/ripple/SHAMapSync.cpp +++ b/src/cpp/ripple/SHAMapSync.cpp @@ -15,6 +15,8 @@ SETUP_LOG(); static const uint256 uZero; +KeyCache SHAMap::fullBelowCache("fullBelowCache", 65536, 240); + void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vector& hashes, int max, SHAMapSyncFilter* filter) { @@ -49,46 +51,56 @@ void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vectorisEmptyBranch(branch)) { - SHAMapNode childID = node->getChildNodeID(branch); const uint256& childHash = node->getChildHash(branch); - SHAMapTreeNode* d = NULL; - try + if (!fullBelowCache.isPresent(childHash)) { - d = getNodePointer(childID, childHash); - } - catch (SHAMapMissingNode&) - { // node is not in the map - if (filter != NULL) + SHAMapNode childID = node->getChildNodeID(branch); + SHAMapTreeNode* d = NULL; + try { - std::vector nodeData; - if (filter->haveNode(childID, childHash, nodeData)) + d = getNodePointer(childID, childHash); + } + catch (SHAMapMissingNode&) + { // node is not in the map + if (filter != NULL) { - assert(mSeq >= 1); - SHAMapTreeNode::pointer ptr = - boost::make_shared(childID, nodeData, mSeq - 1, snfPREFIX, childHash, true); - cLog(lsTRACE) << "Got sync node from cache: " << *ptr; - mTNByID[*ptr] = ptr; - d = ptr.get(); + std::vector nodeData; + if (filter->haveNode(childID, childHash, nodeData)) + { + assert(mSeq >= 1); + SHAMapTreeNode::pointer ptr = + boost::make_shared(childID, nodeData, mSeq - 1, snfPREFIX, childHash, true); + cLog(lsTRACE) << "Got sync node from cache: " << *ptr; + mTNByID[*ptr] = ptr; + d = ptr.get(); + } } } - } - if (!d) - { // we need this node - nodeIDs.push_back(childID); - hashes.push_back(childHash); - if (--max <= 0) - return; - have_all = false; - } - else if (d->isInner() && !d->isFullBelow()) // we might need children of this node - { - have_all = false; - stack.push(d); + if (!d) + { // we need this node + nodeIDs.push_back(childID); + hashes.push_back(childHash); + if (--max <= 0) + return; + have_all = false; + } + else if (d->isInner() && !d->isFullBelow()) // we might need children of this node + { + have_all = false; + stack.push(d); + } } } } if (have_all) + { node->setFullBelow(); + if (mType == smtSTATE) + { + fullBelowCache.add(node->getHash()); + dropBelow(node); + } + } } if (nodeIDs.empty()) clearSynching(); @@ -123,27 +135,37 @@ std::vector SHAMap::getNeededHashes(int max) if (!node->isEmptyBranch(branch)) { const uint256& childHash = node->getChildHash(branch); - try + if (!fullBelowCache.isPresent(childHash)) { - SHAMapTreeNode* d = getNodePointer(node->getChildNodeID(branch), childHash); - assert(d); - if (d->isInner() && !d->isFullBelow()) + try { - have_all = false; - stack.push(d); + SHAMapTreeNode* d = getNodePointer(node->getChildNodeID(branch), childHash); + assert(d); + if (d->isInner() && !d->isFullBelow()) + { + have_all = false; + stack.push(d); + } + } + catch (SHAMapMissingNode&) + { // node is not in the map + have_all = false; + ret.push_back(childHash); + if (--max <= 0) + return ret; } - } - catch (SHAMapMissingNode&) - { // node is not in the map - have_all = false; - ret.push_back(childHash); - if (--max <= 0) - return ret; } } } if (have_all) + { node->setFullBelow(); + if (mType == smtSTATE) + { + fullBelowCache.add(node->getHash()); + dropBelow(node); + } + } } if (ret.empty()) clearSynching();