Reduce download timeouts as blocks arrive

Compare the block download timeout to what the timeout would be if calculated
based on current time and current value of nQueuedValidatedHeaders, but
ignoring other in-flight blocks from the same peer. If the calculation based on
present conditions is shorter, then set that to be the time after which we
disconnect the peer for not delivering this block.
This commit is contained in:
Suhas Daftuar 2015-04-06 13:10:33 -04:00
parent ea2b425b00
commit 8ba7f842e5
1 changed files with 29 additions and 5 deletions

View File

@ -141,8 +141,8 @@ namespace {
uint256 hash; uint256 hash;
CBlockIndex *pindex; //! Optional. CBlockIndex *pindex; //! Optional.
int64_t nTime; //! Time of "getdata" request in microseconds. int64_t nTime; //! Time of "getdata" request in microseconds.
int nValidatedQueuedBefore; //! Number of blocks queued with validated headers (globally) at the time this one is requested.
bool fValidatedHeaders; //! Whether this block has validated headers at the time of request. bool fValidatedHeaders; //! Whether this block has validated headers at the time of request.
int64_t nTimeDisconnect; //! The timeout for this block request (for disconnecting a slow peer)
}; };
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight; map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
@ -203,6 +203,7 @@ struct CNodeState {
int64_t nStallingSince; int64_t nStallingSince;
list<QueuedBlock> vBlocksInFlight; list<QueuedBlock> vBlocksInFlight;
int nBlocksInFlight; int nBlocksInFlight;
int nBlocksInFlightValidHeaders;
//! Whether we consider this a preferred download peer. //! Whether we consider this a preferred download peer.
bool fPreferredDownload; bool fPreferredDownload;
@ -216,6 +217,7 @@ struct CNodeState {
fSyncStarted = false; fSyncStarted = false;
nStallingSince = 0; nStallingSince = 0;
nBlocksInFlight = 0; nBlocksInFlight = 0;
nBlocksInFlightValidHeaders = 0;
fPreferredDownload = false; fPreferredDownload = false;
} }
}; };
@ -247,6 +249,12 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state)
nPreferredDownload += state->fPreferredDownload; nPreferredDownload += state->fPreferredDownload;
} }
// Returns time at which to timeout block request (nTime in microseconds)
int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore)
{
return nTime + 500000 * Params().GetConsensus().nPowTargetSpacing * (4 + nValidatedQueuedBefore);
}
void InitializeNode(NodeId nodeid, const CNode *pnode) { void InitializeNode(NodeId nodeid, const CNode *pnode) {
LOCK(cs_main); LOCK(cs_main);
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
@ -279,6 +287,7 @@ void MarkBlockAsReceived(const uint256& hash) {
if (itInFlight != mapBlocksInFlight.end()) { if (itInFlight != mapBlocksInFlight.end()) {
CNodeState *state = State(itInFlight->second.first); CNodeState *state = State(itInFlight->second.first);
nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders; nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders;
state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders;
state->vBlocksInFlight.erase(itInFlight->second.second); state->vBlocksInFlight.erase(itInFlight->second.second);
state->nBlocksInFlight--; state->nBlocksInFlight--;
state->nStallingSince = 0; state->nStallingSince = 0;
@ -294,10 +303,12 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, CBlockIndex *pindex
// Make sure it's not listed somewhere already. // Make sure it's not listed somewhere already.
MarkBlockAsReceived(hash); MarkBlockAsReceived(hash);
QueuedBlock newentry = {hash, pindex, GetTimeMicros(), nQueuedValidatedHeaders, pindex != NULL}; int64_t nNow = GetTimeMicros();
QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL, GetBlockTimeout(nNow, nQueuedValidatedHeaders)};
nQueuedValidatedHeaders += newentry.fValidatedHeaders; nQueuedValidatedHeaders += newentry.fValidatedHeaders;
list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry);
state->nBlocksInFlight++; state->nBlocksInFlight++;
state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders;
mapBlocksInFlight[hash] = std::make_pair(nodeid, it); mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
} }
@ -4693,9 +4704,22 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link // timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link
// being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes // being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes
// to unreasonably increase our timeout. // to unreasonably increase our timeout.
if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0 && state.vBlocksInFlight.front().nTime < nNow - 500000 * consensusParams.nPowTargetSpacing * (4 + state.vBlocksInFlight.front().nValidatedQueuedBefore)) { // We also compare the block download timeout originally calculated against the time at which we'd disconnect
LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", state.vBlocksInFlight.front().hash.ToString(), pto->id); // if we assumed the block were being requested now (ignoring blocks we've requested from this peer, since we're
pto->fDisconnect = true; // only looking at this peer's oldest request). This way a large queue in the past doesn't result in a
// permanently large window for this block to be delivered (ie if the number of blocks in flight is decreasing
// more quickly than once every 5 minutes, then we'll shorten the download window for this block).
if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) {
QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
int64_t nTimeoutIfRequestedNow = GetBlockTimeout(nNow, nQueuedValidatedHeaders - state.nBlocksInFlightValidHeaders);
if (queuedBlock.nTimeDisconnect > nTimeoutIfRequestedNow) {
LogPrint("net", "Reducing block download timeout for peer=%d block=%s, orig=%d new=%d\n", pto->id, queuedBlock.hash.ToString(), queuedBlock.nTimeDisconnect, nTimeoutIfRequestedNow);
queuedBlock.nTimeDisconnect = nTimeoutIfRequestedNow;
}
if (queuedBlock.nTimeDisconnect < nNow) {
LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id);
pto->fDisconnect = true;
}
} }
// //