diff --git a/src/cpp/ripple/Ledger.cpp b/src/cpp/ripple/Ledger.cpp index 3db595c5aa..803f240044 100644 --- a/src/cpp/ripple/Ledger.cpp +++ b/src/cpp/ripple/Ledger.cpp @@ -538,7 +538,24 @@ Ledger::pointer Ledger::loadByHash(const uint256& ledgerHash) std::string sql="SELECT * from Ledgers WHERE LedgerHash='"; sql.append(ledgerHash.GetHex()); sql.append("';"); - return getSQL(sql); + Ledger::pointer ret = getSQL(sql); + if (ret) + return ret; + HashedObject::pointer node = theApp->getHashedObjectStore().retrieve(ledgerHash); + if (!node) + return Ledger::pointer(); + try + { + Ledger::pointer ledger = boost::make_shared(strCopy(node->getData()), true); + if (ledger->getHash() == ledgerHash) + return ledger; + } + catch (...) + { + cLog(lsDEBUG) << "Exception trying to load ledger by hash: " << ledgerHash; + return Ledger::pointer(); + } + return Ledger::pointer(); } Ledger::pointer Ledger::getLastFullLedger() diff --git a/src/cpp/ripple/LedgerAcquire.cpp b/src/cpp/ripple/LedgerAcquire.cpp index 55c539be1b..6312d61c4c 100644 --- a/src/cpp/ripple/LedgerAcquire.cpp +++ b/src/cpp/ripple/LedgerAcquire.cpp @@ -175,18 +175,21 @@ void LedgerAcquire::done() #endif std::vector< boost::function > triggers; - setComplete(); + assert(isComplete() || isFailed()); + mLock.lock(); triggers = mOnComplete; mOnComplete.clear(); mLock.unlock(); - if (mLedger) + if (isComplete() && mLedger) { if (mAccept) mLedger->setAccepted(); theApp->getLedgerMaster().storeLedger(mLedger); } + else if (isFailed()) + theApp->getMasterLedgerAcquire().logFailure(mHash); for (unsigned int i = 0; i < triggers.size(); ++i) triggers[i](shared_from_this()); @@ -528,6 +531,21 @@ LedgerAcquire::pointer LedgerAcquireMaster::find(const uint256& hash) return LedgerAcquire::pointer(); } +std::vector LedgerAcquire::getNeededHashes() +{ + std::vector ret; + if (!mHaveBase) + { + ret.push_back(mHash); + return ret; + } + if (!mHaveState) + mLedger->peekAccountStateMap()->getNeededHashes(ret, 16); + if (!mHaveTransactions) + mLedger->peekTransactionMap()->getNeededHashes(ret, 16); + return ret; +} + bool LedgerAcquireMaster::hasLedger(const uint256& hash) { assert(hash.isNonZero()); @@ -621,4 +639,36 @@ SMAddNode LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer: return SMAddNode::invalid(); } +void LedgerAcquireMaster::logFailure(const uint256& hash) +{ + time_t now = time(NULL); + boost::mutex::scoped_lock sl(mLock); + + std::map::iterator it = mRecentFailures.begin(); + while (it != mRecentFailures.end()) + { + if (it->first == hash) + { + it->second = now; + return; + } + if (it->second > now) + { // time jump or discontinuity + it->second = now; + ++it; + } + else if ((it->second + 180) < now) + mRecentFailures.erase(it++); + else + ++it; + } + mRecentFailures[hash] = now; +} + +bool LedgerAcquireMaster::isFailure(const uint256& hash) +{ + boost::mutex::scoped_lock sl(mLock); + return mRecentFailures.find(hash) != mRecentFailures.end(); +} + // vim:ts=4 diff --git a/src/cpp/ripple/LedgerAcquire.h b/src/cpp/ripple/LedgerAcquire.h index 68753afab6..a4b54a3ae4 100644 --- a/src/cpp/ripple/LedgerAcquire.h +++ b/src/cpp/ripple/LedgerAcquire.h @@ -108,6 +108,8 @@ public: void trigger(Peer::ref, bool timer); bool tryLocal(); void addPeers(); + + std::vector getNeededHashes(); }; class LedgerAcquireMaster @@ -115,6 +117,7 @@ class LedgerAcquireMaster protected: boost::mutex mLock; std::map mLedgers; + std::map mRecentFailures; public: LedgerAcquireMaster() { ; } @@ -124,6 +127,9 @@ public: bool hasLedger(const uint256& ledgerHash); void dropLedger(const uint256& ledgerHash); SMAddNode gotLedgerData(ripple::TMLedgerData& packet, Peer::ref); + + void logFailure(const uint256&); + bool isFailure(const uint256&); }; #endif diff --git a/src/cpp/ripple/LedgerMaster.cpp b/src/cpp/ripple/LedgerMaster.cpp index db7faa57a3..c8eafcb4c7 100644 --- a/src/cpp/ripple/LedgerMaster.cpp +++ b/src/cpp/ripple/LedgerMaster.cpp @@ -170,6 +170,11 @@ void LedgerMaster::acquireMissingLedger(const uint256& ledgerHash, uint32 ledger mMissingLedger.reset(); return; } + else if (mMissingLedger->isDone()) + { + mMissingLedger.reset(); + return; + } mMissingSeq = ledgerSeq; if (mMissingLedger->setAccept()) mMissingLedger->addOnComplete(boost::bind(&LedgerMaster::missingAcquireComplete, this, _1)); @@ -290,7 +295,11 @@ void LedgerMaster::setFullLedger(Ledger::ref ledger) } if (mMissingLedger && mMissingLedger->isDone()) + { + if (mMissingLedger->isFailed()) + theApp->getMasterLedgerAcquire().dropLedger(mMissingLedger->getHash()); mMissingLedger.reset(); + } if (mMissingLedger || !theConfig.LEDGER_HISTORY) { @@ -397,7 +406,7 @@ void LedgerMaster::checkPublish(const uint256& hash, uint32 seq) } } - if (!mPubThread) + if (!mPubLedgers.empty() && !mPubThread) { mPubThread = true; theApp->getJobQueue().addJob(jtPUBLEDGER, boost::bind(&LedgerMaster::pubThread, this)); diff --git a/src/cpp/ripple/SHAMap.h b/src/cpp/ripple/SHAMap.h index e7d4565588..6071603f58 100644 --- a/src/cpp/ripple/SHAMap.h +++ b/src/cpp/ripple/SHAMap.h @@ -413,6 +413,7 @@ public: bool getNodeFat(const SHAMapNode& node, std::vector& nodeIDs, std::list >& rawNode, bool fatRoot, bool fatLeaves); bool getRootNode(Serializer& s, SHANodeFormat format); + void getNeededHashes(std::vector& hashes, int max); SMAddNode addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format, SHAMapSyncFilter* filter); SMAddNode addRootNode(const std::vector& rootNode, SHANodeFormat format, diff --git a/src/cpp/ripple/SHAMapSync.cpp b/src/cpp/ripple/SHAMapSync.cpp index 344e2bdc1c..eb5e11b23c 100644 --- a/src/cpp/ripple/SHAMapSync.cpp +++ b/src/cpp/ripple/SHAMapSync.cpp @@ -19,7 +19,7 @@ void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vectorisValid()); - + if (root->isFullBelow()) { clearSynching(); @@ -91,6 +91,57 @@ void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vector& ret, int max) +{ + boost::recursive_mutex::scoped_lock sl(mLock); + + assert(root->isValid()); + + if (root->isFullBelow() || !root->isInner()) + { + clearSynching(); + return; + } + + std::stack stack; + stack.push(root.get()); + + while (!stack.empty()) + { + SHAMapTreeNode* node = stack.top(); + stack.pop(); + + int base = rand() % 256; + bool have_all = false; + for (int ii = 0; ii < 16; ++ii) + { // traverse in semi-random order + int branch = (base + ii) % 16; + if (!node->isEmptyBranch(branch)) + { + SHAMapNode childID = node->getChildNodeID(branch); + const uint256& childHash = node->getChildHash(branch); + SHAMapTreeNode* d; + try + { + d = getNodePointer(childID, childHash); + assert(d); + if (d->isInner() && !d->isFullBelow()) + stack.push(d); + } + catch (SHAMapMissingNode&) + { // node is not in the map + have_all = false; + ret.push_back(childHash); + if (--max <= 0) + return; + } + } + } + if (have_all) + node->setFullBelow(); + } +} + bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector& nodeIDs, std::list >& rawNodes, bool fatRoot, bool fatLeaves) { // Gets a node and some of its children