separated the queue of blocks to be requested from peers and those allocated for peers. This sets a hard limit on the remote request queue size and works better with BitComet
This commit is contained in:
@@ -139,6 +139,7 @@ namespace libtorrent
|
||||
bool has_piece(int i) const;
|
||||
|
||||
const std::deque<piece_block>& download_queue() const;
|
||||
const std::deque<piece_block>& request_queue() const;
|
||||
const std::deque<peer_request>& upload_queue() const;
|
||||
|
||||
// returns the block currently being
|
||||
@@ -283,6 +284,7 @@ namespace libtorrent
|
||||
|
||||
private:
|
||||
|
||||
void send_block_requests();
|
||||
bool dispatch_message(int received);
|
||||
|
||||
// if we don't have all metadata
|
||||
@@ -324,6 +326,7 @@ namespace libtorrent
|
||||
msg_request,
|
||||
msg_piece,
|
||||
msg_cancel,
|
||||
msg_dht_port,
|
||||
// extension protocol message
|
||||
msg_extension_list = 20,
|
||||
msg_extended,
|
||||
@@ -451,6 +454,10 @@ namespace libtorrent
|
||||
// the peer
|
||||
std::vector<int> m_announce_queue;
|
||||
|
||||
// the blocks we have reserved in the piece
|
||||
// picker and will send to this peer.
|
||||
std::deque<piece_block> m_request_queue;
|
||||
|
||||
// the queue of blocks we have requested
|
||||
// from this peer
|
||||
std::deque<piece_block> m_download_queue;
|
||||
|
@@ -59,6 +59,18 @@ namespace libtorrent
|
||||
class address;
|
||||
class peer_connection;
|
||||
|
||||
enum
|
||||
{
|
||||
// the limits of the download queue size
|
||||
max_request_queue = 48,
|
||||
min_request_queue = 2,
|
||||
|
||||
// the amount of free upload allowed before
|
||||
// the peer is choked
|
||||
free_upload_amount = 4 * 16 * 1024
|
||||
};
|
||||
|
||||
|
||||
class policy
|
||||
{
|
||||
public:
|
||||
|
@@ -386,12 +386,17 @@ namespace libtorrent
|
||||
return m_have_piece[i];
|
||||
}
|
||||
|
||||
const std::deque<piece_block>& peer_connection::download_queue() const
|
||||
std::deque<piece_block> const& peer_connection::request_queue() const
|
||||
{
|
||||
return m_request_queue;
|
||||
}
|
||||
|
||||
std::deque<piece_block> const& peer_connection::download_queue() const
|
||||
{
|
||||
return m_download_queue;
|
||||
}
|
||||
|
||||
const std::deque<peer_request>& peer_connection::upload_queue() const
|
||||
std::deque<peer_request> const& peer_connection::upload_queue() const
|
||||
{
|
||||
return m_requests;
|
||||
}
|
||||
@@ -401,7 +406,7 @@ namespace libtorrent
|
||||
m_statistics.add_stat(downloaded, uploaded);
|
||||
}
|
||||
|
||||
const std::vector<bool>& peer_connection::get_bitfield() const
|
||||
std::vector<bool> const& peer_connection::get_bitfield() const
|
||||
{
|
||||
return m_have_piece;
|
||||
}
|
||||
@@ -584,7 +589,16 @@ namespace libtorrent
|
||||
{
|
||||
m_torrent->picker().abort_download(*i);
|
||||
}
|
||||
for (std::deque<piece_block>::const_iterator i = m_request_queue.begin()
|
||||
, end(m_request_queue.end()); i != end; ++i)
|
||||
{
|
||||
// since this piece was skipped, clear it and allow it to
|
||||
// be requested from other peers
|
||||
m_torrent->picker().abort_download(*i);
|
||||
}
|
||||
m_download_queue.clear();
|
||||
m_request_queue.clear();
|
||||
|
||||
#ifndef NDEBUG
|
||||
// m_torrent->picker().integrity_check(m_torrent);
|
||||
#endif
|
||||
@@ -1011,6 +1025,7 @@ namespace libtorrent
|
||||
// skipped blocks.
|
||||
m_download_queue.erase(m_download_queue.begin()
|
||||
, boost::next(b));
|
||||
send_block_requests();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1480,7 +1495,7 @@ namespace libtorrent
|
||||
assert(it != m_download_queue.end());
|
||||
|
||||
m_download_queue.erase(it);
|
||||
|
||||
send_block_requests();
|
||||
|
||||
int block_offset = block.block_index * m_torrent->block_size();
|
||||
int block_size
|
||||
@@ -1515,19 +1530,30 @@ namespace libtorrent
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
||||
void peer_connection::send_request(piece_block block)
|
||||
void peer_connection::send_block_requests()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
// TODO: calculate the desired request queue each tick instead.
|
||||
// TODO: make this constant user-settable
|
||||
const int queue_time = 3; // seconds
|
||||
// (if the latency is more than this, the download will stall)
|
||||
// so, the queue size is 5 * down_rate / 16 kiB (16 kB is the size of each request)
|
||||
// the minimum request size is 2 and the maximum is 48
|
||||
// the block size doesn't have to be 16. So we first query the torrent for it
|
||||
const int block_size = m_torrent->block_size();
|
||||
assert(block_size > 0);
|
||||
|
||||
assert(m_torrent->valid_metadata());
|
||||
assert(block.piece_index >= 0);
|
||||
assert(block.piece_index < m_torrent->torrent_file().num_pieces());
|
||||
assert(block.block_index >= 0);
|
||||
assert(block.block_index < m_torrent->torrent_file().piece_size(block.piece_index));
|
||||
assert(!m_torrent->picker().is_downloading(block));
|
||||
int desired_queue_size = static_cast<int>(queue_time
|
||||
* statistics().download_rate() / block_size);
|
||||
if (desired_queue_size > max_request_queue) desired_queue_size = max_request_queue;
|
||||
if (desired_queue_size < min_request_queue) desired_queue_size = min_request_queue;
|
||||
|
||||
m_torrent->picker().mark_as_downloading(block, m_socket->sender());
|
||||
if ((int)m_download_queue.size() >= desired_queue_size) return;
|
||||
|
||||
while (!m_request_queue.empty()
|
||||
&& (int)m_download_queue.size() < desired_queue_size)
|
||||
{
|
||||
piece_block block = m_request_queue.front();
|
||||
m_request_queue.pop_front();
|
||||
m_download_queue.push_back(block);
|
||||
|
||||
int block_offset = block.block_index * m_torrent->block_size();
|
||||
@@ -1568,9 +1594,26 @@ namespace libtorrent
|
||||
r.length = block_size;
|
||||
assert(verify_piece(r));
|
||||
#endif
|
||||
|
||||
}
|
||||
m_last_piece = second_clock::universal_time();
|
||||
send_buffer_updated();
|
||||
|
||||
}
|
||||
|
||||
void peer_connection::send_request(piece_block block)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
assert(m_torrent->valid_metadata());
|
||||
assert(block.piece_index >= 0);
|
||||
assert(block.piece_index < m_torrent->torrent_file().num_pieces());
|
||||
assert(block.block_index >= 0);
|
||||
assert(block.block_index < m_torrent->torrent_file().piece_size(block.piece_index));
|
||||
assert(!m_torrent->picker().is_downloading(block));
|
||||
|
||||
m_torrent->picker().mark_as_downloading(block, m_socket->sender());
|
||||
m_request_queue.push_back(block);
|
||||
send_block_requests();
|
||||
}
|
||||
|
||||
void peer_connection::send_metadata(std::pair<int, int> req)
|
||||
@@ -1884,8 +1927,9 @@ namespace libtorrent
|
||||
|
||||
ptime now(second_clock::universal_time());
|
||||
|
||||
// TODO: the timeout should be user-settable
|
||||
if (!m_download_queue.empty()
|
||||
&& now - m_last_piece > seconds(30))
|
||||
&& now - m_last_piece > seconds(15))
|
||||
{
|
||||
// this peer isn't sending the pieces we've
|
||||
// requested (this has been observed by BitComet)
|
||||
@@ -1904,7 +1948,16 @@ namespace libtorrent
|
||||
// be requested from other peers
|
||||
picker.abort_download(*i);
|
||||
}
|
||||
for (std::deque<piece_block>::const_iterator i = m_request_queue.begin()
|
||||
, end(m_request_queue.end()); i != end; ++i)
|
||||
{
|
||||
// since this piece was skipped, clear it and allow it to
|
||||
// be requested from other peers
|
||||
picker.abort_download(*i);
|
||||
}
|
||||
|
||||
m_download_queue.clear();
|
||||
m_request_queue.clear();
|
||||
|
||||
// this will trigger new picking of pieces
|
||||
m_torrent->get_policy().unchoked(*this);
|
||||
|
@@ -58,17 +58,6 @@ using namespace boost::posix_time;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum
|
||||
{
|
||||
// the limits of the download queue size
|
||||
max_request_queue = 48,
|
||||
min_request_queue = 2,
|
||||
|
||||
// the amount of free upload allowed before
|
||||
// the peer is choked
|
||||
free_upload_amount = 4 * 16 * 1024
|
||||
};
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
// the case where ignore_peer is motivated is if two peers
|
||||
@@ -83,7 +72,8 @@ namespace
|
||||
// this will make the number of requests linearly dependent
|
||||
// on the rate in which we download from the peer.
|
||||
// we want the queue to represent:
|
||||
const int queue_time = 5; // seconds
|
||||
// TODO: make this constant user-settable
|
||||
const int queue_time = 3; // seconds
|
||||
// (if the latency is more than this, the download will stall)
|
||||
// so, the queue size is 5 * down_rate / 16 kiB (16 kB is the size of each request)
|
||||
// the minimum request size is 2 and the maximum is 48
|
||||
@@ -98,7 +88,8 @@ namespace
|
||||
|
||||
assert(desired_queue_size >= min_request_queue);
|
||||
|
||||
int num_requests = desired_queue_size - (int)c.download_queue().size();
|
||||
int num_requests = desired_queue_size - (int)c.download_queue().size()
|
||||
- (int)c.request_queue().size();
|
||||
|
||||
// if our request queue is already full, we
|
||||
// don't have to make any new requests yet
|
||||
|
Reference in New Issue
Block a user