optimized piece picking to not cause busy loops in some end-game modes

This commit is contained in:
Arvid Norberg 2010-12-18 10:19:34 +00:00
parent f2416af718
commit 20d4279177
7 changed files with 69 additions and 7 deletions

View File

@ -63,6 +63,7 @@
incoming connection
* added more detailed instrumentation of the disk I/O thread
* optimized piece picking to not cause busy loops in some end-game modes
* fixed python bindings for tcp::endpoint
* fixed edge case of pad file support
* limit number of torrents tracked by DHT

View File

@ -3411,7 +3411,8 @@ It contains the following fields::
optimistic_unchoke = 0x800,
snubbed = 0x1000,
upload_only = 0x2000,
holepunched = 0x4000,
endgame_mode = 0x4000,
holepunched = 0x8000,
rc4_encrypted = 0x100000,
plaintext_encrypted = 0x200000
};
@ -3560,6 +3561,11 @@ any combination of the enums above. The following table describes each flag:
| | will not downloading anything more, regardless of |
| | which pieces we have. |
+-------------------------+-------------------------------------------------------+
| ``endgame_mode`` | This means the last time this peer picket a piece, |
| | it could not pick as many as it wanted because there |
| | were not enough free ones. i.e. all pieces this peer |
| | has were already requested from other peers. |
+-------------------------+-------------------------------------------------------+
| ``holepunched`` | This flag is set if the peer was in holepunch mode |
| | when the connection succeeded. This typically only |
| | happens if both peers are behind a NAT and the peers |

View File

@ -426,7 +426,7 @@ void print_peer_info(std::string& out, std::vector<libtorrent::peer_info> const&
#endif
snprintf(str, sizeof(str)
, "%s%s (%s|%s) %s%s (%s|%s) %s%3d (%3d) %3d %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c%c%c%c%c%c "
, "%s%s (%s|%s) %s%s (%s|%s) %s%3d (%3d) %3d %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c%c%c%c%c%c "
, esc("32"), add_suffix(i->down_speed, "/s").c_str()
, add_suffix(i->total_download).c_str(), add_suffix(i->download_rate_peak, "/s").c_str()
, esc("31"), add_suffix(i->up_speed, "/s").c_str(), add_suffix(i->total_upload).c_str()
@ -451,6 +451,7 @@ void print_peer_info(std::string& out, std::vector<libtorrent::peer_info> const&
(i->write_state == peer_info::bw_network)?'W':'.'
, (i->flags & peer_info::snubbed)?'S':'.'
, (i->flags & peer_info::upload_only)?'U':'D'
, (i->flags & peer_info::endgame_mode)?'-':'.'
#ifndef TORRENT_DISABLE_ENCRYPTION
, (i->flags & peer_info::rc4_encrypted)?'E':
(i->flags & peer_info::plaintext_encrypted)?'e':'.'

View File

@ -248,6 +248,9 @@ namespace libtorrent
void request_large_blocks(bool b)
{ m_request_large_blocks = b; }
void set_endgame(bool b) { m_endgame_mode = b; }
bool endgame() const { return m_endgame_mode; }
bool no_download() const { return m_no_download; }
void no_download(bool b) { m_no_download = b; }
@ -409,7 +412,12 @@ namespace libtorrent
bool failed() const { return m_failed; }
int desired_queue_size() const { return m_desired_queue_size; }
int desired_queue_size() const
{
// this peer is in end-game mode we only want
// one outstanding request
return m_endgame_mode ? 1: m_desired_queue_size;
}
bool bittyrant_unchoke_compare(
boost::intrusive_ptr<peer_connection const> const& p) const;
@ -1101,6 +1109,13 @@ namespace libtorrent
// pick any pieces from this peer
bool m_no_download:1;
// this is set to true if the last time we tried to
// pick a piece to download, we could only find
// blocks that were already requested from other
// peers. In this case, we should not try to pick
// another piece until the last one we requested is done
bool m_endgame_mode:1;
// set to true when we've sent the first round of suggests
bool m_sent_suggests:1;

View File

@ -60,7 +60,8 @@ namespace libtorrent
optimistic_unchoke = 0x800,
snubbed = 0x1000,
upload_only = 0x2000,
holepunched = 0x4000
endgame_mode = 0x4000,
holepunched = 0x8000
#ifndef TORRENT_DISABLE_ENCRYPTION
, rc4_encrypted = 0x100000,
plaintext_encrypted = 0x200000

View File

@ -150,6 +150,7 @@ namespace libtorrent
, m_snubbed(false)
, m_bitfield_received(false)
, m_no_download(false)
, m_endgame_mode(false)
, m_sent_suggests(false)
, m_holepunch_mode(false)
, m_ignore_stats(false)
@ -292,6 +293,7 @@ namespace libtorrent
, m_snubbed(false)
, m_bitfield_received(false)
, m_no_download(false)
, m_endgame_mode(false)
, m_sent_suggests(false)
, m_holepunch_mode(false)
, m_ignore_stats(false)
@ -3593,6 +3595,7 @@ namespace libtorrent
p.flags |= is_seed() ? peer_info::seed : 0;
p.flags |= m_snubbed ? peer_info::snubbed : 0;
p.flags |= m_upload_only ? peer_info::upload_only : 0;
p.flags |= m_endgame_mode ? peer_info::endgame_mode : 0;
p.flags |= m_holepunch_mode ? peer_info::holepunched : 0;
if (peer_info_struct())
{
@ -3852,6 +3855,23 @@ namespace libtorrent
return;
}
if (m_endgame_mode
&& m_interesting
&& m_download_queue.empty()
&& m_request_queue.empty()
&& total_seconds(now - m_last_request) > 5)
{
// this happens when we're in strict end-game
// mode and the peer could not request any blocks
// because they were all taken but there were still
// unrequested blocks. Now, 5 seconds later, there
// might not be any unrequested blocks anymore, so
// we should try to pick another block to see
// if we can pick a busy one
request_a_block(*t, *this);
if (m_disconnecting) return;
}
on_tick();
#ifndef TORRENT_DISABLE_EXTENSIONS

View File

@ -145,7 +145,7 @@ namespace libtorrent
- (int)c.request_queue().size();
#ifdef TORRENT_VERBOSE_LOGGING
c.peer_log("*** PIECE_PICKER [ req: %d ]", num_requests);
c.peer_log("*** PIECE_PICKER [ req: %d engame: %d ]", num_requests, c.endgame());
#endif
TORRENT_ASSERT(c.desired_queue_size() > 0);
// if our request queue is already full, we
@ -252,7 +252,10 @@ namespace libtorrent
// don't request pieces we already have in our request queue
if (std::find_if(dq.begin(), dq.end(), has_block(*i)) != dq.end()
|| std::find_if(rq.begin(), rq.end(), has_block(*i)) != rq.end())
{
TORRENT_ASSERT(false); // this shouldn't happen!
continue;
}
// ok, we found a piece that's not being downloaded
// by somebody else. request it from this peer
@ -263,12 +266,27 @@ namespace libtorrent
num_requests--;
}
// we have picked as many blocks as we should
// we're done!
if (num_requests <= 0)
{
// since we could pick as many blocks as we
// requested without having to resort to picking
// busy ones, we're not in end-game mode
c.set_endgame(false);
return;
}
// we did not pick as many pieces as we wanted, because
// there aren't enough. This means we're in end-game mode
// as long as we have at least one request outstanding,
// we shouldn't pick another piece
c.set_endgame(true);
// if we don't have any potential busy blocks to request
// or if we have picked as many blocks as we should
// or if we already have outstanding requests, don't
// pick a busy piece
if (busy_pieces.empty()
|| num_requests <= 0
|| dq.size() + rq.size() > 0)
{
return;