forked from premiere/premiere-libtorrent
bugfixes, fixes for boost 1.33, made the piece picker pick whole pieces from fast peers
This commit is contained in:
parent
f7c90b8511
commit
1934171431
|
@ -1255,7 +1255,7 @@ struct partial_piece_info
|
|||
int blocks_in_piece;
|
||||
std::bitset<max_blocks_per_piece> requested_blocks;
|
||||
std::bitset<max_blocks_per_piece> finished_blocks;
|
||||
peer_id peer[max_blocks_per_piece];
|
||||
address peer[max_blocks_per_piece];
|
||||
int num_downloads[max_blocks_per_piece];
|
||||
};
|
||||
</pre>
|
||||
|
@ -1266,7 +1266,7 @@ the last piece may have fewer blocks than the standard pieces.</p>
|
|||
means that that block has been requested, but not necessarily fully downloaded yet. To know
|
||||
from whom the block has been requested, have a look in the <tt class="docutils literal"><span class="pre">peer</span></tt> array. The bit-index
|
||||
in the <tt class="docutils literal"><span class="pre">requested_blocks</span></tt> and <tt class="docutils literal"><span class="pre">finished_blocks</span></tt> correspons to the array-index into
|
||||
<tt class="docutils literal"><span class="pre">peers</span></tt> and <tt class="docutils literal"><span class="pre">num_downloads</span></tt>. The array of peers is contains the id of the
|
||||
<tt class="docutils literal"><span class="pre">peers</span></tt> and <tt class="docutils literal"><span class="pre">num_downloads</span></tt>. The array of peers is contains the address of the
|
||||
peer the piece was requested from. If a piece hasn't been requested (the bit in
|
||||
<tt class="docutils literal"><span class="pre">requested_blocks</span></tt> is not set) the peer array entry will be undefined.</p>
|
||||
<p>The <tt class="docutils literal"><span class="pre">finished_blocks</span></tt> is a bitset where each bit says if the block is fully downloaded
|
||||
|
|
|
@ -1192,7 +1192,7 @@ requested. The entry in the vector (``partial_piece_info``) looks like this::
|
|||
int blocks_in_piece;
|
||||
std::bitset<max_blocks_per_piece> requested_blocks;
|
||||
std::bitset<max_blocks_per_piece> finished_blocks;
|
||||
peer_id peer[max_blocks_per_piece];
|
||||
address peer[max_blocks_per_piece];
|
||||
int num_downloads[max_blocks_per_piece];
|
||||
};
|
||||
|
||||
|
@ -1204,7 +1204,7 @@ the last piece may have fewer blocks than the standard pieces.
|
|||
means that that block has been requested, but not necessarily fully downloaded yet. To know
|
||||
from whom the block has been requested, have a look in the ``peer`` array. The bit-index
|
||||
in the ``requested_blocks`` and ``finished_blocks`` correspons to the array-index into
|
||||
``peers`` and ``num_downloads``. The array of peers is contains the id of the
|
||||
``peers`` and ``num_downloads``. The array of peers is contains the address of the
|
||||
peer the piece was requested from. If a piece hasn't been requested (the bit in
|
||||
``requested_blocks`` is not set) the peer array entry will be undefined.
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use-project /torrent : .. ;
|
||||
|
||||
project
|
||||
project client_test
|
||||
: requirements <threading>multi <library>/torrent
|
||||
;
|
||||
|
||||
exe client_test : client_test.cpp ;
|
||||
exe client_test : client_test.cpp ;
|
||||
exe simple_client : simple_client.cpp ;
|
||||
exe dump_torrent : dump_torrent.cpp ;
|
||||
exe make_torrent : make_torrent.cpp ;
|
||||
|
||||
stage . : dump_torrent make_torrent simple_client client_test ;
|
||||
#stage . : dump_torrent make_torrent simple_client client_test ;
|
||||
|
||||
|
|
|
@ -55,6 +55,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/identify_client.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
|
||||
using boost::bind;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
@ -100,6 +102,8 @@ void clear()
|
|||
#include <termios.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ANSI_TERMINAL_COLORS
|
||||
|
||||
struct set_keypress
|
||||
{
|
||||
set_keypress()
|
||||
|
@ -147,6 +151,20 @@ void clear()
|
|||
|
||||
#endif
|
||||
|
||||
std::string esc(char const* code)
|
||||
{
|
||||
#ifdef ANSI_TERMINAL_COLORS
|
||||
std::string ret;
|
||||
ret += char(0x1b);
|
||||
ret += "[";
|
||||
ret += code;
|
||||
ret += "m";
|
||||
return ret;
|
||||
#else
|
||||
return std::string();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string to_string(float v, int width, int precision = 3)
|
||||
{
|
||||
std::stringstream s;
|
||||
|
@ -203,17 +221,32 @@ std::string add_suffix(float val)
|
|||
return to_string(val, 6) + "PB";
|
||||
}
|
||||
|
||||
std::string progress_bar(float progress, int width)
|
||||
std::string progress_bar(float progress, int width, char const* code = "33")
|
||||
{
|
||||
std::vector<char> bar;
|
||||
std::string bar;
|
||||
bar.reserve(width);
|
||||
|
||||
int progress_chars = static_cast<int>(progress * width + .5f);
|
||||
bar = esc(code);
|
||||
std::fill_n(std::back_inserter(bar), progress_chars, '#');
|
||||
bar += esc("0");
|
||||
std::fill_n(std::back_inserter(bar), width - progress_chars, '-');
|
||||
return std::string(bar.begin(), bar.end());
|
||||
}
|
||||
|
||||
char const* peer_index(libtorrent::address addr, std::vector<libtorrent::peer_info> const& peers)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
std::vector<peer_info>::const_iterator i = std::find_if(peers.begin()
|
||||
, peers.end(), bind(std::equal_to<address>(), bind(&peer_info::ip, _1), addr));
|
||||
if (i == peers.end()) return "+";
|
||||
|
||||
static char str[] = " ";
|
||||
int index = i - peers.begin();
|
||||
str[0] = (index < 10)?'0' + index:'A' + index - 10;
|
||||
return str;
|
||||
}
|
||||
|
||||
void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const& peers)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
|
@ -225,9 +258,9 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
|
|||
{
|
||||
out.fill(' ');
|
||||
out.width(2);
|
||||
out << add_suffix(i->down_speed) << "/s "
|
||||
out << esc("32") << add_suffix(i->down_speed) << "/s " << esc("0")
|
||||
// << "(" << add_suffix(i->total_download) << ") "
|
||||
<< add_suffix(i->up_speed) << "/s "
|
||||
<< esc("31") << add_suffix(i->up_speed) << "/s " << esc("0")
|
||||
// << "(" << add_suffix(i->total_upload) << ") "
|
||||
// << "ul:" << add_suffix(i->upload_limit) << "/s "
|
||||
// << "uc:" << add_suffix(i->upload_ceiling) << "/s "
|
||||
|
@ -486,6 +519,8 @@ int main(int argc, char* argv[])
|
|||
a = ses.pop_alert();
|
||||
}
|
||||
|
||||
session_status sess_stat = ses.status();
|
||||
|
||||
std::stringstream out;
|
||||
for (std::vector<torrent_handle>::iterator i = handles.begin();
|
||||
i != handles.end(); ++i)
|
||||
|
@ -496,10 +531,10 @@ int main(int argc, char* argv[])
|
|||
--i;
|
||||
continue;
|
||||
}
|
||||
out << "name: ";
|
||||
out << "name: " << esc("37");
|
||||
if (i->has_metadata()) out << i->get_torrent_info().name();
|
||||
else out << "-";
|
||||
out << "\n";
|
||||
out << esc("0") << "\n";
|
||||
torrent_status s = i->status();
|
||||
|
||||
if (s.state != torrent_status::seeding)
|
||||
|
@ -534,28 +569,42 @@ int main(int argc, char* argv[])
|
|||
|
||||
if (s.state != torrent_status::seeding)
|
||||
{
|
||||
char const* progress_bar_color = "33"; // yellow
|
||||
if (s.state == torrent_status::checking_files
|
||||
|| s.state == torrent_status::downloading_metadata)
|
||||
{
|
||||
progress_bar_color = "35"; // magenta
|
||||
}
|
||||
else if (s.current_tracker.empty())
|
||||
{
|
||||
progress_bar_color = "31"; // red
|
||||
}
|
||||
else if (sess_stat.has_incoming_connections)
|
||||
{
|
||||
progress_bar_color = "32"; // green
|
||||
}
|
||||
out.precision(4);
|
||||
out.width(5);
|
||||
out.fill(' ');
|
||||
out << (s.progress*100) << "% ";
|
||||
out << progress_bar(s.progress, 49);
|
||||
out << progress_bar(s.progress, 49, progress_bar_color);
|
||||
out << "\n";
|
||||
out << "total downloaded: " << s.total_done << " Bytes\n";
|
||||
out << "total downloaded: " << esc("32") << s.total_done << esc("0") << " Bytes\n";
|
||||
out << "peers: " << s.num_peers << " "
|
||||
<< "seeds: " << s.num_seeds << " "
|
||||
<< "distributed copies: " << s.distributed_copies << "\n";
|
||||
}
|
||||
out << "download: " << add_suffix(s.download_rate) << "/s "
|
||||
<< "(" << add_suffix(s.total_download) << ") "
|
||||
<< "upload: " << add_suffix(s.upload_rate) << "/s "
|
||||
<< "(" << add_suffix(s.total_upload) << ") "
|
||||
out << "download: " << esc("32") << add_suffix(s.download_rate) << "/s " << esc("0")
|
||||
<< "(" << esc("32") << add_suffix(s.total_download) << esc("0") << ") "
|
||||
<< "upload: " << esc("31") << add_suffix(s.upload_rate) << "/s " << esc("0")
|
||||
<< "(" << esc("31") << add_suffix(s.total_upload) << esc("0") << ") "
|
||||
<< "ratio: " << ratio(s.total_payload_download, s.total_payload_upload) << "\n";
|
||||
if (s.state != torrent_status::seeding)
|
||||
{
|
||||
out << "info-hash: " << i->info_hash() << "\n";
|
||||
|
||||
boost::posix_time::time_duration t = s.next_announce;
|
||||
out << "next announce: " << boost::posix_time::to_simple_string(t) << "\n";
|
||||
out << "next announce: " << esc("37") << boost::posix_time::to_simple_string(t) << esc("0") << "\n";
|
||||
out << "tracker: " << s.current_tracker << "\n";
|
||||
}
|
||||
|
||||
|
@ -578,9 +627,16 @@ int main(int argc, char* argv[])
|
|||
out << i->piece_index << ": [";
|
||||
for (int j = 0; j < i->blocks_in_piece; ++j)
|
||||
{
|
||||
if (i->finished_blocks[j]) out << "#";
|
||||
else if (i->requested_blocks[j]) out << "+";
|
||||
char const* peer_str = peer_index(i->peer[j], peers);
|
||||
#ifdef ANSI_TERMINAL_COLORS
|
||||
if (i->finished_blocks[j]) out << esc("32;7") << peer_str << esc("0");
|
||||
else if (i->requested_blocks[j]) out << peer_str;
|
||||
else out << "-";
|
||||
#else
|
||||
if (i->finished_blocks[j]) out << "#";
|
||||
else if (i->requested_blocks[j]) out << peer_str;
|
||||
else out << "-";
|
||||
#endif
|
||||
}
|
||||
out << "]\n";
|
||||
}
|
||||
|
@ -592,8 +648,7 @@ int main(int argc, char* argv[])
|
|||
if (print_log)
|
||||
{
|
||||
for (std::deque<std::string>::iterator i = events.begin();
|
||||
i != events.end();
|
||||
++i)
|
||||
i != events.end(); ++i)
|
||||
{
|
||||
out << *i << "\n";
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace libtorrent
|
|||
struct null_logger: libtorrent::logger
|
||||
{
|
||||
public:
|
||||
virtual void log(const char* text) {}
|
||||
virtual void log(const char*) {}
|
||||
};
|
||||
|
||||
struct cout_logger: libtorrent::logger
|
||||
|
|
|
@ -160,13 +160,16 @@ namespace libtorrent
|
|||
// decides to download a piece, it must mark it as being downloaded
|
||||
// itself, by using the mark_as_downloading() member function.
|
||||
// THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
|
||||
void pick_pieces(const std::vector<bool>& pieces,
|
||||
std::vector<piece_block>& interesting_blocks,
|
||||
int num_pieces) const;
|
||||
// The last argument is the address of the peer that we'll download
|
||||
// from.
|
||||
void pick_pieces(const std::vector<bool>& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_pieces, bool prefer_whole_pieces
|
||||
, address peer) const;
|
||||
|
||||
// returns true if any client is currently downloading this
|
||||
// piece-block, or if it's queued for downloading by some client
|
||||
// or if it already has been successfully downlloaded
|
||||
// or if it already has been successfully downloaded
|
||||
bool is_downloading(piece_block block) const;
|
||||
bool is_finished(piece_block block) const;
|
||||
|
||||
|
@ -265,10 +268,18 @@ namespace libtorrent
|
|||
std::vector<std::vector<int> > const& pick_piece_info_vector(
|
||||
bool downloading, bool filtered) const;
|
||||
|
||||
int add_interesting_blocks(const std::vector<int>& piece_list,
|
||||
const std::vector<bool>& pieces,
|
||||
std::vector<piece_block>& interesting_pieces,
|
||||
int num_blocks) const;
|
||||
int add_interesting_blocks_free(const std::vector<int>& piece_list
|
||||
, const std::vector<bool>& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_blocks, bool prefer_whole_pieces) const;
|
||||
|
||||
int add_interesting_blocks_partial(const std::vector<int>& piece_list
|
||||
, const std::vector<bool>& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, int num_blocks, bool prefer_whole_pieces
|
||||
, address peer) const;
|
||||
|
||||
|
||||
// this vector contains all pieces we don't have.
|
||||
// in the first entry (index 0) is a vector of all pieces
|
||||
|
|
|
@ -408,7 +408,7 @@ namespace libtorrent
|
|||
try
|
||||
{
|
||||
m_content_length = boost::lexical_cast<int>(
|
||||
line.substr(16));
|
||||
line.substr(16, line.length() - 17));
|
||||
}
|
||||
catch(boost::bad_lexical_cast&)
|
||||
{
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace libtorrent
|
|||
, m_num_have_filtered(0)
|
||||
{
|
||||
assert(blocks_per_piece > 0);
|
||||
assert(total_num_blocks > 0);
|
||||
assert(total_num_blocks >= 0);
|
||||
|
||||
// the piece index is stored in 20 bits, which limits the allowed
|
||||
// number of pieces somewhat
|
||||
|
@ -271,7 +271,7 @@ namespace libtorrent
|
|||
for (int i = 0; i < (int)m_piece_info.size(); ++i)
|
||||
{
|
||||
int p = (int)m_piece_info[i].size();
|
||||
assert(float(p) / num_pieces <= 1.f);
|
||||
assert(num_pieces == 0 || float(p) / num_pieces <= 1.f);
|
||||
if (p > 0)
|
||||
{
|
||||
float fraction_above_count =
|
||||
|
@ -560,8 +560,9 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
void piece_picker::pick_pieces(const std::vector<bool>& pieces
|
||||
, std::vector<piece_block>& interesting_pieces
|
||||
, int num_blocks) const
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_blocks, bool prefer_whole_pieces
|
||||
, address peer) const
|
||||
{
|
||||
assert(num_blocks > 0);
|
||||
assert(pieces.size() == m_piece_map.size());
|
||||
|
@ -582,14 +583,33 @@ namespace libtorrent
|
|||
assert(m_downloading_piece_info.begin() != m_downloading_piece_info.end());
|
||||
std::vector<std::vector<int> >::const_iterator partial = m_downloading_piece_info.begin()+1;
|
||||
|
||||
while((free != m_piece_info.end()) || (partial != m_downloading_piece_info.end()))
|
||||
std::vector<piece_block> backup_blocks;
|
||||
|
||||
// this loop will loop from pieces with 1 peer and up
|
||||
// until we either reach the end of the piece list or
|
||||
// has filled the interesting_blocks with num_blocks
|
||||
// blocks.
|
||||
|
||||
// it iterates over two ranges simultaneously. The pieces that are partially downloaded
|
||||
// or partially requested, and the pieces that hasn't been requested at all.
|
||||
// The default is to prioritize pieces that are partially requested/downloaded, so the
|
||||
// loop will first look for blocks among those pieces. And it will also take two steps
|
||||
// in that range when iterating. This has the effect that partial pieces doesn't have to
|
||||
// be as rare as non-requested pieces in order to be prefered.
|
||||
|
||||
// When prefer_whole_pieces is set (usually set when downloading from fast peers) the
|
||||
// partial pieces will not be prioritized, but actually ignored as long as possible.
|
||||
|
||||
while((free != m_piece_info.end())
|
||||
|| (partial != m_downloading_piece_info.end()))
|
||||
{
|
||||
if (partial != m_downloading_piece_info.end())
|
||||
{
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
num_blocks = add_interesting_blocks(*partial, pieces
|
||||
, interesting_pieces, num_blocks);
|
||||
num_blocks = add_interesting_blocks_partial(*partial, pieces
|
||||
, interesting_blocks, backup_blocks, num_blocks
|
||||
, prefer_whole_pieces, peer);
|
||||
assert(num_blocks >= 0);
|
||||
if (num_blocks == 0) return;
|
||||
++partial;
|
||||
|
@ -599,18 +619,77 @@ namespace libtorrent
|
|||
|
||||
if (free != m_piece_info.end())
|
||||
{
|
||||
num_blocks = add_interesting_blocks(*free, pieces, interesting_pieces, num_blocks);
|
||||
num_blocks = add_interesting_blocks_free(*free, pieces
|
||||
, interesting_blocks, num_blocks, prefer_whole_pieces);
|
||||
assert(num_blocks >= 0);
|
||||
if (num_blocks == 0) return;
|
||||
++free;
|
||||
}
|
||||
}
|
||||
|
||||
if (!prefer_whole_pieces) return;
|
||||
assert(num_blocks > 0);
|
||||
|
||||
interesting_blocks.insert(interesting_blocks.end()
|
||||
, backup_blocks.begin(), backup_blocks.begin()
|
||||
+ std::min(num_blocks, (int)backup_blocks.size()));
|
||||
}
|
||||
|
||||
int piece_picker::add_interesting_blocks(const std::vector<int>& piece_list
|
||||
namespace
|
||||
{
|
||||
bool exclusively_requested_from(piece_picker::downloading_piece const& p
|
||||
, int num_blocks_in_piece, address peer)
|
||||
{
|
||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||
{
|
||||
if ((p.finished_blocks[j] == 1
|
||||
|| p.requested_blocks[j] == 1)
|
||||
&& p.info[j].peer != peer
|
||||
&& p.info[j].peer != address())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int piece_picker::add_interesting_blocks_free(std::vector<int> const& piece_list
|
||||
, std::vector<bool> const& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_blocks, bool prefer_whole_pieces) const
|
||||
{
|
||||
for (std::vector<int>::const_iterator i = piece_list.begin();
|
||||
i != piece_list.end(); ++i)
|
||||
{
|
||||
assert(*i >= 0);
|
||||
assert(*i < (int)m_piece_map.size());
|
||||
assert(m_piece_map[*i].downloading == 0);
|
||||
|
||||
// if the peer doesn't have the piece
|
||||
// skip it
|
||||
if (!pieces[*i]) continue;
|
||||
|
||||
int piece_blocks = blocks_in_piece(*i);
|
||||
if (!prefer_whole_pieces && piece_blocks > num_blocks)
|
||||
piece_blocks = num_blocks;
|
||||
for (int j = 0; j < piece_blocks; ++j)
|
||||
{
|
||||
interesting_blocks.push_back(piece_block(*i, j));
|
||||
}
|
||||
num_blocks -= std::min(piece_blocks, num_blocks);
|
||||
assert(num_blocks >= 0);
|
||||
if (num_blocks == 0) return num_blocks;
|
||||
}
|
||||
return num_blocks;
|
||||
}
|
||||
|
||||
int piece_picker::add_interesting_blocks_partial(std::vector<int> const& piece_list
|
||||
, const std::vector<bool>& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_blocks) const
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, int num_blocks, bool prefer_whole_pieces
|
||||
, address peer) const
|
||||
{
|
||||
assert(num_blocks > 0);
|
||||
|
||||
|
@ -623,24 +702,9 @@ namespace libtorrent
|
|||
// skip it
|
||||
if (!pieces[*i]) continue;
|
||||
|
||||
// if there's at least one block that
|
||||
// we can request from this peer
|
||||
// we can break our search (return)
|
||||
assert(m_piece_map[*i].downloading == 1);
|
||||
|
||||
if (m_piece_map[*i].downloading == 0)
|
||||
{
|
||||
int piece_blocks = std::min(blocks_in_piece(*i), num_blocks);
|
||||
for (int j = 0; j < piece_blocks; ++j)
|
||||
{
|
||||
interesting_blocks.push_back(piece_block(*i, j));
|
||||
}
|
||||
num_blocks -= piece_blocks;
|
||||
assert(num_blocks >= 0);
|
||||
if (num_blocks == 0) return num_blocks;
|
||||
continue;
|
||||
}
|
||||
|
||||
// calculate the number of blocks in this
|
||||
// calculate the number of blocks in this
|
||||
// piece. It's always m_blocks_per_piece, except
|
||||
// in the last piece.
|
||||
int num_blocks_in_piece = blocks_in_piece(*i);
|
||||
|
@ -648,11 +712,33 @@ namespace libtorrent
|
|||
std::vector<downloading_piece>::const_iterator p
|
||||
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(*i));
|
||||
assert(p != m_downloads.end());
|
||||
|
||||
|
||||
// this means that this partial piece has
|
||||
// been downloaded/requested partially from
|
||||
// another peer that isn't us. And since
|
||||
// we prefer whole pieces, add this piece's
|
||||
// blocks to the backup list. If the prioritized
|
||||
// blocks aren't enough, blocks from this list
|
||||
// will be picked.
|
||||
if (prefer_whole_pieces
|
||||
&& !exclusively_requested_from(*p, num_blocks_in_piece, peer))
|
||||
{
|
||||
if ((int)backup_blocks.size() >= num_blocks) continue;
|
||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||
{
|
||||
if (p->finished_blocks[j] == 1) continue;
|
||||
if (p->requested_blocks[j] == 1
|
||||
&& p->info[j].peer == peer) continue;
|
||||
backup_blocks.push_back(piece_block(*i, j));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||
{
|
||||
if (p->finished_blocks[j] == 1) continue;
|
||||
|
||||
if (p->requested_blocks[j] == 1
|
||||
&& p->info[j].peer == peer) continue;
|
||||
// this block is interesting (we don't have it
|
||||
// yet). But it may already have been requested
|
||||
// from another peer. We have to add it anyway
|
||||
|
@ -665,14 +751,17 @@ namespace libtorrent
|
|||
interesting_blocks.push_back(piece_block(*i, j));
|
||||
if (p->requested_blocks[j] == 0)
|
||||
{
|
||||
// we have found a piece that's free to download
|
||||
// we have found a block that's free to download
|
||||
num_blocks--;
|
||||
if (prefer_whole_pieces) continue;
|
||||
assert(num_blocks >= 0);
|
||||
if (num_blocks == 0) return num_blocks;
|
||||
}
|
||||
}
|
||||
assert(num_blocks >= 0 || prefer_whole_pieces);
|
||||
if (num_blocks < 0) num_blocks = 0;
|
||||
if (num_blocks == 0) return num_blocks;
|
||||
}
|
||||
assert(num_blocks >= 0);
|
||||
return num_blocks;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace
|
|||
// the case where ignore_peer is motivated is if two peers
|
||||
// have only one piece that we don't have, and it's the
|
||||
// same piece for both peers. Then they might get into an
|
||||
// infinite recursion, fighting to request the same blocks.
|
||||
// infinite loop, fighting to request the same blocks.
|
||||
void request_a_block(
|
||||
torrent& t
|
||||
, peer_connection& c
|
||||
|
@ -91,8 +91,12 @@ namespace
|
|||
// (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
|
||||
|
||||
int desired_queue_size = static_cast<int>(queue_time * c.statistics().download_rate() / (16 * 1024));
|
||||
// the block size doesn't have to be 16. So we first query the torrent for it
|
||||
const int block_size = t.block_size();
|
||||
assert(block_size > 0);
|
||||
|
||||
int desired_queue_size = static_cast<int>(queue_time
|
||||
* c.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;
|
||||
|
||||
|
@ -113,7 +117,18 @@ namespace
|
|||
// should be guaranteed to be available for download
|
||||
// (if num_requests is too big, too many pieces are
|
||||
// picked and cpu-time is wasted)
|
||||
p.pick_pieces(c.get_bitfield(), interesting_pieces, num_requests);
|
||||
// the last argument is if we should prefer whole pieces
|
||||
// for this peer. If we're downloading one piece in 20 seconds
|
||||
// then use this mode.
|
||||
bool prefer_whole_pieces = c.statistics().download_payload_rate() * 20.f
|
||||
> t.torrent_file().piece_length();
|
||||
|
||||
// if we prefer whole pieces, the piece picker will pick at least
|
||||
// the number of blocks we want, but it will try to make the picked
|
||||
// blocks be from whole pieces, possibly by returning more blocks
|
||||
// than we requested.
|
||||
p.pick_pieces(c.get_bitfield(), interesting_pieces
|
||||
, num_requests, prefer_whole_pieces, c.get_socket()->sender());
|
||||
|
||||
// this vector is filled with the interesting pieces
|
||||
// that some other peer is currently downloading
|
||||
|
@ -137,7 +152,6 @@ namespace
|
|||
// and return
|
||||
c.send_request(*i);
|
||||
num_requests--;
|
||||
if (num_requests <= 0) return;
|
||||
}
|
||||
|
||||
// in this case, we could not find any blocks
|
||||
|
@ -155,13 +169,18 @@ namespace
|
|||
while (num_requests > 0)
|
||||
{
|
||||
peer_connection* peer = 0;
|
||||
float min_weight = std::numeric_limits<float>::max();
|
||||
|
||||
// This peer's weight will be the minimum, to prevent
|
||||
// cancelling requests from a faster peer.
|
||||
float min_weight = (int)c.download_queue().size() == 0
|
||||
? std::numeric_limits<float>::max()
|
||||
: c.statistics().download_payload_rate() / (int)c.download_queue().size();
|
||||
|
||||
// find the peer with the lowest download
|
||||
// speed that also has a piece that this
|
||||
// peer could send us
|
||||
for (torrent::peer_iterator i = t.begin();
|
||||
i != t.end();
|
||||
++i)
|
||||
i != t.end(); ++i)
|
||||
{
|
||||
// don't try to take over blocks from ourself
|
||||
if (i->second == &c)
|
||||
|
|
|
@ -364,9 +364,6 @@ namespace libtorrent { namespace detail
|
|||
std::vector<boost::shared_ptr<socket> > error_clients;
|
||||
boost::posix_time::ptime timer = second_clock::universal_time();
|
||||
|
||||
#ifndef NDEBUG
|
||||
int loops_per_second = 0;
|
||||
#endif
|
||||
for(;;)
|
||||
{
|
||||
try
|
||||
|
@ -377,7 +374,6 @@ namespace libtorrent { namespace detail
|
|||
boost::mutex::scoped_lock l(m_mutex);
|
||||
check_invariant("before SELECT");
|
||||
}
|
||||
loops_per_second++;
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -650,11 +646,6 @@ namespace libtorrent { namespace detail
|
|||
// THE SECTION BELOW IS EXECUTED ONCE EVERY SECOND
|
||||
// ************************
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (loops_per_second > 800) std::cout << "\n\nloops: " << loops_per_second << "\n";
|
||||
loops_per_second = 0;
|
||||
#endif
|
||||
|
||||
// do the second_tick() on each connection
|
||||
// this will update their statistics (download and upload speeds)
|
||||
// also purge sockets that have timed out
|
||||
|
|
|
@ -1476,7 +1476,7 @@ namespace libtorrent
|
|||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
INVARIANT_CHECK;
|
||||
// INVARIANT_CHECK;
|
||||
|
||||
assert(piece_index >= 0);
|
||||
assert(piece_index < (int)m_piece_to_slot.size());
|
||||
|
@ -1635,7 +1635,7 @@ namespace libtorrent
|
|||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
INVARIANT_CHECK;
|
||||
// INVARIANT_CHECK;
|
||||
|
||||
assert(!m_unallocated_slots.empty());
|
||||
|
||||
|
|
|
@ -263,7 +263,7 @@ namespace libtorrent
|
|||
{
|
||||
assert(m_torrent_file.is_valid());
|
||||
assert(m_torrent_file.num_files() > 0);
|
||||
assert(m_torrent_file.total_size() > 0);
|
||||
assert(m_torrent_file.total_size() >= 0);
|
||||
|
||||
m_have_pieces.resize(m_torrent_file.num_pieces(), false);
|
||||
m_storage = std::auto_ptr<piece_manager>(new piece_manager(m_torrent_file, m_save_path));
|
||||
|
@ -396,6 +396,9 @@ namespace libtorrent
|
|||
if (!valid_metadata()) return 0;
|
||||
|
||||
assert(m_picker.get());
|
||||
|
||||
if (m_torrent_file.num_pieces() == 0)
|
||||
return boost::tuple<size_type, size_type>(0,0);
|
||||
const int last_piece = m_torrent_file.num_pieces() - 1;
|
||||
|
||||
size_type wanted_done = (m_num_pieces - m_picker->num_have_filtered())
|
||||
|
@ -554,7 +557,7 @@ namespace libtorrent
|
|||
m_abort = true;
|
||||
m_event = tracker_request::stopped;
|
||||
// disconnect all peers and close all
|
||||
// files belonging to the torrent
|
||||
// files belonging to the torrents
|
||||
disconnect_all();
|
||||
if (m_storage.get()) m_storage->release_files();
|
||||
}
|
||||
|
@ -1263,8 +1266,9 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
assert(st.total_wanted >= st.total_wanted_done);
|
||||
|
||||
st.progress = st.total_wanted_done
|
||||
|
||||
if (st.total_wanted == 0) st.progress = 1.f;
|
||||
else st.progress = st.total_wanted_done
|
||||
/ static_cast<float>(st.total_wanted);
|
||||
|
||||
st.pieces = &m_have_pieces;
|
||||
|
|
|
@ -673,9 +673,7 @@ namespace libtorrent
|
|||
= p.get_download_queue();
|
||||
|
||||
for (std::vector<piece_picker::downloading_piece>::const_iterator i
|
||||
= q.begin();
|
||||
i != q.end();
|
||||
++i)
|
||||
= q.begin(); i != q.end(); ++i)
|
||||
{
|
||||
partial_piece_info pi;
|
||||
pi.finished_blocks = i->finished_blocks;
|
||||
|
|
|
@ -5,7 +5,7 @@ project
|
|||
requirements <threading>multi
|
||||
<library>/torrent
|
||||
<source>main.cpp
|
||||
;
|
||||
;
|
||||
|
||||
test-suite libtorrent :
|
||||
# [ run test_storage.cpp ]
|
||||
|
|
|
@ -86,21 +86,21 @@ int test_main()
|
|||
|
||||
std::vector<piece_block> picked;
|
||||
picked.clear();
|
||||
p.pick_pieces(peer1, picked, 1);
|
||||
p.pick_pieces(peer1, picked, 1, false, address());
|
||||
TEST_CHECK(picked.size() == 1);
|
||||
TEST_CHECK(picked.front().piece_index == 2);
|
||||
|
||||
// now pick a piece from peer2. The block is supposed to be
|
||||
// from piece 3, since it is the rarest piece that peer has.
|
||||
picked.clear();
|
||||
p.pick_pieces(peer2, picked, 1);
|
||||
p.pick_pieces(peer2, picked, 1, false, address());
|
||||
TEST_CHECK(picked.size() == 1);
|
||||
TEST_CHECK(picked.front().piece_index == 3);
|
||||
|
||||
// same thing for peer3.
|
||||
|
||||
picked.clear();
|
||||
p.pick_pieces(peer3, picked, 1);
|
||||
p.pick_pieces(peer3, picked, 1, false, address());
|
||||
TEST_CHECK(picked.size() == 1);
|
||||
TEST_CHECK(picked.front().piece_index == 5);
|
||||
|
||||
|
@ -114,7 +114,7 @@ int test_main()
|
|||
p.inc_refcount(1);
|
||||
|
||||
picked.clear();
|
||||
p.pick_pieces(peer3, picked, 1);
|
||||
p.pick_pieces(peer3, picked, 1, false, address());
|
||||
TEST_CHECK(picked.size() == 1);
|
||||
TEST_CHECK(picked.front().piece_index == 1);
|
||||
// and the block picked should not be 0 or 2
|
||||
|
@ -138,9 +138,9 @@ int test_main()
|
|||
|
||||
// we have block 0 and 2 already, so we can't mark
|
||||
// them as begin downloaded.
|
||||
p.mark_as_downloading(piece_block(1, 1), address());
|
||||
p.mark_as_downloading(piece_block(1, 3), address());
|
||||
p.mark_as_downloading(piece_block(2, 0), address());
|
||||
p.mark_as_downloading(piece_block(1, 1), address(1,1,1,1,0));
|
||||
p.mark_as_downloading(piece_block(1, 3), address(1,1,1,1,0));
|
||||
p.mark_as_downloading(piece_block(2, 0), address(1,1,1,1,0));
|
||||
|
||||
std::vector<piece_picker::downloading_piece> const& downloads = p.get_download_queue();
|
||||
TEST_CHECK(downloads.size() == 2);
|
||||
|
@ -168,13 +168,84 @@ int test_main()
|
|||
TEST_CHECK(!p.is_downloading(piece_block(2, 1)));
|
||||
|
||||
picked.clear();
|
||||
p.pick_pieces(peer1, picked, 1);
|
||||
p.pick_pieces(peer1, picked, 1, false, address());
|
||||
TEST_CHECK(picked.size() == 2);
|
||||
|
||||
piece_block expected3[] = { piece_block(2, 0), piece_block(2, 1) };
|
||||
TEST_CHECK(std::equal(picked.begin()
|
||||
, picked.end(), expected3));
|
||||
|
||||
// now, if we assume we're downloading at such a speed that
|
||||
// we might prefer to download whole pieces at a time from
|
||||
// this peer. It should not pick piece 1 or 2 (since those are
|
||||
// partially selected)
|
||||
|
||||
picked.clear();
|
||||
p.pick_pieces(peer1, picked, 1, true, address());
|
||||
|
||||
// it will pick 4 blocks, since we said we
|
||||
// wanted whole pieces.
|
||||
TEST_CHECK(picked.size() == 4);
|
||||
|
||||
piece_block expected4[] =
|
||||
{
|
||||
piece_block(3, 0), piece_block(3, 1)
|
||||
, piece_block(3, 2), piece_block(3, 3)
|
||||
};
|
||||
TEST_CHECK(std::equal(picked.begin()
|
||||
, picked.end(), expected4));
|
||||
|
||||
// now, try the same thing, but pick as many pieces as possible
|
||||
// to make sure it can still fall back on partial pieces
|
||||
|
||||
picked.clear();
|
||||
p.pick_pieces(peer1, picked, 100, true, address());
|
||||
|
||||
TEST_CHECK(picked.size() == 14);
|
||||
|
||||
piece_block expected5[] =
|
||||
{
|
||||
piece_block(3, 0), piece_block(3, 1)
|
||||
, piece_block(3, 2), piece_block(3, 3)
|
||||
, piece_block(5, 0), piece_block(5, 1)
|
||||
, piece_block(5, 2), piece_block(5, 3)
|
||||
, piece_block(2, 0), piece_block(2, 1)
|
||||
, piece_block(2, 2), piece_block(2, 3)
|
||||
, piece_block(1, 1), piece_block(1, 3)
|
||||
};
|
||||
|
||||
TEST_CHECK(std::equal(picked.begin()
|
||||
, picked.end(), expected5));
|
||||
|
||||
// now, try the same thing, but pick as many pieces as possible
|
||||
// to make sure it can still fall back on partial pieces
|
||||
|
||||
picked.clear();
|
||||
p.pick_pieces(peer1, picked, 100, true, address(1,1,1,1,0));
|
||||
|
||||
for (std::vector<piece_block>::iterator i = picked.begin(); i != picked.end(); ++i)
|
||||
{
|
||||
std::cerr << "(" << i->piece_index << "," << i->block_index << ")\n";
|
||||
}
|
||||
|
||||
TEST_CHECK(picked.size() == 11);
|
||||
|
||||
piece_block expected6[] =
|
||||
{
|
||||
piece_block(2, 1), piece_block(2, 2)
|
||||
, piece_block(2, 3)
|
||||
, piece_block(3, 0), piece_block(3, 1)
|
||||
, piece_block(3, 2), piece_block(3, 3)
|
||||
, piece_block(5, 0), piece_block(5, 1)
|
||||
, piece_block(5, 2), piece_block(5, 3)
|
||||
};
|
||||
|
||||
TEST_CHECK(std::equal(picked.begin()
|
||||
, picked.end(), expected6));
|
||||
|
||||
|
||||
// TODO: make sure there are no duplicates
|
||||
// in the picked blocks!
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue