From 49f74be42f10dd85bc64fdbe7a73c1d04b68748d Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 23 Apr 2012 05:48:46 +0000 Subject: [PATCH] make super-seeding a bit more robust --- include/libtorrent/peer_connection.hpp | 14 +++--- include/libtorrent/torrent.hpp | 5 ++- src/bt_peer_connection.cpp | 10 +++-- src/peer_connection.cpp | 62 ++++++++++++++++---------- src/torrent.cpp | 7 ++- 5 files changed, 62 insertions(+), 36 deletions(-) diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 60483ded0..b175b0df7 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -275,8 +275,12 @@ namespace libtorrent // this will tell the peer to announce the given piece // and only allow it to request that piece - void superseed_piece(int index); - int superseed_piece() const { return m_superseed_piece; } + void superseed_piece(int replace_piece, int new_piece); + bool super_seeded_piece(int index) const + { + return m_superseed_piece[0] == index + || m_superseed_piece[1] == index; + } // tells if this connection has data it want to send // and has enough upload bandwidth quota left to send it. @@ -993,12 +997,12 @@ namespace libtorrent // once the connection completes int m_connection_ticket; - // if this is -1, superseeding is not active. If it is >= 0 + // if [0] is -1, superseeding is not active. If it is >= 0 // this is the piece that is available to this peer. Only - // this piece can be downloaded from us by this peer. + // these two pieces can be downloaded from us by this peer. // This will remain the current piece for this peer until // another peer sends us a have message for this piece - int m_superseed_piece; + int m_superseed_piece[2]; // bytes downloaded since last second // timer timeout; used for determining diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index f8198ee7f..683b14b20 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -492,7 +492,10 @@ namespace libtorrent void get_suggested_pieces(std::vector& s) const; bool super_seeding() const - { return m_super_seeding; } + { + // we're not super seeding if we're not a seed + return m_super_seeding && is_seed(); + } void super_seeding(bool on); int get_piece_to_super_seed(bitfield const&); diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index d1accacec..97f61dd38 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -338,6 +338,10 @@ namespace libtorrent if (!m_supports_fast) return; +#ifdef TORRENT_VERBOSE_LOGGING + peer_log("==> REJECT_PIECE [ piece: %d | s: %d | l: %d ]" + , r.piece, r.start, r.length); +#endif TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield); TORRENT_ASSERT(associated_torrent().lock()->valid_metadata()); @@ -1989,9 +1993,9 @@ namespace libtorrent m_sent_bitfield = true; #endif - // bootstrap superseeding by sending one have message - superseed_piece(t->get_piece_to_super_seed( - get_bitfield())); + // bootstrap superseeding by sending two have message + superseed_piece(-1, t->get_piece_to_super_seed(get_bitfield())); + superseed_piece(-1, t->get_piece_to_super_seed(get_bitfield())); return; } else if (m_supports_fast && t->is_seed()) diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 38451eb07..62612aee5 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -158,7 +158,6 @@ namespace libtorrent , m_peer_info(peerinfo) , m_speed(slow) , m_connection_ticket(-1) - , m_superseed_piece(-1) , m_remote_bytes_dled(0) , m_remote_dl_rate(0) , m_outstanding_writing_bytes(0) @@ -202,6 +201,8 @@ namespace libtorrent , m_received_in_piece(0) #endif { + m_superseed_piece[0] = -1; + m_superseed_piece[1] = -1; boost::shared_ptr t = m_torrent.lock(); // if t is NULL, we better not be connecting, since // we can't decrement the connecting counter @@ -311,7 +312,6 @@ namespace libtorrent , m_peer_info(peerinfo) , m_speed(slow) , m_connection_ticket(-1) - , m_superseed_piece(-1) , m_remote_bytes_dled(0) , m_remote_dl_rate(0) , m_outstanding_writing_bytes(0) @@ -355,6 +355,8 @@ namespace libtorrent , m_received_in_piece(0) #endif { + m_superseed_piece[0] = -1; + m_superseed_piece[1] = -1; m_est_reciprocation_rate = m_ses.m_settings.default_est_reciprocation_rate; #if TORRENT_USE_I2P @@ -1661,11 +1663,11 @@ namespace libtorrent } } - if (t->super_seeding() && m_superseed_piece != -1) + if (t->super_seeding()) { - // assume the peer has the piece we're superseeding to it - // and give it another one - if (!m_have_piece[m_superseed_piece]) incoming_have(m_superseed_piece); + // maybe we need to try another piece, to see if the peer + // is interested in us then + superseed_piece(-1, t->get_piece_to_super_seed(m_have_piece)); } } @@ -1733,9 +1735,9 @@ namespace libtorrent // if the peer optimizes out redundant have messages // this will be handled when the peer sends not-interested // instead. - if (m_superseed_piece == index) + if (super_seeded_piece(index)) { - superseed_piece(t->get_piece_to_super_seed(m_have_piece)); + superseed_piece(index, t->get_piece_to_super_seed(m_have_piece)); } } @@ -1798,15 +1800,15 @@ namespace libtorrent // a new piece to that peer if (t->super_seeding() && m_ses.settings().strict_super_seeding - && (index != m_superseed_piece || t->num_peers() == 1)) + && (!super_seeded_piece(index) || t->num_peers() == 1)) { for (torrent::peer_iterator i = t->begin() , end(t->end()); i != end; ++i) { peer_connection* p = *i; - if (p->superseed_piece() != index) continue; + if (!p->super_seeded_piece(index)) continue; if (!p->has_piece(index)) continue; - p->superseed_piece(t->get_piece_to_super_seed(p->get_bitfield())); + p->superseed_piece(index, t->get_piece_to_super_seed(p->get_bitfield())); } } } @@ -2034,8 +2036,8 @@ namespace libtorrent , r.piece, r.start, r.length); #endif - if (m_superseed_piece != -1 - && r.piece != m_superseed_piece) + if (t->super_seeding() + && !super_seeded_piece(r.piece)) { #ifdef TORRENT_STATS ++m_ses.m_invalid_piece_requests; @@ -2043,14 +2045,17 @@ namespace libtorrent ++m_num_invalid_requests; #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING peer_log("*** INVALID_REQUEST [ piece not superseeded " - "i: %d t: %d n: %d h: %d ss: %d ]" + "i: %d t: %d n: %d h: %d ss1: %d ss2: %d ]" , m_peer_interested , int(t->torrent_file().piece_size(r.piece)) , t->torrent_file().num_pieces() , t->have_piece(r.piece) - , m_superseed_piece); + , m_superseed_piece[0] + , m_superseed_piece[1]); #endif + write_reject_request(r); + if (t->alerts().should_post()) { t->alerts().post_alert(invalid_request_alert( @@ -3990,12 +3995,13 @@ namespace libtorrent m_packet_size = packet_size; } - void peer_connection::superseed_piece(int index) + void peer_connection::superseed_piece(int replace_piece, int new_piece) { - if (index == -1) + if (new_piece == -1) { - if (m_superseed_piece == -1) return; - m_superseed_piece = -1; + if (m_superseed_piece[0] == -1) return; + m_superseed_piece[0] = -1; + m_superseed_piece[1] = -1; #ifdef TORRENT_VERBOSE_LOGGING peer_log("*** ending super seed mode"); @@ -4003,6 +4009,7 @@ namespace libtorrent boost::shared_ptr t = m_torrent.lock(); assert(t); + // TODO: we should probably just send a HAVE_ALL here for (int i = 0; i < int(m_have_piece.size()); ++i) { if (m_have_piece[i] || !t->have_piece(i)) continue; @@ -4015,13 +4022,22 @@ namespace libtorrent return; } - assert(!has_piece(index)); + assert(!has_piece(new_piece)); #ifdef TORRENT_VERBOSE_LOGGING - peer_log("==> HAVE [ piece: %d ] (super seed)", index); + peer_log("==> HAVE [ piece: %d ] (super seed)", new_piece); #endif - write_have(index); - m_superseed_piece = index; + write_have(new_piece); + + if (replace_piece >= 0) + { + // move the piece we're replacing to the tail + if (m_superseed_piece[0] == replace_piece) + std::swap(m_superseed_piece[0], m_superseed_piece[1]); + } + + m_superseed_piece[1] = m_superseed_piece[0]; + m_superseed_piece[0] = new_piece; } void peer_connection::update_desired_queue_size() diff --git a/src/torrent.cpp b/src/torrent.cpp index 4e853800a..18fca1570 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -923,8 +923,6 @@ namespace libtorrent // been closed by the time the torrent is destructed. And they are // supposed to be closed. So we can still do the invariant check. - TORRENT_ASSERT(m_connections.empty()); - INVARIANT_CHECK; #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING || defined TORRENT_LOGGING @@ -932,6 +930,7 @@ namespace libtorrent #endif TORRENT_ASSERT(m_abort); + TORRENT_ASSERT(m_connections.empty()); if (!m_connections.empty()) disconnect_all(errors::torrent_aborted); } @@ -3474,7 +3473,7 @@ namespace libtorrent // disable super seeding for all peers for (peer_iterator i = begin(); i != end(); ++i) { - (*i)->superseed_piece(-1); + (*i)->superseed_piece(-1, -1); } } @@ -3495,7 +3494,7 @@ namespace libtorrent int availability = 0; for (const_peer_iterator j = begin(); j != end(); ++j) { - if ((*j)->superseed_piece() == i) + if ((*j)->super_seeded_piece(i)) { // avoid superseeding the same piece to more than one // peer if we can avoid it. Do this by artificially