From 1056d874bff24f2a21580cb71945314298ceeb08 Mon Sep 17 00:00:00 2001 From: Miguel Freitas Date: Sat, 30 May 2015 20:49:13 -0300 Subject: [PATCH] introducing a new torrent piece property to be persisted on disk: max_seen is the maximum availability (peer count) ever seen for this piece. new rpc getpiecemaxseen. --- .../include/libtorrent/piece_picker.hpp | 15 +++++- libtorrent/include/libtorrent/torrent.hpp | 1 + .../include/libtorrent/torrent_handle.hpp | 1 + libtorrent/src/piece_picker.cpp | 46 +++++++++++++++++++ libtorrent/src/torrent.cpp | 29 ++++++++++++ libtorrent/src/torrent_handle.cpp | 6 +++ src/bitcoinrpc.cpp | 2 + src/bitcoinrpc.h | 1 + src/twister.cpp | 20 ++++++++ 9 files changed, 119 insertions(+), 2 deletions(-) diff --git a/libtorrent/include/libtorrent/piece_picker.hpp b/libtorrent/include/libtorrent/piece_picker.hpp index f333c599..a572ba70 100644 --- a/libtorrent/include/libtorrent/piece_picker.hpp +++ b/libtorrent/include/libtorrent/piece_picker.hpp @@ -180,6 +180,7 @@ namespace libtorrent piece_picker(); void get_availability(std::vector& avail) const; + void get_max_seen(std::vector& max_seen) const; // increases the peer count for the given piece // (is used when a HAVE message is received) @@ -249,6 +250,12 @@ namespace libtorrent // returns the current piece priorities for all pieces void piece_priorities(std::vector& pieces) const; + // sets the max_seen of a piece. + void set_piece_max_seen(int index, int new_piece_max_seen); + + // returns the max_seen for the piece at 'index' + int piece_max_seen(int index) const; + // ========== start deprecation ============== // fills the bitmask with 1's for pieces that are filtered @@ -412,6 +419,7 @@ namespace libtorrent piece_pos() {} piece_pos(int peer_count_, int index_) : peer_count(peer_count_) + , max_seen((peer_count_ <= max_seen_count) ? peer_count_ : max_seen_count) , downloading(0) , full(0) , piece_priority(1) @@ -428,6 +436,8 @@ namespace libtorrent #else boost::uint32_t peer_count : 16; #endif + // max_seen is max of peer_count (saturated to 6 bits = max_seen_count) + boost::uint32_t max_seen : 6; // post flags (1 = rt, 2 = dm, 4 = fav, 12 = pfav) boost::uint32_t post_flags : 4; // is 1 if the piece is marked as being downloaded @@ -467,10 +477,11 @@ namespace libtorrent filter_priority = 0, // the max number the peer count can hold #if TORRENT_COMPACT_PICKER - max_peer_count = 0x1ff + max_peer_count = 0x1ff, #else - max_peer_count = 0xffff + max_peer_count = 0xffff, #endif + max_seen_count = 0x3f }; bool have() const { return index == we_have_index; } diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index 195354c9..bf002d22 100644 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -302,6 +302,7 @@ namespace libtorrent // ============ end deprecation ============= void piece_availability(std::vector& avail) const; + void piece_max_seen(std::vector& max_seen) const; void set_piece_priority(int index, int priority); int piece_priority(int index) const; diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp index fd236057..7646c52f 100644 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -351,6 +351,7 @@ namespace libtorrent #endif void piece_availability(std::vector& avail) const; + void piece_max_seen(std::vector& max_seen) const; // priority must be within the range [0, 7] void piece_priority(int index, int priority) const; diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp index 90376412..3fd5f0f5 100644 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -111,6 +111,7 @@ namespace libtorrent , end(m_piece_map.end()); i != end; ++i) { i->peer_count = 0; + i->max_seen = 0; i->downloading = 0; i->index = 0; #ifdef TORRENT_DEBUG_REFCOUNTS @@ -157,6 +158,7 @@ namespace libtorrent , end(m_piece_map.end()); i != end; ++i) { i->peer_count = 0; + i->max_seen = 0; i->downloading = 0; i->index = 0; #ifdef TORRENT_DEBUG_REFCOUNTS @@ -987,6 +989,11 @@ namespace libtorrent int prev_priority = p.priority(this); ++p.peer_count; + if( p.peer_count > p.max_seen ) { + p.max_seen = (p.peer_count <= piece_pos::max_seen_count) + ? p.peer_count : piece_pos::max_seen_count; + } + if (m_dirty) return; int new_priority = p.priority(this); if (prev_priority == new_priority) return; @@ -1013,6 +1020,10 @@ namespace libtorrent , end(m_piece_map.end()); i != end; ++i) { ++i->peer_count; + if( i->peer_count > i->max_seen ) { + i->max_seen = (i->peer_count <= piece_pos::max_seen_count) + ? i->peer_count : piece_pos::max_seen_count; + } } m_dirty = true; @@ -1068,6 +1079,10 @@ namespace libtorrent #endif ++m_piece_map[index].peer_count; + if( m_piece_map[index].peer_count > m_piece_map[index].max_seen ) { + m_piece_map[index].max_seen = (m_piece_map[index].peer_count <= piece_pos::max_seen_count) + ? m_piece_map[index].peer_count : piece_pos::max_seen_count; + } updated = true; } } @@ -1449,6 +1464,26 @@ namespace libtorrent } } + void piece_picker::set_piece_max_seen(int index, int new_piece_max_seen) + { +#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS + TORRENT_PIECE_PICKER_INVARIANT_CHECK; +#endif + TORRENT_ASSERT(new_piece_max_seen >= 0); + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < (int)m_piece_map.size()); + m_piece_map[index].max_seen = new_piece_max_seen < piece_pos::max_seen_count ? + new_piece_max_seen : piece_pos::max_seen_count; + } + + int piece_picker::piece_max_seen(int index) const + { + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < (int)m_piece_map.size()); + + return m_piece_map[index].max_seen; + } + // ============ start deprecation ============== void piece_picker::filtered_pieces(std::vector& mask) const @@ -2339,6 +2374,17 @@ namespace libtorrent *j = i->peer_count + m_seeds; } + void piece_picker::get_max_seen(std::vector& max_seen) const + { + TORRENT_PIECE_PICKER_INVARIANT_CHECK; + + max_seen.resize(m_piece_map.size()); + std::vector::iterator j = max_seen.begin(); + for (std::vector::const_iterator i = m_piece_map.begin() + , end(m_piece_map.end()); i != end; ++i, ++j) + *j = i->max_seen; + } + bool piece_picker::mark_as_writing(piece_block block, void* peer) { #ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index d8819ef4..6cda9725 100644 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -3830,6 +3830,20 @@ namespace libtorrent m_picker->get_availability(avail); } + void torrent::piece_max_seen(std::vector& max_seen) const + { + INVARIANT_CHECK; + + TORRENT_ASSERT(valid_metadata()); + if (!has_picker()) + { + max_seen.clear(); + return; + } + + m_picker->get_max_seen(max_seen); + } + void torrent::set_piece_priority(int index, int priority) { // INVARIANT_CHECK; @@ -5043,6 +5057,15 @@ namespace libtorrent m_policy.recalculate_connect_candidates(); } + lazy_entry const* piece_max_seen = rd.dict_find_string("piece_max_seen"); + if (piece_max_seen && piece_max_seen->string_length() + == m_torrent_file->num_pieces()) + { + char const* p = piece_max_seen->string_ptr(); + for (int i = 0; i < piece_max_seen->string_length(); ++i) + m_picker->set_piece_max_seen(i, p[i]); + } + if (!m_override_resume_data) { int auto_managed_ = rd.dict_find_int_value("auto_managed", -1); @@ -5385,6 +5408,12 @@ namespace libtorrent piece_priority[i] = m_picker->piece_priority(i); } + // write piece max_seen + entry::string_type& piece_max_seen = ret["piece_max_seen"].string(); + piece_max_seen.resize(m_torrent_file->num_pieces()); + for (int i = 0, end(piece_max_seen.size()); i < end; ++i) + piece_max_seen[i] = m_picker->piece_max_seen(i); + // write file priorities entry::list_type& file_priority = ret["file_priority"].list(); file_priority.clear(); diff --git a/libtorrent/src/torrent_handle.cpp b/libtorrent/src/torrent_handle.cpp index c1c098ff..c79a16a0 100644 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -555,6 +555,12 @@ namespace libtorrent TORRENT_SYNC_CALL1(piece_availability, boost::ref(avail)); } + void torrent_handle::piece_max_seen(std::vector& max_seen) const + { + INVARIANT_CHECK; + TORRENT_SYNC_CALL1(piece_max_seen, boost::ref(max_seen)); + } + void torrent_handle::piece_priority(int index, int priority) const { INVARIANT_CHECK; diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 8e97fd21..e51ebe26 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -280,6 +280,7 @@ static const CRPCCommand vRPCCommands[] = { "newgroupdescription", &newgroupdescription, false, true, false }, { "leavegroup", &leavegroup, false, true, false }, { "getpieceavailability", &getpieceavailability, false, true, true }, + { "getpiecemaxseen", &getpiecemaxseen, false, true, true }, }; CRPCTable::CRPCTable() @@ -1346,6 +1347,7 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector 3) ConvertTo(params[3]); if (strMethod == "newgroupdescription" && n > 1) ConvertTo(params[1]); if (strMethod == "getpieceavailability" && n > 1) ConvertTo(params[1]); + if (strMethod == "getpiecemaxseen" && n > 1) ConvertTo(params[1]); return params; } diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index e589ea77..7d8c9578 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -233,5 +233,6 @@ extern json_spirit::Value newgroupinvite(const json_spirit::Array& params, bool extern json_spirit::Value newgroupdescription(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value leavegroup(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getpieceavailability(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getpiecemaxseen(const json_spirit::Array& params, bool fHelp); #endif diff --git a/src/twister.cpp b/src/twister.cpp index 765133e8..dbfe67a7 100644 --- a/src/twister.cpp +++ b/src/twister.cpp @@ -3824,3 +3824,23 @@ Value getpieceavailability(const Array& params, bool fHelp) return avail.size() > k ? avail.at(k) : 0; } + +Value getpiecemaxseen(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 2 ) + throw runtime_error( + "getpiecemaxseen '\n" + "Get piece max seen availability (max peer count for this piece)"); + + EnsureWalletIsUnlocked(); + + string strUsername = params[0].get_str(); + int k = params[1].get_int(); + + torrent_handle h = getTorrentUser(strUsername); + std::vector max_seen; + h.piece_max_seen(max_seen); + + return max_seen.size() > k ? max_seen.at(k) : 0; +} +