Be more aggressive about avoiding publishing ledger holes. Make the logic simpler and more sensible.

This commit is contained in:
JoelKatz
2013-01-07 01:33:14 -08:00
parent 63fd3818fb
commit f493ea6478
3 changed files with 76 additions and 35 deletions

View File

@@ -10,7 +10,7 @@
SETUP_LOG(); SETUP_LOG();
#define MIN_VALIDATION_RATIO 150 // 150/256ths of validations of previous ledger #define MIN_VALIDATION_RATIO 150 // 150/256ths of validations of previous ledger
#define MAX_LEDGER_GAP 100 // Don't catch up more than 100 ledgers #define MAX_LEDGER_GAP 100 // Don't catch up more than 100 ledgers (cannot exceed 256)
uint32 LedgerMaster::getCurrentLedgerIndex() uint32 LedgerMaster::getCurrentLedgerIndex()
{ {
@@ -58,7 +58,7 @@ void LedgerMaster::pushLedger(Ledger::ref newLCL, Ledger::ref newOL, bool fromCo
mCurrentLedger = newOL; mCurrentLedger = newOL;
mEngine.setLedger(newOL); mEngine.setLedger(newOL);
} }
checkPublish(newLCL->getHash(), newLCL->getLedgerSeq()); checkAccept(newLCL->getHash(), newLCL->getLedgerSeq());
} }
void LedgerMaster::switchLedgers(Ledger::ref lastClosed, Ledger::ref current) void LedgerMaster::switchLedgers(Ledger::ref lastClosed, Ledger::ref current)
@@ -75,7 +75,7 @@ void LedgerMaster::switchLedgers(Ledger::ref lastClosed, Ledger::ref current)
assert(!mCurrentLedger->isClosed()); assert(!mCurrentLedger->isClosed());
mEngine.setLedger(mCurrentLedger); mEngine.setLedger(mCurrentLedger);
checkPublish(lastClosed->getHash(), lastClosed->getLedgerSeq()); checkAccept(lastClosed->getHash(), lastClosed->getLedgerSeq());
} }
void LedgerMaster::storeLedger(Ledger::ref ledger) void LedgerMaster::storeLedger(Ledger::ref ledger)
@@ -346,21 +346,18 @@ void LedgerMaster::setFullLedger(Ledger::ref ledger)
} }
} }
void LedgerMaster::checkPublish(const uint256& hash) void LedgerMaster::checkAccept(const uint256& hash)
{ {
Ledger::pointer ledger = mLedgerHistory.getLedgerByHash(hash); Ledger::pointer ledger = mLedgerHistory.getLedgerByHash(hash);
if (ledger) if (ledger)
checkPublish(hash, ledger->getLedgerSeq()); checkAccept(hash, ledger->getLedgerSeq());
} }
void LedgerMaster::checkPublish(const uint256& hash, uint32 seq) void LedgerMaster::checkAccept(const uint256& hash, uint32 seq)
{ // check if we need to publish any held ledgers { // Can we advance the last fully accepted ledger? If so, can we publish?
boost::recursive_mutex::scoped_lock ml(mLock); boost::recursive_mutex::scoped_lock ml(mLock);
// FIXME: This code needs to try much more aggressively to fill holes if (mValidLedger && (seq <= mValidLedger->getLedgerSeq()))
// before publishing them.
if (seq <= mLastValidateSeq)
return; return;
int minVal = mMinValidations; int minVal = mMinValidations;
@@ -379,32 +376,73 @@ void LedgerMaster::checkPublish(const uint256& hash, uint32 seq)
else if (theApp->getOPs().isNeedNetworkLedger()) else if (theApp->getOPs().isNeedNetworkLedger())
minVal = 1; minVal = 1;
cLog(lsTRACE) << "Sweeping for ledgers to publish: minval=" << minVal; if (theApp->getValidations().getTrustedValidationCount(hash) < minVal) // nothing we can do
return;
// See if this ledger have at least the minimum number of validations mLastValidateHash = hash;
Ledger::pointer ledger = mLedgerHistory.getLedgerBySeq(seq); mLastValidateSeq = seq;
if (ledger && (theApp->getValidations().getTrustedValidationCount(ledger->getHash()) >= minVal))
{ // this ledger (and any priors) can be published
theApp->getOPs().clearNeedNetworkLedger();
if (ledger->getLedgerSeq() > (mLastValidateSeq + MAX_LEDGER_GAP))
mLastValidateSeq = ledger->getLedgerSeq() - MAX_LEDGER_GAP;
cLog(lsTRACE) << "Ledger " << ledger->getLedgerSeq() << " can be published"; Ledger::pointer ledger = mLedgerHistory.getLedgerByHash(hash);
for (uint32 pubSeq = mLastValidateSeq + 1; pubSeq <= seq; ++pubSeq) if (!ledger)
return;
mValidLedger = ledger;
tryPublish();
}
void LedgerMaster::tryPublish()
{
boost::recursive_mutex::scoped_lock ml(mLock);
assert(mValidLedger);
if (!mPubLedger)
{ {
uint256 pubHash = ledger->getLedgerHash(pubSeq); mPubLedger = mValidLedger;
if (pubHash.isZero()) // CHECKME: Should we double-check validations in this case? mPubLedgers.push_back(mValidLedger);
pubHash = mLedgerHistory.getLedgerHash(pubSeq); }
if (pubHash.isNonZero()) else if (mValidLedger->getLedgerSeq() > (mPubLedger->getLedgerSeq() + MAX_LEDGER_GAP))
{ {
Ledger::pointer ledger = mLedgerHistory.getLedgerByHash(pubHash); mPubLedger = mValidLedger;
mPubLedgers.push_back(mValidLedger);
}
else if (mValidLedger->getLedgerSeq() > mPubLedger->getLedgerSeq())
{
for (uint32 seq = mPubLedger->getLedgerSeq() + 1; seq <= mValidLedger->getLedgerSeq(); ++seq)
{
cLog(lsDEBUG) << "Trying to publish ledger " << seq;
Ledger::pointer ledger;
uint256 hash;
if (seq == mValidLedger->getLedgerSeq())
{
ledger = mValidLedger;
hash = ledger->getHash();
}
else
{
hash = mValidLedger->getLedgerHash(seq);
assert(hash.isNonZero());
ledger = mLedgerHistory.getLedgerByHash(hash);
}
if (ledger) if (ledger)
{ {
mPubLedger = ledger;
mPubLedgers.push_back(ledger); mPubLedgers.push_back(ledger);
mValidLedger = ledger;
mLastValidateSeq = ledger->getLedgerSeq();
mLastValidateHash = ledger->getHash();
} }
else
{
LedgerAcquire::pointer acq = theApp->getMasterLedgerAcquire().findCreate(hash);
if (!acq->isDone())
break;
else if (acq->isComplete() && !acq->isFailed())
{
mPubLedger = acq->getLedger();
mPubLedgers.push_back(mPubLedger);
}
else
cLog(lsWARNING) << "Failed to acquire a published ledger";
} }
} }
} }
@@ -436,6 +474,7 @@ void LedgerMaster::pubThread()
BOOST_FOREACH(Ledger::ref l, ledgers) BOOST_FOREACH(Ledger::ref l, ledgers)
{ {
cLog(lsDEBUG) << "Publishing ledger " << l->getLedgerSeq();
setFullLedger(l); // OPTIMIZEME: This is actually more work than we need to do setFullLedger(l); // OPTIMIZEME: This is actually more work than we need to do
theApp->getOPs().pubLedger(l); theApp->getOPs().pubLedger(l);
BOOST_FOREACH(callback& c, mOnValidate) BOOST_FOREACH(callback& c, mOnValidate)

View File

@@ -27,7 +27,8 @@ protected:
Ledger::pointer mCurrentLedger; // The ledger we are currently processiong Ledger::pointer mCurrentLedger; // The ledger we are currently processiong
Ledger::pointer mFinalizedLedger; // The ledger that most recently closed Ledger::pointer mFinalizedLedger; // The ledger that most recently closed
Ledger::pointer mValidLedger; // The ledger we most recently fully accepted Ledger::pointer mValidLedger; // The highest-sequence ledger we have fully accepted
Ledger::pointer mPubLedger; // The last ledger we have published
LedgerHistory mLedgerHistory; LedgerHistory mLedgerHistory;
@@ -120,8 +121,9 @@ public:
void addValidateCallback(callback& c) { mOnValidate.push_back(c); } void addValidateCallback(callback& c) { mOnValidate.push_back(c); }
void checkPublish(const uint256& hash); void checkAccept(const uint256& hash);
void checkPublish(const uint256& hash, uint32 seq); void checkAccept(const uint256& hash, uint32 seq);
void tryPublish();
}; };
#endif #endif

View File

@@ -76,7 +76,7 @@ bool ValidationCollection::addValidation(const SerializedValidation::pointer& va
cLog(lsINFO) << "Val for " << hash << " from " << signer.humanNodePublic() cLog(lsINFO) << "Val for " << hash << " from " << signer.humanNodePublic()
<< " added " << (val->isTrusted() ? "trusted/" : "UNtrusted/") << (isCurrent ? "current" : "stale"); << " added " << (val->isTrusted() ? "trusted/" : "UNtrusted/") << (isCurrent ? "current" : "stale");
if (val->isTrusted()) if (val->isTrusted())
theApp->getLedgerMaster().checkPublish(hash); theApp->getLedgerMaster().checkAccept(hash);
return isCurrent; return isCurrent;
} }