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 incoming connection
* added more detailed instrumentation of the disk I/O thread * 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 python bindings for tcp::endpoint
* fixed edge case of pad file support * fixed edge case of pad file support
* limit number of torrents tracked by DHT * limit number of torrents tracked by DHT

View File

@ -3411,7 +3411,8 @@ It contains the following fields::
optimistic_unchoke = 0x800, optimistic_unchoke = 0x800,
snubbed = 0x1000, snubbed = 0x1000,
upload_only = 0x2000, upload_only = 0x2000,
holepunched = 0x4000, endgame_mode = 0x4000,
holepunched = 0x8000,
rc4_encrypted = 0x100000, rc4_encrypted = 0x100000,
plaintext_encrypted = 0x200000 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 | | | will not downloading anything more, regardless of |
| | which pieces we have. | | | 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 | | ``holepunched`` | This flag is set if the peer was in holepunch mode |
| | when the connection succeeded. This typically only | | | when the connection succeeded. This typically only |
| | happens if both peers are behind a NAT and the peers | | | 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 #endif
snprintf(str, sizeof(str) 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() , 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() , 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() , 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->write_state == peer_info::bw_network)?'W':'.'
, (i->flags & peer_info::snubbed)?'S':'.' , (i->flags & peer_info::snubbed)?'S':'.'
, (i->flags & peer_info::upload_only)?'U':'D' , (i->flags & peer_info::upload_only)?'U':'D'
, (i->flags & peer_info::endgame_mode)?'-':'.'
#ifndef TORRENT_DISABLE_ENCRYPTION #ifndef TORRENT_DISABLE_ENCRYPTION
, (i->flags & peer_info::rc4_encrypted)?'E': , (i->flags & peer_info::rc4_encrypted)?'E':
(i->flags & peer_info::plaintext_encrypted)?'e':'.' (i->flags & peer_info::plaintext_encrypted)?'e':'.'

View File

@ -248,6 +248,9 @@ namespace libtorrent
void request_large_blocks(bool b) void request_large_blocks(bool b)
{ m_request_large_blocks = 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; } bool no_download() const { return m_no_download; }
void no_download(bool b) { m_no_download = b; } void no_download(bool b) { m_no_download = b; }
@ -409,7 +412,12 @@ namespace libtorrent
bool failed() const { return m_failed; } 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( bool bittyrant_unchoke_compare(
boost::intrusive_ptr<peer_connection const> const& p) const; boost::intrusive_ptr<peer_connection const> const& p) const;
@ -1101,6 +1109,13 @@ namespace libtorrent
// pick any pieces from this peer // pick any pieces from this peer
bool m_no_download:1; 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 // set to true when we've sent the first round of suggests
bool m_sent_suggests:1; bool m_sent_suggests:1;

View File

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

View File

@ -150,6 +150,7 @@ namespace libtorrent
, m_snubbed(false) , m_snubbed(false)
, m_bitfield_received(false) , m_bitfield_received(false)
, m_no_download(false) , m_no_download(false)
, m_endgame_mode(false)
, m_sent_suggests(false) , m_sent_suggests(false)
, m_holepunch_mode(false) , m_holepunch_mode(false)
, m_ignore_stats(false) , m_ignore_stats(false)
@ -292,6 +293,7 @@ namespace libtorrent
, m_snubbed(false) , m_snubbed(false)
, m_bitfield_received(false) , m_bitfield_received(false)
, m_no_download(false) , m_no_download(false)
, m_endgame_mode(false)
, m_sent_suggests(false) , m_sent_suggests(false)
, m_holepunch_mode(false) , m_holepunch_mode(false)
, m_ignore_stats(false) , m_ignore_stats(false)
@ -3593,6 +3595,7 @@ namespace libtorrent
p.flags |= is_seed() ? peer_info::seed : 0; p.flags |= is_seed() ? peer_info::seed : 0;
p.flags |= m_snubbed ? peer_info::snubbed : 0; p.flags |= m_snubbed ? peer_info::snubbed : 0;
p.flags |= m_upload_only ? peer_info::upload_only : 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; p.flags |= m_holepunch_mode ? peer_info::holepunched : 0;
if (peer_info_struct()) if (peer_info_struct())
{ {
@ -3852,6 +3855,23 @@ namespace libtorrent
return; 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(); on_tick();
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS

View File

@ -145,7 +145,7 @@ namespace libtorrent
- (int)c.request_queue().size(); - (int)c.request_queue().size();
#ifdef TORRENT_VERBOSE_LOGGING #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 #endif
TORRENT_ASSERT(c.desired_queue_size() > 0); TORRENT_ASSERT(c.desired_queue_size() > 0);
// if our request queue is already full, we // 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 // don't request pieces we already have in our request queue
if (std::find_if(dq.begin(), dq.end(), has_block(*i)) != dq.end() 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()) || std::find_if(rq.begin(), rq.end(), has_block(*i)) != rq.end())
{
TORRENT_ASSERT(false); // this shouldn't happen!
continue; continue;
}
// ok, we found a piece that's not being downloaded // ok, we found a piece that's not being downloaded
// by somebody else. request it from this peer // by somebody else. request it from this peer
@ -263,12 +266,27 @@ namespace libtorrent
num_requests--; 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 // 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 // or if we already have outstanding requests, don't
// pick a busy piece // pick a busy piece
if (busy_pieces.empty() if (busy_pieces.empty()
|| num_requests <= 0
|| dq.size() + rq.size() > 0) || dq.size() + rq.size() > 0)
{ {
return; return;