introduced a stricter timeout on piece requests and snubbing. exposed some more data about this through the peer_info. Fixes #40

This commit is contained in:
Arvid Norberg 2008-06-29 09:50:42 +00:00
parent ae9f1e0465
commit 2ac5c13e6f
6 changed files with 99 additions and 24 deletions

View File

@ -2457,6 +2457,7 @@ It contains the following fields::
on_parole = 0x200,
seed = 0x400,
optimistic_unchoke = 0x800,
snubbed = 0x1000,
rc4_encrypted = 0x100000,
plaintext_encrypted = 0x200000
};
@ -2492,6 +2493,7 @@ It contains the following fields::
time_duration last_request;
time_duration last_active;
int request_timeout;
int send_buffer_size;
int used_send_buffer;
@ -2587,17 +2589,10 @@ any combination of the enums above. The following table describes each flag:
| | doesn't within some period of time, it will be choked |
| | and another peer will be optimistically unchoked. |
+-------------------------+-------------------------------------------------------+
| ``writing`` | The peer is currently waiting for a write operation |
| | on the socket to complete. |
+-------------------------+-------------------------------------------------------+
| ``reading`` | The peer is currently waiting for a read operation |
| | on the socket to complete. |
+-------------------------+-------------------------------------------------------+
| ``waiting_write_quota`` | The peer is currently waiting for the bandwidth- |
| | manager to hand out more write quota to this peer. |
+-------------------------+-------------------------------------------------------+
| ``waiting_read_quota`` | The peer is currently waiting for the bandwidth- |
| | manager to hand out more read quota to this peer. |
| ``snubbed`` | This peer has recently failed to send a block within |
| | the request timeout from when the request was sent. |
| | We're currently picking one block at a time from this |
| | peer. |
+-------------------------+-------------------------------------------------------+
__ extension_protocol.html
@ -2678,6 +2673,10 @@ receive. -1 means it's unlimited.
``last_request`` and ``last_active`` is the time since we last sent a request
to this peer and since any transfer occurred with this peer, respectively.
``request_timeout`` is the number of seconds until the current front piece request
will time out. This timeout can be adjusted through ``session_settings::request_timeout``.
-1 means that there is not outstanding request.
``send_buffer_size`` and ``used_send_buffer`` is the number of bytes allocated
and used for the peer's send buffer, respectively.

View File

@ -317,10 +317,10 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
#ifndef TORRENT_DISABLE_GEO_IP
if (print_as) out << "AS ";
#endif
out << "down (total | peak ) up (total | peak ) sent-req recv flags source ";
out << "down (total | peak ) up (total | peak ) sent-req recv flags source ";
if (print_fails) out << "fail hshf ";
if (print_send_bufs) out << "sndb quota rcvb ";
if (print_timers) out << "inactive wait ";
if (print_timers) out << "inactive wait timeout ";
out << "disk rtt ";
if (print_block) out << "block-progress ";
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
@ -378,6 +378,7 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
<< ((i->write_state == peer_info::bw_torrent)?'t':
(i->write_state == peer_info::bw_global)?'w':
(i->write_state == peer_info::bw_network)?'W':'.')
<< ((i->flags & peer_info::snubbed)?'S':'.')
#ifndef TORRENT_DISABLE_ENCRYPTION
<< ((i->flags & peer_info::rc4_encrypted)?'E':
(i->flags & peer_info::plaintext_encrypted)?'e':'.')
@ -404,7 +405,8 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
if (print_timers)
{
out << to_string(total_seconds(i->last_active), 8) << " "
<< to_string(total_seconds(i->last_request), 4) << " ";
<< to_string(total_seconds(i->last_request), 4) << " "
<< to_string(i->request_timeout, 7) << " ";
}
out << add_suffix(i->pending_disk_bytes) << " "
<< to_string(i->rtt, 4) << " ";

View File

@ -567,6 +567,12 @@ namespace libtorrent
ptime m_last_receive;
ptime m_last_sent;
// the time when the first entry in the
// request queue was requested, increased
// for each entry that is popped from the
// download queue. Used for request timeout
ptime m_requested;
// a timestamp when the remote download rate
// was last updated
ptime m_remote_dl_update;
@ -823,6 +829,11 @@ namespace libtorrent
// set to true when this peer is only uploading
bool m_upload_only:1;
// set to true when a piece request times out. The
// result is that the desired pending queue size
// is set to 1
bool m_snubbed:1;
#ifndef NDEBUG
public:
bool m_in_constructor:1;

View File

@ -56,7 +56,8 @@ namespace libtorrent
queued = 0x100,
on_parole = 0x200,
seed = 0x400,
optimistic_unchoke = 0x800
optimistic_unchoke = 0x800,
snubbed = 0x1000
#ifndef TORRENT_DISABLE_ENCRYPTION
, rc4_encrypted = 0x100000,
plaintext_encrypted = 0x200000
@ -105,6 +106,10 @@ namespace libtorrent
// time since last download or upload
time_duration last_active;
// the number of seconds until the current
// pending request times out
int request_timeout;
// the size of the send buffer for this peer, in bytes
int send_buffer_size;
// the number bytes that's actually used of the send buffer

View File

@ -88,6 +88,7 @@ namespace libtorrent
, stop_tracker_timeout(5)
, tracker_maximum_response_length(1024*1024)
, piece_timeout(10)
, request_timeout(40)
, request_queue_time(3.f)
, max_allowed_in_request_queue(250)
, max_out_request_queue(200)
@ -168,6 +169,11 @@ namespace libtorrent
// it times out if no piece response is returned.
int piece_timeout;
// the number of seconds one block (16kB) is expected
// to be received within. If it's not, the block is
// requested from a different peer
int request_timeout;
// the length of the request queue given in the number
// of seconds it should take for the other end to send
// all the pieces. i.e. the actual number of requests

View File

@ -81,6 +81,7 @@ namespace libtorrent
, m_last_unchoke(min_time())
, m_last_receive(time_now())
, m_last_sent(time_now())
, m_requested(min_time())
, m_remote_dl_update(time_now())
, m_became_uninterested(time_now())
, m_became_uninteresting(time_now())
@ -126,6 +127,7 @@ namespace libtorrent
, m_queued(true)
, m_request_large_blocks(false)
, m_upload_only(false)
, m_snubbed(false)
#ifndef NDEBUG
, m_in_constructor(true)
#endif
@ -166,7 +168,7 @@ namespace libtorrent
// incoming connection
peer_connection::peer_connection(
session_impl& ses
, boost::shared_ptr<socket_type> s
, shared_ptr<socket_type> s
, tcp::endpoint const& endp
, policy::peer* peerinfo)
:
@ -182,6 +184,7 @@ namespace libtorrent
, m_last_unchoke(min_time())
, m_last_receive(time_now())
, m_last_sent(time_now())
, m_requested(min_time())
, m_remote_dl_update(time_now())
, m_became_uninterested(time_now())
, m_became_uninteresting(time_now())
@ -226,6 +229,7 @@ namespace libtorrent
, m_queued(false)
, m_request_large_blocks(false)
, m_upload_only(false)
, m_snubbed(false)
#ifndef NDEBUG
, m_in_constructor(true)
#endif
@ -1433,7 +1437,7 @@ namespace libtorrent
{
disconnect("out of memory");
return;
}
}
disk_buffer_holder holder(m_ses, buffer);
std::memcpy(buffer, data, p.length);
incoming_piece(p, holder);
@ -1562,12 +1566,19 @@ namespace libtorrent
TORRENT_ASSERT(*b == block_finished);
}
if (total_seconds(time_now() - m_requested) < m_ses.settings().request_timeout)
m_snubbed = false;
// if the block we got is already finished, then ignore it
if (picker.is_downloaded(block_finished))
{
t->received_redundant_data(p.length);
m_download_queue.erase(b);
if (!m_download_queue.empty())
m_requested = time_now();
request_a_block(*t, *this);
send_block_requests();
return;
@ -1579,6 +1590,9 @@ namespace libtorrent
TORRENT_ASSERT(m_channel_state[download_channel] == peer_info::bw_idle);
m_download_queue.erase(b);
if (!m_download_queue.empty())
m_requested = time_now();
// did we request this block from any other peers?
bool multi = picker.num_peers(block_finished) > 1;
picker.mark_as_writing(block_finished, peer_info_struct());
@ -2073,6 +2087,8 @@ namespace libtorrent
if ((int)m_download_queue.size() >= m_desired_queue_size) return;
bool empty_download_queue = m_download_queue.empty();
while (!m_request_queue.empty()
&& (int)m_download_queue.size() < m_desired_queue_size)
{
@ -2166,6 +2182,13 @@ namespace libtorrent
#endif
}
m_last_piece = time_now();
if (!m_download_queue.empty()
&& empty_download_queue)
{
// This means we just added a request to this connection
m_requested = time_now();
}
}
void peer_connection::timed_out()
@ -2321,6 +2344,8 @@ namespace libtorrent
{
TORRENT_ASSERT(!associated_torrent().expired());
ptime now = time_now();
p.download_rate_peak = m_download_rate_peak;
p.upload_rate_peak = m_upload_rate_peak;
p.rtt = m_rtt;
@ -2333,6 +2358,8 @@ namespace libtorrent
p.pending_disk_bytes = m_outstanding_writing_bytes;
p.send_quota = m_bandwidth_limit[upload_channel].quota_left();
p.receive_quota = m_bandwidth_limit[download_channel].quota_left();
if (m_download_queue.empty()) p.request_timeout = -1;
else p.request_timeout = total_seconds(m_requested - now) + m_ses.settings().request_timeout;
#ifndef TORRENT_DISABLE_GEO_IP
p.inet_as_name = m_inet_as_name;
#endif
@ -2377,7 +2404,6 @@ namespace libtorrent
}
p.pieces = get_bitfield();
ptime now = time_now();
p.last_request = now - m_last_request;
p.last_active = now - (std::max)(m_last_sent, m_last_receive);
@ -2386,6 +2412,7 @@ namespace libtorrent
get_specific_peer_info(p);
p.flags |= is_seed() ? peer_info::seed : 0;
p.flags |= m_snubbed ? peer_info::snubbed : 0;
if (peer_info_struct())
{
policy::peer* pi = peer_info_struct();
@ -2583,6 +2610,21 @@ namespace libtorrent
return;
}
if (!m_download_queue.empty()
&& now > m_requested + seconds(m_ses.settings().request_timeout))
{
m_snubbed = true;
m_desired_queue_size = 1;
piece_picker& picker = t->picker();
// the front request timed out!
picker.abort_download(m_download_queue[0]);
m_download_queue.pop_front();
if (!m_download_queue.empty())
m_requested = time_now();
request_a_block(*t, *this);
send_block_requests();
}
// if we haven't sent something in too long, send a keep-alive
keep_alive();
@ -2623,12 +2665,19 @@ namespace libtorrent
? t->torrent_file().piece_length() : t->block_size();
TORRENT_ASSERT(block_size > 0);
m_desired_queue_size = static_cast<int>(queue_time
* statistics().download_rate() / block_size);
if (m_desired_queue_size > m_max_out_request_queue)
m_desired_queue_size = m_max_out_request_queue;
if (m_desired_queue_size < min_request_queue)
m_desired_queue_size = min_request_queue;
if (m_snubbed)
{
m_desired_queue_size = 1;
}
else
{
m_desired_queue_size = static_cast<int>(queue_time
* statistics().download_rate() / block_size);
if (m_desired_queue_size > m_max_out_request_queue)
m_desired_queue_size = m_max_out_request_queue;
if (m_desired_queue_size < min_request_queue)
m_desired_queue_size = min_request_queue;
}
if (!m_download_queue.empty()
&& now - m_last_piece > seconds(m_ses.settings().piece_timeout))
@ -2643,6 +2692,9 @@ namespace libtorrent
<< " " << total_seconds(now - m_last_piece) << "] ***\n";
#endif
m_snubbed = true;
m_desired_queue_size = 1;
if (t->is_seed())
{
m_download_queue.clear();