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:
Arvid Norberg 2005-09-27 08:07:24 +00:00
parent 09c98711d5
commit beee914277
4 changed files with 125 additions and 62 deletions

View File

@ -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;

View File

@ -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:

View File

@ -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,6 +1530,76 @@ namespace libtorrent
send_buffer_updated();
}
void peer_connection::send_block_requests()
{
// 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);
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;
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();
int block_size
= std::min((int)m_torrent->torrent_file().piece_size(block.piece_index)-block_offset,
m_torrent->block_size());
assert(block_size > 0);
assert(block_size <= m_torrent->block_size());
char buf[] = {0,0,0,13, msg_request};
buffer::interval i = m_send_buffer.allocate(17);
std::copy(buf, buf + 5, i.begin);
i.begin += 5;
// index
detail::write_int32(block.piece_index, i.begin);
// begin
detail::write_int32(block_offset, i.begin);
// length
detail::write_int32(block_size, i.begin);
assert(i.begin == i.end);
using namespace boost::posix_time;
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << to_simple_string(second_clock::universal_time())
<< " ==> REQUEST [ "
"piece: " << block.piece_index << " | "
"b: " << block.block_index << " | "
"s: " << block_offset << " | "
"l: " << block_size << " ]\n";
peer_request r;
r.piece = block.piece_index;
r.start = block_offset;
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;
@ -1527,50 +1612,8 @@ namespace libtorrent
assert(!m_torrent->picker().is_downloading(block));
m_torrent->picker().mark_as_downloading(block, m_socket->sender());
m_download_queue.push_back(block);
int block_offset = block.block_index * m_torrent->block_size();
int block_size
= std::min((int)m_torrent->torrent_file().piece_size(block.piece_index)-block_offset,
m_torrent->block_size());
assert(block_size > 0);
assert(block_size <= m_torrent->block_size());
char buf[] = {0,0,0,13, msg_request};
buffer::interval i = m_send_buffer.allocate(17);
std::copy(buf, buf + 5, i.begin);
i.begin += 5;
// index
detail::write_int32(block.piece_index, i.begin);
// begin
detail::write_int32(block_offset, i.begin);
// length
detail::write_int32(block_size, i.begin);
assert(i.begin == i.end);
using namespace boost::posix_time;
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << to_simple_string(second_clock::universal_time())
<< " ==> REQUEST [ "
"piece: " << block.piece_index << " | "
"b: " << block.block_index << " | "
"s: " << block_offset << " | "
"l: " << block_size << " ]\n";
peer_request r;
r.piece = block.piece_index;
r.start = block_offset;
r.length = block_size;
assert(verify_piece(r));
#endif
m_last_piece = second_clock::universal_time();
send_buffer_updated();
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);

View File

@ -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