From 90feac812668f052b128dfa29bffd8d0b051cb37 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 4 Dec 2006 12:20:34 +0000 Subject: [PATCH] deallocates the piece picker when seeding, to free up unused memory --- include/libtorrent/torrent.hpp | 30 ++++++++--- src/peer_connection.cpp | 51 +++++++++++-------- src/policy.cpp | 1 + src/session_impl.cpp | 4 +- src/torrent.cpp | 33 +++++++++--- src/torrent_handle.cpp | 92 ++++++++++++++++++---------------- 6 files changed, 131 insertions(+), 80 deletions(-) diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 4f8a3bdf2..3609a5d69 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -297,17 +297,35 @@ namespace libtorrent // piece a peer has gained. void peer_has(int index) { - assert(m_picker.get()); - assert(index >= 0 && index < (signed)m_have_pieces.size()); - m_picker->inc_refcount(index); + if (m_picker.get()) + { + assert(!is_seed()); + assert(index >= 0 && index < (signed)m_have_pieces.size()); + m_picker->inc_refcount(index); + } +#ifndef NDEBUG + else + { + assert(is_seed()); + } +#endif } // when peer disconnects, this is called for every piece it had void peer_lost(int index) { - assert(m_picker.get()); - assert(index >= 0 && index < (signed)m_have_pieces.size()); - m_picker->dec_refcount(index); + if (m_picker.get()) + { + assert(!is_seed()); + assert(index >= 0 && index < (signed)m_have_pieces.size()); + m_picker->dec_refcount(index); + } +#ifndef NDEBUG + else + { + assert(is_seed()); + } +#endif } int block_size() const { assert(m_block_size > 0); return m_block_size; } diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index b3468d314..105e2acd9 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -595,19 +595,22 @@ namespace libtorrent m_peer_choked = true; t->get_policy().choked(*this); - // remove all pieces from this peers download queue and - // remove the 'downloading' flag from piece_picker. - for (std::deque::iterator i = m_download_queue.begin(); - i != m_download_queue.end(); ++i) + if (!t->is_seed()) { - t->picker().abort_download(*i); - } - for (std::deque::const_iterator i = m_request_queue.begin() - , end(m_request_queue.end()); i != end; ++i) - { - // since this piece was skipped, clear it and allow it to - // be requested from other peers - t->picker().abort_download(*i); + // remove all pieces from this peers download queue and + // remove the 'downloading' flag from piece_picker. + for (std::deque::iterator i = m_download_queue.begin(); + i != m_download_queue.end(); ++i) + { + t->picker().abort_download(*i); + } + for (std::deque::const_iterator i = m_request_queue.begin() + , end(m_request_queue.end()); i != end; ++i) + { + // since this piece was skipped, clear it and allow it to + // be requested from other peers + t->picker().abort_download(*i); + } } m_download_queue.clear(); m_request_queue.clear(); @@ -717,13 +720,16 @@ namespace libtorrent m_have_piece[index] = true; // only update the piece_picker if - // we have the metadata + // we have the metadata and if + // we're not a seed (in which case + // we won't have a piece picker) if (t->valid_metadata()) { ++m_num_pieces; t->peer_has(index); if (!t->have_piece(index) + && !t->is_seed() && !is_interesting() && !t->picker().is_filtered(index)) t->get_policy().peer_is_interesting(*this); @@ -797,14 +803,17 @@ namespace libtorrent // let the torrent know which pieces the // peer has, in a shuffled order bool interesting = false; - for (std::vector::reverse_iterator i = piece_list.rbegin(); - i != piece_list.rend(); ++i) + if (!t->is_seed()) { - int index = *i; - t->peer_has(index); - if (!t->have_piece(index) - && !t->picker().is_filtered(index)) - interesting = true; + for (std::vector::reverse_iterator i = piece_list.rbegin(); + i != piece_list.rend(); ++i) + { + int index = *i; + t->peer_has(index); + if (!t->have_piece(index) + && !t->picker().is_filtered(index)) + interesting = true; + } } if (piece_list.size() == m_have_piece.size()) @@ -1420,7 +1429,7 @@ namespace libtorrent if (t) { - if (t->valid_metadata()) + if (t->valid_metadata() && !t->is_seed()) { piece_picker& picker = t->picker(); diff --git a/src/policy.cpp b/src/policy.cpp index 9736b2719..60c17402e 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -74,6 +74,7 @@ namespace , peer_connection& c , std::vector ignore = std::vector()) { + assert(!t.is_seed()); int num_requests = c.desired_queue_size() - (int)c.download_queue().size() - (int)c.request_queue().size(); diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 8c4cfa478..79ad7c60b 100755 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -465,8 +465,8 @@ namespace libtorrent { namespace detail { seed_random_generator() { - std::srand((unsigned int)boost::posix_time::microsec_clock:: - universal_time().time_of_day().total_microseconds()); + std::srand((unsigned int)(boost::posix_time::microsec_clock:: + universal_time().time_of_day().total_microseconds())); } }; diff --git a/src/torrent.cpp b/src/torrent.cpp index 6e1324075..2134f6894 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -658,10 +658,11 @@ namespace libtorrent if (!valid_metadata()) return 0; - assert(m_picker.get()); - if (m_torrent_file.num_pieces() == 0) return 0; + + if (is_seed()) return m_torrent_file.total_size(); + const int last_piece = m_torrent_file.num_pieces() - 1; size_type total_done @@ -688,12 +689,14 @@ namespace libtorrent if (!valid_metadata()) return tuple(0,0); - assert(m_picker.get()); - if (m_torrent_file.num_pieces() == 0) return tuple(0,0); const int last_piece = m_torrent_file.num_pieces() - 1; + if (is_seed()) + return make_tuple(m_torrent_file.total_size() + , m_torrent_file.total_size()); + size_type wanted_done = (m_num_pieces - m_picker->num_have_filtered()) * m_torrent_file.piece_length(); @@ -880,7 +883,6 @@ namespace libtorrent { INVARIANT_CHECK; - assert(m_picker.get()); assert(index >= 0); assert(index < m_torrent_file.num_pieces()); @@ -911,6 +913,7 @@ namespace libtorrent try { (*i)->on_piece_pass(index); } catch (std::exception&) {} } #endif + if (is_seed()) m_picker.reset(); } std::string torrent::tracker_login() const @@ -1560,7 +1563,14 @@ namespace libtorrent INVARIANT_CHECK; - m_picker->files_checked(m_have_pieces, unfinished_pieces); + if (!is_seed()) + { + m_picker->files_checked(m_have_pieces, unfinished_pieces); + } + else + { + m_picker.reset(); + } if (!m_connections_initialized) { m_connections_initialized = true; @@ -1662,12 +1672,15 @@ namespace libtorrent assert(m_priority >= 0.f && m_priority < 1.f); assert(!valid_metadata() || m_block_size > 0); assert(!valid_metadata() || (m_torrent_file.piece_length() % m_block_size) == 0); +// if (is_seed()) assert(m_picker.get() == 0); } #endif void torrent::set_sequenced_download_threshold(int threshold) { - if (valid_metadata()) + // TODO: if there is not valid metadata, save this setting and + // set it once the piece picker is created. + if (valid_metadata() && !is_seed()) picker().set_sequenced_download_threshold(threshold); } @@ -2040,6 +2053,7 @@ namespace libtorrent assert(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0) == m_num_pieces); + return true; } @@ -2199,7 +2213,10 @@ namespace libtorrent st.state = torrent_status::downloading; st.num_seeds = num_seeds(); - st.distributed_copies = m_picker->distributed_copies(); + if (m_picker.get()) + st.distributed_copies = m_picker->distributed_copies(); + else + st.distributed_copies = -1; return st; } diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 9df79f1a8..303c5d86d 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -455,57 +455,61 @@ namespace libtorrent entry::list_type& slots = ret["slots"].list(); std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots)); - const piece_picker& p = t->picker(); - - const std::vector& q - = p.get_download_queue(); - - // blocks per piece - int num_blocks_per_piece = - static_cast(t->torrent_file().piece_length()) / t->block_size(); - ret["blocks per piece"] = num_blocks_per_piece; - - // unfinished pieces - ret["unfinished"] = entry::list_type(); - entry::list_type& up = ret["unfinished"].list(); - - // info for each unfinished piece - for (std::vector::const_iterator i - = q.begin(); i != q.end(); ++i) + // if this torrent is a seed, we won't have a piece picker + // and there will be no half-finished pieces. + if (!t->is_seed()) { - if (i->finished_blocks.count() == 0) continue; + const piece_picker& p = t->picker(); - entry piece_struct(entry::dictionary_t); + const std::vector& q + = p.get_download_queue(); - // the unfinished piece's index - piece_struct["piece"] = i->index; + // blocks per piece + int num_blocks_per_piece = + static_cast(t->torrent_file().piece_length()) / t->block_size(); + ret["blocks per piece"] = num_blocks_per_piece; - std::string bitmask; - const int num_bitmask_bytes - = std::max(num_blocks_per_piece / 8, 1); + // unfinished pieces + ret["unfinished"] = entry::list_type(); + entry::list_type& up = ret["unfinished"].list(); - for (int j = 0; j < num_bitmask_bytes; ++j) + // info for each unfinished piece + for (std::vector::const_iterator i + = q.begin(); i != q.end(); ++i) { - unsigned char v = 0; - for (int k = 0; k < 8; ++k) - v |= i->finished_blocks[j*8+k]?(1 << k):0; - bitmask.insert(bitmask.end(), v); + if (i->finished_blocks.count() == 0) continue; + + entry piece_struct(entry::dictionary_t); + + // the unfinished piece's index + piece_struct["piece"] = i->index; + + std::string bitmask; + const int num_bitmask_bytes + = std::max(num_blocks_per_piece / 8, 1); + + for (int j = 0; j < num_bitmask_bytes; ++j) + { + unsigned char v = 0; + for (int k = 0; k < 8; ++k) + v |= i->finished_blocks[j*8+k]?(1 << k):0; + bitmask.insert(bitmask.end(), v); + } + piece_struct["bitmask"] = bitmask; + + assert(t->filesystem().slot_for_piece(i->index) >= 0); + unsigned long adler + = t->filesystem().piece_crc( + t->filesystem().slot_for_piece(i->index) + , t->block_size() + , i->finished_blocks); + + piece_struct["adler32"] = adler; + + // push the struct onto the unfinished-piece list + up.push_back(piece_struct); } - piece_struct["bitmask"] = bitmask; - - assert(t->filesystem().slot_for_piece(i->index) >= 0); - unsigned long adler - = t->filesystem().piece_crc( - t->filesystem().slot_for_piece(i->index) - , t->block_size() - , i->finished_blocks); - - piece_struct["adler32"] = adler; - - // push the struct onto the unfinished-piece list - up.push_back(piece_struct); } - // write local peers ret["peers"] = entry::list_type(); @@ -704,6 +708,8 @@ namespace libtorrent queue.clear(); if (!t) return; if (!t->valid_metadata()) return; + // if we're a seed, the piece picker has been removed + if (t->is_seed()) return; const piece_picker& p = t->picker();