deallocates the piece picker when seeding, to free up unused memory

This commit is contained in:
Arvid Norberg 2006-12-04 12:20:34 +00:00
parent 7fa3d899a1
commit 90feac8126
6 changed files with 131 additions and 80 deletions

View File

@ -297,17 +297,35 @@ namespace libtorrent
// piece a peer has gained. // piece a peer has gained.
void peer_has(int index) void peer_has(int index)
{ {
assert(m_picker.get()); if (m_picker.get())
assert(index >= 0 && index < (signed)m_have_pieces.size()); {
m_picker->inc_refcount(index); 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 // when peer disconnects, this is called for every piece it had
void peer_lost(int index) void peer_lost(int index)
{ {
assert(m_picker.get()); if (m_picker.get())
assert(index >= 0 && index < (signed)m_have_pieces.size()); {
m_picker->dec_refcount(index); 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; } int block_size() const { assert(m_block_size > 0); return m_block_size; }

View File

@ -595,19 +595,22 @@ namespace libtorrent
m_peer_choked = true; m_peer_choked = true;
t->get_policy().choked(*this); t->get_policy().choked(*this);
// remove all pieces from this peers download queue and if (!t->is_seed())
// remove the 'downloading' flag from piece_picker.
for (std::deque<piece_block>::iterator i = m_download_queue.begin();
i != m_download_queue.end(); ++i)
{ {
t->picker().abort_download(*i); // remove all pieces from this peers download queue and
} // remove the 'downloading' flag from piece_picker.
for (std::deque<piece_block>::const_iterator i = m_request_queue.begin() for (std::deque<piece_block>::iterator i = m_download_queue.begin();
, end(m_request_queue.end()); i != end; ++i) i != m_download_queue.end(); ++i)
{ {
// since this piece was skipped, clear it and allow it to t->picker().abort_download(*i);
// be requested from other peers }
t->picker().abort_download(*i); for (std::deque<piece_block>::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_download_queue.clear();
m_request_queue.clear(); m_request_queue.clear();
@ -717,13 +720,16 @@ namespace libtorrent
m_have_piece[index] = true; m_have_piece[index] = true;
// only update the piece_picker if // 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()) if (t->valid_metadata())
{ {
++m_num_pieces; ++m_num_pieces;
t->peer_has(index); t->peer_has(index);
if (!t->have_piece(index) if (!t->have_piece(index)
&& !t->is_seed()
&& !is_interesting() && !is_interesting()
&& !t->picker().is_filtered(index)) && !t->picker().is_filtered(index))
t->get_policy().peer_is_interesting(*this); t->get_policy().peer_is_interesting(*this);
@ -797,14 +803,17 @@ namespace libtorrent
// let the torrent know which pieces the // let the torrent know which pieces the
// peer has, in a shuffled order // peer has, in a shuffled order
bool interesting = false; bool interesting = false;
for (std::vector<int>::reverse_iterator i = piece_list.rbegin(); if (!t->is_seed())
i != piece_list.rend(); ++i)
{ {
int index = *i; for (std::vector<int>::reverse_iterator i = piece_list.rbegin();
t->peer_has(index); i != piece_list.rend(); ++i)
if (!t->have_piece(index) {
&& !t->picker().is_filtered(index)) int index = *i;
interesting = true; t->peer_has(index);
if (!t->have_piece(index)
&& !t->picker().is_filtered(index))
interesting = true;
}
} }
if (piece_list.size() == m_have_piece.size()) if (piece_list.size() == m_have_piece.size())
@ -1420,7 +1429,7 @@ namespace libtorrent
if (t) if (t)
{ {
if (t->valid_metadata()) if (t->valid_metadata() && !t->is_seed())
{ {
piece_picker& picker = t->picker(); piece_picker& picker = t->picker();

View File

@ -74,6 +74,7 @@ namespace
, peer_connection& c , peer_connection& c
, std::vector<peer_connection*> ignore = std::vector<peer_connection*>()) , std::vector<peer_connection*> ignore = std::vector<peer_connection*>())
{ {
assert(!t.is_seed());
int num_requests = c.desired_queue_size() int num_requests = c.desired_queue_size()
- (int)c.download_queue().size() - (int)c.download_queue().size()
- (int)c.request_queue().size(); - (int)c.request_queue().size();

View File

@ -465,8 +465,8 @@ namespace libtorrent { namespace detail
{ {
seed_random_generator() seed_random_generator()
{ {
std::srand((unsigned int)boost::posix_time::microsec_clock:: std::srand((unsigned int)(boost::posix_time::microsec_clock::
universal_time().time_of_day().total_microseconds()); universal_time().time_of_day().total_microseconds()));
} }
}; };

View File

@ -658,10 +658,11 @@ namespace libtorrent
if (!valid_metadata()) return 0; if (!valid_metadata()) return 0;
assert(m_picker.get());
if (m_torrent_file.num_pieces() == 0) if (m_torrent_file.num_pieces() == 0)
return 0; return 0;
if (is_seed()) return m_torrent_file.total_size();
const int last_piece = m_torrent_file.num_pieces() - 1; const int last_piece = m_torrent_file.num_pieces() - 1;
size_type total_done size_type total_done
@ -688,12 +689,14 @@ namespace libtorrent
if (!valid_metadata()) return tuple<size_type, size_type>(0,0); if (!valid_metadata()) return tuple<size_type, size_type>(0,0);
assert(m_picker.get());
if (m_torrent_file.num_pieces() == 0) if (m_torrent_file.num_pieces() == 0)
return tuple<size_type, size_type>(0,0); return tuple<size_type, size_type>(0,0);
const int last_piece = m_torrent_file.num_pieces() - 1; 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()) size_type wanted_done = (m_num_pieces - m_picker->num_have_filtered())
* m_torrent_file.piece_length(); * m_torrent_file.piece_length();
@ -880,7 +883,6 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
assert(m_picker.get());
assert(index >= 0); assert(index >= 0);
assert(index < m_torrent_file.num_pieces()); assert(index < m_torrent_file.num_pieces());
@ -911,6 +913,7 @@ namespace libtorrent
try { (*i)->on_piece_pass(index); } catch (std::exception&) {} try { (*i)->on_piece_pass(index); } catch (std::exception&) {}
} }
#endif #endif
if (is_seed()) m_picker.reset();
} }
std::string torrent::tracker_login() const std::string torrent::tracker_login() const
@ -1560,7 +1563,14 @@ namespace libtorrent
INVARIANT_CHECK; 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) if (!m_connections_initialized)
{ {
m_connections_initialized = true; m_connections_initialized = true;
@ -1662,12 +1672,15 @@ namespace libtorrent
assert(m_priority >= 0.f && m_priority < 1.f); assert(m_priority >= 0.f && m_priority < 1.f);
assert(!valid_metadata() || m_block_size > 0); assert(!valid_metadata() || m_block_size > 0);
assert(!valid_metadata() || (m_torrent_file.piece_length() % 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 #endif
void torrent::set_sequenced_download_threshold(int threshold) 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); picker().set_sequenced_download_threshold(threshold);
} }
@ -2040,6 +2053,7 @@ namespace libtorrent
assert(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0) assert(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0)
== m_num_pieces); == m_num_pieces);
return true; return true;
} }
@ -2199,7 +2213,10 @@ namespace libtorrent
st.state = torrent_status::downloading; st.state = torrent_status::downloading;
st.num_seeds = num_seeds(); 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; return st;
} }

View File

@ -455,57 +455,61 @@ namespace libtorrent
entry::list_type& slots = ret["slots"].list(); entry::list_type& slots = ret["slots"].list();
std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots)); std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots));
const piece_picker& p = t->picker(); // if this torrent is a seed, we won't have a piece picker
// and there will be no half-finished pieces.
const std::vector<piece_picker::downloading_piece>& q if (!t->is_seed())
= p.get_download_queue();
// blocks per piece
int num_blocks_per_piece =
static_cast<int>(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<piece_picker::downloading_piece>::const_iterator i
= q.begin(); i != q.end(); ++i)
{ {
if (i->finished_blocks.count() == 0) continue; const piece_picker& p = t->picker();
entry piece_struct(entry::dictionary_t); const std::vector<piece_picker::downloading_piece>& q
= p.get_download_queue();
// the unfinished piece's index // blocks per piece
piece_struct["piece"] = i->index; int num_blocks_per_piece =
static_cast<int>(t->torrent_file().piece_length()) / t->block_size();
ret["blocks per piece"] = num_blocks_per_piece;
std::string bitmask; // unfinished pieces
const int num_bitmask_bytes ret["unfinished"] = entry::list_type();
= std::max(num_blocks_per_piece / 8, 1); entry::list_type& up = ret["unfinished"].list();
for (int j = 0; j < num_bitmask_bytes; ++j) // info for each unfinished piece
for (std::vector<piece_picker::downloading_piece>::const_iterator i
= q.begin(); i != q.end(); ++i)
{ {
unsigned char v = 0; if (i->finished_blocks.count() == 0) continue;
for (int k = 0; k < 8; ++k)
v |= i->finished_blocks[j*8+k]?(1 << k):0; entry piece_struct(entry::dictionary_t);
bitmask.insert(bitmask.end(), v);
// 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 // write local peers
ret["peers"] = entry::list_type(); ret["peers"] = entry::list_type();
@ -704,6 +708,8 @@ namespace libtorrent
queue.clear(); queue.clear();
if (!t) return; if (!t) return;
if (!t->valid_metadata()) 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(); const piece_picker& p = t->picker();