From fbffae19814c1cdef06530638c31f70aa27fb751 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 30 May 2005 17:43:03 +0000 Subject: [PATCH] *** empty log message *** --- docs/manual.html | 21 +++++--- docs/manual.rst | 26 ++++++++-- examples/client_test.cpp | 39 ++++++++++---- include/libtorrent/piece_picker.hpp | 13 +++++ include/libtorrent/torrent.hpp | 3 +- include/libtorrent/torrent_handle.hpp | 15 ++++++ src/peer_connection.cpp | 5 +- src/piece_picker.cpp | 42 ++++++++++++++- src/session.cpp | 8 +-- src/torrent.cpp | 73 +++++++++++++++++++++------ src/torrent_handle.cpp | 2 +- 11 files changed, 196 insertions(+), 51 deletions(-) diff --git a/docs/manual.html b/docs/manual.html index 4a680b465..a27f04740 100755 --- a/docs/manual.html +++ b/docs/manual.html @@ -1237,6 +1237,8 @@ struct torrent_status const std::vector<bool>* pieces; size_type total_done; + size_type total_wanted_done; + size_type total_wanted; int num_seeds; float distributed_copies; @@ -1278,6 +1280,7 @@ is a pure seeder. +

When downloading, the progress is total_wanted_done / total_wanted.

paused is set to true if the torrent is paused and false otherwise.

next_announce is the time until the torrent will announce itself to the tracker. And announce_interval is the time the tracker want us to wait until we announce ourself @@ -1311,6 +1314,11 @@ that are still downloading (incomplete) this torrent.

total_done is the total number of bytes of the file(s) that we have. All this does not necessarily has to be downloaded during this session (that's total_download_payload).

+

total_wanted_done is the number of bytes we have downloadd, only counting the +pieces that we actually want to download. i.e. excluding any pieces that we have but +are filtered as not wanted.

+

total_wanted is the total number of bytes we want to download. This is also +excluding pieces that have been filtered.

num_seeds is the number of peers that are seeding that this client is currently connected to.

distributed_copies is the number of distributed copies of the torrent. @@ -1375,15 +1383,16 @@ any combination of the enums above. The following table describes each flag:

interesting -we are interested in pieces from this peer. +we are interested in pieces from this peer. choked we have choked this peer. -remote_interested -remote_choked -means the same thing but that the peer is interested -in pieces from us and the peer has choked us. +remote_interested +the peer is interested in us + +remote_choked +the peer has choked us. support_extensions means that this peer supports the @@ -1391,7 +1400,7 @@ in pieces from us and the peer has choked us. local_connection The connection was initiated by us, the peer has a -listen port open, and that port is the same is in the +listen port open, and that port is the same as in the address of this peer. If this flag is not set, this peer connection was opened by this peer connecting to us. diff --git a/docs/manual.rst b/docs/manual.rst index 153c5bf7b..11adf9bf7 100755 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -1159,6 +1159,7 @@ It contains the following fields:: checking_files, connecting_to_tracker, downloading, + finished, seeding }; @@ -1191,6 +1192,8 @@ It contains the following fields:: const std::vector* pieces; size_type total_done; + size_type total_wanted_done; + size_type total_wanted; int num_seeds; float distributed_copies; @@ -1220,13 +1223,18 @@ current task is in the ``state`` member, it will be one of the following: | |most torrents will be in most of the time. The progress | | |meter will tell how much of the files that has been | | |downloaded. | -| | | ++--------------------------+----------------------------------------------------------+ +|``finished`` |In this state the torrent has finished downloading but | +| |still doesn't have the entire torrent. i.e. some pieces | +| |are filtered and won't get downloaded. | +--------------------------+----------------------------------------------------------+ |``seeding`` |In this state the torrent has finished downloading and | | |is a pure seeder. | | | | +--------------------------+----------------------------------------------------------+ +When downloading, the progress is ``total_wanted_done`` / ``total_wanted``. + ``paused`` is set to true if the torrent is paused and false otherwise. ``next_announce`` is the time until the torrent will announce itself to the tracker. And @@ -1271,6 +1279,13 @@ that are still downloading (incomplete) this torrent. this does not necessarily has to be downloaded during this session (that's ``total_download_payload``). +``total_wanted_done`` is the number of bytes we have downloadd, only counting the +pieces that we actually want to download. i.e. excluding any pieces that we have but +are filtered as not wanted. + +``total_wanted`` is the total number of bytes we want to download. This is also +excluding pieces that have been filtered. + ``num_seeds`` is the number of peers that are seeding that this client is currently connected to. @@ -1333,18 +1348,19 @@ The ``flags`` attribute tells you in which state the peer is. It is set to any combination of the enums above. The following table describes each flag: +-------------------------+-------------------------------------------------------+ -| ``interesting`` | we are interested in pieces from this peer. | +| ``interesting`` | **we** are interested in pieces from this peer. | +-------------------------+-------------------------------------------------------+ | ``choked`` | **we** have choked this peer. | +-------------------------+-------------------------------------------------------+ -| ``remote_interested`` | means the same thing but that the peer is interested | -| ``remote_choked`` | in pieces from us and the peer has choked **us**. | +| ``remote_interested`` | the peer is interested in **us** | ++-------------------------+-------------------------------------------------------+ +| ``remote_choked`` | the peer has choked **us**. | +-------------------------+-------------------------------------------------------+ | ``support_extensions`` | means that this peer supports the | | | `extension protocol`__. | +-------------------------+-------------------------------------------------------+ | ``local_connection`` | The connection was initiated by us, the peer has a | -| | listen port open, and that port is the same is in the | +| | listen port open, and that port is the same as in the | | | address_ of this peer. If this flag is not set, this | | | peer connection was opened by this peer connecting to | | | us. | diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 271ac4b0e..e6859b1da 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -147,7 +147,7 @@ void clear() #endif -std::string to_string(float v, int width, int precision = 4) +std::string to_string(float v, int width, int precision = 3) { std::stringstream s; s.precision(precision); @@ -197,7 +197,7 @@ std::string add_suffix(float val) for (int i = 0; i < num_prefix; ++i) { if (fabs(val) < 1000.f) - return to_string(val, i==0?7:6) + prefix[i]; + return to_string(val, i==0?5:4) + prefix[i]; val /= 1000.f; } return to_string(val, 6) + "PB"; @@ -208,8 +208,9 @@ std::string progress_bar(float progress, int width) std::vector bar; bar.reserve(width); - std::fill_n(std::back_inserter(bar), progress * width, '#'); - std::fill_n(std::back_inserter(bar), width - (progress * width), '-'); + int progress_chars = progress * width + .5f; + std::fill_n(std::back_inserter(bar), progress_chars, '#'); + std::fill_n(std::back_inserter(bar), width - progress_chars, '-'); return std::string(bar.begin(), bar.end()); } @@ -217,7 +218,7 @@ void print_peer_info(std::ostream& out, std::vector const { using namespace libtorrent; - out << " down up q r flags client block\n"; + out << " down up q r flags block progress client \n"; for (std::vector::const_iterator i = peers.begin(); i != peers.end(); ++i) @@ -238,17 +239,20 @@ void print_peer_info(std::ostream& out, std::vector const << static_cast((i->flags & peer_info::remote_interested)?"i":"_") << static_cast((i->flags & peer_info::remote_choked)?"c":"_") << static_cast((i->flags & peer_info::supports_extensions)?"e":"_") - << static_cast((i->flags & peer_info::local_connection)?"l":"r") << " " - << identify_client(i->id); + << static_cast((i->flags & peer_info::local_connection)?"l":"r") << " "; if (i->downloading_piece_index >= 0) { - out << " " << progress_bar( + out << progress_bar( i->downloading_progress / static_cast(i->downloading_total) , 15); } + else + { + out << progress_bar(0.f, 15); + } - out << "\n"; + out << " " << identify_client(i->id) << "\n"; } } @@ -328,6 +332,12 @@ int main(int argc, char* argv[]) handles.back().set_max_connections(100); handles.back().set_max_uploads(-1); handles.back().set_ratio(1.02f); +/* + for (int i = 0; i < t.num_pieces(); ++i) + { + handles.back().filter_piece(i, i % 2 == 0); + } +*/ } catch (std::exception& e) { @@ -446,6 +456,10 @@ int main(int argc, char* argv[]) --i; continue; } + out << "name: "; + if (i->has_metadata()) out << i->get_torrent_info().name(); + else out << "-"; + out << "\n"; torrent_status s = i->status(); switch(s.state) @@ -465,6 +479,9 @@ int main(int argc, char* argv[]) case torrent_status::downloading: out << "downloading "; break; + case torrent_status::finished: + out << "finished "; + break; case torrent_status::seeding: out << "seeding "; break; @@ -483,9 +500,9 @@ int main(int argc, char* argv[]) out << "peers: " << s.num_peers << " " << "seeds: " << s.num_seeds << " " << "distributed copies: " << s.distributed_copies << "\n"; - out << "download:" << add_suffix(s.download_rate) << "/s " + out << "download: " << add_suffix(s.download_rate) << "/s " << "(" << add_suffix(s.total_download) << ") " - << "upload:" << add_suffix(s.upload_rate) << "/s " + << "upload: " << add_suffix(s.upload_rate) << "/s " << "(" << add_suffix(s.total_upload) << ") " << "ratio: " << ratio(s.total_payload_download, s.total_payload_upload) << "\n"; out << "info-hash: " << i->info_hash() << "\n"; diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index 47784cc36..c35882231 100755 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -199,6 +199,11 @@ namespace libtorrent boost::optional
get_downloader(piece_block block) const; + // the number of filtered pieces we don't have + int num_filtered() const { return m_num_filtered; } + + // the number of filtered pieces we already have + int num_have_filtered() const { return m_num_have_filtered; } #ifndef NDEBUG // used in debug mode void integrity_check(const torrent* t = 0) const; @@ -298,6 +303,14 @@ namespace libtorrent int m_blocks_per_piece; int m_blocks_in_last_piece; + // the number of filtered pieces that we don't already + // have. total_number_of_pieces - number_of_pieces_we_have + // - num_filtered is supposed to the number of pieces + // we still want to download + int m_num_filtered; + + // the number of pieces we have that also are filtered + int m_num_have_filtered; }; inline int piece_picker::blocks_in_piece(int index) const diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 5a9ac0143..514ecb2b3 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #ifdef _MSC_VER #pragma warning(pop) @@ -135,7 +136,7 @@ namespace libtorrent stat statistics() const { return m_stat; } size_type bytes_left() const; - size_type bytes_done() const; + boost::tuple bytes_done() const; void pause(); void resume(); diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index 2d1278fce..141d5eb57 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -89,6 +89,8 @@ namespace libtorrent , num_incomplete(-1) , pieces(0) , total_done(0) + , total_wanted_done(0) + , total_wanted(0) , num_seeds(0) , distributed_copies(0.f) , block_size(0) @@ -101,6 +103,7 @@ namespace libtorrent connecting_to_tracker, downloading_metadata, downloading, + finished, seeding }; @@ -150,8 +153,20 @@ namespace libtorrent const std::vector* pieces; // the number of bytes of the file we have + // including pieces that may have been filtered + // after we downloaded them size_type total_done; + // the number of bytes we have of those that we + // want. i.e. not counting bytes from pieces that + // are filtered as not wanted. + size_type total_wanted_done; + + // the total number of bytes we want to download + // this may be smaller than the total torrent size + // in case any pieces are filtered as not wanted + size_type total_wanted; + // the number of peers this torrent is connected to // that are seeding. int num_seeds; diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 972aff873..aebffbef4 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -268,13 +268,12 @@ namespace libtorrent // peer has, in a shuffled order bool interesting = false; for (std::vector::iterator i = piece_list.begin(); - i != piece_list.end(); - ++i) + i != piece_list.end(); ++i) { int index = *i; m_torrent->peer_has(index); if (!m_torrent->have_piece(index) - && m_torrent->picker().is_filtered(index)) + && !m_torrent->picker().is_filtered(index)) interesting = true; } diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index 7ced557cb..7086088d6 100755 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -59,6 +59,8 @@ namespace libtorrent , m_downloading_piece_info(2) , m_filtered_piece_info(2) , m_piece_map((total_num_blocks + blocks_per_piece-1) / blocks_per_piece) + , m_num_filtered(0) + , m_num_have_filtered(0) { assert(blocks_per_piece > 0); assert(total_num_blocks > 0); @@ -80,6 +82,7 @@ namespace libtorrent std::fill(m_piece_map.begin(), m_piece_map.end(), piece_pos(0, piece_pos::we_have_index)); } + // pieces is a bitmask with the pieces we have void piece_picker::files_checked( const std::vector& pieces , const std::vector& unfinished) @@ -93,6 +96,11 @@ namespace libtorrent { if (*i) continue; int index = static_cast(i - pieces.begin()); + if (m_piece_map[index].filtered) + { + ++m_num_filtered; + --m_num_have_filtered; + } piece_list.push_back(index); } @@ -149,11 +157,19 @@ namespace libtorrent if (t != 0) assert((int)m_piece_map.size() == t->torrent_file().num_pieces()); + int num_filtered = 0; + int num_have_filtered = 0; for (std::vector::const_iterator i = m_piece_map.begin(); i != m_piece_map.end(); ++i) { int index = static_cast(i - m_piece_map.begin()); - + if (i->filtered) + { + if (i->index != piece_pos::we_have_index) + ++num_filtered; + else + ++num_have_filtered; + } if (t != 0) { int actual_peer_count = 0; @@ -241,7 +257,8 @@ namespace libtorrent assert(down == m_downloads.end()); } } - + assert(num_filtered == m_num_filtered); + assert(num_have_filtered == m_num_have_filtered); } #endif @@ -452,6 +469,11 @@ namespace libtorrent assert(info_index != piece_pos::we_have_index); piece_pos& p = m_piece_map[index]; + if (p.filtered) + { + --m_num_filtered; + ++m_num_have_filtered; + } remove(p.downloading, p.filtered, peer_count, info_index); #ifndef NDEBUG integrity_check(); @@ -472,7 +494,14 @@ namespace libtorrent if (p.filtered == 1) return; p.filtered = 1; if (p.index != piece_pos::we_have_index) + { + ++m_num_filtered; move(p.downloading, false, p.peer_count, p.index); + } + else + { + ++m_num_have_filtered; + } #ifndef NDEBUG integrity_check(); @@ -493,7 +522,16 @@ namespace libtorrent if (p.filtered == 0) return; p.filtered = 0; if (p.index != piece_pos::we_have_index) + { + --m_num_filtered; + assert(m_num_filtered >= 0); move(p.downloading, true, p.peer_count, p.index); + } + else + { + --m_num_have_filtered; + assert(m_num_have_filtered >= 0); + } #ifndef NDEBUG integrity_check(); diff --git a/src/session.cpp b/src/session.cpp index 92eb52a49..af70198c6 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -188,9 +188,7 @@ namespace libtorrent { namespace detail detail::piece_checker_data* checker_impl::find_torrent(sha1_hash const& info_hash) { for (std::deque::iterator i - = m_torrents.begin(); - i != m_torrents.end(); - ++i) + = m_torrents.begin(); i != m_torrents.end(); ++i) { if (i->info_hash == info_hash) return &(*i); } @@ -200,9 +198,7 @@ namespace libtorrent { namespace detail void checker_impl::remove_torrent(sha1_hash const& info_hash) { for (std::deque::iterator i - = m_torrents.begin(); - i != m_torrents.end(); - ++i) + = m_torrents.begin(); i != m_torrents.end(); ++i) { if (i->info_hash == info_hash) { diff --git a/src/torrent.cpp b/src/torrent.cpp index bba490efe..0c5484ac2 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -364,16 +364,22 @@ namespace libtorrent // if we don't have the metadata yet, we // cannot tell how big the torrent is. if (!valid_metadata()) return -1; - return m_torrent_file.total_size() - bytes_done(); + return m_torrent_file.total_size() - boost::get<0>(bytes_done()); } - size_type torrent::bytes_done() const + // the first value is the total number of bytes downloaded + // the second value is the number of bytes of those that haven't + // been filtered as not wanted we have downloaded + boost::tuple torrent::bytes_done() const { if (!valid_metadata()) return 0; assert(m_picker.get()); - const int last_piece = m_torrent_file.num_pieces()-1; + const int last_piece = m_torrent_file.num_pieces() - 1; + size_type wanted_done = (m_num_pieces - m_picker->num_have_filtered()) + * m_torrent_file.piece_length(); + size_type total_done = m_num_pieces * m_torrent_file.piece_length(); @@ -382,25 +388,28 @@ namespace libtorrent // assumed all pieces were of equal size if (m_have_pieces[last_piece]) { - total_done -= m_torrent_file.piece_length(); - total_done += m_torrent_file.piece_size(last_piece); + int corr = m_torrent_file.piece_size(last_piece) + - m_torrent_file.piece_length(); + total_done += corr; + if (!m_picker->is_filtered(last_piece)) + wanted_done += corr; } const std::vector& dl_queue = m_picker->get_download_queue(); - const int blocks_per_piece = static_cast(m_torrent_file.piece_length() / m_block_size); + const int blocks_per_piece = static_cast( + m_torrent_file.piece_length() / m_block_size); for (std::vector::const_iterator i = - dl_queue.begin(); - i != dl_queue.end(); - ++i) + dl_queue.begin(); i != dl_queue.end(); ++i) { + int corr = 0; assert(!m_have_pieces[i->index]); for (int j = 0; j < blocks_per_piece; ++j) { - total_done += (i->finished_blocks[j]) * m_block_size; + corr += (i->finished_blocks[j]) * m_block_size; } // correction if this was the last piece @@ -408,9 +417,12 @@ namespace libtorrent if (i->index == last_piece && i->finished_blocks[m_picker->blocks_in_last_piece()-1]) { - total_done -= m_block_size; - total_done += m_torrent_file.piece_size(last_piece) % m_block_size; + corr -= m_block_size; + corr += m_torrent_file.piece_size(last_piece) % m_block_size; } + total_done += corr; + if (!m_picker->is_filtered(i->index)) + wanted_done += corr; } std::map downloading_piece; @@ -443,8 +455,12 @@ namespace libtorrent } for (std::map::iterator i = downloading_piece.begin(); i != downloading_piece.end(); ++i) + { total_done += i->second; - return total_done; + if (!m_picker->is_filtered(i->first.piece_index)) + wanted_done += i->second; + } + return boost::make_tuple(total_done, wanted_done); } void torrent::piece_failed(int index) @@ -562,10 +578,14 @@ namespace libtorrent assert(index >= 0); assert(index < m_torrent_file.num_pieces()); + // TODO: update peer's interesting-bit + if (filter) m_picker->mark_as_filtered(index); else m_picker->mark_as_unfiltered(index); } + // TODO: add a function to set the filter with one call + bool torrent::is_piece_filtered(int index) const { // this call is only valid on torrents with metadata @@ -1050,7 +1070,7 @@ namespace libtorrent st.num_complete = m_complete; st.num_incomplete = m_incomplete; st.paused = m_paused; - st.total_done = bytes_done(); + boost::tie(st.total_done, st.total_wanted_done) = bytes_done(); // payload transfer st.total_payload_download = m_stat.total_payload_download(); @@ -1102,8 +1122,27 @@ namespace libtorrent // fill in status that depends on metadata - st.progress = st.total_done - / static_cast(m_torrent_file.total_size()); + st.total_wanted = m_torrent_file.total_size(); + + if (m_picker.get() && (m_picker->num_filtered() > 0 + || m_picker->num_have_filtered() > 0)) + { + int filtered_pieces = m_picker->num_filtered() + + m_picker->num_have_filtered(); + int last_piece_index = m_torrent_file.num_pieces() - 1; + if (m_picker->is_filtered(last_piece_index)) + { + st.total_wanted -= m_torrent_file.piece_size(last_piece_index); + --filtered_pieces; + } + + st.total_wanted -= filtered_pieces * m_torrent_file.piece_length(); + } + + assert(st.total_wanted >= st.total_wanted_done); + + st.progress = st.total_wanted_done + / static_cast(st.total_wanted); st.pieces = &m_have_pieces; @@ -1111,6 +1150,8 @@ namespace libtorrent st.state = torrent_status::connecting_to_tracker; else if (m_num_pieces == (int)m_have_pieces.size()) st.state = torrent_status::seeding; + else if (st.total_wanted_done == st.total_wanted) + st.state = torrent_status::finished; else st.state = torrent_status::downloading; diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index c8cafde1d..43191399a 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -78,7 +78,7 @@ namespace libtorrent { void throw_invalid_handle() { - throw_invalid_handle(); + throw invalid_handle(); } template