optimized piece picking to not cause busy loops in some end-game modes
This commit is contained in:
parent
f2416af718
commit
20d4279177
|
@ -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
|
||||||
|
|
|
@ -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 |
|
||||||
|
|
|
@ -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':'.'
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue