diff --git a/modules/ripple_app/ledger/Ledger.cpp b/modules/ripple_app/ledger/Ledger.cpp index c27c26f49..aafa3a111 100644 --- a/modules/ripple_app/ledger/Ledger.cpp +++ b/modules/ripple_app/ledger/Ledger.cpp @@ -615,6 +615,11 @@ void Ledger::saveAcceptedLedger (Job&, bool fromConsensus) if (!fromConsensus && (getConfig ().NODE_SIZE < 2)) // tiny or small dropCache (); + { // Clients can now trust the database for information about this ledger sequence + boost::mutex::scoped_lock sl (sPendingSaveLock); + sPendingSaves.erase(getLedgerSeq()); + } + if (getApp().getJobQueue ().getJobCountTotal (jtPUBOLDLEDGER) < 2) getApp().getLedgerMaster ().resumeAcquiring (); else @@ -1816,6 +1821,12 @@ void Ledger::pendSave (bool fromConsensus) assert (isImmutable ()); + { + boost::mutex::scoped_lock sl (sPendingSaveLock); + if (!sPendingSaves.insert(getLedgerSeq()).second) + return; + } + getApp().getJobQueue ().addJob ( fromConsensus ? jtPUBLEDGER : jtPUBOLDLEDGER, fromConsensus ? "Ledger::pendSave" : "Ledger::pendOldSave", @@ -1823,6 +1834,12 @@ void Ledger::pendSave (bool fromConsensus) } +std::set Ledger::getPendingSaves() +{ + boost::mutex::scoped_lock sl (sPendingSaveLock); + return sPendingSaves; +} + void Ledger::ownerDirDescriber (SLE::ref sle, const uint160& owner) { sle->setFieldAccount (sfOwner, owner); @@ -1941,3 +1958,6 @@ public: }; static LedgerTests ledgerTests; + +boost::mutex Ledger::sPendingSaveLock; +std::set Ledger::sPendingSaves; diff --git a/modules/ripple_app/ledger/Ledger.h b/modules/ripple_app/ledger/Ledger.h index 869a0963f..7b29a373c 100644 --- a/modules/ripple_app/ledger/Ledger.h +++ b/modules/ripple_app/ledger/Ledger.h @@ -421,6 +421,7 @@ public: uint64 scaleFeeBase (uint64 fee); uint64 scaleFeeLoad (uint64 fee, bool bAdmin); + static std::set getPendingSaves(); Json::Value getJson (int options); void addJson (Json::Value&, int options); @@ -467,6 +468,10 @@ private: SHAMap::pointer mAccountStateMap; mutable boost::recursive_mutex mLock; + + // ledgers not fully saved, validated ledger present but DB may not be correct yet + static boost::mutex sPendingSaveLock; + static std::set sPendingSaves; }; inline LedgerStateParms operator| (const LedgerStateParms& l1, const LedgerStateParms& l2) diff --git a/modules/ripple_app/ledger/LedgerMaster.cpp b/modules/ripple_app/ledger/LedgerMaster.cpp index 6dca9fa09..c87438223 100644 --- a/modules/ripple_app/ledger/LedgerMaster.cpp +++ b/modules/ripple_app/ledger/LedgerMaster.cpp @@ -244,7 +244,7 @@ bool LedgerMaster::getValidatedRange (uint32& minVal, uint32& maxVal) if (!mValidLedger) return false; - maxVal = mValidLedger->getLedgerSeq (); + maxVal = mPubLedger->getLedgerSeq (); if (maxVal == 0) return false; @@ -256,6 +256,37 @@ bool LedgerMaster::getValidatedRange (uint32& minVal, uint32& maxVal) else ++minVal; + // Remove from the validated range any ledger sequences that may not be + // fully updated in the database yet + + std::set sPendingSaves = Ledger::getPendingSaves(); + + if (!sPendingSaves.empty() && ((minVal != 0) || (maxVal != 0))) + { + // Ensure we shrink the tips as much as possible + // If we have 7-9 and 8,9 are invalid, we don't want to see the 8 and shrink to just 9 + // because then we'll have nothing when we could have 7. + while (sPendingSaves.count(maxVal) > 0) + --maxVal; + while (sPendingSaves.count(minVal) > 0) + ++minVal; + + // Best effort for remaining exclusions + BOOST_FOREACH(uint32 v, sPendingSaves) + { + if ((v >= minVal) && (v <= maxVal)) + { + if (v > ((minVal + maxVal) / 2)) + maxVal = v - 1; + else + minVal = v + 1; + } + } + + if (minVal > maxVal) + minVal = maxVal = 0; + } + return true; }