diff --git a/src/ripple/app/ledger/Ledger.h b/src/ripple/app/ledger/Ledger.h index 51f222adb..fce2b6f81 100644 --- a/src/ripple/app/ledger/Ledger.h +++ b/src/ripple/app/ledger/Ledger.h @@ -46,7 +46,7 @@ class SqliteStatement; all of the transactions and associated metadata that made it into that particular ledger. Most of the operations on a ledger are concerned with the state map. - + A View provides a structured interface to manipulate the state map in a reversible way, with facilities to automatically produce metadata when applying changes. @@ -173,12 +173,12 @@ public: { mClosed = true; } - + void setValidated() { mValidated = true; } - + void setAccepted (std::uint32_t closeTime, int closeResolution, bool correctCloseTime); @@ -545,6 +545,25 @@ boost::optional hashOfSeq (Ledger& ledger, LedgerIndex seq, SLECache& cache, beast::Journal journal); +/** Find a ledger index from which we could easily get the requested ledger + + The index that we return should meet two requirements: + 1) It must be the index of a ledger that has the hash of the ledger + we are looking for. This means that its sequence must be equal to + greater than the sequence that we want but not more than 256 greater + since each ledger contains the hashes of the 256 previous ledgers. + + 2) Its hash must be easy for us to find. This means it must be 0 mod 256 + because every such ledger is permanently enshrined in a LedgerHashes + page which we can easily retrieve via the skip list. +*/ +inline +LedgerIndex +getCandidateLedger (LedgerIndex requested) +{ + return (requested + 255) & (~255); +} + } // ripple #endif diff --git a/src/ripple/app/ledger/impl/InboundLedgers.cpp b/src/ripple/app/ledger/impl/InboundLedgers.cpp index 3109c0219..6db584480 100644 --- a/src/ripple/app/ledger/impl/InboundLedgers.cpp +++ b/src/ripple/app/ledger/impl/InboundLedgers.cpp @@ -57,8 +57,7 @@ public: Ledger::pointer acquire (uint256 const& hash, std::uint32_t seq, InboundLedger::fcReason reason) { assert (hash.isNonZero ()); - Ledger::pointer ret; - + InboundLedger::pointer inbound; { ScopedLockType sl (mLock); @@ -67,26 +66,26 @@ public: auto it = mLedgers.find (hash); if (it != mLedgers.end ()) { - // Don't touch failed acquires so they can expire - if (! it->second->isFailed ()) - { - it->second->update (seq); - if (it->second->isComplete ()) - ret = it->second->getLedger (); - } + inbound = it->second; + // If the acquisition failed, don't mark the item as + // recently accessed so that it can expire. + if (! inbound->isFailed ()) + inbound->update (seq); } else { - auto il = std::make_shared (hash, seq, reason, std::ref (m_clock)); - mLedgers.insert (std::make_pair (hash, il)); - il->init (sl); + inbound = std::make_shared ( + hash, seq, reason, std::ref (m_clock)); + mLedgers.emplace (hash, inbound); + inbound->init (sl); ++mCounter; } } } - - return ret; + if (inbound && inbound->isComplete ()) + return inbound->getLedger(); + return {}; } InboundLedger::pointer find (uint256 const& hash) diff --git a/src/ripple/app/ledger/impl/LedgerCleaner.cpp b/src/ripple/app/ledger/impl/LedgerCleaner.cpp index 0c3b9dbc5..38f84b9e5 100644 --- a/src/ripple/app/ledger/impl/LedgerCleaner.cpp +++ b/src/ripple/app/ledger/impl/LedgerCleaner.cpp @@ -352,7 +352,7 @@ public: { // No, Try to get another ledger that might have the hash we need // Compute the index and hash of a ledger that will have the hash we need - LedgerIndex refIndex = (ledgerIndex + 255) & (~255); + LedgerIndex refIndex = getCandidateLedger (ledgerIndex); LedgerHash refHash = getLedgerHash (referenceLedger, refIndex); bool const nonzero (refHash.isNonZero ()); diff --git a/src/ripple/app/ledger/impl/LedgerMaster.cpp b/src/ripple/app/ledger/impl/LedgerMaster.cpp index 84cbbb592..a1369d355 100644 --- a/src/ripple/app/ledger/impl/LedgerMaster.cpp +++ b/src/ripple/app/ledger/impl/LedgerMaster.cpp @@ -1441,7 +1441,7 @@ public: if (!referenceLedger || (referenceLedger->getLedgerSeq() < index)) { // Nothing we can do. No validated ledger. - return zero; + return zero; } // See if the hash for the ledger we need is in the reference ledger @@ -1450,23 +1450,41 @@ public: if (ledgerHash) return *ledgerHash; - // No, Try to get another ledger that might have the hash we need - // Compute the index and hash of a ledger that will have the hash we need - LedgerIndex refIndex = (index + 255) & (~255); + // The hash is not in the reference ledger. Get another ledger which can + // be located easily and should contain the hash. + LedgerIndex refIndex = getCandidateLedger(index); auto const refHash = hashOfSeq(*referenceLedger, refIndex, getApp().getSLECache(), m_journal); assert(refHash); if (refHash) { - // We found the hash and sequence of a better reference ledger - auto const ledger = - getApp().getInboundLedgers().acquire ( - *refHash, refIndex, InboundLedger::fcGENERIC); + // Try the hash and sequence of a better reference ledger just found + auto ledger = mLedgerHistory.getLedgerByHash (*refHash); + if (ledger) { - ledgerHash = hashOfSeq(*ledger, index, - getApp().getSLECache(), m_journal); - assert (ledgerHash); + try + { + ledgerHash = hashOfSeq(*ledger, index, + getApp().getSLECache(), m_journal); + } + catch(SHAMapMissingNode&) + { + ledger.reset(); + } + } + + // Try to acquire the complete ledger + if (!ledger) + { + auto const ledger = getApp().getInboundLedgers().acquire ( + *refHash, refIndex, InboundLedger::fcGENERIC); + if (ledger) + { + ledgerHash = hashOfSeq(*ledger, index, + getApp().getSLECache(), m_journal); + assert (ledgerHash); + } } } return ledgerHash ? *ledgerHash : zero; // kludge diff --git a/src/ripple/rpc/handlers/LedgerRequest.cpp b/src/ripple/rpc/handlers/LedgerRequest.cpp index eb69e9784..6a2491f1e 100644 --- a/src/ripple/rpc/handlers/LedgerRequest.cpp +++ b/src/ripple/rpc/handlers/LedgerRequest.cpp @@ -71,7 +71,7 @@ Json::Value doLedgerRequest (RPC::Context& context) if (! ledgerHash) { // Find a ledger more likely to have the hash of the desired ledger - auto refIndex = (ledgerIndex + 255) & (~255); + auto const refIndex = getCandidateLedger(ledgerIndex); auto refHash = hashOfSeq(*ledger, refIndex, getApp().getSLECache(), j); assert(refHash);