deallocates the piece picker when seeding, to free up unused memory
This commit is contained in:
parent
7fa3d899a1
commit
90feac8126
|
@ -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; }
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue