optimized away torrent::m_have_pieces (#62) and added some documentation on bitfield. The piece picker is now constructed with the torrent, but still freed when turned into a seed

This commit is contained in:
Arvid Norberg 2008-06-07 02:58:28 +00:00
parent bcc24bf831
commit 9d1e77dc88
12 changed files with 394 additions and 276 deletions

View File

@ -127,95 +127,96 @@
</ul>
</li>
<li><a class="reference" href="#big-number" id="id109" name="id109">big_number</a></li>
<li><a class="reference" href="#hasher" id="id110" name="id110">hasher</a></li>
<li><a class="reference" href="#fingerprint" id="id111" name="id111">fingerprint</a></li>
<li><a class="reference" href="#upnp-and-nat-pmp" id="id112" name="id112">UPnP and NAT-PMP</a><ul>
<li><a class="reference" href="#add-mapping" id="id113" name="id113">add_mapping</a></li>
<li><a class="reference" href="#delete-mapping" id="id114" name="id114">delete_mapping</a></li>
<li><a class="reference" href="#router-model" id="id115" name="id115">router_model()</a></li>
<li><a class="reference" href="#bitfield" id="id110" name="id110">bitfield</a></li>
<li><a class="reference" href="#hasher" id="id111" name="id111">hasher</a></li>
<li><a class="reference" href="#fingerprint" id="id112" name="id112">fingerprint</a></li>
<li><a class="reference" href="#upnp-and-nat-pmp" id="id113" name="id113">UPnP and NAT-PMP</a><ul>
<li><a class="reference" href="#add-mapping" id="id114" name="id114">add_mapping</a></li>
<li><a class="reference" href="#delete-mapping" id="id115" name="id115">delete_mapping</a></li>
<li><a class="reference" href="#router-model" id="id116" name="id116">router_model()</a></li>
</ul>
</li>
<li><a class="reference" href="#free-functions" id="id116" name="id116">free functions</a><ul>
<li><a class="reference" href="#identify-client" id="id117" name="id117">identify_client()</a></li>
<li><a class="reference" href="#client-fingerprint" id="id118" name="id118">client_fingerprint()</a></li>
<li><a class="reference" href="#bdecode-bencode" id="id119" name="id119">bdecode() bencode()</a></li>
<li><a class="reference" href="#free-functions" id="id117" name="id117">free functions</a><ul>
<li><a class="reference" href="#identify-client" id="id118" name="id118">identify_client()</a></li>
<li><a class="reference" href="#client-fingerprint" id="id119" name="id119">client_fingerprint()</a></li>
<li><a class="reference" href="#bdecode-bencode" id="id120" name="id120">bdecode() bencode()</a></li>
</ul>
</li>
<li><a class="reference" href="#alerts" id="id120" name="id120">alerts</a><ul>
<li><a class="reference" href="#external-ip-alert" id="id121" name="id121">external_ip_alert</a></li>
<li><a class="reference" href="#listen-failed-alert" id="id122" name="id122">listen_failed_alert</a></li>
<li><a class="reference" href="#portmap-error-alert" id="id123" name="id123">portmap_error_alert</a></li>
<li><a class="reference" href="#portmap-alert" id="id124" name="id124">portmap_alert</a></li>
<li><a class="reference" href="#file-error-alert" id="id125" name="id125">file_error_alert</a></li>
<li><a class="reference" href="#tracker-announce-alert" id="id126" name="id126">tracker_announce_alert</a></li>
<li><a class="reference" href="#tracker-alert" id="id127" name="id127">tracker_alert</a></li>
<li><a class="reference" href="#tracker-error-alert" id="id128" name="id128">tracker_error_alert</a></li>
<li><a class="reference" href="#tracker-reply-alert" id="id129" name="id129">tracker_reply_alert</a></li>
<li><a class="reference" href="#tracker-warning-alert" id="id130" name="id130">tracker_warning_alert</a></li>
<li><a class="reference" href="#scrape-reply-alert" id="id131" name="id131">scrape_reply_alert</a></li>
<li><a class="reference" href="#scrape-failed-alert" id="id132" name="id132">scrape_failed_alert</a></li>
<li><a class="reference" href="#url-seed-alert" id="id133" name="id133">url_seed_alert</a></li>
<li><a class="reference" href="#hash-failed-alert" id="id134" name="id134">hash_failed_alert</a></li>
<li><a class="reference" href="#peer-ban-alert" id="id135" name="id135">peer_ban_alert</a></li>
<li><a class="reference" href="#peer-error-alert" id="id136" name="id136">peer_error_alert</a></li>
<li><a class="reference" href="#invalid-request-alert" id="id137" name="id137">invalid_request_alert</a></li>
<li><a class="reference" href="#torrent-finished-alert" id="id138" name="id138">torrent_finished_alert</a></li>
<li><a class="reference" href="#metadata-failed-alert" id="id139" name="id139">metadata_failed_alert</a></li>
<li><a class="reference" href="#metadata-received-alert" id="id140" name="id140">metadata_received_alert</a></li>
<li><a class="reference" href="#fastresume-rejected-alert" id="id141" name="id141">fastresume_rejected_alert</a></li>
<li><a class="reference" href="#peer-blocked-alert" id="id142" name="id142">peer_blocked_alert</a></li>
<li><a class="reference" href="#storage-moved-alert" id="id143" name="id143">storage_moved_alert</a></li>
<li><a class="reference" href="#torrent-paused-alert" id="id144" name="id144">torrent_paused_alert</a></li>
<li><a class="reference" href="#save-resume-data-alert" id="id145" name="id145">save_resume_data_alert</a></li>
<li><a class="reference" href="#dispatcher" id="id146" name="id146">dispatcher</a></li>
<li><a class="reference" href="#alerts" id="id121" name="id121">alerts</a><ul>
<li><a class="reference" href="#external-ip-alert" id="id122" name="id122">external_ip_alert</a></li>
<li><a class="reference" href="#listen-failed-alert" id="id123" name="id123">listen_failed_alert</a></li>
<li><a class="reference" href="#portmap-error-alert" id="id124" name="id124">portmap_error_alert</a></li>
<li><a class="reference" href="#portmap-alert" id="id125" name="id125">portmap_alert</a></li>
<li><a class="reference" href="#file-error-alert" id="id126" name="id126">file_error_alert</a></li>
<li><a class="reference" href="#tracker-announce-alert" id="id127" name="id127">tracker_announce_alert</a></li>
<li><a class="reference" href="#tracker-alert" id="id128" name="id128">tracker_alert</a></li>
<li><a class="reference" href="#tracker-error-alert" id="id129" name="id129">tracker_error_alert</a></li>
<li><a class="reference" href="#tracker-reply-alert" id="id130" name="id130">tracker_reply_alert</a></li>
<li><a class="reference" href="#tracker-warning-alert" id="id131" name="id131">tracker_warning_alert</a></li>
<li><a class="reference" href="#scrape-reply-alert" id="id132" name="id132">scrape_reply_alert</a></li>
<li><a class="reference" href="#scrape-failed-alert" id="id133" name="id133">scrape_failed_alert</a></li>
<li><a class="reference" href="#url-seed-alert" id="id134" name="id134">url_seed_alert</a></li>
<li><a class="reference" href="#hash-failed-alert" id="id135" name="id135">hash_failed_alert</a></li>
<li><a class="reference" href="#peer-ban-alert" id="id136" name="id136">peer_ban_alert</a></li>
<li><a class="reference" href="#peer-error-alert" id="id137" name="id137">peer_error_alert</a></li>
<li><a class="reference" href="#invalid-request-alert" id="id138" name="id138">invalid_request_alert</a></li>
<li><a class="reference" href="#torrent-finished-alert" id="id139" name="id139">torrent_finished_alert</a></li>
<li><a class="reference" href="#metadata-failed-alert" id="id140" name="id140">metadata_failed_alert</a></li>
<li><a class="reference" href="#metadata-received-alert" id="id141" name="id141">metadata_received_alert</a></li>
<li><a class="reference" href="#fastresume-rejected-alert" id="id142" name="id142">fastresume_rejected_alert</a></li>
<li><a class="reference" href="#peer-blocked-alert" id="id143" name="id143">peer_blocked_alert</a></li>
<li><a class="reference" href="#storage-moved-alert" id="id144" name="id144">storage_moved_alert</a></li>
<li><a class="reference" href="#torrent-paused-alert" id="id145" name="id145">torrent_paused_alert</a></li>
<li><a class="reference" href="#save-resume-data-alert" id="id146" name="id146">save_resume_data_alert</a></li>
<li><a class="reference" href="#dispatcher" id="id147" name="id147">dispatcher</a></li>
</ul>
</li>
<li><a class="reference" href="#exceptions" id="id147" name="id147">exceptions</a><ul>
<li><a class="reference" href="#invalid-handle" id="id148" name="id148">invalid_handle</a></li>
<li><a class="reference" href="#duplicate-torrent" id="id149" name="id149">duplicate_torrent</a></li>
<li><a class="reference" href="#invalid-encoding" id="id150" name="id150">invalid_encoding</a></li>
<li><a class="reference" href="#type-error" id="id151" name="id151">type_error</a></li>
<li><a class="reference" href="#invalid-torrent-file" id="id152" name="id152">invalid_torrent_file</a></li>
<li><a class="reference" href="#exceptions" id="id148" name="id148">exceptions</a><ul>
<li><a class="reference" href="#invalid-handle" id="id149" name="id149">invalid_handle</a></li>
<li><a class="reference" href="#duplicate-torrent" id="id150" name="id150">duplicate_torrent</a></li>
<li><a class="reference" href="#invalid-encoding" id="id151" name="id151">invalid_encoding</a></li>
<li><a class="reference" href="#type-error" id="id152" name="id152">type_error</a></li>
<li><a class="reference" href="#invalid-torrent-file" id="id153" name="id153">invalid_torrent_file</a></li>
</ul>
</li>
<li><a class="reference" href="#storage-interface" id="id153" name="id153">storage_interface</a><ul>
<li><a class="reference" href="#initialize" id="id154" name="id154">initialize()</a></li>
<li><a class="reference" href="#read" id="id155" name="id155">read()</a></li>
<li><a class="reference" href="#write" id="id156" name="id156">write()</a></li>
<li><a class="reference" href="#id11" id="id157" name="id157">move_storage()</a></li>
<li><a class="reference" href="#verify-resume-data" id="id158" name="id158">verify_resume_data()</a></li>
<li><a class="reference" href="#write-resume-data" id="id159" name="id159">write_resume_data()</a></li>
<li><a class="reference" href="#move-slot" id="id160" name="id160">move_slot()</a></li>
<li><a class="reference" href="#swap-slots" id="id161" name="id161">swap_slots()</a></li>
<li><a class="reference" href="#swap-slots3" id="id162" name="id162">swap_slots3()</a></li>
<li><a class="reference" href="#hash-for-slot" id="id163" name="id163">hash_for_slot()</a></li>
<li><a class="reference" href="#release-files" id="id164" name="id164">release_files()</a></li>
<li><a class="reference" href="#delete-files" id="id165" name="id165">delete_files()</a></li>
<li><a class="reference" href="#storage-interface" id="id154" name="id154">storage_interface</a><ul>
<li><a class="reference" href="#initialize" id="id155" name="id155">initialize()</a></li>
<li><a class="reference" href="#read" id="id156" name="id156">read()</a></li>
<li><a class="reference" href="#write" id="id157" name="id157">write()</a></li>
<li><a class="reference" href="#id11" id="id158" name="id158">move_storage()</a></li>
<li><a class="reference" href="#verify-resume-data" id="id159" name="id159">verify_resume_data()</a></li>
<li><a class="reference" href="#write-resume-data" id="id160" name="id160">write_resume_data()</a></li>
<li><a class="reference" href="#move-slot" id="id161" name="id161">move_slot()</a></li>
<li><a class="reference" href="#swap-slots" id="id162" name="id162">swap_slots()</a></li>
<li><a class="reference" href="#swap-slots3" id="id163" name="id163">swap_slots3()</a></li>
<li><a class="reference" href="#hash-for-slot" id="id164" name="id164">hash_for_slot()</a></li>
<li><a class="reference" href="#release-files" id="id165" name="id165">release_files()</a></li>
<li><a class="reference" href="#delete-files" id="id166" name="id166">delete_files()</a></li>
</ul>
</li>
<li><a class="reference" href="#queuing" id="id166" name="id166">queuing</a><ul>
<li><a class="reference" href="#downloading" id="id167" name="id167">downloading</a></li>
<li><a class="reference" href="#seeding" id="id168" name="id168">seeding</a></li>
<li><a class="reference" href="#queuing" id="id167" name="id167">queuing</a><ul>
<li><a class="reference" href="#downloading" id="id168" name="id168">downloading</a></li>
<li><a class="reference" href="#seeding" id="id169" name="id169">seeding</a></li>
</ul>
</li>
<li><a class="reference" href="#fast-resume" id="id169" name="id169">fast resume</a><ul>
<li><a class="reference" href="#file-format" id="id170" name="id170">file format</a></li>
<li><a class="reference" href="#fast-resume" id="id170" name="id170">fast resume</a><ul>
<li><a class="reference" href="#file-format" id="id171" name="id171">file format</a></li>
</ul>
</li>
<li><a class="reference" href="#threads" id="id171" name="id171">threads</a></li>
<li><a class="reference" href="#storage-allocation" id="id172" name="id172">storage allocation</a><ul>
<li><a class="reference" href="#sparse-allocation" id="id173" name="id173">sparse allocation</a></li>
<li><a class="reference" href="#full-allocation" id="id174" name="id174">full allocation</a></li>
<li><a class="reference" href="#compact-allocation" id="id175" name="id175">compact allocation</a></li>
<li><a class="reference" href="#threads" id="id172" name="id172">threads</a></li>
<li><a class="reference" href="#storage-allocation" id="id173" name="id173">storage allocation</a><ul>
<li><a class="reference" href="#sparse-allocation" id="id174" name="id174">sparse allocation</a></li>
<li><a class="reference" href="#full-allocation" id="id175" name="id175">full allocation</a></li>
<li><a class="reference" href="#compact-allocation" id="id176" name="id176">compact allocation</a></li>
</ul>
</li>
<li><a class="reference" href="#extensions" id="id176" name="id176">extensions</a><ul>
<li><a class="reference" href="#metadata-from-peers" id="id177" name="id177">metadata from peers</a></li>
<li><a class="reference" href="#http-seeding" id="id178" name="id178">HTTP seeding</a></li>
<li><a class="reference" href="#extensions" id="id177" name="id177">extensions</a><ul>
<li><a class="reference" href="#metadata-from-peers" id="id178" name="id178">metadata from peers</a></li>
<li><a class="reference" href="#http-seeding" id="id179" name="id179">HTTP seeding</a></li>
</ul>
</li>
<li><a class="reference" href="#filename-checks" id="id179" name="id179">filename checks</a></li>
<li><a class="reference" href="#acknowledgments" id="id180" name="id180">acknowledgments</a></li>
<li><a class="reference" href="#filename-checks" id="id180" name="id180">filename checks</a></li>
<li><a class="reference" href="#acknowledgments" id="id181" name="id181">acknowledgments</a></li>
</ul>
</div>
<div class="section">
@ -2236,7 +2237,7 @@ struct torrent_status
int connect_candidates;
const std::vector&lt;bool&gt;* pieces;
bitfield pieces;
int num_pieces;
size_type total_done;
@ -2482,7 +2483,7 @@ struct peer_info
size_type total_download;
size_type total_upload;
peer_id pid;
std::vector&lt;bool&gt; pieces;
bitfield pieces;
int upload_limit;
int download_limit;
@ -2686,9 +2687,9 @@ the payload data.</p>
<p><tt class="docutils literal"><span class="pre">pid</span></tt> is the peer's id as used in the bit torrent protocol. This id can be used to
extract 'fingerprints' from the peer. Sometimes it can tell you which client the peer
is using. See identify_client()_</p>
<p><tt class="docutils literal"><span class="pre">pieces</span></tt> is a vector of booleans that has as many entries as there are pieces
in the torrent. Each boolean tells you if the peer has that piece (if it's set to true)
or if the peer miss that piece (set to false).</p>
<p><tt class="docutils literal"><span class="pre">pieces</span></tt> is a bitfield, with one bit per piece in the torrent.
Each bit tells you if the peer has that piece (if it's set to 1)
or if the peer miss that piece (set to 0).</p>
<p><tt class="docutils literal"><span class="pre">seed</span></tt> is true if this peer is a seed.</p>
<p><tt class="docutils literal"><span class="pre">upload_limit</span></tt> is the number of bytes per second we are allowed to send to this
peer every second. It may be -1 if there's no local limit on the peer. The global
@ -3235,6 +3236,50 @@ public:
<p>The iterators gives you access to individual bytes.</p>
</div>
<div class="section">
<h1><a id="bitfield" name="bitfield">bitfield</a></h1>
<p>The bitfiled type stores any number of bits as a bitfield in an array.</p>
<pre class="literal-block">
class bitfield
{
bitfield();
bitfield(int bits);
bitfield(int bits, bool val);
bitfield(char const* bytes, int bits);
bitfield(bitfield const&amp; rhs);
void borrow_bytes(char* bytes, int bits);
~bitfield();
void assign(char const* bytes, int bits);
bool operator[](int index) const;
bool get_bit(int index) const;
void clear_bit(int index);
void set_bit(int index);
std::size_t size() const;
bool empty() const;
char const* bytes() const;
bitfield&amp; operator=(bitfield const&amp; rhs);
int count() const;
typedef const_iterator;
const_iterator begin() const;
const_iterator end() const;
void resize(int bits, bool val);
void set_all();
void clear_all();
void resize(int bits);
};
</pre>
</div>
<div class="section">
<h1><a id="hasher" name="hasher">hasher</a></h1>
<p>This class creates sha1-hashes. Its declaration looks like this:</p>
<pre class="literal-block">

View File

@ -2197,7 +2197,7 @@ It contains the following fields::
int connect_candidates;
const std::vector<bool>* pieces;
bitfield pieces;
int num_pieces;
size_type total_done;
@ -2466,7 +2466,7 @@ It contains the following fields::
size_type total_download;
size_type total_upload;
peer_id pid;
std::vector<bool> pieces;
bitfield pieces;
int upload_limit;
int download_limit;
@ -2642,9 +2642,9 @@ the payload data.
extract 'fingerprints' from the peer. Sometimes it can tell you which client the peer
is using. See identify_client()_
``pieces`` is a vector of booleans that has as many entries as there are pieces
in the torrent. Each boolean tells you if the peer has that piece (if it's set to true)
or if the peer miss that piece (set to false).
``pieces`` is a bitfield, with one bit per piece in the torrent.
Each bit tells you if the peer has that piece (if it's set to 1)
or if the peer miss that piece (set to 0).
``seed`` is true if this peer is a seed.
@ -3291,6 +3291,53 @@ Both the ``peer_id`` and ``sha1_hash`` types are typedefs of the class
The iterators gives you access to individual bytes.
bitfield
========
The bitfiled type stores any number of bits as a bitfield in an array.
::
class bitfield
{
bitfield();
bitfield(int bits);
bitfield(int bits, bool val);
bitfield(char const* bytes, int bits);
bitfield(bitfield const& rhs);
void borrow_bytes(char* bytes, int bits);
~bitfield();
void assign(char const* bytes, int bits);
bool operator[](int index) const;
bool get_bit(int index) const;
void clear_bit(int index);
void set_bit(int index);
std::size_t size() const;
bool empty() const;
char const* bytes() const;
bitfield& operator=(bitfield const& rhs);
int count() const;
typedef const_iterator;
const_iterator begin() const;
const_iterator end() const;
void resize(int bits, bool val);
void set_all();
void clear_all();
void resize(int bits);
};
hasher
======

View File

@ -1317,8 +1317,8 @@ int main(int ac, char* av[])
out.fill(' ');
out << (s.progress*100) << "% ";
out << progress_bar(s.progress, terminal_width - 37, progress_bar_color) << "\n";
if (print_piece_bar && s.progress < 1.f && s.pieces)
out << " " << piece_bar(*s.pieces, terminal_width - 5) << "\n";
if (print_piece_bar && s.progress < 1.f)
out << " " << piece_bar(s.pieces, terminal_width - 5) << "\n";
out << " peers: " << esc("37") << s.num_peers << esc("0") << " (" << esc("37") << s.connect_candidates << esc("0") << ") "
<< "seeds: " << esc("37") << s.num_seeds << esc("0") << " "
<< "distributed copies: " << esc("37") << s.distributed_copies << esc("0")

View File

@ -209,7 +209,7 @@ namespace libtorrent
void write_not_interested();
void write_request(peer_request const& r);
void write_cancel(peer_request const& r);
void write_bitfield(bitfield const& bits);
void write_bitfield();
void write_have(int index);
void write_piece(peer_request const& r, disk_buffer_holder& buffer);
void write_handshake();

View File

@ -129,18 +129,13 @@ namespace libtorrent
boost::int16_t requested;
};
piece_picker(int blocks_per_piece
, int total_num_blocks);
piece_picker();
void get_availability(std::vector<int>& avail) const;
void sequential_download(bool sd);
bool sequential_download() const { return m_sequential_download >= 0; }
// the vector tells which pieces we already have
// and which we don't have.
void init(bitfield const& pieces);
// increases the peer count for the given piece
// (is used when a HAVE message is received)
void inc_refcount(int index);
@ -164,6 +159,17 @@ namespace libtorrent
// we are not interested in this piece anymore
// (i.e. we don't have to maintain a refcount)
void we_have(int index);
void we_dont_have(int index);
void init(int blocks_per_piece, int total_num_blocks);
int num_pieces() const { return int(m_piece_map.size()); }
bool have_piece(int index) const
{
TORRENT_ASSERT(index >= 0);
TORRENT_ASSERT(index < int(m_piece_map.size()));
return m_piece_map[index].index == piece_pos::we_have_index;
}
// sets the priority of a piece.
// returns true if the priority was changed from 0 to non-0
@ -276,6 +282,8 @@ namespace libtorrent
// the number of filtered pieces we already have
int num_have_filtered() const { return m_num_have_filtered; }
int num_have() const { return m_num_have; }
#ifndef NDEBUG
// used in debug mode
void verify_priority(int start, int end, int prio) const;
@ -350,6 +358,7 @@ namespace libtorrent
bool have() const { return index == we_have_index; }
void set_have() { index = we_have_index; TORRENT_ASSERT(have()); }
void set_not_have() { index = 0; TORRENT_ASSERT(!have()); }
bool filtered() const { return piece_priority == filter_priority; }
void filtered(bool f) { piece_priority = f ? filter_priority : 0; }
@ -466,10 +475,6 @@ namespace libtorrent
// if this is set to true, it means update_pieces()
// has to be called before accessing m_pieces.
mutable bool m_dirty;
#ifndef NDEBUG
bool m_files_checked_called;
#endif
};
inline int piece_picker::blocks_in_piece(int index) const

View File

@ -378,14 +378,15 @@ namespace libtorrent
// returns true if we have downloaded the given piece
bool have_piece(int index) const
{
TORRENT_ASSERT(index >= 0 && index < (signed)m_have_pieces.size());
return m_have_pieces[index];
return has_picker()?m_picker->have_piece(index):true;
}
bitfield const& pieces() const
{ return m_have_pieces; }
int num_pieces() const { return m_num_pieces; }
int num_pieces() const
{
return has_picker()
?m_picker->num_have()
:m_torrent_file->num_pieces();
}
// when we get a have message, this is called for that piece
void peer_has(int index)
@ -393,7 +394,6 @@ namespace libtorrent
if (m_picker.get())
{
TORRENT_ASSERT(!is_seed());
TORRENT_ASSERT(index >= 0 && index < (signed)m_have_pieces.size());
m_picker->inc_refcount(index);
}
#ifndef NDEBUG
@ -440,7 +440,6 @@ namespace libtorrent
if (m_picker.get())
{
TORRENT_ASSERT(!is_seed());
TORRENT_ASSERT(index >= 0 && index < (signed)m_have_pieces.size());
m_picker->dec_refcount(index);
}
#ifndef NDEBUG
@ -507,7 +506,9 @@ namespace libtorrent
bool is_seed() const
{
return valid_metadata()
&& m_num_pieces == m_torrent_file->num_pieces();
&& (!m_picker
|| m_state == torrent_status::seeding
|| m_picker->num_have() == m_picker->num_pieces());
}
// this is true if we have all the pieces that we want
@ -515,7 +516,7 @@ namespace libtorrent
{
if (is_seed()) return true;
return valid_metadata() && m_torrent_file->num_pieces()
- m_num_pieces - m_picker->num_filtered() == 0;
- m_picker->num_have() - m_picker->num_filtered() == 0;
}
fs::path save_path() const;
@ -741,9 +742,6 @@ namespace libtorrent
std::vector<announce_entry> m_trackers;
// this is an index into m_trackers
// the bitmask that says which pieces we have
bitfield m_have_pieces;
// the number of bytes that has been
// downloaded that failed the hash-test
size_type m_total_failed_bytes;
@ -782,11 +780,6 @@ namespace libtorrent
float m_progress;
// the number of pieces we have. The same as
// std::accumulate(m_have_pieces.begin(),
// m_have_pieces.end(), 0)
int m_num_pieces;
// the upload/download ratio that each peer
// tries to maintain.
// 0 is infinite

View File

@ -100,7 +100,6 @@ namespace libtorrent
, num_incomplete(-1)
, list_seeds(0)
, list_peers(0)
, pieces(0)
, num_pieces(0)
, total_done(0)
, total_wanted_done(0)
@ -201,7 +200,7 @@ namespace libtorrent
// we potentially could connect to
int connect_candidates;
bitfield const* pieces;
bitfield pieces;
// this is the number of pieces the client has
// downloaded. it is equal to:

View File

@ -245,7 +245,7 @@ namespace libtorrent
{
boost::shared_ptr<torrent> t = associated_torrent().lock();
TORRENT_ASSERT(t);
write_bitfield(t->pieces());
write_bitfield();
#ifndef TORRENT_DISABLE_DHT
if (m_supports_dht_port && m_ses.m_dht)
write_dht_port(m_ses.get_dht_settings().service_port);
@ -1416,7 +1416,7 @@ namespace libtorrent
send_buffer(msg, sizeof(msg));
}
void bt_peer_connection::write_bitfield(bitfield const& bits)
void bt_peer_connection::write_bitfield()
{
INVARIANT_CHECK;
@ -1449,14 +1449,11 @@ namespace libtorrent
return;
}
int num_pieces = bits.size();
int num_pieces = t->picker().num_pieces();
int lazy_pieces[50];
int num_lazy_pieces = 0;
int lazy_piece = 0;
TORRENT_ASSERT(t->is_seed() == (bits.count()
== num_pieces));
if (t->is_seed() && m_ses.settings().lazy_bitfields)
{
num_lazy_pieces = (std::min)(50, num_pieces / 10);
@ -1470,26 +1467,6 @@ namespace libtorrent
lazy_piece = 0;
}
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() << " ==> BITFIELD ";
std::stringstream bitfield_string;
for (int i = 0; i < (int)get_bitfield().size(); ++i)
{
if (lazy_piece < num_lazy_pieces
&& lazy_pieces[lazy_piece] == i)
{
bitfield_string << "0";
++lazy_piece;
continue;
}
if (bits[i]) bitfield_string << "1";
else bitfield_string << "0";
}
bitfield_string << "\n";
(*m_logger) << bitfield_string.str();
lazy_piece = 0;
#endif
const int packet_size = (num_pieces + 7) / 8 + 5;
buffer::interval i = allocate_send_buffer(packet_size);
@ -1498,15 +1475,46 @@ namespace libtorrent
detail::write_int32(packet_size - 4, i.begin);
detail::write_uint8(msg_bitfield, i.begin);
memcpy(i.begin, bits.bytes(), packet_size - 5);
if (t->is_seed())
{
memset(i.begin, 0xff, packet_size - 5);
}
else
{
memset(i.begin, 0, packet_size - 5);
piece_picker const& p = t->picker();
int mask = 0x80;
unsigned char* byte = (unsigned char*)i.begin;
for (int i = 0; i < num_pieces; ++i)
{
if (p.have_piece(i)) *byte |= mask;
mask >>= 1;
if (mask == 0)
{
mask = 0x80;
++byte;
}
}
}
for (int c = 0; c < num_lazy_pieces; ++c)
i.begin[lazy_pieces[c] / 8] &= ~(0x80 >> (lazy_pieces[c] & 7));
TORRENT_ASSERT(i.end - i.begin == (num_pieces + 7) / 8);
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() << " ==> BITFIELD ";
std::stringstream bitfield_string;
for (int k = 0; k < num_pieces; ++k)
{
if (i.begin[k / 8] & (0x80 >> (k % 8))) bitfield_string << "1";
else bitfield_string << "0";
}
bitfield_string << "\n";
(*m_logger) << bitfield_string.str();
#endif
#ifndef NDEBUG
m_sent_bitfield = true;
#endif
setup_send();
if (num_lazy_pieces > 0)
{
@ -1522,6 +1530,7 @@ namespace libtorrent
if (m_supports_fast)
send_allowed_set();
setup_send();
}
#ifndef TORRENT_DISABLE_EXTENSIONS
@ -2377,7 +2386,7 @@ namespace libtorrent
// sent the handshake
if (!is_local()) write_handshake();
// if (t->valid_metadata())
// write_bitfield(t->pieces());
// write_bitfield();
if (is_disconnecting()) return;
@ -2511,7 +2520,7 @@ namespace libtorrent
reset_recv_buffer(5);
if (t->valid_metadata())
{
write_bitfield(t->pieces());
write_bitfield();
#ifndef TORRENT_DISABLE_DHT
if (m_supports_dht_port && m_ses.m_dht)
write_dht_port(m_ses.get_dht_settings().service_port);

View File

@ -326,15 +326,19 @@ namespace libtorrent
TORRENT_ASSERT(t);
bool interested = false;
bitfield const& we_have = t->pieces();
for (int j = 0; j != (int)we_have.size(); ++j)
if (!t->is_finished())
{
if (!we_have[j]
&& t->piece_priority(j) > 0
&& m_have_piece[j])
piece_picker const& p = t->picker();
int num_pieces = p.num_pieces();
for (int j = 0; j != num_pieces; ++j)
{
interested = true;
break;
if (!p.have_piece(j)
&& t->piece_priority(j) > 0
&& m_have_piece[j])
{
interested = true;
break;
}
}
}
try

View File

@ -58,10 +58,9 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent
{
piece_picker::piece_picker(int blocks_per_piece, int total_num_blocks)
piece_picker::piece_picker()
: m_seeds(0)
, m_priority_boundries(1, int(m_pieces.size()))
, m_piece_map((total_num_blocks + blocks_per_piece-1) / blocks_per_piece)
, m_num_filtered(0)
, m_num_have_filtered(0)
, m_num_have(0)
@ -69,13 +68,22 @@ namespace libtorrent
, m_dirty(false)
{
#ifdef TORRENT_PICKER_LOG
std::cout << "new piece_picker" << std::endl;
std::cerr << "new piece_picker" << std::endl;
#endif
#ifndef NDEBUG
check_invariant();
#endif
}
void piece_picker::init(int blocks_per_piece, int total_num_blocks)
{
TORRENT_ASSERT(blocks_per_piece > 0);
TORRENT_ASSERT(total_num_blocks >= 0);
#ifndef NDEBUG
m_files_checked_called = false;
#endif
// allocate the piece_map to cover all pieces
// and make them invalid (as if we don't have a single piece)
m_piece_map.resize((total_num_blocks + blocks_per_piece-1) / blocks_per_piece
, piece_pos(0, 0));
// the piece index is stored in 20 bits, which limits the allowed
// number of pieces somewhat
@ -87,15 +95,6 @@ namespace libtorrent
if (m_blocks_in_last_piece == 0) m_blocks_in_last_piece = blocks_per_piece;
TORRENT_ASSERT(m_blocks_in_last_piece <= m_blocks_per_piece);
// allocate the piece_map to cover all pieces
// and make them invalid (as if we don't have a single piece)
std::fill(m_piece_map.begin(), m_piece_map.end()
, piece_pos(0, 0));
m_num_have = 0;
#ifndef NDEBUG
check_invariant();
#endif
}
void piece_picker::sequential_download(bool sd)
@ -122,24 +121,6 @@ namespace libtorrent
}
}
// pieces is a bitmask with the pieces we have
void piece_picker::init(bitfield const& pieces)
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
#ifndef NDEBUG
m_files_checked_called = true;
#endif
int index = 0;
for (bitfield::const_iterator i = pieces.begin();
i != pieces.end(); ++i, ++index)
{
TORRENT_ASSERT(index < pieces.size());
piece_pos& p = m_piece_map[index];
if (*i) we_have(index);
else TORRENT_ASSERT(p.index == 0);
}
}
void piece_picker::piece_info(int index, piece_picker::downloading_piece& st) const
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
@ -249,7 +230,7 @@ namespace libtorrent
for (std::vector<int>::const_iterator i = m_priority_boundries.begin()
, end(m_priority_boundries.end()); i != end; ++i)
{
std::cout << *i << " ";
std::cerr << *i << " ";
}
std::cout << std::endl;
int index = 0;
@ -260,12 +241,12 @@ namespace libtorrent
if (*i == -1) break;
while (j != m_priority_boundries.end() && *j <= index)
{
std::cout << "| ";
std::cerr << "| ";
++j;
}
std::cout << *i << "(" << m_piece_map[*i].index << ") ";
std::cerr << *i << "(" << m_piece_map[*i].index << ") ";
}
std::cout << std::endl;
std::cerr << std::endl;
}
void piece_picker::check_invariant(const torrent* t) const
@ -534,7 +515,7 @@ namespace libtorrent
else new_index = rand() % (range_end - range_start) + range_start;
#ifdef TORRENT_PICKER_LOG
std::cout << "add " << index << " (" << priority << ")" << std::endl;
std::cerr << "add " << index << " (" << priority << ")" << std::endl;
print_pieces();
#endif
m_pieces.push_back(-1);
@ -554,7 +535,7 @@ namespace libtorrent
new_index = temp;
#ifdef TORRENT_PICKER_LOG
print_pieces();
std::cout << " index: " << index
std::cerr << " index: " << index
<< " prio: " << priority
<< " new_index: " << new_index
<< std::endl;
@ -581,7 +562,7 @@ namespace libtorrent
TORRENT_ASSERT(m_sequential_download == -1);
#ifdef TORRENT_PICKER_LOG
std::cout << "remove " << m_pieces[elem_index] << " (" << priority << ")" << std::endl;
std::cerr << "remove " << m_pieces[elem_index] << " (" << priority << ")" << std::endl;
#endif
int next_index = elem_index;
TORRENT_ASSERT(m_piece_map[m_pieces[elem_index]].priority(this) == -1);
@ -624,7 +605,6 @@ namespace libtorrent
TORRENT_ASSERT(!m_dirty);
TORRENT_ASSERT(priority >= 0);
TORRENT_ASSERT(elem_index >= 0);
TORRENT_ASSERT(m_files_checked_called);
TORRENT_ASSERT(m_sequential_download == -1);
TORRENT_ASSERT(int(m_priority_boundries.size()) > priority);
@ -648,7 +628,7 @@ namespace libtorrent
m_priority_boundries.resize(new_priority + 1, m_pieces.size());
#ifdef TORRENT_PICKER_LOG
std::cout << "update " << index << " (" << priority << "->" << new_priority << ")" << std::endl;
std::cerr << "update " << index << " (" << priority << "->" << new_priority << ")" << std::endl;
#endif
if (priority > new_priority)
{
@ -772,7 +752,6 @@ namespace libtorrent
TORRENT_ASSERT(index >= 0);
TORRENT_ASSERT(index < (int)m_piece_map.size());
TORRENT_ASSERT(m_files_checked_called);
TORRENT_ASSERT(m_piece_map[index].downloading == 1);
@ -804,7 +783,6 @@ namespace libtorrent
void piece_picker::inc_refcount_all()
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
TORRENT_ASSERT(m_files_checked_called);
++m_seeds;
if (m_sequential_download >= 0) return;
if (m_seeds == 1)
@ -819,7 +797,6 @@ namespace libtorrent
void piece_picker::dec_refcount_all()
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
TORRENT_ASSERT(m_files_checked_called);
if (m_sequential_download >= 0)
{
@ -935,7 +912,7 @@ namespace libtorrent
TORRENT_ASSERT(m_sequential_download == -1);
if (m_priority_boundries.empty()) m_priority_boundries.resize(1, 0);
#ifdef TORRENT_PICKER_LOG
std::cout << "update_pieces" << std::endl;
std::cerr << "update_pieces" << std::endl;
#endif
std::fill(m_priority_boundries.begin(), m_priority_boundries.end(), 0);
for (std::vector<piece_pos>::iterator i = m_piece_map.begin()
@ -1004,6 +981,33 @@ namespace libtorrent
#endif
}
void piece_picker::we_dont_have(int index)
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
TORRENT_ASSERT(index >= 0);
TORRENT_ASSERT(index < (int)m_piece_map.size());
piece_pos& p = m_piece_map[index];
TORRENT_ASSERT(p.downloading == 0);
if (!p.have()) return;
if (m_sequential_download > index)
m_sequential_download = index;
if (p.filtered())
{
++m_num_filtered;
--m_num_have_filtered;
}
--m_num_have;
p.set_not_have();
if (m_dirty) return;
if (!p.filtered()) add(index);
}
// this is used to indicate that we succesfully have
// downloaded a piece, and that no further attempts
// to pick that piece should be made. The piece will
@ -1167,7 +1171,6 @@ namespace libtorrent
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
TORRENT_ASSERT(num_blocks > 0);
TORRENT_ASSERT(pieces.size() == m_piece_map.size());
TORRENT_ASSERT(m_files_checked_called);
TORRENT_ASSERT(!m_priority_boundries.empty()
|| m_sequential_download >= 0

View File

@ -164,7 +164,7 @@ namespace libtorrent
, m_last_dht_announce(time_now() - minutes(15))
#endif
, m_ses(ses)
, m_picker(0)
, m_picker(new piece_picker())
, m_trackers(m_torrent_file->trackers())
, m_total_failed_bytes(0)
, m_total_redundant_bytes(0)
@ -175,7 +175,6 @@ namespace libtorrent
, m_settings(ses.settings())
, m_storage_constructor(sc)
, m_progress(0.f)
, m_num_pieces(0)
, m_ratio(0.f)
, m_max_uploads((std::numeric_limits<int>::max)())
, m_num_uploads(0)
@ -240,7 +239,7 @@ namespace libtorrent
, m_last_dht_announce(time_now() - minutes(15))
#endif
, m_ses(ses)
, m_picker(0)
, m_picker(new piece_picker())
, m_total_failed_bytes(0)
, m_total_redundant_bytes(0)
, m_net_interface(net_interface.address(), 0)
@ -250,7 +249,6 @@ namespace libtorrent
, m_settings(ses.settings())
, m_storage_constructor(sc)
, m_progress(0.f)
, m_num_pieces(0)
, m_ratio(0.f)
, m_max_uploads((std::numeric_limits<int>::max)())
, m_num_uploads(0)
@ -409,16 +407,14 @@ namespace libtorrent
TORRENT_ASSERT(m_torrent_file->num_files() > 0);
TORRENT_ASSERT(m_torrent_file->total_size() >= 0);
m_have_pieces.resize(m_torrent_file->num_pieces(), false);
// the shared_from_this() will create an intentional
// cycle of ownership, se the hpp file for description.
m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
, m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor
, m_storage_mode);
m_storage = m_owning_storage.get();
m_picker.reset(new piece_picker(
m_torrent_file->piece_length() / m_block_size
, int((m_torrent_file->total_size()+m_block_size-1)/m_block_size)));
m_picker->init(m_torrent_file->piece_length() / m_block_size
, int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
std::vector<std::string> const& url_seeds = m_torrent_file->url_seeds();
std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
@ -475,8 +471,6 @@ namespace libtorrent
" ]\n";
#endif
}
m_have_pieces.clear_all();
m_num_pieces = 0;
m_error = j.str;
pause();
return;
@ -550,8 +544,6 @@ namespace libtorrent
// there are either no files for this torrent
// or the resume_data was accepted
m_num_pieces = 0;
m_have_pieces.clear_all();
if (!fastresume_rejected)
{
TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t);
@ -565,8 +557,7 @@ namespace libtorrent
for (int i = 0, end(pieces_str.size()); i < end; ++i)
{
if ((pieces_str[i] & 1) == 0) continue;
m_have_pieces.set_bit(i);
++m_num_pieces;
m_picker->we_have(i);
}
}
@ -589,11 +580,8 @@ namespace libtorrent
if (piece_index < 0 || piece_index >= torrent_file().num_pieces())
continue;
if (m_have_pieces[piece_index])
{
m_have_pieces.clear_bit(piece_index);
--m_num_pieces;
}
if (m_picker->have_piece(piece_index))
m_picker->we_dont_have(piece_index);
entry const* bitmask_ent = i->find_key("bitmask");
if (bitmask_ent == 0 || bitmask_ent->type() != entry::string_t) break;
@ -619,13 +607,6 @@ namespace libtorrent
}
}
}
int index = 0;
for (bitfield::const_iterator i = m_have_pieces.begin()
, end(m_have_pieces.end()); i != end; ++i, ++index)
{
if (*i) m_picker->we_have(index);
}
}
files_checked();
@ -663,8 +644,6 @@ namespace libtorrent
" ]\n";
#endif
}
m_have_pieces.clear_all();
m_num_pieces = 0;
m_error = j.str;
pause();
m_ses.done_checking(shared_from_this());
@ -673,13 +652,9 @@ namespace libtorrent
m_progress = j.piece / float(torrent_file().num_pieces());
if (j.offset >= 0 && !m_have_pieces[j.offset])
{
m_have_pieces.set_bit(j.offset);
++m_num_pieces;
TORRENT_ASSERT(m_picker);
TORRENT_ASSERT(m_picker);
if (j.offset >= 0 && !m_picker->have_piece(j.offset))
m_picker->we_have(j.offset);
}
// we're not done checking yet
// this handler will be called repeatedly until
@ -984,12 +959,12 @@ namespace libtorrent
const int last_piece = m_torrent_file->num_pieces() - 1;
size_type total_done
= size_type(m_num_pieces) * m_torrent_file->piece_length();
= size_type(num_pieces()) * m_torrent_file->piece_length();
// if we have the last piece, we have to correct
// the amount we have, since the first calculation
// assumed all pieces were of equal size
if (m_have_pieces[last_piece])
if (m_picker->have_piece(last_piece))
{
int corr = m_torrent_file->piece_size(last_piece)
- m_torrent_file->piece_length();
@ -1015,19 +990,19 @@ namespace libtorrent
return make_tuple(m_torrent_file->total_size()
, m_torrent_file->total_size());
TORRENT_ASSERT(m_num_pieces >= m_picker->num_have_filtered());
size_type wanted_done = size_type(m_num_pieces - m_picker->num_have_filtered())
TORRENT_ASSERT(num_pieces() >= m_picker->num_have_filtered());
size_type wanted_done = size_type(num_pieces() - m_picker->num_have_filtered())
* piece_size;
TORRENT_ASSERT(wanted_done >= 0);
size_type total_done
= size_type(m_num_pieces) * piece_size;
TORRENT_ASSERT(m_num_pieces < m_torrent_file->num_pieces());
= size_type(num_pieces()) * piece_size;
TORRENT_ASSERT(num_pieces() < m_torrent_file->num_pieces());
// if we have the last piece, we have to correct
// the amount we have, since the first calculation
// assumed all pieces were of equal size
if (m_have_pieces[last_piece])
if (m_picker->have_piece(last_piece))
{
TORRENT_ASSERT(total_done >= piece_size);
int corr = m_torrent_file->piece_size(last_piece)
@ -1056,7 +1031,7 @@ namespace libtorrent
{
int corr = 0;
int index = i->index;
if (m_have_pieces[index]) continue;
if (m_picker->have_piece(index)) continue;
TORRENT_ASSERT(i->finished <= m_picker->blocks_in_piece(index));
#ifndef NDEBUG
@ -1101,7 +1076,7 @@ namespace libtorrent
= pc->downloading_piece_progress();
if (p)
{
if (m_have_pieces[p->piece_index])
if (m_picker->have_piece(p->piece_index))
continue;
piece_block block(p->piece_index, p->block_index);
@ -1138,16 +1113,16 @@ namespace libtorrent
wanted_done += i->second;
}
TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
#ifndef NDEBUG
if (total_done >= m_torrent_file->total_size())
{
// Thist happens when a piece has been downloaded completely
// but not yet verified against the hash
std::copy(m_have_pieces.begin(), m_have_pieces.end()
, std::ostream_iterator<bool>(std::cerr, " "));
std::cerr << std::endl;
std::cerr << "num_pieces: " << m_num_pieces << std::endl;
std::cerr << "num_pieces: " << num_pieces() << std::endl;
std::cerr << "unfinished:" << std::endl;
@ -1352,7 +1327,7 @@ namespace libtorrent
m_picker->restore_piece(index);
TORRENT_ASSERT(m_storage);
TORRENT_ASSERT(m_have_pieces[index] == false);
TORRENT_ASSERT(m_picker->have_piece(index) == false);
#ifndef NDEBUG
for (std::vector<void*>::iterator i = downloaders.begin()
@ -1488,13 +1463,6 @@ namespace libtorrent
std::set<void*> peers;
std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
if (!m_have_pieces[index])
m_num_pieces++;
m_have_pieces.set_bit(index);
TORRENT_ASSERT(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0)
== m_num_pieces);
m_picker->we_have(index);
for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i)
(*i)->announce_piece(index);
@ -1560,7 +1528,7 @@ namespace libtorrent
bool was_finished = is_finished();
bool filter_updated = m_picker->set_piece_priority(index, priority);
TORRENT_ASSERT(m_num_pieces >= m_picker->num_have_filtered());
TORRENT_ASSERT(num_pieces() >= m_picker->num_have_filtered());
if (filter_updated) update_peer_interest(was_finished);
}
@ -1598,7 +1566,7 @@ namespace libtorrent
TORRENT_ASSERT(*i >= 0);
TORRENT_ASSERT(*i <= 7);
filter_updated |= m_picker->set_piece_priority(index, *i);
TORRENT_ASSERT(m_num_pieces >= m_picker->num_have_filtered());
TORRENT_ASSERT(num_pieces() >= m_picker->num_have_filtered());
}
if (filter_updated) update_peer_interest(was_finished);
}
@ -2444,8 +2412,16 @@ namespace libtorrent
// write have bitmask
entry::string_type& pieces = ret["pieces"].string();
pieces.resize(m_torrent_file->num_pieces());
for (int i = 0, end(pieces.size()); i < end; ++i)
pieces[i] = m_have_pieces[i] ? 1 : 0;
if (is_seed())
{
for (int i = 0, end(pieces.size()); i < end; ++i)
pieces[i] = 1;
}
else
{
for (int i = 0, end(pieces.size()); i < end; ++i)
pieces[i] = m_picker->have_piece(i) ? 1 : 0;
}
// write local peers
@ -3119,7 +3095,6 @@ namespace libtorrent
if (!is_seed())
{
m_picker->init(m_have_pieces);
if (m_sequential_download)
picker().sequential_download(m_sequential_download);
}
@ -3293,16 +3268,16 @@ namespace libtorrent
if (!m_picker->is_downloaded(i->first))
TORRENT_ASSERT(m_picker->num_peers(i->first) == i->second);
}
TORRENT_ASSERT(m_num_pieces >= m_picker->num_have_filtered());
TORRENT_ASSERT(num_pieces() >= m_picker->num_have_filtered());
}
if (valid_metadata())
{
TORRENT_ASSERT(m_abort || int(m_have_pieces.size()) == m_torrent_file->num_pieces());
TORRENT_ASSERT(m_abort || !m_picker || m_picker->num_pieces() == m_torrent_file->num_pieces());
}
else
{
TORRENT_ASSERT(m_abort || m_have_pieces.empty());
TORRENT_ASSERT(m_abort || m_picker->num_pieces() == 0);
}
for (policy::const_iterator i = m_policy.begin_peer()
@ -3317,7 +3292,7 @@ namespace libtorrent
if (is_seed())
TORRENT_ASSERT(total_done == m_torrent_file->total_size());
else
TORRENT_ASSERT(total_done != m_torrent_file->total_size());
TORRENT_ASSERT(total_done != m_torrent_file->total_size() || !m_files_checked);
}
else
{
@ -3348,8 +3323,6 @@ namespace libtorrent
}
// This check is very expensive.
TORRENT_ASSERT(m_num_pieces
== std::count(m_have_pieces.begin(), m_have_pieces.end(), true));
TORRENT_ASSERT(!valid_metadata() || m_block_size > 0);
TORRENT_ASSERT(!valid_metadata() || (m_torrent_file->piece_length() % m_block_size) == 0);
// if (is_seed()) TORRENT_ASSERT(m_picker.get() == 0);
@ -3821,7 +3794,7 @@ namespace libtorrent
TORRENT_ASSERT(m_storage->refcount() > 0);
TORRENT_ASSERT(piece_index >= 0);
TORRENT_ASSERT(piece_index < m_torrent_file->num_pieces());
TORRENT_ASSERT(piece_index < (int)m_have_pieces.size());
TORRENT_ASSERT(piece_index < (int)m_picker->num_pieces());
#ifndef NDEBUG
if (m_picker)
{
@ -3872,6 +3845,12 @@ namespace libtorrent
TORRENT_ASSERT(valid_metadata());
fp.clear();
if (is_seed())
{
fp.resize(m_torrent_file->num_files(), 1.f);
return;
}
fp.resize(m_torrent_file->num_files(), 0.f);
for (int i = 0; i < m_torrent_file->num_files(); ++i)
@ -3892,7 +3871,7 @@ namespace libtorrent
{
size_type bytes_step = (std::min)(size_type(m_torrent_file->piece_size(ret.piece)
- ret.start), size);
if (m_have_pieces[ret.piece]) done += bytes_step;
if (m_picker->have_piece(ret.piece)) done += bytes_step;
++ret.piece;
ret.start = 0;
size -= bytes_step;
@ -3907,11 +3886,6 @@ namespace libtorrent
{
INVARIANT_CHECK;
TORRENT_ASSERT(std::accumulate(
m_have_pieces.begin()
, m_have_pieces.end()
, 0) == m_num_pieces);
ptime now = time_now();
torrent_status st;
@ -4038,8 +4012,14 @@ namespace libtorrent
else st.progress = st.total_wanted_done
/ static_cast<float>(st.total_wanted);
st.pieces = &m_have_pieces;
st.num_pieces = m_num_pieces;
if (has_picker())
{
int num_pieces = m_picker->num_pieces();
st.pieces.resize(num_pieces, false);
for (int i = 0; i < num_pieces; ++i)
if (m_picker->have_piece(i)) st.pieces.set_bit(i);
}
st.num_pieces = num_pieces();
st.num_seeds = num_seeds();
if (m_picker.get())
st.distributed_copies = m_picker->distributed_copies();

View File

@ -36,7 +36,8 @@ boost::shared_ptr<piece_picker> setup_picker(
const int num_pieces = strlen(availability);
assert(int(strlen(have_str)) == num_pieces);
boost::shared_ptr<piece_picker> p(new piece_picker(blocks_per_piece, num_pieces * blocks_per_piece));
boost::shared_ptr<piece_picker> p(new piece_picker);
p->init(blocks_per_piece, num_pieces * blocks_per_piece);
bitfield have = string2vec(have_str);
@ -93,11 +94,10 @@ boost::shared_ptr<piece_picker> setup_picker(
TEST_CHECK(p->piece_priority(i) == prio);
}
p->init(have);
for (int i = 0; i < num_pieces; ++i)
{
if (!have[i]) continue;
p->we_have(i);
for (int j = 0; j < blocks_per_piece; ++j)
TEST_CHECK(p->is_finished(piece_block(i, j)));
}
@ -152,6 +152,11 @@ void print_pick(std::vector<piece_block> const& picked)
std::cout << std::endl;
}
void print_title(char const* name)
{
std::cerr << "==== " << name << " ====\n";
}
int test_pick(boost::shared_ptr<piece_picker> const& p)
{
std::vector<piece_block> picked;
@ -174,6 +179,7 @@ int test_main()
// make sure the block that is picked is from piece 1, since it
// it is the piece with the lowest availability
print_title("test pick lowest availability");
p = setup_picker("2223333", "* * * ", "", "");
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
@ -185,6 +191,7 @@ int test_main()
// make sure the block that is picked is from piece 5, since it
// has the highest priority among the available pieces
print_title("test pick highest priority");
p = setup_picker("1111111", "* * * ", "1111122", "");
picked.clear();
p->pick_pieces(string2vec("****** "), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
@ -196,6 +203,7 @@ int test_main()
// make sure the 4 blocks are picked from the same piece if
// whole pieces are preferred. The only whole piece is 1.
print_title("test pick whole pieces");
p = setup_picker("1111111", " ", "1111111", "1023460");
picked.clear();
p->pick_pieces(string2vec("****** "), picked, 1, 1, &peer_struct, piece_picker::fast, true, true, empty_vector);
@ -209,6 +217,7 @@ int test_main()
// test the distributed copies function. It should include ourself
// in the availability. i.e. piece 0 has availability 2.
// there are 2 pieces with availability 2 and 5 with availability 3
print_title("test distributed copies");
p = setup_picker("1233333", "* ", "", "");
float dc = p->distributed_copies();
TEST_CHECK(fabs(dc - (2.f + 5.f / 7.f)) < 0.01f);
@ -216,6 +225,7 @@ int test_main()
// ========================================================
// make sure filtered pieces are ignored
print_title("test filtered pieces");
p = setup_picker("1111111", " ", "0010000", "");
picked.clear();
p->pick_pieces(string2vec("*** ** "), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
@ -223,9 +233,23 @@ int test_main()
TEST_CHECK(int(picked.size()) > 0);
TEST_CHECK(picked.front().piece_index == 2);
// ========================================================
// make sure we_dont_have works
print_title("test we_dont_have");
p = setup_picker("1111111", "*******", "0100000", "");
picked.clear();
p->we_dont_have(1);
p->we_dont_have(2);
p->pick_pieces(string2vec("*** ** "), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
TEST_CHECK(verify_pick(p, picked));
TEST_CHECK(int(picked.size()) > 0);
TEST_CHECK(picked.front().piece_index == 1);
// ========================================================
// make sure requested blocks aren't picked
print_title("test don't pick requested blocks");
p = setup_picker("1234567", " ", "", "");
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
@ -294,6 +318,7 @@ int test_main()
// ========================================================
// test piece priorities
print_title("test piece priorities");
p = setup_picker("5555555", " ", "3214576", "");
TEST_CHECK(p->num_filtered() == 0);
TEST_CHECK(p->num_have_filtered() == 0);
@ -327,6 +352,7 @@ int test_main()
// ========================================================
// test restore_piece
print_title("test restore piece");
p = setup_picker("1234567", " ", "", "");
p->mark_as_finished(piece_block(0,0), 0);
p->mark_as_finished(piece_block(0,1), 0);
@ -380,6 +406,7 @@ int test_main()
// ========================================================
// test non-rarest-first mode
print_title("test not rarest first");
p = setup_picker("1234567", "* * * ", "1111122", "");
picked.clear();
p->pick_pieces(string2vec("****** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, false, false, empty_vector);
@ -397,6 +424,7 @@ int test_main()
// ========================================================
// test have_all and have_none
print_title("test have_all and have_none");
p = setup_picker("0123333", "* ", "", "");
dc = p->distributed_copies();
std::cout << "distributed copies: " << dc << std::endl;
@ -413,6 +441,7 @@ int test_main()
// ========================================================
// test inc_ref and dec_ref
print_title("test inc_ref dec_ref");
p = setup_picker("1233333", " * ", "", "");
TEST_CHECK(test_pick(p) == 0);
@ -464,6 +493,7 @@ int test_main()
// ========================================================
// test unverified_blocks, marking blocks and get_downloader
print_title("test unverified blocks");
p = setup_picker("1111111", " ", "", "0300700");
TEST_CHECK(p->unverified_blocks() == 2 + 3);
TEST_CHECK(p->get_downloader(piece_block(4, 0)) == 0);
@ -503,6 +533,7 @@ int test_main()
// ========================================================
// test prefer_whole_pieces
print_title("test prefer whole pieces");
p = setup_picker("1111111", " ", "", "");
picked.clear();
p->pick_pieces(string2vec("*******"), picked, 1, 3, 0, piece_picker::fast, true, false, empty_vector);
@ -533,6 +564,7 @@ int test_main()
// ========================================================
// test parole mode
print_title("test parole mode");
p = setup_picker("3333133", " ", "", "");
p->mark_as_finished(piece_block(0, 0), 0);
picked.clear();
@ -561,6 +593,7 @@ int test_main()
// ========================================================
// test suggested pieces
print_title("test suggested pieces");
p = setup_picker("1111222233334444", " ", "", "");
int v[] = {1, 5};
std::vector<int> suggested_pieces(v, v + 2);