bugfixes, fixes for boost 1.33, made the piece picker pick whole pieces from fast peers

This commit is contained in:
Arvid Norberg 2005-08-14 22:04:58 +00:00
parent f7c90b8511
commit 1934171431
15 changed files with 338 additions and 100 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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&)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@ project
requirements <threading>multi
<library>/torrent
<source>main.cpp
;
;
test-suite libtorrent :
# [ run test_storage.cpp ]

View File

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