From 5224e0c34066dac013ad77807d044f8bf0245914 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Fri, 19 Mar 2010 18:39:51 +0000 Subject: [PATCH] complete_ago extension --- ChangeLog | 1 + docs/manual.rst | 30 +++++++++++++++++++++++--- include/libtorrent/peer_connection.hpp | 7 ++++++ include/libtorrent/torrent.hpp | 5 +++++ include/libtorrent/torrent_handle.hpp | 6 +++++- src/bt_peer_connection.cpp | 6 ++++++ src/peer_connection.cpp | 9 ++++++++ src/torrent.cpp | 21 ++++++++++++++++++ 8 files changed, 81 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 39b562a60..8d229d633 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * supports complete_ago extension * dropped zlib as a dependency and builds using puff.c instead * made the default cache size depend on available physical RAM * added flags to torrent::status() that can filter which values are calculated diff --git a/docs/manual.rst b/docs/manual.rst index 028d2752e..935adbaa5 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -1943,7 +1943,14 @@ Its declaration looks like this:: { torrent_handle(); - torrent_status status(); + enum status_flags_t + { + query_distributed_copies = 1, + query_accurate_download_counters = 2, + query_last_seen_complete = 4 + }; + + torrent_status status(boost::uint32_t flags = 0xffffffff); void file_progress(std::vector& fp, int flags = 0); void get_download_queue(std::vector& queue) const; void get_peer_info(std::vector& v) const; @@ -2837,11 +2844,24 @@ status() :: - torrent_status status() const; + torrent_status status(boost::uint32_t flags = 0xffffffff) const; ``status()`` will return a structure with information about the status of this torrent. If the torrent_handle_ is invalid, it will throw libtorrent_exception_ exception. -See torrent_status_. +See torrent_status_. The ``flags`` argument filters what information is returned +in the torrent_status. Some information in there is relatively expensive to calculate, and +if you're not interested in it (and see performance issues), you can filter them out. + +By default everything is included. The flags you can use to decide what to *include* are: + +* ``query_distributed_copies`` + calculates ``distributed_copies``, ``distributed_full_copies`` and ``distributed_fraction``. + +* ``query_accurate_download_counters`` + includes partial downloaded blocks in ``total_done`` and ``total_wanted_done``. + +* ``query_last_seen_complete`` + includes ``last_seen_complete``. get_download_queue() @@ -3058,6 +3078,7 @@ It contains the following fields:: time_t added_time; time_t completed_time; + time_t last_seen_complete; }; ``progress`` is a value in the range [0, 1], that represents the progress of the @@ -3287,6 +3308,9 @@ torrent_handle_. ``completed_time`` is the posix-time when this torrent was finished. If the torrent is not yet finished, this is 0. +``last_seen_complete`` is the time when we, or one of our peers, last +saw a complete copy of this torrent. + peer_info ========= diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 95c15539d..7de9dc4e2 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -543,6 +543,9 @@ namespace libtorrent bool piece_failed; #endif + time_t last_seen_complete() const { return m_last_seen_complete; } + void set_last_seen_complete(int ago) { m_last_seen_complete = time(0) - ago; } + // upload and download channel state // enum from peer_info::bw_state char m_channel_state[2]; @@ -809,6 +812,10 @@ namespace libtorrent // (-1, -1) if we're not receiving one piece_block m_receiving_block; + // the time when this peer last saw a complete copy + // of this torrent + time_t m_last_seen_complete; + // if the timeout is extended for the outstanding // requests, this is the number of seconds it was // extended. diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 3008fcdda..0365d2d06 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -671,6 +671,10 @@ namespace libtorrent void write_resume_data(entry& rd) const; void read_resume_data(lazy_entry const& rd); + void seen_complete() { m_last_seen_complete = time(0); } + int time_since_complete() const { return time(0) - m_last_seen_complete; } + time_t last_seen_complete() const { return m_last_seen_complete; } + // LOGGING #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING virtual void debug_log(const std::string& line); @@ -974,6 +978,7 @@ namespace libtorrent // completed, m_completed_time is 0 time_t m_added_time; time_t m_completed_time; + time_t m_last_seen_complete; // ============================== // The following members are specifically diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index e19b21443..ec8cae96c 100644 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -126,6 +126,7 @@ namespace libtorrent , priority(0) , added_time(0) , completed_time(0) + , last_seen_complete(0) {} enum state_t @@ -309,6 +310,7 @@ namespace libtorrent // the time this torrent was added and completed time_t added_time; time_t completed_time; + time_t last_seen_complete; }; struct TORRENT_EXPORT block_info @@ -400,8 +402,10 @@ namespace libtorrent enum status_flags_t { query_distributed_copies = 1, - query_accurate_download_counters = 2 + query_accurate_download_counters = 2, + query_last_seen_complete = 4 }; + // the flags specify which fields are calculated. By default everything // is included, you may save CPU by not querying fields you don't need torrent_status status(boost::uint32_t flags = 0xffffffff) const; diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 1abd09516..b857f9d4d 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -1536,6 +1536,9 @@ namespace libtorrent } // there should be a version too // but where do we put that info? + + int last_seen_complete = root.dict_find_int_value("complete_ago", -1); + if (last_seen_complete >= 0) set_last_seen_complete(last_seen_complete); std::string client_info = root.dict_find_string_value("v"); if (!client_info.empty()) m_client_version = client_info; @@ -1877,6 +1880,9 @@ namespace libtorrent TORRENT_ASSERT(t); m["upload_only"] = upload_only_msg; + int complete_ago = -1; + if (t->last_seen_complete() > 0) complete_ago = t->time_since_complete(); + handshake["complete_ago"] = complete_ago; // if we're using lazy bitfields or if we're super seeding, don't say // we're upload only, since it might make peers disconnect diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 938262eb8..333d78d45 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -101,6 +101,7 @@ namespace libtorrent , m_remote(endp) , m_torrent(tor) , m_receiving_block(-1, -1) + , m_last_seen_complete(0) , m_timeout_extend(0) , m_outstanding_bytes(0) , m_extension_outstanding_bytes(0) @@ -235,6 +236,7 @@ namespace libtorrent , m_socket(s) , m_remote(endp) , m_receiving_block(-1, -1) + , m_last_seen_complete(0) , m_timeout_extend(0) , m_outstanding_bytes(0) , m_extension_outstanding_bytes(0) @@ -1632,6 +1634,7 @@ namespace libtorrent // decrement the piece count without first incrementing it if (is_seed()) { + t->seen_complete(); t->get_policy().set_seed(m_peer_info, true); m_upload_only = true; disconnect_if_redundant(); @@ -4657,6 +4660,12 @@ namespace libtorrent } while (bytes_transferred > 0); + if (is_seed()) + { + boost::shared_ptr t = m_torrent.lock(); + if (t) t->seen_complete(); + } + m_statistics.trancieve_ip_packet(bytes_in_loop, m_remote.address().is_v6()); setup_receive(); } diff --git a/src/torrent.cpp b/src/torrent.cpp index 20362cbd4..f7c67bdb0 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -242,6 +242,9 @@ namespace libtorrent PRINT_OFFSETOF(torrent, m_piece_time_deviation) PRINT_OFFSETOF(torrent, m_total_failed_bytes) PRINT_OFFSETOF(torrent, m_total_redundant_bytes) + PRINT_OFFSETOF(torrent, m_added_time) + PRINT_OFFSETOF(torrent, m_completed_time) + PRINT_OFFSETOF(torrent, m_last_seen_complete) // PRINT_OFFSETOF(torrent, m_upload_mode_time:24) // PRINT_OFFSETOF(torrent, m_state:3) // PRINT_OFFSETOF(torrent, m_storage_mode:2) @@ -328,6 +331,7 @@ namespace libtorrent , m_total_redundant_bytes(0) , m_added_time(time(0)) , m_completed_time(0) + , m_last_seen_complete(0) , m_upload_mode_time(0) , m_state(torrent_status::checking_resume_data) , m_storage_mode(p.storage_mode) @@ -3592,6 +3596,7 @@ namespace libtorrent m_active_time = rd.dict_find_int_value("active_time"); m_finished_time = rd.dict_find_int_value("finished_time"); m_seeding_time = rd.dict_find_int_value("seeding_time"); + m_last_seen_complete = rd.dict_find_int_value("last_seen_complete"); m_complete = rd.dict_find_int_value("num_seeds", -1); m_incomplete = rd.dict_find_int_value("num_downloaders", -1); set_upload_limit(rd.dict_find_int_value("upload_rate_limit", -1)); @@ -3739,6 +3744,7 @@ namespace libtorrent ret["active_time"] = m_active_time; ret["finished_time"] = m_finished_time; ret["seeding_time"] = m_seeding_time; + ret["last_seen_complete"] = m_last_seen_complete; int seeds = 0; int downloaders = 0; @@ -6269,6 +6275,21 @@ namespace libtorrent st.distributed_fraction = -1; st.distributed_copies = -1.f; } + + if (flags & torrent_handle::query_last_seen_complete) + { + time_t last = last_seen_complete(); + for (std::set::iterator i = m_connections.begin() + , end(m_connections.end()); i != i; ++i) + { + last = (std::max)(last, (*i)->last_seen_complete()); + } + st.last_seen_complete = last; + } + else + { + st.last_seen_complete = 0; + } return st; }