2003-10-23 01:00:57 +02:00
|
|
|
/*
|
|
|
|
|
2016-01-18 00:57:46 +01:00
|
|
|
Copyright (c) 2003-2016, Arvid Norberg
|
2003-10-23 01:00:57 +02:00
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions
|
|
|
|
are met:
|
|
|
|
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer in
|
|
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
* Neither the name of the author nor the names of its
|
|
|
|
contributors may be used to endorse or promote products derived
|
|
|
|
from this software without specific prior written permission.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <cmath>
|
2003-12-01 06:01:40 +01:00
|
|
|
#include <algorithm>
|
2003-12-17 20:03:23 +01:00
|
|
|
#include <numeric>
|
2015-03-08 05:49:10 +01:00
|
|
|
#include <limits>
|
2016-05-25 06:31:52 +02:00
|
|
|
#include <functional>
|
2016-06-20 17:32:06 +02:00
|
|
|
#include <tuple>
|
2015-04-18 04:33:39 +02:00
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
#include "libtorrent/piece_picker.hpp"
|
2008-05-28 04:35:02 +02:00
|
|
|
#include "libtorrent/bitfield.hpp"
|
2011-02-26 08:55:51 +01:00
|
|
|
#include "libtorrent/random.hpp"
|
2017-01-27 18:43:34 +01:00
|
|
|
#include "libtorrent/aux_/alloca.hpp"
|
2017-01-22 04:40:19 +01:00
|
|
|
#include "libtorrent/aux_/range.hpp"
|
2014-07-06 21:18:00 +02:00
|
|
|
#include "libtorrent/performance_counters.hpp" // for counters
|
2015-11-29 06:58:46 +01:00
|
|
|
#include "libtorrent/alert_types.hpp" // for picker_log_alert
|
2017-10-29 00:44:40 +02:00
|
|
|
#include "libtorrent/download_priority.hpp"
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2014-01-19 20:45:50 +01:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2003-10-23 01:00:57 +02:00
|
|
|
#include "libtorrent/peer_connection.hpp"
|
2006-01-11 02:32:26 +01:00
|
|
|
#include "libtorrent/torrent.hpp"
|
2014-07-06 21:18:00 +02:00
|
|
|
#include "libtorrent/torrent_peer.hpp"
|
2003-10-23 01:00:57 +02:00
|
|
|
#endif
|
|
|
|
|
2011-11-02 06:28:25 +01:00
|
|
|
#include "libtorrent/invariant_check.hpp"
|
|
|
|
|
2015-11-29 06:58:46 +01:00
|
|
|
// this is really only useful for debugging unit tests
|
|
|
|
//#define TORRENT_PICKER_LOG
|
|
|
|
|
2016-05-25 06:31:52 +02:00
|
|
|
using namespace std::placeholders;
|
|
|
|
|
2017-04-12 19:00:57 +02:00
|
|
|
namespace libtorrent {
|
|
|
|
|
2016-09-24 17:46:56 +02:00
|
|
|
// TODO: find a better place for this
|
2016-12-22 16:42:33 +01:00
|
|
|
const piece_block piece_block::invalid(
|
|
|
|
std::numeric_limits<piece_index_t>::max()
|
|
|
|
, std::numeric_limits<int>::max());
|
2010-05-13 08:29:33 +02:00
|
|
|
|
2016-12-26 17:25:50 +01:00
|
|
|
constexpr prio_index_t piece_picker::piece_pos::we_have_index;
|
|
|
|
|
2018-01-28 14:39:43 +01:00
|
|
|
constexpr picker_options_t piece_picker::rarest_first;
|
|
|
|
constexpr picker_options_t piece_picker::reverse;
|
|
|
|
constexpr picker_options_t piece_picker::on_parole;
|
|
|
|
constexpr picker_options_t piece_picker::prioritize_partials;
|
|
|
|
constexpr picker_options_t piece_picker::sequential;
|
|
|
|
constexpr picker_options_t piece_picker::time_critical_mode;
|
|
|
|
constexpr picker_options_t piece_picker::align_expanded_pieces;
|
|
|
|
|
2017-10-25 22:31:49 +02:00
|
|
|
piece_picker::piece_picker(int const blocks_per_piece
|
|
|
|
, int const blocks_in_last_piece, int const total_num_pieces)
|
2016-12-26 17:25:50 +01:00
|
|
|
: m_priority_boundaries(1, m_pieces.end_index())
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-01-31 18:52:29 +01:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2014-07-06 21:18:00 +02:00
|
|
|
std::cerr << "[" << this << "] " << "new piece_picker" << std::endl;
|
2008-01-31 18:52:29 +01:00
|
|
|
#endif
|
2014-01-21 20:26:09 +01:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2008-06-07 04:58:28 +02:00
|
|
|
check_invariant();
|
2007-03-17 18:28:59 +01:00
|
|
|
#endif
|
2017-10-25 22:31:49 +02:00
|
|
|
|
|
|
|
resize(blocks_per_piece, blocks_in_last_piece, total_num_pieces);
|
2008-06-07 04:58:28 +02:00
|
|
|
}
|
|
|
|
|
2017-10-25 22:31:49 +02:00
|
|
|
void piece_picker::resize(int const blocks_per_piece
|
|
|
|
, int const blocks_in_last_piece, int const total_num_pieces)
|
2008-06-07 04:58:28 +02:00
|
|
|
{
|
|
|
|
TORRENT_ASSERT(blocks_per_piece > 0);
|
2010-02-23 17:26:24 +01:00
|
|
|
TORRENT_ASSERT(total_num_pieces > 0);
|
2008-06-07 04:58:28 +02:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2017-10-25 22:31:49 +02:00
|
|
|
std::cerr << "[" << this << "] " << "piece_picker::resize()" << std::endl;
|
2008-09-06 23:04:57 +02:00
|
|
|
#endif
|
2008-06-07 04:58:28 +02:00
|
|
|
// allocate the piece_map to cover all pieces
|
|
|
|
// and make them invalid (as if we don't have a single piece)
|
2010-02-23 17:26:24 +01:00
|
|
|
m_piece_map.resize(total_num_pieces, piece_pos(0, 0));
|
2016-12-22 16:42:33 +01:00
|
|
|
m_reverse_cursor = m_piece_map.end_index();
|
|
|
|
m_cursor = piece_index_t(0);
|
2004-01-25 23:41:55 +01:00
|
|
|
|
2018-01-11 01:35:15 +01:00
|
|
|
for (auto& c : m_downloads) c.clear();
|
2009-05-25 22:31:20 +02:00
|
|
|
m_block_info.clear();
|
2015-08-20 21:37:12 +02:00
|
|
|
m_free_block_infos.clear();
|
2009-05-25 22:31:20 +02:00
|
|
|
|
2008-08-26 00:32:50 +02:00
|
|
|
m_num_filtered += m_num_have_filtered;
|
|
|
|
m_num_have_filtered = 0;
|
|
|
|
m_num_have = 0;
|
2014-07-06 21:18:00 +02:00
|
|
|
m_num_passed = 0;
|
2008-08-26 00:32:50 +02:00
|
|
|
m_dirty = true;
|
2018-01-11 01:35:15 +01:00
|
|
|
for (auto& m : m_piece_map)
|
2008-08-26 00:32:50 +02:00
|
|
|
{
|
2018-01-11 01:35:15 +01:00
|
|
|
m.peer_count = 0;
|
|
|
|
m.download_state = piece_pos::piece_open;
|
|
|
|
m.index = prio_index_t(0);
|
2013-01-06 05:02:29 +01:00
|
|
|
#ifdef TORRENT_DEBUG_REFCOUNTS
|
2018-01-11 01:35:15 +01:00
|
|
|
m.have_peers.clear();
|
2013-01-06 05:02:29 +01:00
|
|
|
#endif
|
2008-08-26 00:32:50 +02:00
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto i = m_piece_map.begin() + static_cast<int>(m_cursor)
|
2008-09-06 23:04:57 +02:00
|
|
|
, end(m_piece_map.end()); i != end && (i->have() || i->filtered());
|
|
|
|
++i, ++m_cursor);
|
2016-12-22 16:42:33 +01:00
|
|
|
|
|
|
|
for (auto i = m_piece_map.rend() - static_cast<int>(m_reverse_cursor);
|
|
|
|
m_reverse_cursor > piece_index_t(0) && (i->have() || i->filtered());
|
2008-09-15 18:21:03 +02:00
|
|
|
++i, --m_reverse_cursor);
|
2008-09-06 23:04:57 +02:00
|
|
|
|
2016-11-25 17:17:25 +01:00
|
|
|
m_blocks_per_piece = std::uint16_t(blocks_per_piece);
|
|
|
|
m_blocks_in_last_piece = std::uint16_t(blocks_in_last_piece);
|
|
|
|
if (m_blocks_in_last_piece == 0) m_blocks_in_last_piece = std::uint16_t(blocks_per_piece);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_blocks_in_last_piece <= m_blocks_per_piece);
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::piece_info(piece_index_t const index, piece_picker::downloading_piece& st) const
|
2007-08-03 08:13:26 +02:00
|
|
|
{
|
2008-10-10 07:25:55 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2008-10-10 07:25:55 +02:00
|
|
|
#endif
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
int state = m_piece_map[index].download_queue();
|
|
|
|
if (state != piece_pos::piece_open)
|
2007-08-03 08:13:26 +02:00
|
|
|
{
|
2018-01-11 01:35:15 +01:00
|
|
|
auto piece = find_dl_piece(state, index);
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(piece != m_downloads[state].end());
|
2007-08-03 08:13:26 +02:00
|
|
|
st = *piece;
|
|
|
|
return;
|
|
|
|
}
|
2015-02-14 22:32:41 +01:00
|
|
|
st.info_idx = 0;
|
2007-08-03 08:13:26 +02:00
|
|
|
st.index = index;
|
|
|
|
st.writing = 0;
|
|
|
|
st.requested = 0;
|
|
|
|
if (m_piece_map[index].have())
|
|
|
|
{
|
2016-11-25 17:17:25 +01:00
|
|
|
st.finished = std::uint16_t(blocks_in_piece(index));
|
2007-08-03 08:13:26 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
st.finished = 0;
|
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_picker::piece_stats_t piece_picker::piece_stats(piece_index_t const index) const
|
2015-02-08 23:15:59 +01:00
|
|
|
{
|
|
|
|
piece_pos const& pp = m_piece_map[index];
|
|
|
|
piece_stats_t ret = {
|
2016-04-17 22:56:07 +02:00
|
|
|
int(pp.peer_count + m_seeds),
|
2015-02-08 23:15:59 +01:00
|
|
|
pp.priority(this),
|
|
|
|
pp.have(),
|
|
|
|
pp.downloading()
|
|
|
|
};
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
std::vector<piece_picker::downloading_piece>::iterator
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_picker::add_download_piece(piece_index_t const piece)
|
2007-05-09 02:49:13 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(piece >= piece_index_t(0));
|
|
|
|
TORRENT_ASSERT(piece < m_piece_map.end_index());
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
|
|
|
|
2015-02-14 22:32:41 +01:00
|
|
|
int block_index;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-02-14 22:32:41 +01:00
|
|
|
if (m_free_block_infos.empty())
|
2007-05-09 02:49:13 +02:00
|
|
|
{
|
2015-02-14 22:32:41 +01:00
|
|
|
// we need to allocate more space in m_block_info
|
2016-04-25 23:22:09 +02:00
|
|
|
block_index = int(m_block_info.size() / m_blocks_per_piece);
|
2015-02-14 22:32:41 +01:00
|
|
|
TORRENT_ASSERT((m_block_info.size() % m_blocks_per_piece) == 0);
|
|
|
|
m_block_info.resize(m_block_info.size() + m_blocks_per_piece);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// there is already free space in m_block_info, grab one range
|
2016-11-27 14:46:53 +01:00
|
|
|
block_index = int(m_free_block_infos.back());
|
2015-02-14 22:32:41 +01:00
|
|
|
m_free_block_infos.pop_back();
|
2007-05-09 02:49:13 +02:00
|
|
|
}
|
2015-02-14 22:32:41 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// always insert into bucket 0 (piece_downloading)
|
2013-10-02 23:51:30 +02:00
|
|
|
downloading_piece ret;
|
2011-08-15 06:16:43 +02:00
|
|
|
ret.index = piece;
|
2018-01-11 01:35:15 +01:00
|
|
|
int const download_state = piece_pos::piece_downloading;
|
|
|
|
auto downloading_iter = std::lower_bound(m_downloads[download_state].begin()
|
2015-01-26 03:04:58 +01:00
|
|
|
, m_downloads[download_state].end(), ret);
|
2015-08-16 18:17:23 +02:00
|
|
|
TORRENT_ASSERT(downloading_iter == m_downloads[download_state].end()
|
|
|
|
|| downloading_iter->index != piece);
|
2015-02-14 22:32:41 +01:00
|
|
|
TORRENT_ASSERT(block_index >= 0);
|
2016-06-18 20:01:38 +02:00
|
|
|
TORRENT_ASSERT(block_index < (std::numeric_limits<std::uint16_t>::max)());
|
2016-11-25 17:17:25 +01:00
|
|
|
ret.info_idx = std::uint16_t(block_index);
|
2015-02-14 22:32:41 +01:00
|
|
|
TORRENT_ASSERT(int(ret.info_idx) * m_blocks_per_piece
|
2015-04-29 07:46:35 +02:00
|
|
|
+ m_blocks_per_piece <= int(m_block_info.size()));
|
2015-02-14 22:32:41 +01:00
|
|
|
|
2017-03-05 05:45:07 +01:00
|
|
|
for (auto& info : mutable_blocks_for_piece(ret))
|
2007-05-09 02:49:13 +02:00
|
|
|
{
|
2017-03-05 05:45:07 +01:00
|
|
|
info.num_peers = 0;
|
|
|
|
info.state = block_info::state_none;
|
|
|
|
info.peer = nullptr;
|
2014-01-19 20:45:50 +01:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2017-03-05 05:45:07 +01:00
|
|
|
info.piece_index = piece;
|
|
|
|
info.peers.clear();
|
2012-04-12 07:00:20 +02:00
|
|
|
#endif
|
2007-05-09 02:49:13 +02:00
|
|
|
}
|
2015-08-16 18:17:23 +02:00
|
|
|
downloading_iter = m_downloads[download_state].insert(downloading_iter, ret);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
2015-08-16 18:17:23 +02:00
|
|
|
return downloading_iter;
|
2007-05-09 02:49:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void piece_picker::erase_download_piece(std::vector<downloading_piece>::iterator i)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
|
|
|
|
2018-01-11 01:35:15 +01:00
|
|
|
int const download_state = m_piece_map[i->index].download_queue();
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(download_state != piece_pos::piece_open);
|
|
|
|
TORRENT_ASSERT(find_dl_piece(download_state, i->index) == i);
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2016-05-13 03:24:45 +02:00
|
|
|
int prev_size = int(m_downloads[download_state].size());
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
|
2015-02-14 22:32:41 +01:00
|
|
|
// since we're removing a downloading_piece, we also need to free its
|
2015-08-09 06:56:37 +02:00
|
|
|
// blocks that are allocated from the m_block_info array.
|
2015-02-14 22:32:41 +01:00
|
|
|
m_free_block_infos.push_back(i->info_idx);
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2015-02-15 23:01:15 +01:00
|
|
|
TORRENT_ASSERT(find_dl_piece(download_state, i->index) == i);
|
2015-01-26 03:04:58 +01:00
|
|
|
m_piece_map[i->index].download_state = piece_pos::piece_open;
|
|
|
|
m_downloads[download_state].erase(i);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
TORRENT_ASSERT(prev_size == int(m_downloads[download_state].size()) + 1);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<piece_picker::downloading_piece> piece_picker::get_download_queue() const
|
|
|
|
{
|
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
std::vector<downloading_piece> ret;
|
2018-01-11 01:35:15 +01:00
|
|
|
for (auto const& c : m_downloads)
|
|
|
|
ret.insert(ret.end(), c.begin(), c.end());
|
2014-07-06 21:18:00 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int piece_picker::get_download_queue_size() const
|
|
|
|
{
|
|
|
|
int ret = 0;
|
2018-01-11 01:35:15 +01:00
|
|
|
for (auto const& c : m_downloads)
|
|
|
|
ret += int(c.size());
|
2014-07-06 21:18:00 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
void piece_picker::get_download_queue_sizes(int* partial
|
|
|
|
, int* full, int* finished, int* zero_prio) const
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-04-25 23:22:09 +02:00
|
|
|
*partial = int(m_downloads[piece_pos::piece_downloading].size());
|
|
|
|
*full = int(m_downloads[piece_pos::piece_full].size());
|
|
|
|
*finished = int(m_downloads[piece_pos::piece_finished].size());
|
|
|
|
*zero_prio = int(m_downloads[piece_pos::piece_zero_prio].size());
|
2007-05-09 02:49:13 +02:00
|
|
|
}
|
2007-09-10 01:46:28 +02:00
|
|
|
|
2017-03-05 05:45:07 +01:00
|
|
|
aux::typed_span<piece_picker::block_info> piece_picker::mutable_blocks_for_piece(
|
2015-02-14 22:32:41 +01:00
|
|
|
downloading_piece const& dp)
|
|
|
|
{
|
|
|
|
int idx = int(dp.info_idx) * m_blocks_per_piece;
|
2016-11-27 14:46:53 +01:00
|
|
|
TORRENT_ASSERT(idx + m_blocks_per_piece <= int(m_block_info.size()));
|
2017-03-05 05:45:07 +01:00
|
|
|
return { &m_block_info[idx], static_cast<std::size_t>(blocks_in_piece(dp.index)) };
|
2015-02-14 22:32:41 +01:00
|
|
|
}
|
|
|
|
|
2017-03-05 05:45:07 +01:00
|
|
|
aux::typed_span<piece_picker::block_info const> piece_picker::blocks_for_piece(
|
2015-02-14 22:32:41 +01:00
|
|
|
downloading_piece const& dp) const
|
|
|
|
{
|
2017-03-05 05:45:07 +01:00
|
|
|
return const_cast<piece_picker*>(this)->mutable_blocks_for_piece(dp);
|
2015-02-14 22:32:41 +01:00
|
|
|
}
|
|
|
|
|
2014-01-21 20:26:09 +01:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void piece_picker::check_piece_state() const
|
|
|
|
{
|
2015-01-26 03:04:58 +01:00
|
|
|
for (int k = 0; k < piece_pos::num_download_categories; ++k)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
if (!m_downloads[k].empty())
|
|
|
|
{
|
|
|
|
for (std::vector<downloading_piece>::const_iterator i = m_downloads[k].begin();
|
|
|
|
i != m_downloads[k].end() - 1; ++i)
|
|
|
|
{
|
|
|
|
downloading_piece const& dp = *i;
|
|
|
|
downloading_piece const& next = *(i + 1);
|
|
|
|
TORRENT_ASSERT(dp.index < next.index);
|
2015-02-14 22:32:41 +01:00
|
|
|
TORRENT_ASSERT(int(dp.info_idx) * m_blocks_per_piece
|
2015-04-29 07:46:35 +02:00
|
|
|
+ m_blocks_per_piece <= int(m_block_info.size()));
|
2017-03-05 05:45:07 +01:00
|
|
|
for (auto const& bl : blocks_for_piece(dp))
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2017-03-05 05:45:07 +01:00
|
|
|
if (bl.peer)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2017-03-05 05:45:07 +01:00
|
|
|
torrent_peer* p = bl.peer;
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(p->in_use);
|
2016-06-20 17:32:06 +02:00
|
|
|
TORRENT_ASSERT(p->connection == nullptr
|
2015-02-14 22:32:41 +01:00
|
|
|
|| static_cast<peer_connection*>(p->connection)->m_in_use);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-10 01:46:28 +02:00
|
|
|
void piece_picker::verify_pick(std::vector<piece_block> const& picked
|
2016-12-22 16:42:33 +01:00
|
|
|
, typed_bitfield<piece_index_t> const& bits) const
|
2007-09-10 01:46:28 +02:00
|
|
|
{
|
2016-11-27 14:46:53 +01:00
|
|
|
TORRENT_ASSERT(bits.size() == int(m_piece_map.size()));
|
2016-12-22 16:42:33 +01:00
|
|
|
for (piece_block const& pb : picked)
|
2007-09-10 01:46:28 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(bits[pb.piece_index]);
|
|
|
|
TORRENT_ASSERT(!m_piece_map[pb.piece_index].have());
|
|
|
|
TORRENT_ASSERT(!m_piece_map[pb.piece_index].filtered());
|
2007-09-10 01:46:28 +02:00
|
|
|
}
|
|
|
|
}
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2016-12-26 17:25:50 +01:00
|
|
|
void piece_picker::verify_priority(prio_index_t const range_start
|
|
|
|
, prio_index_t const range_end
|
2016-08-07 22:05:20 +02:00
|
|
|
, int const prio) const
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
|
|
|
TORRENT_ASSERT(range_start <= range_end);
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(range_end <= m_pieces.end_index());
|
|
|
|
for (auto index : range(m_pieces, range_start, range_end))
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
|
|
|
int p = m_piece_map[index].priority(this);
|
|
|
|
TORRENT_ASSERT(p == prio);
|
|
|
|
}
|
|
|
|
}
|
2008-02-18 04:07:14 +01:00
|
|
|
|
2015-11-29 06:58:46 +01:00
|
|
|
#if defined TORRENT_PICKER_LOG
|
2008-01-31 18:52:29 +01:00
|
|
|
void piece_picker::print_pieces() const
|
|
|
|
{
|
2015-01-26 03:04:58 +01:00
|
|
|
int limit = 20;
|
2014-07-06 21:18:00 +02:00
|
|
|
std::cerr << "[" << this << "] ";
|
2015-01-26 03:04:58 +01:00
|
|
|
if (m_dirty)
|
|
|
|
{
|
|
|
|
std::cerr << " === dirty ===" << std::endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-12-26 17:25:50 +01:00
|
|
|
for (prio_index_t b : m_priority_boundaries)
|
2016-08-02 13:20:13 +02:00
|
|
|
std::cerr << b << " ";
|
2016-12-26 17:25:50 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
std::cerr << std::endl;
|
2016-12-26 17:25:50 +01:00
|
|
|
prio_index_t index(0);
|
2014-07-06 21:18:00 +02:00
|
|
|
std::cerr << "[" << this << "] ";
|
2016-12-26 17:25:50 +01:00
|
|
|
auto j = m_priority_boundaries.begin();
|
|
|
|
for (auto i = m_pieces.begin(), end(m_pieces.end()); i != end; ++i, ++index)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
2015-01-26 03:04:58 +01:00
|
|
|
if (limit == 0)
|
|
|
|
{
|
|
|
|
std::cerr << " ...";
|
|
|
|
break;
|
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
if (*i == -1) break;
|
2016-08-02 13:20:13 +02:00
|
|
|
while (j != m_priority_boundaries.end() && *j <= index)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
2008-06-07 04:58:28 +02:00
|
|
|
std::cerr << "| ";
|
2008-01-31 18:52:29 +01:00
|
|
|
++j;
|
|
|
|
}
|
2008-06-07 04:58:28 +02:00
|
|
|
std::cerr << *i << "(" << m_piece_map[*i].index << ") ";
|
2014-07-06 21:18:00 +02:00
|
|
|
--limit;
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
2008-06-07 04:58:28 +02:00
|
|
|
std::cerr << std::endl;
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
2015-11-29 06:58:46 +01:00
|
|
|
#endif // TORRENT_PICKER_LOG
|
2014-01-21 20:26:09 +01:00
|
|
|
#endif // TORRENT_USE_INVARIANT_CHECKS
|
2008-02-18 04:07:14 +01:00
|
|
|
|
2014-01-21 20:26:09 +01:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::check_peer_invariant(typed_bitfield<piece_index_t> const& have
|
2015-08-18 10:25:13 +02:00
|
|
|
, torrent_peer const* p) const
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
#ifdef TORRENT_DEBUG_REFCOUNTS
|
2016-12-22 16:42:33 +01:00
|
|
|
for (piece_index_t i(0); i < have.end_index(); ++i)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
bool const h = have[i];
|
2016-12-13 16:30:36 +01:00
|
|
|
TORRENT_ASSERT(int(m_piece_map[i].have_peers.count(p)) == (h ? 1 : 0));
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2015-04-20 06:52:49 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(have);
|
|
|
|
TORRENT_UNUSED(p);
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void piece_picker::check_invariant(torrent const* t) const
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2007-12-16 02:35:42 +01:00
|
|
|
TORRENT_ASSERT(m_num_have >= 0);
|
|
|
|
TORRENT_ASSERT(m_num_have_filtered >= 0);
|
|
|
|
TORRENT_ASSERT(m_num_filtered >= 0);
|
2008-06-11 10:30:06 +02:00
|
|
|
TORRENT_ASSERT(m_seeds >= 0);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2016-08-02 13:20:13 +02:00
|
|
|
// make sure the priority boundaries are monotonically increasing. The
|
|
|
|
// difference between two cursors cannot be negative, but ranges are
|
|
|
|
// allowed to be empty.
|
2016-12-26 17:25:50 +01:00
|
|
|
prio_index_t last(0);
|
|
|
|
for (prio_index_t b : m_priority_boundaries)
|
2016-08-02 13:20:13 +02:00
|
|
|
{
|
|
|
|
TORRENT_ASSERT(b >= last);
|
|
|
|
last = b;
|
|
|
|
}
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
for (int k = 0; k < piece_pos::num_download_categories; ++k)
|
2007-07-15 17:41:55 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!m_downloads[k].empty())
|
2007-07-15 17:41:55 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
for (std::vector<downloading_piece>::const_iterator i = m_downloads[k].begin();
|
|
|
|
i != m_downloads[k].end() - 1; ++i)
|
|
|
|
{
|
|
|
|
downloading_piece const& dp = *i;
|
|
|
|
downloading_piece const& next = *(i + 1);
|
|
|
|
// TORRENT_ASSERT(dp.finished + dp.writing >= next.finished + next.writing);
|
|
|
|
TORRENT_ASSERT(dp.index < next.index);
|
2015-02-14 22:32:41 +01:00
|
|
|
TORRENT_ASSERT(int(dp.info_idx) * m_blocks_per_piece
|
2015-04-29 07:46:35 +02:00
|
|
|
+ m_blocks_per_piece <= int(m_block_info.size()));
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2017-03-05 05:45:07 +01:00
|
|
|
for (auto const& bl : blocks_for_piece(dp))
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2017-03-05 05:45:07 +01:00
|
|
|
if (!bl.peer) continue;
|
|
|
|
torrent_peer* p = bl.peer;
|
2015-02-14 22:32:41 +01:00
|
|
|
TORRENT_ASSERT(p->in_use);
|
2016-06-20 17:32:06 +02:00
|
|
|
TORRENT_ASSERT(p->connection == nullptr
|
2015-02-14 22:32:41 +01:00
|
|
|
|| static_cast<peer_connection*>(p->connection)->m_in_use);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2007-07-15 17:41:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-09 22:26:26 +02:00
|
|
|
if (t != nullptr)
|
2015-08-02 05:57:11 +02:00
|
|
|
TORRENT_ASSERT(int(m_piece_map.size()) == t->torrent_file().num_pieces());
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
for (int j = 0; j < piece_pos::num_download_categories; ++j)
|
2007-04-27 02:27:37 +02:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
for (auto const& dp : m_downloads[j])
|
2007-04-27 02:27:37 +02:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(m_piece_map[dp.index].download_queue() == j);
|
|
|
|
const int num_blocks = blocks_in_piece(dp.index);
|
2014-07-06 21:18:00 +02:00
|
|
|
int num_requested = 0;
|
|
|
|
int num_finished = 0;
|
|
|
|
int num_writing = 0;
|
|
|
|
int num_open = 0;
|
2017-03-05 05:45:07 +01:00
|
|
|
for (auto const& bl : blocks_for_piece(dp))
|
2007-04-27 02:27:37 +02:00
|
|
|
{
|
2017-03-05 05:45:07 +01:00
|
|
|
TORRENT_ASSERT(bl.piece_index == dp.index);
|
|
|
|
TORRENT_ASSERT(bl.peer == nullptr
|
|
|
|
|| bl.peer->in_use);
|
2015-01-26 03:04:58 +01:00
|
|
|
|
2017-03-05 05:45:07 +01:00
|
|
|
if (bl.state == block_info::state_finished)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
++num_finished;
|
2017-03-05 05:45:07 +01:00
|
|
|
TORRENT_ASSERT(bl.num_peers == 0);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2017-03-05 05:45:07 +01:00
|
|
|
else if (bl.state == block_info::state_requested)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
++num_requested;
|
2017-03-05 05:45:07 +01:00
|
|
|
TORRENT_ASSERT(bl.num_peers > 0);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2017-03-05 05:45:07 +01:00
|
|
|
else if (bl.state == block_info::state_writing)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
++num_writing;
|
2017-03-05 05:45:07 +01:00
|
|
|
TORRENT_ASSERT(bl.num_peers == 0);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2017-03-05 05:45:07 +01:00
|
|
|
else if (bl.state == block_info::state_none)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
++num_open;
|
2017-03-05 05:45:07 +01:00
|
|
|
TORRENT_ASSERT(bl.num_peers == 0);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2007-04-27 02:27:37 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
switch(j)
|
2007-06-10 22:46:09 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
case piece_pos::piece_downloading:
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(!m_piece_map[dp.index].filtered());
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(num_open > 0);
|
|
|
|
break;
|
|
|
|
case piece_pos::piece_full:
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(!m_piece_map[dp.index].filtered());
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(num_open == 0);
|
|
|
|
// if requested == 0, the piece should be in the finished state
|
|
|
|
TORRENT_ASSERT(num_requested > 0);
|
|
|
|
break;
|
|
|
|
case piece_pos::piece_finished:
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(!m_piece_map[dp.index].filtered());
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(num_open == 0);
|
|
|
|
TORRENT_ASSERT(num_requested == 0);
|
|
|
|
TORRENT_ASSERT(num_finished + num_writing == num_blocks);
|
|
|
|
break;
|
|
|
|
case piece_pos::piece_zero_prio:
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(m_piece_map[dp.index].filtered());
|
2014-07-06 21:18:00 +02:00
|
|
|
break;
|
2007-06-10 22:46:09 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(num_requested == dp.requested);
|
|
|
|
TORRENT_ASSERT(num_writing == dp.writing);
|
|
|
|
TORRENT_ASSERT(num_finished == dp.finished);
|
2015-01-26 03:04:58 +01:00
|
|
|
|
2016-08-02 13:20:13 +02:00
|
|
|
if (m_piece_map[dp.index].download_queue() == piece_pos::piece_full
|
|
|
|
|| m_piece_map[dp.index].download_queue() == piece_pos::piece_finished)
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(num_finished + num_writing + num_requested == num_blocks);
|
2007-04-27 02:27:37 +02:00
|
|
|
}
|
|
|
|
}
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(m_cursor >= piece_index_t(0));
|
|
|
|
TORRENT_ASSERT(m_cursor <= m_piece_map.end_index());
|
|
|
|
TORRENT_ASSERT(m_reverse_cursor >= piece_index_t(0));
|
|
|
|
TORRENT_ASSERT(m_reverse_cursor <= m_piece_map.end_index());
|
2008-09-06 23:04:57 +02:00
|
|
|
TORRENT_ASSERT(m_reverse_cursor > m_cursor
|
2016-12-22 16:42:33 +01:00
|
|
|
|| (m_cursor == m_piece_map.end_index()
|
|
|
|
&& m_reverse_cursor == piece_index_t(0)));
|
2008-09-06 23:04:57 +02:00
|
|
|
|
|
|
|
if (!m_dirty)
|
2008-02-18 04:07:14 +01:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(!m_priority_boundaries.empty());
|
2008-02-18 04:07:14 +01:00
|
|
|
int prio = 0;
|
2016-12-26 17:25:50 +01:00
|
|
|
prio_index_t start(0);
|
|
|
|
for (prio_index_t b : m_priority_boundaries)
|
2008-02-18 04:07:14 +01:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
verify_priority(start, b, prio);
|
2008-02-18 04:07:14 +01:00
|
|
|
++prio;
|
2016-08-02 13:20:13 +02:00
|
|
|
start = b;
|
2008-02-18 04:07:14 +01:00
|
|
|
}
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(m_priority_boundaries.back() == m_pieces.end_index());
|
2008-02-18 04:07:14 +01:00
|
|
|
}
|
2015-01-26 03:04:58 +01:00
|
|
|
|
2016-10-03 08:08:03 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t index(0);
|
|
|
|
for (auto i = m_piece_map.begin()
|
2015-08-16 18:17:23 +02:00
|
|
|
, end(m_piece_map.end()); i != end && (i->have() || i->filtered());
|
|
|
|
++i, ++index);
|
|
|
|
TORRENT_ASSERT(m_cursor == index);
|
2016-12-22 16:42:33 +01:00
|
|
|
int const num_pieces = int(m_piece_map.size());
|
|
|
|
index = m_piece_map.end_index();
|
2015-08-16 18:17:23 +02:00
|
|
|
if (num_pieces > 0)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto i = m_piece_map.rend() - static_cast<int>(index); index > piece_index_t(0)
|
|
|
|
&& (i->have() || i->filtered()); ++i, --index);
|
|
|
|
TORRENT_ASSERT(index == m_piece_map.end_index()
|
2015-08-16 18:17:23 +02:00
|
|
|
|| m_piece_map[index].have()
|
|
|
|
|| m_piece_map[index].filtered());
|
|
|
|
TORRENT_ASSERT(m_reverse_cursor == index);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(m_reverse_cursor == piece_index_t(0));
|
2015-08-16 18:17:23 +02:00
|
|
|
}
|
2008-02-18 04:07:14 +01:00
|
|
|
}
|
2007-04-27 02:27:37 +02:00
|
|
|
|
2005-05-30 19:43:03 +02:00
|
|
|
int num_filtered = 0;
|
|
|
|
int num_have_filtered = 0;
|
2007-05-14 12:54:18 +02:00
|
|
|
int num_have = 0;
|
2016-12-26 17:25:50 +01:00
|
|
|
piece_index_t piece(0);
|
|
|
|
for (auto i = m_piece_map.begin(); i != m_piece_map.end(); ++i, ++piece)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-01-31 18:52:29 +01:00
|
|
|
piece_pos const& p = *i;
|
|
|
|
|
|
|
|
if (p.filtered())
|
2005-05-30 19:43:03 +02:00
|
|
|
{
|
2008-01-31 18:52:29 +01:00
|
|
|
if (p.index != piece_pos::we_have_index)
|
2005-05-30 19:43:03 +02:00
|
|
|
++num_filtered;
|
|
|
|
else
|
|
|
|
++num_have_filtered;
|
|
|
|
}
|
2013-01-06 05:02:29 +01:00
|
|
|
|
|
|
|
#ifdef TORRENT_DEBUG_REFCOUNTS
|
2016-11-27 14:46:53 +01:00
|
|
|
TORRENT_ASSERT(int(p.have_peers.size()) == p.peer_count + m_seeds);
|
2013-01-06 05:02:29 +01:00
|
|
|
#endif
|
2008-01-31 18:52:29 +01:00
|
|
|
if (p.index == piece_pos::we_have_index)
|
2007-05-14 12:54:18 +02:00
|
|
|
++num_have;
|
|
|
|
|
2008-01-31 18:52:29 +01:00
|
|
|
if (p.index == piece_pos::we_have_index)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(t == nullptr || t->have_piece(piece));
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(p.downloading() == false);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2016-07-09 22:26:26 +02:00
|
|
|
if (t != nullptr)
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(!t->have_piece(piece));
|
2008-01-31 18:52:29 +01:00
|
|
|
|
2016-08-07 22:05:20 +02:00
|
|
|
int const prio = p.priority(this);
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
#if TORRENT_USE_ASSERTS
|
|
|
|
if (p.downloading())
|
|
|
|
{
|
|
|
|
if (p.reverse())
|
|
|
|
TORRENT_ASSERT(prio == -1 || (prio % piece_picker::prio_factor == 2));
|
|
|
|
else
|
|
|
|
TORRENT_ASSERT(prio == -1 || (prio % piece_picker::prio_factor == 0));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(prio == -1 || (prio % piece_picker::prio_factor == 1));
|
|
|
|
}
|
|
|
|
#endif
|
2008-09-06 23:04:57 +02:00
|
|
|
|
|
|
|
if (!m_dirty)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
2016-08-07 22:05:20 +02:00
|
|
|
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()));
|
2008-01-31 18:52:29 +01:00
|
|
|
if (prio >= 0)
|
2006-07-16 02:08:50 +02:00
|
|
|
{
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(p.index < m_pieces.end_index());
|
|
|
|
TORRENT_ASSERT(m_pieces[p.index] == piece);
|
2006-07-16 02:08:50 +02:00
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
else
|
2007-03-21 03:09:50 +01:00
|
|
|
{
|
2008-01-31 18:52:29 +01:00
|
|
|
TORRENT_ASSERT(prio == -1);
|
|
|
|
// make sure there's no entry
|
|
|
|
// with this index. (there shouldn't
|
|
|
|
// be since the priority is -1)
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(std::count(m_pieces.begin(), m_pieces.end(), piece) == 0);
|
2007-03-21 03:09:50 +01:00
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
2007-04-15 04:14:02 +02:00
|
|
|
|
2016-12-06 14:24:01 +01:00
|
|
|
int const count_downloading = int(std::count_if(
|
2015-01-26 03:04:58 +01:00
|
|
|
m_downloads[piece_pos::piece_downloading].begin()
|
|
|
|
, m_downloads[piece_pos::piece_downloading].end()
|
2016-12-26 17:25:50 +01:00
|
|
|
, has_index(piece)));
|
2015-01-26 03:04:58 +01:00
|
|
|
|
2016-12-06 14:24:01 +01:00
|
|
|
int const count_full = int(std::count_if(
|
2015-01-26 03:04:58 +01:00
|
|
|
m_downloads[piece_pos::piece_full].begin()
|
|
|
|
, m_downloads[piece_pos::piece_full].end()
|
2016-12-26 17:25:50 +01:00
|
|
|
, has_index(piece)));
|
2015-01-26 03:04:58 +01:00
|
|
|
|
2016-12-06 14:24:01 +01:00
|
|
|
int const count_finished = int(std::count_if(
|
2015-01-26 03:04:58 +01:00
|
|
|
m_downloads[piece_pos::piece_finished].begin()
|
|
|
|
, m_downloads[piece_pos::piece_finished].end()
|
2016-12-26 17:25:50 +01:00
|
|
|
, has_index(piece)));
|
2015-01-26 03:04:58 +01:00
|
|
|
|
2016-12-06 14:24:01 +01:00
|
|
|
int const count_zero = int(std::count_if(
|
2015-01-26 03:04:58 +01:00
|
|
|
m_downloads[piece_pos::piece_zero_prio].begin()
|
|
|
|
, m_downloads[piece_pos::piece_zero_prio].end()
|
2016-12-26 17:25:50 +01:00
|
|
|
, has_index(piece)));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i->download_queue() == piece_pos::piece_open
|
|
|
|
|| count_zero + count_downloading + count_full
|
|
|
|
+ count_finished == 1);
|
|
|
|
|
|
|
|
switch(i->download_queue())
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
case piece_pos::piece_open:
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(count_downloading
|
|
|
|
+ count_full + count_finished + count_zero == 0);
|
2014-07-06 21:18:00 +02:00
|
|
|
break;
|
|
|
|
case piece_pos::piece_downloading:
|
|
|
|
TORRENT_ASSERT(count_downloading == 1);
|
|
|
|
break;
|
|
|
|
case piece_pos::piece_full:
|
|
|
|
TORRENT_ASSERT(count_full == 1);
|
|
|
|
break;
|
|
|
|
case piece_pos::piece_finished:
|
|
|
|
TORRENT_ASSERT(count_finished == 1);
|
|
|
|
break;
|
2015-01-26 03:04:58 +01:00
|
|
|
case piece_pos::piece_zero_prio:
|
|
|
|
TORRENT_ASSERT(count_zero == 1);
|
|
|
|
break;
|
2014-07-06 21:18:00 +02:00
|
|
|
};
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(num_have == m_num_have);
|
|
|
|
TORRENT_ASSERT(num_filtered == m_num_filtered);
|
|
|
|
TORRENT_ASSERT(num_have_filtered == m_num_have_filtered);
|
2008-01-31 18:52:29 +01:00
|
|
|
|
|
|
|
if (!m_dirty)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
for (piece_index_t i : m_pieces)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(m_piece_map[i].priority(this) >= 0);
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
|
|
|
}
|
2016-10-03 08:08:03 +02:00
|
|
|
#endif // TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2004-09-08 01:16:11 +02:00
|
|
|
#endif
|
|
|
|
|
2009-07-19 06:59:27 +02:00
|
|
|
std::pair<int, int> piece_picker::distributed_copies() const
|
2004-08-05 15:56:26 +02:00
|
|
|
{
|
2008-06-11 10:30:06 +02:00
|
|
|
TORRENT_ASSERT(m_seeds >= 0);
|
2016-04-25 23:22:09 +02:00
|
|
|
const int num_pieces = int(m_piece_map.size());
|
2004-09-08 01:16:11 +02:00
|
|
|
|
2010-02-22 02:51:25 +01:00
|
|
|
if (num_pieces == 0) return std::make_pair(1, 0);
|
2007-04-11 22:33:28 +02:00
|
|
|
int min_availability = piece_pos::max_peer_count;
|
|
|
|
// find the lowest availability count
|
|
|
|
// count the number of pieces that have that availability
|
|
|
|
// and also the number of pieces that have more than that.
|
|
|
|
int integer_part = 0;
|
|
|
|
int fraction_part = 0;
|
|
|
|
for (std::vector<piece_pos>::const_iterator i = m_piece_map.begin()
|
|
|
|
, end(m_piece_map.end()); i != end; ++i)
|
2004-08-05 15:56:26 +02:00
|
|
|
{
|
2007-04-11 22:33:28 +02:00
|
|
|
int peer_count = int(i->peer_count);
|
|
|
|
// take ourself into account
|
|
|
|
if (i->have()) ++peer_count;
|
|
|
|
if (min_availability > peer_count)
|
|
|
|
{
|
2007-08-27 07:13:09 +02:00
|
|
|
min_availability = peer_count;
|
2007-04-11 22:33:28 +02:00
|
|
|
fraction_part += integer_part;
|
|
|
|
integer_part = 1;
|
|
|
|
}
|
|
|
|
else if (peer_count == min_availability)
|
|
|
|
{
|
|
|
|
++integer_part;
|
|
|
|
}
|
|
|
|
else
|
2004-09-08 01:16:11 +02:00
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(peer_count > min_availability);
|
2007-04-11 22:33:28 +02:00
|
|
|
++fraction_part;
|
2004-08-05 15:56:26 +02:00
|
|
|
}
|
|
|
|
}
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(integer_part + fraction_part == num_pieces);
|
2009-07-19 06:59:27 +02:00
|
|
|
return std::make_pair(min_availability + m_seeds, fraction_part * 1000 / num_pieces);
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
|
|
|
|
2016-12-26 17:25:50 +01:00
|
|
|
prio_index_t piece_picker::priority_begin(int const prio) const
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
|
|
|
TORRENT_ASSERT(prio >= 0);
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()));
|
2017-02-08 16:54:55 +01:00
|
|
|
return prio == 0 ? prio_index_t(0) : m_priority_boundaries[prio - 1];
|
2016-12-26 17:25:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
prio_index_t piece_picker::priority_end(int const prio) const
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(prio >= 0);
|
|
|
|
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()));
|
|
|
|
return m_priority_boundaries[prio];
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<prio_index_t, prio_index_t> piece_picker::priority_range(int const prio) const
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(prio >= 0);
|
|
|
|
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()));
|
2017-02-08 16:54:55 +01:00
|
|
|
return {priority_begin(prio), priority_end(prio)};
|
2004-08-05 15:56:26 +02:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::add(piece_index_t index)
|
2005-09-01 23:04:21 +02:00
|
|
|
{
|
2008-01-31 18:52:29 +01:00
|
|
|
TORRENT_ASSERT(!m_dirty);
|
2016-08-07 22:05:20 +02:00
|
|
|
piece_pos const& p = m_piece_map[index];
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!p.filtered());
|
|
|
|
TORRENT_ASSERT(!p.have());
|
2005-09-01 23:04:21 +02:00
|
|
|
|
2008-01-31 18:52:29 +01:00
|
|
|
int priority = p.priority(this);
|
|
|
|
TORRENT_ASSERT(priority >= 0);
|
2015-05-03 05:28:39 +02:00
|
|
|
if (priority < 0) return;
|
|
|
|
|
2016-08-02 13:20:13 +02:00
|
|
|
if (int(m_priority_boundaries.size()) <= priority)
|
2016-12-26 17:25:50 +01:00
|
|
|
m_priority_boundaries.resize(priority + 1, m_pieces.end_index());
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(int(m_priority_boundaries.size()) >= priority);
|
2005-09-01 23:04:21 +02:00
|
|
|
|
2016-08-07 22:05:20 +02:00
|
|
|
auto const range = priority_range(priority);
|
2016-12-26 17:25:50 +01:00
|
|
|
prio_index_t new_index = (range.second == range.first)
|
2016-08-06 19:18:48 +02:00
|
|
|
? range.first
|
2017-02-08 16:54:55 +01:00
|
|
|
: prio_index_t(
|
|
|
|
int(random(aux::numeric_cast<std::uint32_t>(static_cast<int>(range.second - range.first))))
|
|
|
|
+ static_cast<int>(range.first));
|
2008-01-31 18:52:29 +01:00
|
|
|
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2014-07-06 21:18:00 +02:00
|
|
|
std::cerr << "[" << this << "] " << "add " << index << " (" << priority << ")" << std::endl;
|
2015-01-26 03:04:58 +01:00
|
|
|
std::cerr << "[" << this << "] " << " p: state: " << p.download_state
|
2014-07-06 21:18:00 +02:00
|
|
|
<< " peer_count: " << p.peer_count
|
|
|
|
<< " prio: " << p.piece_priority
|
|
|
|
<< " index: " << p.index << std::endl;
|
2008-01-31 18:52:29 +01:00
|
|
|
print_pieces();
|
|
|
|
#endif
|
2016-12-22 16:42:33 +01:00
|
|
|
m_pieces.push_back(piece_index_t(-1));
|
2008-01-31 18:52:29 +01:00
|
|
|
|
|
|
|
for (;;)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(new_index < m_pieces.end_index());
|
2016-12-22 16:42:33 +01:00
|
|
|
{
|
|
|
|
piece_index_t temp = m_pieces[new_index];
|
|
|
|
m_pieces[new_index] = index;
|
|
|
|
m_piece_map[index].index = new_index;
|
|
|
|
index = temp;
|
|
|
|
}
|
2016-12-26 17:25:50 +01:00
|
|
|
prio_index_t temp(-1);
|
2008-01-31 18:52:29 +01:00
|
|
|
do
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
temp = m_priority_boundaries[priority]++;
|
2008-01-31 18:52:29 +01:00
|
|
|
++priority;
|
2016-08-02 13:20:13 +02:00
|
|
|
} while (temp == new_index && priority < int(m_priority_boundaries.size()));
|
2008-01-31 18:52:29 +01:00
|
|
|
new_index = temp;
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
2014-07-06 21:18:00 +02:00
|
|
|
std::cerr << "[" << this << "] " << " index: " << index
|
2008-01-31 18:52:29 +01:00
|
|
|
<< " prio: " << priority
|
|
|
|
<< " new_index: " << new_index
|
|
|
|
<< std::endl;
|
|
|
|
#endif
|
2016-08-02 13:20:13 +02:00
|
|
|
if (priority >= int(m_priority_boundaries.size())) break;
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(temp >= prio_index_t(0));
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2016-12-22 16:42:33 +01:00
|
|
|
if (index != piece_index_t(-1))
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(new_index == prev(m_pieces.end_index()));
|
2008-01-31 18:52:29 +01:00
|
|
|
m_pieces[new_index] = index;
|
|
|
|
m_piece_map[index].index = new_index;
|
|
|
|
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2016-12-26 17:25:50 +01:00
|
|
|
void piece_picker::remove(int priority, prio_index_t elem_index)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
|
|
|
TORRENT_ASSERT(!m_dirty);
|
|
|
|
TORRENT_ASSERT(priority >= 0);
|
|
|
|
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2014-07-06 21:18:00 +02:00
|
|
|
std::cerr << "[" << this << "] " << "remove " << m_pieces[elem_index] << " (" << priority << ")" << std::endl;
|
2008-01-31 18:52:29 +01:00
|
|
|
#endif
|
2016-12-26 17:25:50 +01:00
|
|
|
prio_index_t next_index = elem_index;
|
2008-01-31 18:52:29 +01:00
|
|
|
TORRENT_ASSERT(m_piece_map[m_pieces[elem_index]].priority(this) == -1);
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(elem_index < m_pieces.end_index());
|
2018-01-11 01:35:15 +01:00
|
|
|
prio_index_t temp{};
|
2008-01-31 18:52:29 +01:00
|
|
|
do
|
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
temp = --m_priority_boundaries[priority];
|
2008-01-31 18:52:29 +01:00
|
|
|
++priority;
|
2016-08-02 13:20:13 +02:00
|
|
|
} while (next_index == temp && priority < int(m_priority_boundaries.size()));
|
2008-01-31 18:52:29 +01:00
|
|
|
if (next_index == temp) break;
|
|
|
|
next_index = temp;
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t const piece = m_pieces[next_index];
|
2008-01-31 18:52:29 +01:00
|
|
|
m_pieces[elem_index] = piece;
|
|
|
|
m_piece_map[piece].index = elem_index;
|
|
|
|
TORRENT_ASSERT(m_piece_map[piece].priority(this) == priority - 1);
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(elem_index < prev(m_pieces.end_index()));
|
2008-01-31 18:52:29 +01:00
|
|
|
elem_index = next_index;
|
|
|
|
|
2016-08-02 13:20:13 +02:00
|
|
|
if (priority == int(m_priority_boundaries.size()))
|
2008-01-31 18:52:29 +01:00
|
|
|
break;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
m_pieces.pop_back();
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(next_index == m_pieces.end_index());
|
2008-01-31 18:52:29 +01:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
2005-09-01 23:04:21 +02:00
|
|
|
}
|
2005-05-25 12:01:01 +02:00
|
|
|
|
2007-03-15 23:03:56 +01:00
|
|
|
// will update the piece with the given properties (priority, elem_index)
|
2008-01-31 18:52:29 +01:00
|
|
|
// to place it at the correct position
|
2016-12-26 17:25:50 +01:00
|
|
|
void piece_picker::update(int priority, prio_index_t elem_index)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-01-31 18:52:29 +01:00
|
|
|
TORRENT_ASSERT(!m_dirty);
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(priority >= 0);
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(int(m_priority_boundaries.size()) > priority);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// make sure the passed in elem_index actually lives in the specified
|
|
|
|
// priority bucket. If it doesn't, it means this piece changed
|
|
|
|
// state without updating the corresponding entry in the pieces list
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(m_priority_boundaries[priority] >= elem_index);
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(elem_index >= priority_begin(priority));
|
|
|
|
TORRENT_ASSERT(elem_index < priority_end(priority));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t const index = m_pieces[elem_index];
|
2003-10-23 01:00:57 +02:00
|
|
|
// update the piece_map
|
|
|
|
piece_pos& p = m_piece_map[index];
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(p.index == elem_index || p.have());
|
2007-03-21 03:09:50 +01:00
|
|
|
|
2016-08-07 22:05:20 +02:00
|
|
|
int const new_priority = p.priority(this);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2007-03-15 23:03:56 +01:00
|
|
|
if (new_priority == priority) return;
|
|
|
|
|
2008-01-31 18:52:29 +01:00
|
|
|
if (new_priority == -1)
|
2006-07-16 02:08:50 +02:00
|
|
|
{
|
2008-01-31 18:52:29 +01:00
|
|
|
remove(priority, elem_index);
|
|
|
|
return;
|
2006-07-16 02:08:50 +02:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2016-08-02 13:20:13 +02:00
|
|
|
if (int(m_priority_boundaries.size()) <= new_priority)
|
2016-12-26 17:25:50 +01:00
|
|
|
m_priority_boundaries.resize(new_priority + 1, m_pieces.end_index());
|
2008-01-31 18:52:29 +01:00
|
|
|
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2014-07-06 21:18:00 +02:00
|
|
|
std::cerr << "[" << this << "] " << "update " << index << " (" << priority << "->" << new_priority << ")" << std::endl;
|
2008-01-31 18:52:29 +01:00
|
|
|
#endif
|
|
|
|
if (priority > new_priority)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2018-01-11 01:35:15 +01:00
|
|
|
prio_index_t new_index{};
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t temp = index;
|
2008-01-31 18:52:29 +01:00
|
|
|
for (;;)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2008-01-31 18:52:29 +01:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(priority > 0);
|
2008-01-31 18:52:29 +01:00
|
|
|
--priority;
|
2016-08-02 13:20:13 +02:00
|
|
|
new_index = m_priority_boundaries[priority]++;
|
2008-01-31 18:52:29 +01:00
|
|
|
if (temp != m_pieces[new_index])
|
|
|
|
{
|
|
|
|
temp = m_pieces[new_index];
|
|
|
|
m_pieces[elem_index] = temp;
|
|
|
|
m_piece_map[temp].index = elem_index;
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(elem_index < m_pieces.end_index());
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
|
|
|
elem_index = new_index;
|
|
|
|
if (priority == new_priority) break;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
|
|
|
m_pieces[elem_index] = index;
|
|
|
|
m_piece_map[index].index = elem_index;
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(elem_index < m_pieces.end_index());
|
2008-01-31 18:52:29 +01:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
|
|
|
shuffle(priority, elem_index);
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
|
|
|
TORRENT_ASSERT(m_piece_map[index].priority(this) == priority);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-01-11 01:35:15 +01:00
|
|
|
prio_index_t new_index{};
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t temp = index;
|
2008-01-31 18:52:29 +01:00
|
|
|
for (;;)
|
2006-07-16 02:08:50 +02:00
|
|
|
{
|
2008-01-31 18:52:29 +01:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(priority >= 0);
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(priority < int(m_priority_boundaries.size()));
|
|
|
|
new_index = --m_priority_boundaries[priority];
|
2008-01-31 18:52:29 +01:00
|
|
|
if (temp != m_pieces[new_index])
|
|
|
|
{
|
|
|
|
temp = m_pieces[new_index];
|
|
|
|
m_pieces[elem_index] = temp;
|
|
|
|
m_piece_map[temp].index = elem_index;
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(elem_index < m_pieces.end_index());
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
|
|
|
elem_index = new_index;
|
|
|
|
++priority;
|
|
|
|
if (priority == new_priority) break;
|
2006-07-16 02:08:50 +02:00
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
|
|
|
m_pieces[elem_index] = index;
|
|
|
|
m_piece_map[index].index = elem_index;
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(elem_index < m_pieces.end_index());
|
2008-01-31 18:52:29 +01:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
|
|
|
shuffle(priority, elem_index);
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
|
|
|
TORRENT_ASSERT(m_piece_map[index].priority(this) == priority);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
void piece_picker::shuffle(int const priority, prio_index_t const elem_index)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2014-07-06 21:18:00 +02:00
|
|
|
std::cerr << "[" << this << "] " << "shuffle()" << std::endl;
|
2008-09-06 23:04:57 +02:00
|
|
|
#endif
|
|
|
|
|
2008-01-31 18:52:29 +01:00
|
|
|
TORRENT_ASSERT(!m_dirty);
|
|
|
|
TORRENT_ASSERT(priority >= 0);
|
2016-12-26 17:25:50 +01:00
|
|
|
TORRENT_ASSERT(elem_index >= prio_index_t(0));
|
|
|
|
TORRENT_ASSERT(elem_index < m_pieces.end_index());
|
2008-09-06 23:04:57 +02:00
|
|
|
TORRENT_ASSERT(m_piece_map[m_pieces[elem_index]].priority(this) == priority);
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2016-08-06 19:18:48 +02:00
|
|
|
auto const range = priority_range(priority);
|
2017-02-08 16:54:55 +01:00
|
|
|
prio_index_t const other_index(
|
|
|
|
int(random(aux::numeric_cast<std::uint32_t>(static_cast<int>(range.second - range.first) - 1)))
|
|
|
|
+ static_cast<int>(range.first));
|
2008-01-31 18:52:29 +01:00
|
|
|
|
|
|
|
if (other_index == elem_index) return;
|
|
|
|
|
|
|
|
// swap other_index with elem_index
|
|
|
|
piece_pos& p1 = m_piece_map[m_pieces[other_index]];
|
|
|
|
piece_pos& p2 = m_piece_map[m_pieces[elem_index]];
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
std::swap(p1.index, p2.index);
|
2008-01-31 18:52:29 +01:00
|
|
|
std::swap(m_pieces[other_index], m_pieces[elem_index]);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2009-09-08 04:38:53 +02:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
void piece_picker::restore_piece(piece_index_t const index)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2006-07-16 02:08:50 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
std::cerr << "[" << this << "] " << "restore_piece(" << index << ")" << std::endl;
|
|
|
|
#endif
|
2017-06-20 17:45:18 +02:00
|
|
|
int const download_state = m_piece_map[index].download_queue();
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(download_state != piece_pos::piece_open);
|
|
|
|
if (download_state == piece_pos::piece_open) return;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
auto i = find_dl_piece(download_state, index);
|
2008-02-18 04:07:14 +01:00
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[download_state].end());
|
2015-02-14 22:32:41 +01:00
|
|
|
TORRENT_ASSERT(int(i->info_idx) * m_blocks_per_piece
|
2015-04-29 07:46:35 +02:00
|
|
|
+ m_blocks_per_piece <= int(m_block_info.size()));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
i->locked = false;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
piece_pos& p = m_piece_map[index];
|
2016-08-07 22:05:20 +02:00
|
|
|
int const prev_priority = p.priority(this);
|
2009-06-10 10:30:55 +02:00
|
|
|
erase_download_piece(i);
|
2016-08-07 22:05:20 +02:00
|
|
|
int const new_priority = p.priority(this);
|
2007-03-20 20:50:15 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
|
|
|
|
2007-03-20 20:50:15 +01:00
|
|
|
if (new_priority == prev_priority) return;
|
2008-01-31 18:52:29 +01:00
|
|
|
if (m_dirty) return;
|
2011-11-07 05:31:48 +01:00
|
|
|
if (prev_priority == -1) add(index);
|
|
|
|
else update(prev_priority, p.index);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2015-08-18 10:25:13 +02:00
|
|
|
void piece_picker::inc_refcount_all(const torrent_peer* peer)
|
2007-04-15 04:14:02 +02:00
|
|
|
{
|
2010-09-01 05:00:15 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2010-09-01 05:00:15 +02:00
|
|
|
#endif
|
|
|
|
|
2008-01-31 18:52:29 +01:00
|
|
|
++m_seeds;
|
|
|
|
if (m_seeds == 1)
|
2007-04-15 04:14:02 +02:00
|
|
|
{
|
2008-01-31 18:52:29 +01:00
|
|
|
// when m_seeds is increased from 0 to 1
|
|
|
|
// we may have to add pieces that previously
|
|
|
|
// didn't have any peers
|
|
|
|
m_dirty = true;
|
2007-04-15 04:14:02 +02:00
|
|
|
}
|
2013-01-06 05:02:29 +01:00
|
|
|
#ifdef TORRENT_DEBUG_REFCOUNTS
|
|
|
|
for (std::vector<piece_pos>::iterator i = m_piece_map.begin()
|
|
|
|
, end(m_piece_map.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(i->have_peers.count(peer) == 0);
|
|
|
|
i->have_peers.insert(peer);
|
|
|
|
}
|
2015-04-20 06:52:49 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(peer);
|
2013-01-06 05:02:29 +01:00
|
|
|
#endif
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
2007-04-17 02:20:39 +02:00
|
|
|
|
2015-08-18 10:25:13 +02:00
|
|
|
void piece_picker::dec_refcount_all(const torrent_peer* peer)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
2010-09-01 05:00:15 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2010-09-01 05:00:15 +02:00
|
|
|
#endif
|
2008-01-31 18:52:29 +01:00
|
|
|
|
|
|
|
if (m_seeds > 0)
|
2007-04-17 02:20:39 +02:00
|
|
|
{
|
2008-01-31 18:52:29 +01:00
|
|
|
--m_seeds;
|
|
|
|
if (m_seeds == 0)
|
2007-04-17 02:20:39 +02:00
|
|
|
{
|
2008-01-31 18:52:29 +01:00
|
|
|
// when m_seeds is decreased from 1 to 0
|
|
|
|
// we may have to remove pieces that previously
|
|
|
|
// didn't have any peers
|
|
|
|
m_dirty = true;
|
2007-04-17 02:20:39 +02:00
|
|
|
}
|
2013-01-06 05:02:29 +01:00
|
|
|
#ifdef TORRENT_DEBUG_REFCOUNTS
|
|
|
|
for (std::vector<piece_pos>::iterator i = m_piece_map.begin()
|
|
|
|
, end(m_piece_map.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(i->have_peers.count(peer) == 1);
|
|
|
|
i->have_peers.erase(peer);
|
|
|
|
}
|
2015-04-20 06:52:49 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(peer);
|
2013-01-06 05:02:29 +01:00
|
|
|
#endif
|
2008-01-31 18:52:29 +01:00
|
|
|
return;
|
2007-04-17 02:20:39 +02:00
|
|
|
}
|
2008-06-11 10:30:06 +02:00
|
|
|
TORRENT_ASSERT(m_seeds == 0);
|
2008-01-31 18:52:29 +01:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto& i : m_piece_map)
|
2007-04-15 04:14:02 +02:00
|
|
|
{
|
2013-01-06 05:02:29 +01:00
|
|
|
#ifdef TORRENT_DEBUG_REFCOUNTS
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(i.have_peers.count(peer) == 1);
|
|
|
|
i.have_peers.erase(peer);
|
2015-04-20 06:52:49 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(peer);
|
2013-01-06 05:02:29 +01:00
|
|
|
#endif
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(i.peer_count > 0);
|
|
|
|
--i.peer_count;
|
2007-04-15 04:14:02 +02:00
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
|
|
|
|
m_dirty = true;
|
2007-04-15 04:14:02 +02:00
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::inc_refcount(piece_index_t const index
|
|
|
|
, const torrent_peer* peer)
|
2007-04-15 04:14:02 +02:00
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2008-09-06 23:04:57 +02:00
|
|
|
#endif
|
2008-01-31 18:52:29 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
std::cerr << "[" << this << "] " << "inc_refcount(" << index << ")" << std::endl;
|
|
|
|
#endif
|
2008-01-31 18:52:29 +01:00
|
|
|
piece_pos& p = m_piece_map[index];
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2013-01-06 05:02:29 +01:00
|
|
|
#ifdef TORRENT_DEBUG_REFCOUNTS
|
|
|
|
TORRENT_ASSERT(p.have_peers.count(peer) == 0);
|
|
|
|
p.have_peers.insert(peer);
|
2015-04-20 06:52:49 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(peer);
|
2013-01-06 05:02:29 +01:00
|
|
|
#endif
|
|
|
|
|
2008-01-31 18:52:29 +01:00
|
|
|
int prev_priority = p.priority(this);
|
|
|
|
++p.peer_count;
|
|
|
|
if (m_dirty) return;
|
|
|
|
int new_priority = p.priority(this);
|
|
|
|
if (prev_priority == new_priority) return;
|
|
|
|
if (prev_priority == -1)
|
|
|
|
add(index);
|
|
|
|
else
|
|
|
|
update(prev_priority, p.index);
|
|
|
|
}
|
|
|
|
|
2012-05-14 06:48:23 +02:00
|
|
|
// this function decrements the m_seeds counter
|
|
|
|
// and increments the peer counter on every piece
|
|
|
|
// instead. Sometimes of we connect to a seed that
|
|
|
|
// later sends us a dont-have message, we'll need to
|
|
|
|
// turn that m_seed into counts on the pieces since
|
|
|
|
// they can't be negative
|
|
|
|
void piece_picker::break_one_seed()
|
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2012-05-14 06:48:23 +02:00
|
|
|
|
|
|
|
TORRENT_ASSERT(m_seeds > 0);
|
|
|
|
--m_seeds;
|
|
|
|
|
2018-01-11 01:35:15 +01:00
|
|
|
for (auto& m : m_piece_map)
|
|
|
|
++m.peer_count;
|
2012-05-14 06:48:23 +02:00
|
|
|
|
|
|
|
m_dirty = true;
|
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::dec_refcount(piece_index_t const index
|
|
|
|
, const torrent_peer* peer)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2008-09-06 23:04:57 +02:00
|
|
|
#endif
|
2007-04-17 02:20:39 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
std::cerr << "[" << this << "] " << "dec_refcount(" << index << ")" << std::endl;
|
2013-01-06 05:02:29 +01:00
|
|
|
#endif
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
piece_pos& p = m_piece_map[index];
|
|
|
|
|
2012-05-14 06:48:23 +02:00
|
|
|
if (p.peer_count == 0)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(m_seeds > 0);
|
|
|
|
// this is the case where we have one or more
|
|
|
|
// seeds, and one of them saying: I don't have this
|
|
|
|
// piece anymore. we need to break up one of the seed
|
|
|
|
// counters into actual peer counters on the pieces
|
|
|
|
break_one_seed();
|
|
|
|
}
|
|
|
|
|
2018-01-11 01:35:15 +01:00
|
|
|
int const prev_priority = p.priority(this);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_DEBUG_REFCOUNTS
|
|
|
|
TORRENT_ASSERT(p.have_peers.count(peer) == 1);
|
|
|
|
p.have_peers.erase(peer);
|
2015-04-20 06:52:49 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(peer);
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
|
2008-01-31 18:52:29 +01:00
|
|
|
TORRENT_ASSERT(p.peer_count > 0);
|
|
|
|
--p.peer_count;
|
|
|
|
if (m_dirty) return;
|
|
|
|
if (prev_priority >= 0) update(prev_priority, p.index);
|
|
|
|
}
|
2007-04-15 04:14:02 +02:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::inc_refcount(typed_bitfield<piece_index_t> const& bitmask
|
|
|
|
, const torrent_peer* peer)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
2009-05-22 05:36:05 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2009-05-22 05:36:05 +02:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
std::cerr << "[" << this << "] " << "inc_refcount(bitfield)" << std::endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// nothing set, nothing to do here
|
|
|
|
if (bitmask.none_set()) return;
|
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
if (bitmask.all_set() && bitmask.size() == int(m_piece_map.size()))
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
inc_refcount_all(peer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
int const size = std::min(50, bitmask.size() / 2);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// this is an optimization where if just a few
|
|
|
|
// pieces end up changing, instead of making
|
|
|
|
// the piece list dirty, just update those pieces
|
|
|
|
// instead
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ALLOCA(incremented, piece_index_t, size);
|
2014-07-06 21:18:00 +02:00
|
|
|
int num_inc = 0;
|
|
|
|
|
|
|
|
if (!m_dirty)
|
|
|
|
{
|
|
|
|
// first count how many pieces we're updating. If it's few (less than half)
|
2016-07-31 03:53:11 +02:00
|
|
|
// we'll just update them one at a time. Otherwise we'll just update the counters
|
2014-07-06 21:18:00 +02:00
|
|
|
// and mark the picker as dirty, so we'll rebuild it next time we need it.
|
|
|
|
// this only matters if we're not already dirty, in which case the fasted
|
|
|
|
// thing to do is to just update the counters and be done
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t index = piece_index_t(0);
|
|
|
|
for (auto i = bitmask.begin(), end(bitmask.end()); i != end; ++i, ++index)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
if (!*i) continue;
|
|
|
|
if (num_inc < size) incremented[num_inc] = index;
|
|
|
|
++num_inc;
|
|
|
|
if (num_inc >= size) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_inc < size)
|
|
|
|
{
|
|
|
|
// not that many pieces were updated
|
|
|
|
// just update those individually instead of
|
|
|
|
// rebuilding the whole piece list
|
|
|
|
for (int i = 0; i < num_inc; ++i)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t const piece = incremented[i];
|
2014-07-06 21:18:00 +02:00
|
|
|
piece_pos& p = m_piece_map[piece];
|
|
|
|
int prev_priority = p.priority(this);
|
|
|
|
++p.peer_count;
|
|
|
|
#ifdef TORRENT_DEBUG_REFCOUNTS
|
|
|
|
TORRENT_ASSERT(p.have_peers.count(peer) == 0);
|
|
|
|
p.have_peers.insert(peer);
|
2015-04-20 06:52:49 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(peer);
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
int new_priority = p.priority(this);
|
|
|
|
if (prev_priority == new_priority) continue;
|
|
|
|
else if (prev_priority >= 0) update(prev_priority, p.index);
|
|
|
|
else add(piece);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2007-04-15 04:14:02 +02:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t index = piece_index_t(0);
|
2008-01-31 18:52:29 +01:00
|
|
|
bool updated = false;
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto i = bitmask.begin(), end(bitmask.end()); i != end; ++i, ++index)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
|
|
|
if (*i)
|
2007-04-17 02:20:39 +02:00
|
|
|
{
|
2013-01-06 05:02:29 +01:00
|
|
|
#ifdef TORRENT_DEBUG_REFCOUNTS
|
|
|
|
TORRENT_ASSERT(m_piece_map[index].have_peers.count(peer) == 0);
|
|
|
|
m_piece_map[index].have_peers.insert(peer);
|
2015-04-20 06:52:49 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(peer);
|
2013-01-06 05:02:29 +01:00
|
|
|
#endif
|
|
|
|
|
2008-01-31 18:52:29 +01:00
|
|
|
++m_piece_map[index].peer_count;
|
|
|
|
updated = true;
|
2007-04-17 02:20:39 +02:00
|
|
|
}
|
2007-04-15 04:14:02 +02:00
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// if we're already dirty, no point in doing anything more
|
|
|
|
if (m_dirty) return;
|
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
if (updated) m_dirty = true;
|
2007-04-15 04:14:02 +02:00
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::dec_refcount(typed_bitfield<piece_index_t> const& bitmask
|
|
|
|
, const torrent_peer* peer)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2009-05-22 05:36:05 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2009-05-22 05:36:05 +02:00
|
|
|
#endif
|
2016-11-27 14:46:53 +01:00
|
|
|
TORRENT_ASSERT(bitmask.size() <= int(m_piece_map.size()));
|
2007-03-15 23:03:56 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
std::cerr << "[" << this << "] " << "dec_refcount(bitfield)" << std::endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// nothing set, nothing to do here
|
|
|
|
if (bitmask.none_set()) return;
|
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
if (bitmask.all_set() && bitmask.size() == int(m_piece_map.size()))
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
dec_refcount_all(peer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
int const size = std::min(50, bitmask.size() / 2);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// this is an optimization where if just a few
|
|
|
|
// pieces end up changing, instead of making
|
|
|
|
// the piece list dirty, just update those pieces
|
|
|
|
// instead
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ALLOCA(decremented, piece_index_t, size);
|
2014-07-06 21:18:00 +02:00
|
|
|
int num_dec = 0;
|
|
|
|
|
|
|
|
if (!m_dirty)
|
|
|
|
{
|
|
|
|
// first count how many pieces we're updating. If it's few (less than half)
|
2016-07-31 03:53:11 +02:00
|
|
|
// we'll just update them one at a time. Otherwise we'll just update the counters
|
2014-07-06 21:18:00 +02:00
|
|
|
// and mark the picker as dirty, so we'll rebuild it next time we need it.
|
|
|
|
// this only matters if we're not already dirty, in which case the fasted
|
|
|
|
// thing to do is to just update the counters and be done
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t index = piece_index_t(0);
|
|
|
|
for (auto i = bitmask.begin(), end(bitmask.end()); i != end; ++i, ++index)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
if (!*i) continue;
|
|
|
|
if (num_dec < size) decremented[num_dec] = index;
|
|
|
|
++num_dec;
|
|
|
|
if (num_dec >= size) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_dec < size)
|
|
|
|
{
|
|
|
|
// not that many pieces were updated
|
|
|
|
// just update those individually instead of
|
|
|
|
// rebuilding the whole piece list
|
|
|
|
for (int i = 0; i < num_dec; ++i)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t const piece = decremented[i];
|
2014-07-06 21:18:00 +02:00
|
|
|
piece_pos& p = m_piece_map[piece];
|
|
|
|
int prev_priority = p.priority(this);
|
|
|
|
|
|
|
|
if (p.peer_count == 0)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(m_seeds > 0);
|
|
|
|
// this is the case where we have one or more
|
|
|
|
// seeds, and one of them saying: I don't have this
|
|
|
|
// piece anymore. we need to break up one of the seed
|
|
|
|
// counters into actual peer counters on the pieces
|
|
|
|
break_one_seed();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TORRENT_DEBUG_REFCOUNTS
|
|
|
|
TORRENT_ASSERT(p.have_peers.count(peer) == 1);
|
|
|
|
p.have_peers.erase(peer);
|
2015-04-20 06:52:49 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(peer);
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
TORRENT_ASSERT(p.peer_count > 0);
|
|
|
|
--p.peer_count;
|
|
|
|
if (!m_dirty && prev_priority >= 0) update(prev_priority, p.index);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t index = piece_index_t(0);
|
2008-01-31 18:52:29 +01:00
|
|
|
bool updated = false;
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto i = bitmask.begin(), end(bitmask.end()); i != end; ++i, ++index)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
|
|
|
if (*i)
|
|
|
|
{
|
2012-05-14 06:48:23 +02:00
|
|
|
piece_pos& p = m_piece_map[index];
|
|
|
|
if (p.peer_count == 0)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(m_seeds > 0);
|
|
|
|
// this is the case where we have one or more
|
|
|
|
// seeds, and one of them saying: I don't have this
|
|
|
|
// piece anymore. we need to break up one of the seed
|
|
|
|
// counters into actual peer counters on the pieces
|
|
|
|
break_one_seed();
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifdef TORRENT_DEBUG_REFCOUNTS
|
|
|
|
TORRENT_ASSERT(p.have_peers.count(peer) == 1);
|
|
|
|
p.have_peers.erase(peer);
|
2015-04-20 06:52:49 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(peer);
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
TORRENT_ASSERT(p.peer_count > 0);
|
2012-05-14 06:48:23 +02:00
|
|
|
--p.peer_count;
|
2008-01-31 18:52:29 +01:00
|
|
|
updated = true;
|
|
|
|
}
|
|
|
|
}
|
2005-09-01 23:04:21 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// if we're already dirty, no point in doing anything more
|
|
|
|
if (m_dirty) return;
|
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
if (updated) m_dirty = true;
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
2005-09-01 23:04:21 +02:00
|
|
|
|
2008-01-31 18:52:29 +01:00
|
|
|
void piece_picker::update_pieces() const
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(m_dirty);
|
2016-12-26 17:25:50 +01:00
|
|
|
if (m_priority_boundaries.empty()) m_priority_boundaries.resize(1, prio_index_t(0));
|
2008-01-31 18:52:29 +01:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2014-07-06 21:18:00 +02:00
|
|
|
std::cerr << "[" << this << "] " << "update_pieces" << std::endl;
|
2008-01-31 18:52:29 +01:00
|
|
|
#endif
|
2016-12-26 17:25:50 +01:00
|
|
|
|
|
|
|
// This code is unfortunately not very straight-forward. What we do here
|
|
|
|
// is to count the number of pieces at every priority level. After this
|
|
|
|
// first step, m_priority_boundaries will contain *deltas* rather than
|
|
|
|
// absolute indices. This is fixed up in a second pass below
|
|
|
|
std::fill(m_priority_boundaries.begin(), m_priority_boundaries.end(), prio_index_t(0));
|
|
|
|
for (auto& pos : m_piece_map)
|
2007-03-15 23:03:56 +01:00
|
|
|
{
|
2016-12-26 17:25:50 +01:00
|
|
|
int prio = pos.priority(this);
|
2008-01-31 18:52:29 +01:00
|
|
|
if (prio == -1) continue;
|
2016-08-02 13:20:13 +02:00
|
|
|
if (prio >= int(m_priority_boundaries.size()))
|
2016-12-26 17:25:50 +01:00
|
|
|
m_priority_boundaries.resize(prio + 1, prio_index_t(0));
|
|
|
|
pos.index = m_priority_boundaries[prio];
|
2016-08-02 13:20:13 +02:00
|
|
|
++m_priority_boundaries[prio];
|
2007-03-15 23:03:56 +01:00
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
|
|
|
|
2016-12-26 17:25:50 +01:00
|
|
|
// m_priority_boundaries just contain counters of
|
|
|
|
// each priority level at this point. Now, make the m_priority_boundaries
|
|
|
|
// be cumulative indices into m_pieces (but m_pieces hasn't been set up
|
|
|
|
// yet)
|
2016-12-22 16:42:33 +01:00
|
|
|
int new_size = 0;
|
2016-12-26 17:25:50 +01:00
|
|
|
for (prio_index_t& b : m_priority_boundaries)
|
2007-03-15 23:03:56 +01:00
|
|
|
{
|
2016-12-26 17:25:50 +01:00
|
|
|
new_size += static_cast<int>(b);
|
|
|
|
b = prio_index_t(new_size);
|
2007-03-15 23:03:56 +01:00
|
|
|
}
|
2016-12-22 16:42:33 +01:00
|
|
|
m_pieces.resize(new_size, piece_index_t(0));
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2008-01-31 18:52:29 +01:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
2003-10-23 01:00:57 +02:00
|
|
|
#endif
|
|
|
|
|
2016-12-26 17:25:50 +01:00
|
|
|
// set up m_pieces to contain valid piece indices, based on piece
|
|
|
|
// priority. m_piece_map[].index is still just an index relative to the
|
|
|
|
// respective priority range.
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t piece = piece_index_t(0);
|
2016-12-26 17:25:50 +01:00
|
|
|
for (auto i = m_piece_map.begin(), end(m_piece_map.end()); i != end; ++i, ++piece)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
|
|
|
piece_pos& p = *i;
|
2016-08-07 22:05:20 +02:00
|
|
|
int const prio = p.priority(this);
|
2008-01-31 18:52:29 +01:00
|
|
|
if (prio == -1) continue;
|
2016-12-26 17:25:50 +01:00
|
|
|
prio_index_t const new_index(priority_begin(prio)
|
|
|
|
+ prio_index_t::diff_type(static_cast<int>(p.index)));
|
2016-12-22 16:42:33 +01:00
|
|
|
m_pieces[new_index] = piece;
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2016-12-26 17:25:50 +01:00
|
|
|
prio_index_t start(0);
|
|
|
|
for (auto b : m_priority_boundaries)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
if (start == b) continue;
|
2016-12-26 17:25:50 +01:00
|
|
|
auto r = range(m_pieces, start, b);
|
|
|
|
aux::random_shuffle(r.begin(), r.end());
|
2016-08-02 13:20:13 +02:00
|
|
|
start = b;
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
2005-09-01 23:04:21 +02:00
|
|
|
|
2016-12-26 17:25:50 +01:00
|
|
|
// this is where we set fix up the m_piece_map[].index to actually map
|
|
|
|
// back to the piece list ordered by priority (m_pieces)
|
|
|
|
prio_index_t index(0);
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto p : m_pieces)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
m_piece_map[p].index = index;
|
|
|
|
++index;
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
2005-09-01 23:04:21 +02:00
|
|
|
|
2008-01-31 18:52:29 +01:00
|
|
|
m_dirty = false;
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
print_pieces();
|
|
|
|
#endif
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::piece_passed(piece_index_t const index)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_pos& p = m_piece_map[index];
|
2015-01-26 03:04:58 +01:00
|
|
|
int download_state = p.download_queue();
|
2015-02-12 04:16:53 +01:00
|
|
|
|
|
|
|
// this is kind of odd. Could this happen?
|
|
|
|
TORRENT_ASSERT(download_state != piece_pos::piece_open);
|
2015-01-26 03:04:58 +01:00
|
|
|
if (download_state == piece_pos::piece_open) return;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
auto const i = find_dl_piece(download_state, index);
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[download_state].end());
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
TORRENT_ASSERT(i->locked == false);
|
|
|
|
if (i->locked) return;
|
|
|
|
|
|
|
|
TORRENT_ASSERT(!i->passed_hash_check);
|
|
|
|
i->passed_hash_check = true;
|
|
|
|
++m_num_passed;
|
|
|
|
|
|
|
|
if (i->finished < blocks_in_piece(index)) return;
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
we_have(index);
|
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::we_dont_have(piece_index_t const index)
|
2008-06-07 04:58:28 +02:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_pos& p = m_piece_map[index];
|
2008-06-07 04:58:28 +02:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2015-04-20 06:52:49 +02:00
|
|
|
std::cerr << "[" << this << "] " << "piece_picker::we_dont_have("
|
|
|
|
<< index << ")" << std::endl;
|
2008-09-06 23:04:57 +02:00
|
|
|
#endif
|
2015-04-20 06:52:49 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!p.have())
|
|
|
|
{
|
|
|
|
// even though we don't have the piece, it
|
|
|
|
// might still have passed hash check
|
2015-01-26 03:04:58 +01:00
|
|
|
int download_state = p.download_queue();
|
|
|
|
if (download_state == piece_pos::piece_open) return;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
auto const i = find_dl_piece(download_state, index);
|
2014-07-06 21:18:00 +02:00
|
|
|
if (i->passed_hash_check)
|
|
|
|
{
|
|
|
|
i->passed_hash_check = false;
|
|
|
|
TORRENT_ASSERT(m_num_passed > 0);
|
|
|
|
--m_num_passed;
|
|
|
|
}
|
2015-02-12 07:43:46 +01:00
|
|
|
erase_download_piece(i);
|
2014-07-06 21:18:00 +02:00
|
|
|
return;
|
|
|
|
}
|
2008-06-07 04:58:28 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(m_num_passed > 0);
|
|
|
|
--m_num_passed;
|
2008-06-07 04:58:28 +02:00
|
|
|
if (p.filtered())
|
|
|
|
{
|
|
|
|
++m_num_filtered;
|
|
|
|
--m_num_have_filtered;
|
|
|
|
}
|
2008-09-06 23:04:57 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// update cursors
|
2016-12-22 16:42:33 +01:00
|
|
|
if (index < m_cursor) m_cursor = index;
|
|
|
|
if (index >= m_reverse_cursor) m_reverse_cursor = next(index);
|
2008-09-06 23:04:57 +02:00
|
|
|
if (m_reverse_cursor == m_cursor)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
m_reverse_cursor = piece_index_t(0);
|
|
|
|
m_cursor = m_piece_map.end_index();
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
|
|
|
}
|
2008-06-07 04:58:28 +02:00
|
|
|
|
|
|
|
--m_num_have;
|
|
|
|
p.set_not_have();
|
|
|
|
|
|
|
|
if (m_dirty) return;
|
2008-06-12 17:40:50 +02:00
|
|
|
if (p.priority(this) >= 0) add(index);
|
2008-06-07 04:58:28 +02:00
|
|
|
}
|
|
|
|
|
2016-07-31 03:53:11 +02:00
|
|
|
// this is used to indicate that we successfully have
|
2005-05-25 12:01:01 +02:00
|
|
|
// downloaded a piece, and that no further attempts
|
|
|
|
// to pick that piece should be made. The piece will
|
|
|
|
// be removed from the available piece list.
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::we_have(piece_index_t const index)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-10-06 01:28:57 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2008-10-06 01:28:57 +02:00
|
|
|
#endif
|
2008-09-06 23:04:57 +02:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2015-04-20 06:52:49 +02:00
|
|
|
std::cerr << "[" << this << "] " << "piece_picker::we_have("
|
|
|
|
<< index << ")" << std::endl;
|
2008-09-06 23:04:57 +02:00
|
|
|
#endif
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_pos& p = m_piece_map[index];
|
2016-12-26 17:25:50 +01:00
|
|
|
prio_index_t const info_index = p.index;
|
2016-08-07 22:05:20 +02:00
|
|
|
int const priority = p.priority(this);
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(priority < int(m_priority_boundaries.size()) || m_dirty);
|
2007-03-15 23:03:56 +01:00
|
|
|
|
2015-02-12 04:16:53 +01:00
|
|
|
if (p.have()) return;
|
|
|
|
|
2015-02-15 23:01:15 +01:00
|
|
|
int state = p.download_queue();
|
|
|
|
if (state != piece_pos::piece_open)
|
2007-11-04 20:10:58 +01:00
|
|
|
{
|
2016-11-27 14:46:53 +01:00
|
|
|
auto const i = find_dl_piece(state, index);
|
2015-02-15 23:01:15 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[state].end());
|
2014-07-06 21:18:00 +02:00
|
|
|
// decrement num_passed here to compensate
|
|
|
|
// for the unconditional increment further down
|
|
|
|
if (i->passed_hash_check) --m_num_passed;
|
2007-11-04 20:10:58 +01:00
|
|
|
erase_download_piece(i);
|
|
|
|
}
|
2007-03-30 05:09:28 +02:00
|
|
|
|
2007-03-15 23:03:56 +01:00
|
|
|
if (p.filtered())
|
2005-05-30 19:43:03 +02:00
|
|
|
{
|
|
|
|
--m_num_filtered;
|
|
|
|
++m_num_have_filtered;
|
|
|
|
}
|
2007-05-14 12:54:18 +02:00
|
|
|
++m_num_have;
|
2014-07-06 21:18:00 +02:00
|
|
|
++m_num_passed;
|
2007-03-15 23:03:56 +01:00
|
|
|
p.set_have();
|
2016-12-22 16:42:33 +01:00
|
|
|
if (m_cursor == prev(m_reverse_cursor)
|
|
|
|
&& m_cursor == index)
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
m_cursor = m_piece_map.end_index();
|
|
|
|
m_reverse_cursor = piece_index_t(0);
|
2008-09-06 23:04:57 +02:00
|
|
|
TORRENT_ASSERT(num_pieces() > 0);
|
|
|
|
}
|
|
|
|
else if (m_cursor == index)
|
|
|
|
{
|
|
|
|
++m_cursor;
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto i = m_piece_map.begin() + static_cast<int>(m_cursor)
|
2008-09-06 23:04:57 +02:00
|
|
|
, end(m_piece_map.end()); i != end && (i->have() || i->filtered());
|
|
|
|
++i, ++m_cursor);
|
|
|
|
}
|
2016-12-22 16:42:33 +01:00
|
|
|
else if (prev(m_reverse_cursor) == index)
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
|
|
|
--m_reverse_cursor;
|
|
|
|
TORRENT_ASSERT(m_piece_map[m_reverse_cursor].have()
|
|
|
|
|| m_piece_map[m_reverse_cursor].filtered());
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto i = m_piece_map.begin() + static_cast<int>(m_reverse_cursor) - 1;
|
|
|
|
m_reverse_cursor > piece_index_t(0) && (i->have() || i->filtered());
|
2008-09-06 23:04:57 +02:00
|
|
|
--i, --m_reverse_cursor);
|
|
|
|
TORRENT_ASSERT(m_piece_map[m_reverse_cursor].have()
|
|
|
|
|| m_piece_map[m_reverse_cursor].filtered());
|
|
|
|
}
|
|
|
|
TORRENT_ASSERT(m_reverse_cursor > m_cursor
|
2016-12-22 16:42:33 +01:00
|
|
|
|| (m_cursor == m_piece_map.end_index() && m_reverse_cursor == piece_index_t(0)));
|
2008-01-31 18:52:29 +01:00
|
|
|
if (priority == -1) return;
|
|
|
|
if (m_dirty) return;
|
|
|
|
remove(priority, info_index);
|
|
|
|
TORRENT_ASSERT(p.priority(this) == -1);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2017-10-29 00:44:40 +02:00
|
|
|
bool piece_picker::set_piece_priority(piece_index_t const index
|
|
|
|
, download_priority_t const new_piece_priority)
|
2005-05-25 12:01:01 +02:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2015-04-20 06:52:49 +02:00
|
|
|
std::cerr << "[" << this << "] " << "set_piece_priority(" << index
|
|
|
|
<< ", " << new_piece_priority << ")" << std::endl;
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
2015-01-26 03:04:58 +01:00
|
|
|
|
2017-10-29 00:44:40 +02:00
|
|
|
TORRENT_ASSERT(new_piece_priority >= dont_download);
|
|
|
|
TORRENT_ASSERT(new_piece_priority <= top_priority);
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
piece_pos& p = m_piece_map[index];
|
2007-03-21 03:09:50 +01:00
|
|
|
|
2007-03-15 23:03:56 +01:00
|
|
|
// if the priority isn't changed, don't do anything
|
2017-10-29 00:44:40 +02:00
|
|
|
if (new_piece_priority == download_priority_t(p.piece_priority)) return false;
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2017-10-29 00:44:40 +02:00
|
|
|
int const prev_priority = p.priority(this);
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(m_dirty || prev_priority < int(m_priority_boundaries.size()));
|
2007-03-21 03:09:50 +01:00
|
|
|
|
2007-08-10 23:13:35 +02:00
|
|
|
bool ret = false;
|
2017-10-29 00:44:40 +02:00
|
|
|
if (new_piece_priority == dont_download
|
2007-03-15 23:03:56 +01:00
|
|
|
&& p.piece_priority != piece_pos::filter_priority)
|
2005-05-30 19:43:03 +02:00
|
|
|
{
|
2007-03-15 23:03:56 +01:00
|
|
|
// the piece just got filtered
|
2008-09-06 23:04:57 +02:00
|
|
|
if (p.have())
|
|
|
|
{
|
|
|
|
++m_num_have_filtered;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++m_num_filtered;
|
|
|
|
|
|
|
|
// update m_cursor
|
2016-12-22 16:42:33 +01:00
|
|
|
if (m_cursor == prev(m_reverse_cursor) && m_cursor == index)
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
m_cursor = m_piece_map.end_index();
|
|
|
|
m_reverse_cursor = piece_index_t(0);
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
|
|
|
else if (m_cursor == index)
|
|
|
|
{
|
|
|
|
++m_cursor;
|
2016-12-22 16:42:33 +01:00
|
|
|
while (m_cursor < m_piece_map.end_index()
|
2008-09-06 23:04:57 +02:00
|
|
|
&& (m_piece_map[m_cursor].have()
|
|
|
|
|| m_piece_map[m_cursor].filtered()))
|
|
|
|
++m_cursor;
|
|
|
|
}
|
2016-12-22 16:42:33 +01:00
|
|
|
else if (m_reverse_cursor == next(index))
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
|
|
|
--m_reverse_cursor;
|
2016-12-22 16:42:33 +01:00
|
|
|
while (m_reverse_cursor > piece_index_t(0)
|
|
|
|
&& (m_piece_map[prev(m_reverse_cursor)].have()
|
|
|
|
|| m_piece_map[prev(m_reverse_cursor)].filtered()))
|
2008-09-06 23:04:57 +02:00
|
|
|
--m_reverse_cursor;
|
|
|
|
}
|
|
|
|
}
|
2007-08-10 23:13:35 +02:00
|
|
|
ret = true;
|
2007-03-15 23:03:56 +01:00
|
|
|
}
|
2017-10-29 00:44:40 +02:00
|
|
|
else if (new_piece_priority != dont_download
|
2007-03-15 23:03:56 +01:00
|
|
|
&& p.piece_priority == piece_pos::filter_priority)
|
|
|
|
{
|
|
|
|
// the piece just got unfiltered
|
2008-09-06 23:04:57 +02:00
|
|
|
if (p.have())
|
|
|
|
{
|
|
|
|
--m_num_have_filtered;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
--m_num_filtered;
|
|
|
|
// update cursors
|
2016-12-22 16:42:33 +01:00
|
|
|
if (index < m_cursor) m_cursor = index;
|
|
|
|
if (index >= m_reverse_cursor) m_reverse_cursor = next(index);
|
2008-09-06 23:04:57 +02:00
|
|
|
if (m_reverse_cursor == m_cursor)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
m_reverse_cursor = piece_index_t(0);
|
|
|
|
m_cursor = m_piece_map.end_index();
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
|
|
|
}
|
2007-08-10 23:13:35 +02:00
|
|
|
ret = true;
|
2007-03-15 23:03:56 +01:00
|
|
|
}
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_num_filtered >= 0);
|
|
|
|
TORRENT_ASSERT(m_num_have_filtered >= 0);
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2017-10-29 00:44:40 +02:00
|
|
|
p.piece_priority = static_cast<std::uint8_t>(new_piece_priority);
|
2016-08-07 22:05:20 +02:00
|
|
|
int const new_priority = p.priority(this);
|
|
|
|
|
|
|
|
if (prev_priority != new_priority && !m_dirty)
|
|
|
|
{
|
|
|
|
if (prev_priority == -1) add(index);
|
|
|
|
else update(prev_priority, p.index);
|
|
|
|
}
|
2007-03-15 23:03:56 +01:00
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
if (p.downloading())
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2018-01-11 01:35:15 +01:00
|
|
|
auto i = find_dl_piece(p.download_queue(), index);
|
2015-01-26 03:04:58 +01:00
|
|
|
if (i != m_downloads[p.download_queue()].end())
|
2014-07-06 21:18:00 +02:00
|
|
|
update_piece_state(i);
|
|
|
|
}
|
|
|
|
|
2007-08-10 23:13:35 +02:00
|
|
|
return ret;
|
2005-05-25 12:01:01 +02:00
|
|
|
}
|
|
|
|
|
2017-10-29 00:44:40 +02:00
|
|
|
download_priority_t piece_picker::piece_priority(piece_index_t const index) const
|
2005-05-25 12:01:01 +02:00
|
|
|
{
|
2017-10-29 00:44:40 +02:00
|
|
|
return download_priority_t(m_piece_map[index].piece_priority);
|
2005-05-25 12:01:01 +02:00
|
|
|
}
|
|
|
|
|
2017-10-29 00:44:40 +02:00
|
|
|
void piece_picker::piece_priorities(std::vector<download_priority_t>& pieces) const
|
2007-03-20 02:59:00 +01:00
|
|
|
{
|
|
|
|
pieces.resize(m_piece_map.size());
|
2016-12-22 16:42:33 +01:00
|
|
|
auto j = pieces.begin();
|
|
|
|
for (auto i = m_piece_map.begin(),
|
2007-03-20 02:59:00 +01:00
|
|
|
end(m_piece_map.end()); i != end; ++i, ++j)
|
|
|
|
{
|
2017-10-29 00:44:40 +02:00
|
|
|
*j = download_priority_t(i->piece_priority);
|
2007-03-20 02:59:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-12 19:00:57 +02:00
|
|
|
namespace {
|
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
int append_blocks(std::vector<piece_block>& dst, std::vector<piece_block>& src
|
2016-04-06 06:45:21 +02:00
|
|
|
, int const num_blocks)
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
|
|
|
if (src.empty()) return num_blocks;
|
2016-04-06 06:45:21 +02:00
|
|
|
int const to_copy = (std::min)(int(src.size()), num_blocks);
|
|
|
|
|
|
|
|
dst.insert(dst.end(), src.begin(), src.begin() + to_copy);
|
|
|
|
src.erase(src.begin(), src.begin() + to_copy);
|
2008-09-06 23:04:57 +02:00
|
|
|
return num_blocks - to_copy;
|
|
|
|
}
|
2015-02-08 19:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// lower availability comes first. This is a less-than comparison, it returns
|
|
|
|
// true if lhs has lower availability than rhs
|
|
|
|
bool piece_picker::partial_compare_rarest_first(downloading_piece const* lhs
|
|
|
|
, downloading_piece const* rhs) const
|
|
|
|
{
|
|
|
|
int lhs_availability = m_piece_map[lhs->index].peer_count;
|
|
|
|
int rhs_availability = m_piece_map[rhs->index].peer_count;
|
|
|
|
if (lhs_availability != rhs_availability)
|
|
|
|
return lhs_availability < rhs_availability;
|
|
|
|
|
|
|
|
// if the availability is the same, prefer the piece that's closest to
|
|
|
|
// being complete.
|
|
|
|
int lhs_blocks_left = m_blocks_per_piece - lhs->finished - lhs->writing
|
|
|
|
- lhs->requested;
|
|
|
|
TORRENT_ASSERT(lhs_blocks_left > 0);
|
|
|
|
int rhs_blocks_left = m_blocks_per_piece - rhs->finished - rhs->writing
|
|
|
|
- rhs->requested;
|
|
|
|
TORRENT_ASSERT(rhs_blocks_left > 0);
|
|
|
|
return lhs_blocks_left < rhs_blocks_left;
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
// pieces describes which pieces the peer we're requesting from has.
|
|
|
|
// interesting_blocks is an out parameter, and will be filled with (up to)
|
|
|
|
// num_blocks of interesting blocks that the peer has.
|
|
|
|
// prefer_contiguous_blocks can be set if this peer should download whole
|
|
|
|
// pieces rather than trying to download blocks from the same piece as other
|
2015-08-18 10:25:13 +02:00
|
|
|
// peers. the peer argument is the torrent_peer of the peer we're
|
2015-01-26 03:04:58 +01:00
|
|
|
// picking pieces from. This is used when downloading whole pieces, to only
|
|
|
|
// pick from the same piece the same peer is downloading from.
|
2008-09-06 23:04:57 +02:00
|
|
|
|
|
|
|
// options are:
|
|
|
|
// * rarest_first
|
|
|
|
// pick the rarest pieces first
|
|
|
|
// * reverse
|
|
|
|
// reverse the piece picking. Pick the most common
|
|
|
|
// pieces first or the last pieces (if picking sequential)
|
|
|
|
// * sequential
|
|
|
|
// download pieces in-order
|
|
|
|
// * on_parole
|
|
|
|
// the peer is on parole, only pick whole pieces which
|
|
|
|
// has only been downloaded and requested from the same
|
|
|
|
// peer
|
|
|
|
// * prioritize_partials
|
|
|
|
// pick blocks from downloading pieces first
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
// only one of rarest_first or sequential can be set
|
2008-09-06 23:04:57 +02:00
|
|
|
|
2017-07-23 09:55:40 +02:00
|
|
|
// the return value is a combination of picker_flags_t,
|
2016-07-31 03:53:11 +02:00
|
|
|
// indicating which path thought the picker we took to arrive at the
|
2015-11-29 06:58:46 +01:00
|
|
|
// returned block picks.
|
2017-07-23 09:55:40 +02:00
|
|
|
picker_flags_t piece_picker::pick_pieces(typed_bitfield<piece_index_t> const& pieces
|
2008-09-06 23:04:57 +02:00
|
|
|
, std::vector<piece_block>& interesting_blocks, int num_blocks
|
2015-08-18 10:25:13 +02:00
|
|
|
, int prefer_contiguous_blocks, torrent_peer* peer
|
2018-01-28 14:39:43 +01:00
|
|
|
, picker_options_t options, std::vector<piece_index_t> const& suggested_pieces
|
2014-07-06 21:18:00 +02:00
|
|
|
, int num_peers
|
|
|
|
, counters& pc
|
|
|
|
) const
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2016-07-09 22:26:26 +02:00
|
|
|
TORRENT_ASSERT(peer == nullptr || peer->in_use);
|
2017-07-23 09:55:40 +02:00
|
|
|
picker_flags_t ret;
|
2012-04-12 19:10:22 +02:00
|
|
|
|
2008-09-22 02:41:36 +02:00
|
|
|
// prevent the number of partial pieces to grow indefinitely
|
2011-08-15 01:16:12 +02:00
|
|
|
// make this scale by the number of peers we have. For large
|
|
|
|
// scale clients, we would have more peers, and allow a higher
|
|
|
|
// threshold for the number of partials
|
2015-02-08 17:52:57 +01:00
|
|
|
// deduct pad files because they case partial pieces which are OK
|
|
|
|
// the second condition is to make sure we cap the number of partial
|
|
|
|
// _bytes_. The larger the pieces are, the fewer partial pieces we want.
|
|
|
|
// 2048 corresponds to 32 MiB
|
|
|
|
// TODO: 2 make the 2048 limit configurable
|
|
|
|
const int num_partials = int(m_downloads[piece_pos::piece_downloading].size())
|
|
|
|
- m_num_pad_files;
|
|
|
|
if (num_partials > num_peers * 3 / 2
|
|
|
|
|| num_partials * m_blocks_per_piece > 2048)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
// if we have too many partial pieces, prioritize completing
|
|
|
|
// them. In order for this to have an affect, also disable
|
|
|
|
// prefer whole pieces (otherwise partial pieces would be de-prioritized)
|
|
|
|
options |= prioritize_partials;
|
2015-01-20 03:34:55 +01:00
|
|
|
prefer_contiguous_blocks = 0;
|
2015-11-29 06:58:46 +01:00
|
|
|
|
|
|
|
ret |= picker_log_alert::partial_ratio;
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2008-09-22 02:41:36 +02:00
|
|
|
|
2015-11-29 06:58:46 +01:00
|
|
|
if (prefer_contiguous_blocks) ret |= picker_log_alert::prefer_contiguous;
|
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
// only one of rarest_first and sequential can be set.
|
2011-02-21 06:24:41 +01:00
|
|
|
TORRENT_ASSERT(((options & rarest_first) ? 1 : 0)
|
|
|
|
+ ((options & sequential) ? 1 : 0) <= 1);
|
2008-10-10 07:25:55 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2008-10-10 07:25:55 +02:00
|
|
|
#endif
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(num_blocks > 0);
|
2016-11-27 14:46:53 +01:00
|
|
|
TORRENT_ASSERT(pieces.size() == int(m_piece_map.size()));
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(!m_priority_boundaries.empty() || m_dirty);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2007-04-27 02:27:37 +02:00
|
|
|
// this will be filled with blocks that we should not request
|
|
|
|
// unless we can't find num_blocks among the other ones.
|
2005-08-15 00:04:58 +02:00
|
|
|
std::vector<piece_block> backup_blocks;
|
2008-09-06 23:04:57 +02:00
|
|
|
std::vector<piece_block> backup_blocks2;
|
2016-12-22 16:42:33 +01:00
|
|
|
static const std::vector<piece_index_t> empty_vector;
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2015-01-20 03:34:55 +01:00
|
|
|
// When prefer_contiguous_blocks is set (usually set when downloading from
|
2007-08-03 08:13:26 +02:00
|
|
|
// fast peers) the partial pieces will not be prioritized, but actually
|
|
|
|
// ignored as long as possible. All blocks found in downloading
|
|
|
|
// pieces are regarded as backup blocks
|
2007-09-05 23:21:11 +02:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
if (options & prioritize_partials)
|
|
|
|
{
|
2015-02-08 19:01:29 +01:00
|
|
|
// first, allocate a small array on the stack of all the partial
|
|
|
|
// pieces (downloading_piece). We'll then sort this list by
|
|
|
|
// availability or by some other condition. The list of partial pieces
|
|
|
|
// in m_downloads is ordered by piece index, this is to have O(log n)
|
|
|
|
// lookups when finding a downloading_piece for a specific piece index.
|
|
|
|
// this is important and needs to stay sorted that way, that's why
|
|
|
|
// we're copying it here
|
2016-10-22 20:43:40 +02:00
|
|
|
TORRENT_ALLOCA(ordered_partials, downloading_piece const*
|
|
|
|
, m_downloads[piece_pos::piece_downloading].size());
|
2015-02-08 19:01:29 +01:00
|
|
|
int num_ordered_partials = 0;
|
|
|
|
|
|
|
|
// now, copy over the pointers. We also apply a filter here to not
|
|
|
|
// include ineligible pieces in certain modes. For instance, a piece
|
|
|
|
// that the current peer doesn't have is not included.
|
2018-01-11 01:35:15 +01:00
|
|
|
for (auto& dp : m_downloads[piece_pos::piece_downloading])
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2015-02-08 19:01:29 +01:00
|
|
|
pc.inc_stats_counter(counters::piece_picker_partial_loops);
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
// in time critical mode, only pick high priority pieces
|
|
|
|
if ((options & time_critical_mode)
|
2018-01-11 01:35:15 +01:00
|
|
|
&& piece_priority(dp.index) != top_priority)
|
2014-04-22 06:21:14 +02:00
|
|
|
continue;
|
|
|
|
|
2018-01-11 01:35:15 +01:00
|
|
|
if (!is_piece_free(dp.index, pieces)) continue;
|
2015-02-08 19:01:29 +01:00
|
|
|
|
2018-01-11 01:35:15 +01:00
|
|
|
TORRENT_ASSERT(m_piece_map[dp.index].download_queue()
|
2015-01-26 03:04:58 +01:00
|
|
|
== piece_pos::piece_downloading);
|
2011-08-16 08:30:53 +02:00
|
|
|
|
2018-01-11 01:35:15 +01:00
|
|
|
ordered_partials[num_ordered_partials++] = &dp;
|
2015-02-08 19:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// now, sort the list.
|
2015-02-08 22:44:58 +01:00
|
|
|
if (options & rarest_first)
|
|
|
|
{
|
2015-11-29 06:58:46 +01:00
|
|
|
ret |= picker_log_alert::rarest_first_partials;
|
|
|
|
|
2015-02-08 22:44:58 +01:00
|
|
|
// TODO: this could probably be optimized by incrementally
|
|
|
|
// calling partial_sort to sort one more element in the list. Because
|
|
|
|
// chances are that we'll just need a single piece, and once we've
|
|
|
|
// picked from it we're done. Sorting the rest of the list in that
|
|
|
|
// case is a waste of time.
|
2016-10-22 20:43:40 +02:00
|
|
|
std::sort(ordered_partials.begin(), ordered_partials.begin() + num_ordered_partials
|
2016-05-25 06:31:52 +02:00
|
|
|
, std::bind(&piece_picker::partial_compare_rarest_first, this
|
2015-02-08 22:44:58 +01:00
|
|
|
, _1, _2));
|
|
|
|
}
|
2015-02-08 19:01:29 +01:00
|
|
|
|
|
|
|
for (int i = 0; i < num_ordered_partials; ++i)
|
|
|
|
{
|
2015-11-29 06:58:46 +01:00
|
|
|
ret |= picker_log_alert::prioritize_partials;
|
|
|
|
|
2015-02-08 19:01:29 +01:00
|
|
|
num_blocks = add_blocks_downloading(*ordered_partials[i], pieces
|
2008-09-06 23:04:57 +02:00
|
|
|
, interesting_blocks, backup_blocks, backup_blocks2
|
2015-02-08 22:17:00 +01:00
|
|
|
, num_blocks, prefer_contiguous_blocks, peer, options);
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2015-02-08 19:01:29 +01:00
|
|
|
if (int(backup_blocks.size()) >= num_blocks
|
|
|
|
&& int(backup_blocks2.size()) >= num_blocks)
|
|
|
|
break;
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
2007-09-05 23:21:11 +02:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
num_blocks = append_blocks(interesting_blocks, backup_blocks
|
|
|
|
, num_blocks);
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2008-09-06 23:04:57 +02:00
|
|
|
|
|
|
|
num_blocks = append_blocks(interesting_blocks, backup_blocks2
|
|
|
|
, num_blocks);
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
2007-09-05 23:21:11 +02:00
|
|
|
|
2008-01-31 18:52:29 +01:00
|
|
|
if (!suggested_pieces.empty())
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
for (piece_index_t i : suggested_pieces)
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2015-01-26 03:04:58 +01:00
|
|
|
// in time critical mode, only pick high priority pieces
|
|
|
|
if ((options & time_critical_mode)
|
2017-10-29 00:44:40 +02:00
|
|
|
&& piece_priority(i) != top_priority)
|
2014-04-22 06:21:14 +02:00
|
|
|
continue;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
pc.inc_stats_counter(counters::piece_picker_suggest_loops);
|
2016-12-22 16:42:33 +01:00
|
|
|
if (!is_piece_free(i, pieces)) continue;
|
2015-11-29 06:58:46 +01:00
|
|
|
|
|
|
|
ret |= picker_log_alert::suggested_pieces;
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
num_blocks = add_blocks(i, pieces
|
2008-09-06 23:04:57 +02:00
|
|
|
, interesting_blocks, backup_blocks
|
|
|
|
, backup_blocks2, num_blocks
|
2015-01-20 03:34:55 +01:00
|
|
|
, prefer_contiguous_blocks, peer, empty_vector
|
2015-02-08 22:17:00 +01:00
|
|
|
, options);
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
if (options & sequential)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
2014-04-03 04:03:14 +02:00
|
|
|
if (m_dirty) update_pieces();
|
|
|
|
TORRENT_ASSERT(!m_dirty);
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto i = m_pieces.begin();
|
2017-10-29 00:44:40 +02:00
|
|
|
i != m_pieces.end() && piece_priority(*i) == top_priority; ++i)
|
2014-04-03 04:03:14 +02:00
|
|
|
{
|
|
|
|
if (!is_piece_free(*i, pieces)) continue;
|
2015-11-29 06:58:46 +01:00
|
|
|
|
|
|
|
ret |= picker_log_alert::prio_sequential_pieces;
|
|
|
|
|
2014-04-03 04:03:14 +02:00
|
|
|
num_blocks = add_blocks(*i, pieces
|
|
|
|
, interesting_blocks, backup_blocks
|
|
|
|
, backup_blocks2, num_blocks
|
2015-01-20 03:34:55 +01:00
|
|
|
, prefer_contiguous_blocks, peer, suggested_pieces
|
2015-02-08 22:17:00 +01:00
|
|
|
, options);
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2014-04-03 04:03:14 +02:00
|
|
|
}
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
// in time critical mode, only pick high priority pieces
|
2018-01-28 14:39:43 +01:00
|
|
|
if (!(options & time_critical_mode))
|
2007-09-03 09:10:09 +02:00
|
|
|
{
|
2014-04-22 06:21:14 +02:00
|
|
|
if (options & reverse)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
for (piece_index_t i = prev(m_reverse_cursor); i >= m_cursor; --i)
|
2015-06-30 02:40:32 +02:00
|
|
|
{
|
2014-04-22 06:21:14 +02:00
|
|
|
if (!is_piece_free(i, pieces)) continue;
|
2015-01-26 03:04:58 +01:00
|
|
|
// we've already added high priority pieces
|
2017-10-29 00:44:40 +02:00
|
|
|
if (piece_priority(i) == top_priority) continue;
|
2015-11-29 06:58:46 +01:00
|
|
|
|
|
|
|
ret |= picker_log_alert::reverse_sequential;
|
|
|
|
|
2014-04-22 06:21:14 +02:00
|
|
|
num_blocks = add_blocks(i, pieces
|
|
|
|
, interesting_blocks, backup_blocks
|
|
|
|
, backup_blocks2, num_blocks
|
2015-01-20 03:34:55 +01:00
|
|
|
, prefer_contiguous_blocks, peer, suggested_pieces
|
2015-02-08 22:17:00 +01:00
|
|
|
, options);
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2014-04-22 06:21:14 +02:00
|
|
|
}
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
2014-04-22 06:21:14 +02:00
|
|
|
else
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
for (piece_index_t i = m_cursor; i < m_reverse_cursor; ++i)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2014-04-22 06:21:14 +02:00
|
|
|
if (!is_piece_free(i, pieces)) continue;
|
2015-01-26 03:04:58 +01:00
|
|
|
// we've already added high priority pieces
|
2017-10-29 00:44:40 +02:00
|
|
|
if (piece_priority(i) == top_priority) continue;
|
2015-11-29 06:58:46 +01:00
|
|
|
|
|
|
|
ret |= picker_log_alert::sequential_pieces;
|
|
|
|
|
2014-04-22 06:21:14 +02:00
|
|
|
num_blocks = add_blocks(i, pieces
|
|
|
|
, interesting_blocks, backup_blocks
|
|
|
|
, backup_blocks2, num_blocks
|
2015-01-20 03:34:55 +01:00
|
|
|
, prefer_contiguous_blocks, peer, suggested_pieces
|
2015-02-08 22:17:00 +01:00
|
|
|
, options);
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2014-04-22 06:21:14 +02:00
|
|
|
}
|
2007-09-05 23:21:11 +02:00
|
|
|
}
|
2007-09-03 09:10:09 +02:00
|
|
|
}
|
|
|
|
}
|
2008-09-06 23:04:57 +02:00
|
|
|
else if (options & rarest_first)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
|
|
|
if (m_dirty) update_pieces();
|
2008-09-06 23:04:57 +02:00
|
|
|
TORRENT_ASSERT(!m_dirty);
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
// in time critical mode, we're only allowed to pick high priority
|
2014-04-22 06:21:14 +02:00
|
|
|
// pieces. This is why reverse mode is disabled when we're in
|
2015-01-26 03:04:58 +01:00
|
|
|
// time-critical mode, because all high priority pieces are at the
|
|
|
|
// front of the list
|
2018-01-28 14:39:43 +01:00
|
|
|
if ((options & reverse) && !(options & time_critical_mode))
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
for (int i = int(m_priority_boundaries.size()) - 1; i >= 0; --i)
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2016-12-26 17:25:50 +01:00
|
|
|
prio_index_t const start = priority_begin(i);
|
|
|
|
prio_index_t const end = priority_end(i);
|
|
|
|
for (prio_index_t p = prev(end); p >= start; --p)
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
pc.inc_stats_counter(counters::piece_picker_reverse_rare_loops);
|
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
if (!is_piece_free(m_pieces[p], pieces)) continue;
|
2015-11-29 06:58:46 +01:00
|
|
|
|
|
|
|
ret |= picker_log_alert::reverse_rarest_first;
|
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
num_blocks = add_blocks(m_pieces[p], pieces
|
|
|
|
, interesting_blocks, backup_blocks
|
|
|
|
, backup_blocks2, num_blocks
|
2015-01-20 03:34:55 +01:00
|
|
|
, prefer_contiguous_blocks, peer, suggested_pieces
|
2015-02-08 22:17:00 +01:00
|
|
|
, options);
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
for (piece_index_t i : m_pieces)
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
pc.inc_stats_counter(counters::piece_picker_rare_loops);
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
// in time critical mode, only pick high priority pieces
|
2014-04-22 06:21:14 +02:00
|
|
|
// it's safe to break here because in this mode we
|
|
|
|
// pick pieces in priority order. Once we hit a lower priority
|
2015-01-26 03:04:58 +01:00
|
|
|
// piece, we won't encounter any more high priority ones
|
|
|
|
if ((options & time_critical_mode)
|
2017-10-29 00:44:40 +02:00
|
|
|
&& piece_priority(i) != top_priority)
|
2014-04-22 06:21:14 +02:00
|
|
|
break;
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
if (!is_piece_free(i, pieces)) continue;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-11-29 06:58:46 +01:00
|
|
|
ret |= picker_log_alert::rarest_first;
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
num_blocks = add_blocks(i, pieces
|
2008-09-06 23:04:57 +02:00
|
|
|
, interesting_blocks, backup_blocks
|
|
|
|
, backup_blocks2, num_blocks
|
2015-01-20 03:34:55 +01:00
|
|
|
, prefer_contiguous_blocks, peer, suggested_pieces
|
2015-02-08 22:17:00 +01:00
|
|
|
, options);
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
|
|
|
}
|
2008-01-31 18:52:29 +01:00
|
|
|
}
|
2014-04-22 06:21:14 +02:00
|
|
|
else if (options & time_critical_mode)
|
|
|
|
{
|
|
|
|
// if we're in time-critical mode, we are only allowed to pick
|
2015-01-26 03:04:58 +01:00
|
|
|
// high priority pieces.
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto i = m_pieces.begin();
|
2017-10-29 00:44:40 +02:00
|
|
|
i != m_pieces.end() && piece_priority(*i) == top_priority; ++i)
|
2014-04-22 06:21:14 +02:00
|
|
|
{
|
|
|
|
if (!is_piece_free(*i, pieces)) continue;
|
2015-11-29 06:58:46 +01:00
|
|
|
|
|
|
|
ret |= picker_log_alert::time_critical;
|
|
|
|
|
2014-04-22 06:21:14 +02:00
|
|
|
num_blocks = add_blocks(*i, pieces
|
|
|
|
, interesting_blocks, backup_blocks
|
|
|
|
, backup_blocks2, num_blocks
|
2015-01-20 03:34:55 +01:00
|
|
|
, prefer_contiguous_blocks, peer, suggested_pieces
|
2015-02-08 22:17:00 +01:00
|
|
|
, options);
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2014-04-22 06:21:14 +02:00
|
|
|
}
|
|
|
|
}
|
2007-09-03 09:10:09 +02:00
|
|
|
else
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2007-07-07 03:26:30 +02:00
|
|
|
// we're not using rarest first (only for the first
|
|
|
|
// bucket, since that's where the currently downloading
|
|
|
|
// pieces are)
|
2017-02-08 16:54:55 +01:00
|
|
|
piece_index_t const start_piece = piece_index_t(int(random(aux::numeric_cast<std::uint32_t>(m_piece_map.size() - 1))));
|
2007-09-05 23:21:11 +02:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t piece = start_piece;
|
2007-07-07 03:26:30 +02:00
|
|
|
while (num_blocks > 0)
|
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
// skip pieces we can't pick, and suggested pieces
|
|
|
|
// since we've already picked those
|
2015-02-08 22:12:10 +01:00
|
|
|
while (!is_piece_free(piece, pieces)
|
2009-06-28 02:32:14 +02:00
|
|
|
|| std::find(suggested_pieces.begin()
|
2014-07-06 21:18:00 +02:00
|
|
|
, suggested_pieces.end(), piece)
|
|
|
|
!= suggested_pieces.end())
|
2007-07-07 03:26:30 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
pc.inc_stats_counter(counters::piece_picker_rand_start_loops);
|
2007-07-07 03:26:30 +02:00
|
|
|
++piece;
|
2016-12-22 16:42:33 +01:00
|
|
|
if (piece == m_piece_map.end_index()) piece = piece_index_t(0);
|
2007-07-07 03:26:30 +02:00
|
|
|
// could not find any more pieces
|
2015-02-08 22:12:10 +01:00
|
|
|
if (piece == start_piece) { goto get_out; }
|
2007-07-07 03:26:30 +02:00
|
|
|
}
|
|
|
|
|
2015-02-08 22:12:10 +01:00
|
|
|
if (prefer_contiguous_blocks > 1 && !m_piece_map[piece].downloading())
|
2007-09-03 23:16:24 +02:00
|
|
|
{
|
2015-02-08 22:12:10 +01:00
|
|
|
TORRENT_ASSERT(can_pick(piece, pieces));
|
|
|
|
TORRENT_ASSERT(m_piece_map[piece].downloading() == false);
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t start, end;
|
2016-06-20 17:32:06 +02:00
|
|
|
std::tie(start, end) = expand_piece(piece
|
2015-02-08 22:12:10 +01:00
|
|
|
, prefer_contiguous_blocks, pieces, options);
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(end > start);
|
|
|
|
for (piece_index_t k = start; k < end; ++k)
|
2007-09-03 23:16:24 +02:00
|
|
|
{
|
2015-02-08 22:12:10 +01:00
|
|
|
TORRENT_ASSERT(m_piece_map[k].downloading() == false);
|
|
|
|
TORRENT_ASSERT(m_piece_map[k].priority(this) >= 0);
|
2015-08-16 18:17:23 +02:00
|
|
|
const int num_blocks_in_piece = blocks_in_piece(k);
|
2015-11-29 06:58:46 +01:00
|
|
|
|
|
|
|
ret |= picker_log_alert::random_pieces;
|
|
|
|
|
2015-02-08 22:12:10 +01:00
|
|
|
for (int j = 0; j < num_blocks_in_piece; ++j)
|
|
|
|
{
|
|
|
|
pc.inc_stats_counter(counters::piece_picker_rand_loops);
|
|
|
|
TORRENT_ASSERT(is_piece_free(k, pieces));
|
2018-01-11 01:35:15 +01:00
|
|
|
interesting_blocks.emplace_back(k, j);
|
2015-02-08 22:12:10 +01:00
|
|
|
--num_blocks;
|
|
|
|
--prefer_contiguous_blocks;
|
|
|
|
if (prefer_contiguous_blocks <= 0
|
|
|
|
&& num_blocks <= 0) break;
|
|
|
|
}
|
2007-09-03 23:16:24 +02:00
|
|
|
}
|
2015-02-08 22:12:10 +01:00
|
|
|
piece = end;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-11-29 06:58:46 +01:00
|
|
|
ret |= picker_log_alert::random_pieces;
|
|
|
|
|
2015-02-08 22:12:10 +01:00
|
|
|
num_blocks = add_blocks(piece, pieces
|
|
|
|
, interesting_blocks, backup_blocks
|
|
|
|
, backup_blocks2, num_blocks
|
|
|
|
, prefer_contiguous_blocks, peer, empty_vector
|
2015-02-08 22:17:00 +01:00
|
|
|
, options);
|
2015-02-08 22:12:10 +01:00
|
|
|
++piece;
|
2007-09-03 23:16:24 +02:00
|
|
|
}
|
2015-02-08 22:12:10 +01:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
if (piece == m_piece_map.end_index()) piece = piece_index_t(0);
|
2007-08-27 07:13:09 +02:00
|
|
|
// could not find any more pieces
|
2008-09-06 23:04:57 +02:00
|
|
|
if (piece == start_piece) break;
|
2007-07-07 03:26:30 +02:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2015-02-08 22:12:10 +01:00
|
|
|
get_out:
|
2005-08-15 00:04:58 +02:00
|
|
|
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2005-08-15 00:04:58 +02:00
|
|
|
|
2014-03-17 04:41:35 +01:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2008-09-06 23:04:57 +02:00
|
|
|
verify_pick(interesting_blocks, pieces);
|
|
|
|
verify_pick(backup_blocks, pieces);
|
|
|
|
verify_pick(backup_blocks2, pieces);
|
|
|
|
#endif
|
|
|
|
|
2015-11-29 06:58:46 +01:00
|
|
|
ret |= picker_log_alert::backup1;
|
2016-04-06 06:45:21 +02:00
|
|
|
num_blocks = append_blocks(interesting_blocks, backup_blocks, num_blocks);
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-11-29 06:58:46 +01:00
|
|
|
ret |= picker_log_alert::backup2;
|
2014-07-06 21:18:00 +02:00
|
|
|
num_blocks = append_blocks(interesting_blocks, backup_blocks2, num_blocks);
|
2015-11-29 06:58:46 +01:00
|
|
|
if (num_blocks <= 0) return ret;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// ===== THIS IS FOR END-GAME MODE =====
|
|
|
|
|
|
|
|
// don't double-pick anything if the peer is on parole
|
2015-11-29 06:58:46 +01:00
|
|
|
if (options & on_parole) return ret;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// in end game mode we pick a single block
|
|
|
|
// that has already been requested from someone
|
|
|
|
// all pieces that are interesting are in
|
2015-01-26 03:04:58 +01:00
|
|
|
// m_downloads[0] and m_download[1]
|
|
|
|
// (i.e. partial and full pieces)
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2011-02-09 03:56:00 +01:00
|
|
|
std::vector<piece_block> temp;
|
2008-09-06 23:04:57 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// pick one random block from one random partial piece.
|
|
|
|
// only pick from non-downloaded blocks.
|
|
|
|
// first, create a temporary array of the partial pieces
|
|
|
|
// this peer has, and can pick from. Cap the stack allocation
|
|
|
|
// at 200 pieces.
|
2008-09-06 23:04:57 +02:00
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
int partials_size = std::min(200, int(
|
2015-01-26 03:04:58 +01:00
|
|
|
m_downloads[piece_pos::piece_downloading].size()
|
|
|
|
+ m_downloads[piece_pos::piece_full].size()));
|
2015-11-29 06:58:46 +01:00
|
|
|
if (partials_size == 0) return ret;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-10-22 20:43:40 +02:00
|
|
|
TORRENT_ALLOCA(partials, downloading_piece const*, partials_size);
|
2014-07-06 21:18:00 +02:00
|
|
|
int c = 0;
|
|
|
|
|
2016-07-02 01:46:59 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2015-02-08 22:12:10 +01:00
|
|
|
// if we get here, we're about to pick a busy block. First, make sure
|
|
|
|
// we really exhausted the available blocks
|
2014-07-06 21:18:00 +02:00
|
|
|
for (std::vector<downloading_piece>::const_iterator i
|
2015-01-26 03:04:58 +01:00
|
|
|
= m_downloads[piece_pos::piece_downloading].begin()
|
|
|
|
, end(m_downloads[piece_pos::piece_downloading].end()); i != end; ++i)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
downloading_piece const& dp = *i;
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
if ((options & time_critical_mode)
|
2017-10-29 00:44:40 +02:00
|
|
|
&& piece_priority(dp.index) != top_priority)
|
2014-07-06 21:18:00 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// we either don't have this piece, or we've already requested from it
|
2015-02-08 22:12:10 +01:00
|
|
|
if (!pieces[dp.index]) continue;
|
|
|
|
|
2016-04-06 06:45:21 +02:00
|
|
|
// if we already have the piece, obviously we should not have
|
2015-02-08 22:12:10 +01:00
|
|
|
// since this is a partial piece in the piece_downloading state, we
|
|
|
|
// should not already have it
|
|
|
|
TORRENT_ASSERT(!m_piece_map[dp.index].have());
|
|
|
|
|
|
|
|
// if it was filtered, it would be in the prio_zero queue
|
|
|
|
TORRENT_ASSERT(!m_piece_map[dp.index].filtered());
|
|
|
|
|
|
|
|
// we're not allowed to pick from locked pieces
|
|
|
|
if (dp.locked) continue;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
bool found = false;
|
2015-01-26 03:04:58 +01:00
|
|
|
for (std::vector<piece_block>::const_iterator j
|
2015-08-16 18:17:23 +02:00
|
|
|
= interesting_blocks.begin(), end2(interesting_blocks.end());
|
|
|
|
j != end2; ++j)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2015-01-26 03:04:58 +01:00
|
|
|
if (j->piece_index != dp.index) continue;
|
2014-07-06 21:18:00 +02:00
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
2015-02-08 22:12:10 +01:00
|
|
|
|
|
|
|
// we expect to find this piece in our interesting_blocks list
|
|
|
|
TORRENT_ASSERT(found);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
for (auto const& dp : m_downloads[piece_pos::piece_full])
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
if (c == partials_size) break;
|
2015-05-19 05:13:49 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(dp.requested > 0);
|
|
|
|
// this peer doesn't have this piece, try again
|
|
|
|
if (!pieces[dp.index]) continue;
|
|
|
|
// don't pick pieces with priority 0
|
2017-10-29 00:44:40 +02:00
|
|
|
TORRENT_ASSERT(piece_priority(dp.index) > dont_download);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
if ((options & time_critical_mode)
|
2017-10-29 00:44:40 +02:00
|
|
|
&& piece_priority(dp.index) != top_priority)
|
2014-07-06 21:18:00 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
partials[c++] = &dp;
|
|
|
|
}
|
|
|
|
|
|
|
|
partials_size = c;
|
|
|
|
while (partials_size > 0)
|
|
|
|
{
|
|
|
|
pc.inc_stats_counter(counters::piece_picker_busy_loops);
|
2017-02-08 16:54:55 +01:00
|
|
|
int piece = int(random(aux::numeric_cast<std::uint32_t>(partials_size - 1)));
|
2014-07-06 21:18:00 +02:00
|
|
|
downloading_piece const* dp = partials[piece];
|
|
|
|
TORRENT_ASSERT(pieces[dp->index]);
|
2017-10-29 00:44:40 +02:00
|
|
|
TORRENT_ASSERT(piece_priority(dp->index) > dont_download);
|
2014-07-06 21:18:00 +02:00
|
|
|
// fill in with blocks requested from other peers
|
2008-09-06 23:04:57 +02:00
|
|
|
// as backups
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(dp->requested > 0);
|
2017-03-05 05:45:07 +01:00
|
|
|
int idx = -1;
|
|
|
|
for (auto const& info : blocks_for_piece(*dp))
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2017-03-05 05:45:07 +01:00
|
|
|
++idx;
|
2016-11-27 14:46:53 +01:00
|
|
|
TORRENT_ASSERT(info.peer == nullptr || info.peer->in_use);
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == dp->index);
|
2016-11-27 14:46:53 +01:00
|
|
|
if (info.state != block_info::state_requested || info.peer == peer)
|
2008-09-06 23:04:57 +02:00
|
|
|
continue;
|
2018-01-11 01:35:15 +01:00
|
|
|
temp.emplace_back(dp->index, idx);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
// are we done?
|
|
|
|
if (!temp.empty())
|
|
|
|
{
|
2015-11-29 06:58:46 +01:00
|
|
|
ret |= picker_log_alert::end_game;
|
2016-08-06 19:18:48 +02:00
|
|
|
interesting_blocks.push_back(temp[random(std::uint32_t(temp.size()) - 1)]);
|
2014-07-06 21:18:00 +02:00
|
|
|
--num_blocks;
|
|
|
|
break;
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
2011-08-16 08:30:53 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// the piece we picked only had blocks outstanding requested
|
|
|
|
// by ourself. Remove it and pick another one.
|
2016-11-27 14:46:53 +01:00
|
|
|
partials[piece] = partials[partials_size - 1];
|
2014-07-06 21:18:00 +02:00
|
|
|
--partials_size;
|
|
|
|
}
|
2011-02-09 03:56:00 +01:00
|
|
|
|
2016-07-02 01:46:59 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2015-11-29 06:58:46 +01:00
|
|
|
// make sure that we at this point have added requests to all unrequested blocks
|
|
|
|
// in all downloading pieces
|
2008-09-06 23:04:57 +02:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto const& i : m_downloads[piece_pos::piece_downloading])
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
if (!pieces[i.index]) continue;
|
2017-10-29 00:44:40 +02:00
|
|
|
if (piece_priority(i.index) == dont_download) continue;
|
2016-12-22 16:42:33 +01:00
|
|
|
if (i.locked) continue;
|
2015-01-26 03:04:58 +01:00
|
|
|
|
|
|
|
if ((options & time_critical_mode)
|
2017-10-29 00:44:40 +02:00
|
|
|
&& piece_priority(i.index) != top_priority)
|
2014-04-22 06:21:14 +02:00
|
|
|
continue;
|
|
|
|
|
2017-03-05 05:45:07 +01:00
|
|
|
int idx = -1;
|
|
|
|
for (auto const& info : blocks_for_piece(i))
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2017-03-05 05:45:07 +01:00
|
|
|
++idx;
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(info.piece_index == i.index);
|
2008-09-06 23:04:57 +02:00
|
|
|
if (info.state != block_info::state_none) continue;
|
2016-12-22 16:42:33 +01:00
|
|
|
auto k = std::find(interesting_blocks.begin(), interesting_blocks.end()
|
2017-03-05 05:45:07 +01:00
|
|
|
, piece_block(i.index, idx));
|
2008-09-06 23:04:57 +02:00
|
|
|
if (k != interesting_blocks.end()) continue;
|
2014-04-22 06:21:14 +02:00
|
|
|
|
2016-05-17 15:24:06 +02:00
|
|
|
std::fprintf(stderr, "interesting blocks:\n");
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto const& p : interesting_blocks)
|
|
|
|
{
|
|
|
|
std::fprintf(stderr, "(%d, %d)"
|
|
|
|
, static_cast<int>(p.piece_index), p.block_index);
|
|
|
|
}
|
2016-05-17 15:24:06 +02:00
|
|
|
std::fprintf(stderr, "\nnum_blocks: %d\n", num_blocks);
|
2015-01-26 03:04:58 +01:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
for (auto const& l : m_downloads[piece_pos::piece_downloading])
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo2 = blocks_for_piece(l);
|
2016-12-22 16:42:33 +01:00
|
|
|
std::fprintf(stderr, "%d : ", static_cast<int>(l.index));
|
|
|
|
const int cnt = blocks_in_piece(l.index);
|
2015-08-16 18:17:23 +02:00
|
|
|
for (int m = 0; m < cnt; ++m)
|
2016-05-17 15:24:06 +02:00
|
|
|
std::fprintf(stderr, "%d", binfo2[m].state);
|
|
|
|
std::fprintf(stderr, "\n");
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
|
|
|
|
2016-05-02 18:36:21 +02:00
|
|
|
TORRENT_ASSERT_FAIL();
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (interesting_blocks.empty())
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
for (piece_index_t i = piece_index_t(0);
|
|
|
|
i != m_piece_map.end_index(); ++i)
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
|
|
|
if (!pieces[i]) continue;
|
2012-05-14 06:48:23 +02:00
|
|
|
if (m_piece_map[i].priority(this) <= 0) continue;
|
2008-09-06 23:04:57 +02:00
|
|
|
if (have_piece(i)) continue;
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
int const download_state = m_piece_map[i].download_queue();
|
2015-01-26 03:04:58 +01:00
|
|
|
if (download_state == piece_pos::piece_open) continue;
|
|
|
|
std::vector<downloading_piece>::const_iterator k
|
|
|
|
= find_dl_piece(download_state, i);
|
2008-09-06 23:04:57 +02:00
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(k != m_downloads[download_state].end());
|
|
|
|
if (k == m_downloads[download_state].end()) continue;
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
|
|
|
}
|
2016-07-02 01:46:59 +02:00
|
|
|
#endif
|
2015-11-29 06:58:46 +01:00
|
|
|
return ret;
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// have piece means that the piece passed hash check
|
|
|
|
// AND has been successfully written to disk
|
2016-12-22 16:42:33 +01:00
|
|
|
bool piece_picker::have_piece(piece_index_t const index) const
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_pos const& p = m_piece_map[index];
|
2014-07-06 21:18:00 +02:00
|
|
|
return p.index == piece_pos::we_have_index;
|
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
int piece_picker::blocks_in_piece(piece_index_t const index) const
|
2011-02-09 03:56:00 +01:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(index >= piece_index_t(0));
|
|
|
|
TORRENT_ASSERT(index < m_piece_map.end_index());
|
|
|
|
if (next(index) == m_piece_map.end_index())
|
2011-02-09 03:56:00 +01:00
|
|
|
return m_blocks_in_last_piece;
|
|
|
|
else
|
|
|
|
return m_blocks_per_piece;
|
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
bool piece_picker::is_piece_free(piece_index_t const piece
|
|
|
|
, typed_bitfield<piece_index_t> const& bitmask) const
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
|
|
|
return bitmask[piece]
|
2016-12-22 16:42:33 +01:00
|
|
|
&& !m_piece_map[piece].have()
|
|
|
|
&& !m_piece_map[piece].filtered();
|
2005-08-15 00:04:58 +02:00
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
bool piece_picker::can_pick(piece_index_t const piece
|
|
|
|
, typed_bitfield<piece_index_t> const& bitmask) const
|
2007-09-10 01:46:28 +02:00
|
|
|
{
|
|
|
|
return bitmask[piece]
|
2016-12-22 16:42:33 +01:00
|
|
|
&& !m_piece_map[piece].have()
|
2014-07-06 21:18:00 +02:00
|
|
|
// TODO: when expanding pieces for cache stripe reasons,
|
|
|
|
// the !downloading condition doesn't make much sense
|
2016-12-22 16:42:33 +01:00
|
|
|
&& !m_piece_map[piece].downloading()
|
|
|
|
&& !m_piece_map[piece].filtered();
|
2007-09-10 01:46:28 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
void piece_picker::check_peers()
|
|
|
|
{
|
2018-01-11 01:35:15 +01:00
|
|
|
for (auto const& b : m_block_info)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2018-01-11 01:35:15 +01:00
|
|
|
TORRENT_ASSERT(b.peer == nullptr || static_cast<torrent_peer*>(b.peer)->in_use);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-08-18 10:25:13 +02:00
|
|
|
void piece_picker::clear_peer(torrent_peer* peer)
|
2007-07-04 04:16:49 +02:00
|
|
|
{
|
2018-01-11 01:35:15 +01:00
|
|
|
for (auto& b : m_block_info)
|
2012-04-12 19:10:22 +02:00
|
|
|
{
|
2018-01-11 01:35:15 +01:00
|
|
|
if (b.peer == peer) b.peer = nullptr;
|
2012-04-12 19:10:22 +02:00
|
|
|
}
|
2007-07-04 04:16:49 +02:00
|
|
|
}
|
|
|
|
|
2015-02-14 22:32:41 +01:00
|
|
|
// the first bool is true if this is the only peer that has requested and downloaded
|
|
|
|
// blocks from this piece.
|
|
|
|
// the second bool is true if this is the only active peer that is requesting
|
|
|
|
// and downloading blocks from this piece. Active means having a connection.
|
|
|
|
// TODO: 2 the first_block returned here is the largest free range, not
|
|
|
|
// the first-fit range, which would be better
|
2016-06-20 17:32:06 +02:00
|
|
|
std::tuple<bool, bool, int, int> piece_picker::requested_from(
|
2015-02-14 22:32:41 +01:00
|
|
|
piece_picker::downloading_piece const& p
|
2016-11-27 14:46:53 +01:00
|
|
|
, int const num_blocks_in_piece, torrent_peer* peer) const
|
2005-08-15 00:04:58 +02:00
|
|
|
{
|
2015-02-14 22:32:41 +01:00
|
|
|
bool exclusive = true;
|
|
|
|
bool exclusive_active = true;
|
|
|
|
int contiguous_blocks = 0;
|
|
|
|
int max_contiguous = 0;
|
|
|
|
int first_block = 0;
|
2017-03-05 05:45:07 +01:00
|
|
|
int idx = -1;
|
|
|
|
for (auto const& info : blocks_for_piece(p))
|
2015-02-14 22:32:41 +01:00
|
|
|
{
|
2017-03-05 05:45:07 +01:00
|
|
|
++idx;
|
2016-11-27 14:46:53 +01:00
|
|
|
TORRENT_ASSERT(info.peer == nullptr || info.peer->in_use);
|
2015-02-14 22:32:41 +01:00
|
|
|
TORRENT_ASSERT(info.piece_index == p.index);
|
|
|
|
if (info.state == piece_picker::block_info::state_none)
|
2005-08-15 00:04:58 +02:00
|
|
|
{
|
2015-02-14 22:32:41 +01:00
|
|
|
++contiguous_blocks;
|
|
|
|
continue;
|
2005-08-15 00:04:58 +02:00
|
|
|
}
|
2015-01-20 04:46:40 +01:00
|
|
|
if (contiguous_blocks > max_contiguous)
|
|
|
|
{
|
|
|
|
max_contiguous = contiguous_blocks;
|
2017-03-05 05:45:07 +01:00
|
|
|
first_block = idx - contiguous_blocks;
|
2015-02-14 22:32:41 +01:00
|
|
|
}
|
|
|
|
contiguous_blocks = 0;
|
|
|
|
if (info.peer != peer)
|
|
|
|
{
|
|
|
|
exclusive = false;
|
|
|
|
if (info.state == piece_picker::block_info::state_requested
|
2016-07-09 22:26:26 +02:00
|
|
|
&& info.peer != nullptr)
|
2015-02-14 22:32:41 +01:00
|
|
|
{
|
|
|
|
exclusive_active = false;
|
|
|
|
}
|
2015-01-20 04:46:40 +01:00
|
|
|
}
|
2005-08-15 00:04:58 +02:00
|
|
|
}
|
2015-02-14 22:32:41 +01:00
|
|
|
if (contiguous_blocks > max_contiguous)
|
|
|
|
{
|
|
|
|
max_contiguous = contiguous_blocks;
|
|
|
|
first_block = num_blocks_in_piece - contiguous_blocks;
|
|
|
|
}
|
2016-06-20 17:32:06 +02:00
|
|
|
return std::make_tuple(exclusive, exclusive_active, max_contiguous
|
2015-02-14 22:32:41 +01:00
|
|
|
, first_block);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
int piece_picker::add_blocks(piece_index_t piece
|
|
|
|
, typed_bitfield<piece_index_t> const& pieces
|
2005-08-15 00:04:58 +02:00
|
|
|
, std::vector<piece_block>& interesting_blocks
|
2008-09-06 23:04:57 +02:00
|
|
|
, std::vector<piece_block>& backup_blocks
|
|
|
|
, std::vector<piece_block>& backup_blocks2
|
2015-01-20 03:34:55 +01:00
|
|
|
, int num_blocks, int prefer_contiguous_blocks
|
2016-12-22 16:42:33 +01:00
|
|
|
, torrent_peer* peer, std::vector<piece_index_t> const& ignore
|
2018-01-28 14:39:43 +01:00
|
|
|
, picker_options_t const options) const
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
TORRENT_ASSERT(is_piece_free(piece, pieces));
|
|
|
|
|
|
|
|
// ignore pieces found in the ignore list
|
|
|
|
if (std::find(ignore.begin(), ignore.end(), piece) != ignore.end()) return num_blocks;
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
if (m_piece_map[piece].download_queue() != piece_pos::piece_open
|
|
|
|
&& m_piece_map[piece].download_queue() != piece_pos::piece_downloading)
|
|
|
|
return num_blocks;
|
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
TORRENT_ASSERT(m_piece_map[piece].priority(this) >= 0);
|
2015-01-26 03:04:58 +01:00
|
|
|
int state = m_piece_map[piece].download_queue();
|
|
|
|
if (state == piece_pos::piece_downloading)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
// if we're prioritizing partials, we've already
|
|
|
|
// looked through the downloading pieces
|
|
|
|
if (options & prioritize_partials) return num_blocks;
|
2007-03-15 23:03:56 +01:00
|
|
|
|
2018-01-11 01:35:15 +01:00
|
|
|
auto i = find_dl_piece(piece_pos::piece_downloading, piece);
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[state].end());
|
2007-08-21 20:39:44 +02:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
return add_blocks_downloading(*i, pieces
|
|
|
|
, interesting_blocks, backup_blocks, backup_blocks2
|
2015-02-08 22:17:00 +01:00
|
|
|
, num_blocks, prefer_contiguous_blocks, peer, options);
|
2008-09-06 23:04:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int num_blocks_in_piece = blocks_in_piece(piece);
|
2007-03-15 23:03:56 +01:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
// pick a new piece
|
2015-01-20 03:34:55 +01:00
|
|
|
if (prefer_contiguous_blocks == 0)
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
|
|
|
if (num_blocks_in_piece > num_blocks)
|
|
|
|
num_blocks_in_piece = num_blocks;
|
2013-01-30 07:20:37 +01:00
|
|
|
TORRENT_ASSERT(is_piece_free(piece, pieces));
|
2008-09-06 23:04:57 +02:00
|
|
|
for (int j = 0; j < num_blocks_in_piece; ++j)
|
2018-01-11 01:35:15 +01:00
|
|
|
interesting_blocks.emplace_back(piece, j);
|
2008-09-06 23:04:57 +02:00
|
|
|
num_blocks -= num_blocks_in_piece;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t start, end;
|
2016-06-20 17:32:06 +02:00
|
|
|
std::tie(start, end) = expand_piece(piece, prefer_contiguous_blocks
|
2015-01-20 03:34:55 +01:00
|
|
|
, pieces, options);
|
2016-12-22 16:42:33 +01:00
|
|
|
for (piece_index_t k = start; k < end; ++k)
|
2007-09-05 23:21:11 +02:00
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
TORRENT_ASSERT(m_piece_map[k].priority(this) > 0);
|
|
|
|
num_blocks_in_piece = blocks_in_piece(k);
|
2013-01-30 07:20:37 +01:00
|
|
|
TORRENT_ASSERT(is_piece_free(k, pieces));
|
2005-08-15 00:04:58 +02:00
|
|
|
for (int j = 0; j < num_blocks_in_piece; ++j)
|
2015-01-20 03:34:55 +01:00
|
|
|
{
|
2018-01-11 01:35:15 +01:00
|
|
|
interesting_blocks.emplace_back(k, j);
|
2015-01-20 03:34:55 +01:00
|
|
|
--num_blocks;
|
|
|
|
--prefer_contiguous_blocks;
|
|
|
|
if (prefer_contiguous_blocks == 0
|
|
|
|
&& num_blocks <= 0) break;
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
}
|
2014-03-17 04:41:35 +01:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2007-09-10 01:46:28 +02:00
|
|
|
verify_pick(interesting_blocks, pieces);
|
|
|
|
#endif
|
2015-01-19 23:07:53 +01:00
|
|
|
return (std::max)(num_blocks, 0);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
int piece_picker::add_blocks_downloading(downloading_piece const& dp
|
2016-12-22 16:42:33 +01:00
|
|
|
, typed_bitfield<piece_index_t> const& pieces
|
2007-09-05 23:21:11 +02:00
|
|
|
, std::vector<piece_block>& interesting_blocks
|
|
|
|
, std::vector<piece_block>& backup_blocks
|
2008-09-06 23:04:57 +02:00
|
|
|
, std::vector<piece_block>& backup_blocks2
|
2015-01-20 03:34:55 +01:00
|
|
|
, int num_blocks, int prefer_contiguous_blocks
|
2018-01-28 14:39:43 +01:00
|
|
|
, torrent_peer* peer, picker_options_t const options) const
|
2007-09-05 23:21:11 +02:00
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
if (!pieces[dp.index]) return num_blocks;
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(!m_piece_map[dp.index].filtered());
|
|
|
|
|
|
|
|
// this piece failed to write. We're currently restoring
|
|
|
|
// it. It's not OK to send more requests to it right now.
|
|
|
|
if (dp.locked) return num_blocks;
|
2007-09-10 01:46:28 +02:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
int num_blocks_in_piece = blocks_in_piece(dp.index);
|
2007-09-05 23:21:11 +02:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
// is true if all the other pieces that are currently
|
|
|
|
// requested from this piece are from the same
|
|
|
|
// peer as 'peer'.
|
|
|
|
bool exclusive;
|
|
|
|
bool exclusive_active;
|
2015-01-20 04:46:40 +01:00
|
|
|
|
|
|
|
// used to report back the largest contiguous block run
|
2015-01-20 03:34:55 +01:00
|
|
|
int contiguous_blocks;
|
2015-01-20 04:46:40 +01:00
|
|
|
int first_block;
|
2016-06-20 17:32:06 +02:00
|
|
|
std::tie(exclusive, exclusive_active, contiguous_blocks, first_block)
|
2008-09-06 23:04:57 +02:00
|
|
|
= requested_from(dp, num_blocks_in_piece, peer);
|
|
|
|
|
2015-01-20 04:46:40 +01:00
|
|
|
// no need in picking from the largest contiguous block run unless
|
|
|
|
// we're interested in it. In fact, we really want the opposite.
|
|
|
|
if (prefer_contiguous_blocks == 0) first_block = 0;
|
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
// peers on parole are only allowed to pick blocks from
|
|
|
|
// pieces that only they have downloaded/requested from
|
|
|
|
if ((options & on_parole) && !exclusive) return num_blocks;
|
|
|
|
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = blocks_for_piece(dp);
|
2015-02-14 22:32:41 +01:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
// we prefer whole blocks, but there are other peers
|
2015-01-20 03:34:55 +01:00
|
|
|
// downloading from this piece and there aren't enough contiguous blocks
|
|
|
|
// to pick, add it as backups.
|
|
|
|
// if we're on parole, don't let the contiguous blocks stop us, we want
|
|
|
|
// to primarily request from a piece all by ourselves.
|
|
|
|
if (prefer_contiguous_blocks > contiguous_blocks
|
|
|
|
&& !exclusive_active
|
2018-01-28 14:39:43 +01:00
|
|
|
&& !(options & on_parole))
|
2008-09-06 23:04:57 +02:00
|
|
|
{
|
2011-08-16 08:30:53 +02:00
|
|
|
if (int(backup_blocks2.size()) >= num_blocks)
|
2008-09-06 23:04:57 +02:00
|
|
|
return num_blocks;
|
2007-09-10 10:07:18 +02:00
|
|
|
|
2007-09-05 23:21:11 +02:00
|
|
|
for (int j = 0; j < num_blocks_in_piece; ++j)
|
|
|
|
{
|
|
|
|
// ignore completed blocks and already requested blocks
|
2017-03-05 05:45:07 +01:00
|
|
|
int const block_idx = (j + first_block) % num_blocks_in_piece;
|
2015-02-14 22:32:41 +01:00
|
|
|
block_info const& info = binfo[block_idx];
|
2012-04-12 07:00:20 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == dp.index);
|
2008-09-06 23:04:57 +02:00
|
|
|
if (info.state != block_info::state_none) continue;
|
2018-01-11 01:35:15 +01:00
|
|
|
backup_blocks2.emplace_back(dp.index, block_idx);
|
2007-09-05 23:21:11 +02:00
|
|
|
}
|
2008-09-06 23:04:57 +02:00
|
|
|
return num_blocks;
|
2007-09-05 23:21:11 +02:00
|
|
|
}
|
2007-09-10 01:46:28 +02:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
for (int j = 0; j < num_blocks_in_piece; ++j)
|
|
|
|
{
|
|
|
|
// ignore completed blocks and already requested blocks
|
2017-03-05 05:45:07 +01:00
|
|
|
int const block_idx = (j + first_block) % num_blocks_in_piece;
|
2015-02-14 22:32:41 +01:00
|
|
|
block_info const& info = binfo[block_idx];
|
2012-04-12 07:00:20 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == dp.index);
|
2008-09-06 23:04:57 +02:00
|
|
|
if (info.state != block_info::state_none) continue;
|
2007-09-05 23:21:11 +02:00
|
|
|
|
2015-01-20 03:34:55 +01:00
|
|
|
// this block is interesting (we don't have it yet).
|
2018-01-11 01:35:15 +01:00
|
|
|
interesting_blocks.emplace_back(dp.index, block_idx);
|
2008-09-06 23:04:57 +02:00
|
|
|
// we have found a block that's free to download
|
2015-01-20 03:34:55 +01:00
|
|
|
--num_blocks;
|
|
|
|
// if we prefer contiguous blocks, continue picking from this
|
2008-09-06 23:04:57 +02:00
|
|
|
// piece even though we have num_blocks
|
2015-01-20 03:34:55 +01:00
|
|
|
if (prefer_contiguous_blocks > 0)
|
|
|
|
{
|
|
|
|
--prefer_contiguous_blocks;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (num_blocks <= 0) return 0;
|
2007-09-17 02:37:45 +02:00
|
|
|
}
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
if (num_blocks <= 0) return 0;
|
|
|
|
if (options & on_parole) return num_blocks;
|
2007-09-10 01:46:28 +02:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
if (int(backup_blocks.size()) >= num_blocks) return num_blocks;
|
2007-09-05 23:21:11 +02:00
|
|
|
|
2014-03-17 04:41:35 +01:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2007-09-10 01:46:28 +02:00
|
|
|
verify_pick(backup_blocks, pieces);
|
|
|
|
#endif
|
2007-09-05 23:21:11 +02:00
|
|
|
return num_blocks;
|
|
|
|
}
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
std::pair<piece_index_t, piece_index_t>
|
2017-06-20 17:45:18 +02:00
|
|
|
piece_picker::expand_piece(piece_index_t const piece, int const contiguous_blocks
|
2018-01-28 14:39:43 +01:00
|
|
|
, typed_bitfield<piece_index_t> const& have, picker_options_t const options) const
|
2007-09-03 23:16:24 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
if (contiguous_blocks == 0) return std::make_pair(piece, next(piece));
|
2015-01-20 03:34:55 +01:00
|
|
|
|
|
|
|
// round to even pieces and expand in order to get the number of
|
|
|
|
// contiguous pieces we want
|
2016-12-22 16:42:33 +01:00
|
|
|
int const whole_pieces = (contiguous_blocks + m_blocks_per_piece - 1)
|
2015-01-20 03:34:55 +01:00
|
|
|
/ m_blocks_per_piece;
|
2007-09-03 23:16:24 +02:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
piece_index_t start = piece;
|
|
|
|
piece_index_t lower_limit;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
if (options & align_expanded_pieces)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
lower_limit = piece_index_t(static_cast<int>(piece) - (static_cast<int>(piece) % whole_pieces));
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
lower_limit = piece_index_t(static_cast<int>(piece) - whole_pieces + 1);
|
|
|
|
if (lower_limit < piece_index_t(0)) lower_limit = piece_index_t(0);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
while (start > lower_limit && can_pick(prev(start), have))
|
2007-09-03 23:16:24 +02:00
|
|
|
--start;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(start >= piece_index_t(0));
|
|
|
|
piece_index_t end = next(piece);
|
|
|
|
piece_index_t upper_limit;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (options & align_expanded_pieces)
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
upper_limit = piece_index_t(static_cast<int>(lower_limit) + whole_pieces);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
upper_limit = piece_index_t(static_cast<int>(start) + whole_pieces);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2016-12-22 16:42:33 +01:00
|
|
|
if (upper_limit > have.end_index()) upper_limit = have.end_index();
|
|
|
|
while (end < upper_limit && can_pick(end, have))
|
2007-09-03 23:16:24 +02:00
|
|
|
++end;
|
|
|
|
return std::make_pair(start, end);
|
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
bool piece_picker::is_piece_finished(piece_index_t const index) const
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
piece_pos const& p = m_piece_map[index];
|
|
|
|
if (p.index == piece_pos::we_have_index) return true;
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
int state = p.download_queue();
|
2014-07-06 21:18:00 +02:00
|
|
|
if (state == piece_pos::piece_open)
|
2006-12-22 01:45:43 +01:00
|
|
|
{
|
2015-01-26 03:04:58 +01:00
|
|
|
for (int i = 0; i < piece_pos::num_download_categories; ++i)
|
|
|
|
TORRENT_ASSERT(find_dl_piece(i, index) == m_downloads[i].end());
|
2006-12-22 01:45:43 +01:00
|
|
|
return false;
|
|
|
|
}
|
2017-06-20 17:45:18 +02:00
|
|
|
auto const i = find_dl_piece(state, index);
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[state].end());
|
2015-08-02 05:57:11 +02:00
|
|
|
TORRENT_ASSERT(int(i->finished) <= m_blocks_per_piece);
|
2017-03-05 05:45:07 +01:00
|
|
|
int const max_blocks = blocks_in_piece(index);
|
2009-06-10 10:30:55 +02:00
|
|
|
if (int(i->finished) + int(i->writing) < max_blocks) return false;
|
|
|
|
TORRENT_ASSERT(int(i->finished) + int(i->writing) == max_blocks);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2016-07-02 01:46:59 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2017-03-05 05:45:07 +01:00
|
|
|
for (auto const& info : blocks_for_piece(*i))
|
2007-06-10 22:46:09 +02:00
|
|
|
{
|
2017-03-05 05:45:07 +01:00
|
|
|
TORRENT_ASSERT(info.piece_index == index);
|
|
|
|
TORRENT_ASSERT(info.state == block_info::state_finished
|
|
|
|
|| info.state == block_info::state_writing);
|
2007-06-10 22:46:09 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
bool piece_picker::has_piece_passed(piece_index_t const index) const
|
2011-08-15 06:16:43 +02:00
|
|
|
{
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(index < m_piece_map.end_index());
|
|
|
|
TORRENT_ASSERT(index >= piece_index_t(0));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
piece_pos const& p = m_piece_map[index];
|
|
|
|
if (p.index == piece_pos::we_have_index) return true;
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
int const state = p.download_queue();
|
2014-07-06 21:18:00 +02:00
|
|
|
if (state == piece_pos::piece_open)
|
|
|
|
{
|
2015-01-26 03:04:58 +01:00
|
|
|
for (int i = 0; i < piece_pos::num_download_categories; ++i)
|
|
|
|
TORRENT_ASSERT(find_dl_piece(i, index) == m_downloads[i].end());
|
2014-07-06 21:18:00 +02:00
|
|
|
return false;
|
|
|
|
}
|
2017-06-20 17:45:18 +02:00
|
|
|
auto const i = find_dl_piece(state, index);
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[state].end());
|
2017-06-20 17:45:18 +02:00
|
|
|
return bool(i->passed_hash_check);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<piece_picker::downloading_piece>::iterator piece_picker::find_dl_piece(
|
2017-06-20 17:45:18 +02:00
|
|
|
int const queue, piece_index_t const index)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(queue >= 0 && queue < piece_pos::num_download_categories);
|
2011-08-16 11:22:41 +02:00
|
|
|
downloading_piece cmp;
|
|
|
|
cmp.index = index;
|
2017-06-20 17:45:18 +02:00
|
|
|
auto const i = std::lower_bound(
|
2014-07-06 21:18:00 +02:00
|
|
|
m_downloads[queue].begin(), m_downloads[queue].end(), cmp);
|
|
|
|
if (i == m_downloads[queue].end()) return i;
|
2011-08-15 06:16:43 +02:00
|
|
|
if (i->index == index) return i;
|
2014-07-06 21:18:00 +02:00
|
|
|
return m_downloads[queue].end();
|
2011-08-15 06:16:43 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
std::vector<piece_picker::downloading_piece>::const_iterator piece_picker::find_dl_piece(
|
2017-06-20 17:45:18 +02:00
|
|
|
int const queue, piece_index_t const index) const
|
2011-08-15 06:16:43 +02:00
|
|
|
{
|
2015-02-08 22:12:10 +01:00
|
|
|
return const_cast<piece_picker*>(this)->find_dl_piece(queue, index);
|
2011-08-15 06:16:43 +02:00
|
|
|
}
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
std::vector<piece_picker::downloading_piece>::iterator
|
2016-08-07 22:05:20 +02:00
|
|
|
piece_picker::update_piece_state(
|
2014-07-06 21:18:00 +02:00
|
|
|
std::vector<piece_picker::downloading_piece>::iterator dp)
|
2011-08-16 08:30:53 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
std::cerr << "[" << this << "] " << "update_piece_state(" << dp->index << ")" << std::endl;
|
|
|
|
#endif
|
|
|
|
|
2016-08-07 22:05:20 +02:00
|
|
|
int const num_blocks = blocks_in_piece(dp->index);
|
2014-07-06 21:18:00 +02:00
|
|
|
piece_pos& p = m_piece_map[dp->index];
|
2016-08-07 22:05:20 +02:00
|
|
|
int const current_state = p.download_state;
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(current_state != piece_pos::piece_open);
|
|
|
|
if (current_state == piece_pos::piece_open)
|
|
|
|
return dp;
|
|
|
|
|
|
|
|
// this function is not allowed to create new downloading pieces
|
|
|
|
int new_state = 0;
|
|
|
|
if (p.filtered())
|
|
|
|
{
|
|
|
|
new_state = piece_pos::piece_zero_prio;
|
|
|
|
}
|
|
|
|
else if (dp->requested + dp->finished + dp->writing == 0)
|
|
|
|
{
|
|
|
|
new_state = piece_pos::piece_open;
|
|
|
|
}
|
|
|
|
else if (dp->requested + dp->finished + dp->writing < num_blocks)
|
|
|
|
{
|
2015-01-26 03:04:58 +01:00
|
|
|
new_state = p.reverse()
|
|
|
|
? piece_pos::piece_downloading_reverse
|
|
|
|
: piece_pos::piece_downloading;
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
else if (dp->requested > 0)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(dp->requested + dp->finished + dp->writing == num_blocks);
|
2015-01-26 03:04:58 +01:00
|
|
|
new_state = p.reverse()
|
|
|
|
? piece_pos::piece_full_reverse
|
|
|
|
: piece_pos::piece_full;
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(dp->finished + dp->writing == num_blocks);
|
|
|
|
new_state = piece_pos::piece_finished;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
std::cerr << "[" << this << "] " << " new_state: " << new_state << " current_state: " << current_state << std::endl;
|
|
|
|
#endif
|
|
|
|
if (new_state == current_state) return dp;
|
|
|
|
if (new_state == piece_pos::piece_open) return dp;
|
|
|
|
|
|
|
|
// assert that the iterator that was passed-in in fact lives in
|
|
|
|
// the correct list
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(find_dl_piece(p.download_queue(), dp->index) == dp);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-02-08 17:52:57 +01:00
|
|
|
// remove the downloading_piece from the list corresponding
|
2014-07-06 21:18:00 +02:00
|
|
|
// to the old state
|
|
|
|
downloading_piece dp_info = *dp;
|
2015-01-26 03:04:58 +01:00
|
|
|
m_downloads[p.download_queue()].erase(dp);
|
|
|
|
|
2016-08-07 22:05:20 +02:00
|
|
|
int const prio = p.priority(this);
|
|
|
|
TORRENT_ASSERT(prio < int(m_priority_boundaries.size())
|
|
|
|
|| m_dirty);
|
2016-12-22 16:42:33 +01:00
|
|
|
p.download_state = static_cast<std::uint16_t>(new_state);
|
2015-01-26 03:04:58 +01:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
std::cerr << "[" << this << "] " << " " << dp_info.index << " state (" << current_state << " -> " << new_state << ")" << std::endl;
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-02-08 17:52:57 +01:00
|
|
|
// insert the downloading_piece in the list corresponding to
|
2014-07-06 21:18:00 +02:00
|
|
|
// the new state
|
|
|
|
downloading_piece cmp;
|
|
|
|
cmp.index = dp_info.index;
|
2018-01-11 01:35:15 +01:00
|
|
|
auto i = std::lower_bound(m_downloads[p.download_queue()].begin()
|
2015-01-26 03:04:58 +01:00
|
|
|
, m_downloads[p.download_queue()].end(), cmp);
|
|
|
|
TORRENT_ASSERT(i == m_downloads[p.download_queue()].end()
|
|
|
|
|| i->index != dp_info.index);
|
|
|
|
i = m_downloads[p.download_queue()].insert(i, dp_info);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
if (!m_dirty)
|
|
|
|
{
|
|
|
|
if (prio == -1 && p.priority(this) != -1) add(dp_info.index);
|
|
|
|
else if (prio != -1) update(prio, p.index);
|
|
|
|
}
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
bool piece_picker::is_requested(piece_block const block) const
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2012-05-03 03:51:56 +02:00
|
|
|
TORRENT_ASSERT(block.block_index != piece_block::invalid.block_index);
|
|
|
|
TORRENT_ASSERT(block.piece_index != piece_block::invalid.piece_index);
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(block.piece_index < m_piece_map.end_index());
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
int const state = m_piece_map[block.piece_index].download_queue();
|
2014-07-06 21:18:00 +02:00
|
|
|
if (state == piece_pos::piece_open) return false;
|
2017-06-20 17:45:18 +02:00
|
|
|
auto const i = find_dl_piece(state, block.piece_index);
|
2004-01-13 04:08:59 +01:00
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[state].end());
|
2015-02-14 22:32:41 +01:00
|
|
|
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const info = blocks_for_piece(*i);
|
2015-02-14 22:32:41 +01:00
|
|
|
TORRENT_ASSERT(info[block.block_index].piece_index == block.piece_index);
|
|
|
|
return info[block.block_index].state == block_info::state_requested;
|
2007-06-10 22:46:09 +02:00
|
|
|
}
|
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
bool piece_picker::is_downloaded(piece_block const block) const
|
2007-06-10 22:46:09 +02:00
|
|
|
{
|
2012-05-03 03:51:56 +02:00
|
|
|
TORRENT_ASSERT(block.block_index != piece_block::invalid.block_index);
|
|
|
|
TORRENT_ASSERT(block.piece_index != piece_block::invalid.piece_index);
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(block.piece_index < m_piece_map.end_index());
|
2007-06-10 22:46:09 +02:00
|
|
|
|
2018-01-08 23:34:24 +01:00
|
|
|
piece_pos const& p = m_piece_map[block.piece_index];
|
|
|
|
if (p.index == piece_pos::we_have_index) return true;
|
|
|
|
int const state = p.download_queue();
|
2014-07-06 21:18:00 +02:00
|
|
|
if (state == piece_pos::piece_open) return false;
|
2017-06-20 17:45:18 +02:00
|
|
|
auto const i = find_dl_piece(state, block.piece_index);
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[state].end());
|
2015-02-14 22:32:41 +01:00
|
|
|
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const info = blocks_for_piece(*i);
|
2015-02-14 22:32:41 +01:00
|
|
|
TORRENT_ASSERT(info[block.block_index].piece_index == block.piece_index);
|
|
|
|
return info[block.block_index].state == block_info::state_finished
|
|
|
|
|| info[block.block_index].state == block_info::state_writing;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
bool piece_picker::is_finished(piece_block const block) const
|
2003-11-05 00:27:06 +01:00
|
|
|
{
|
2012-05-03 03:51:56 +02:00
|
|
|
TORRENT_ASSERT(block.block_index != piece_block::invalid.block_index);
|
|
|
|
TORRENT_ASSERT(block.piece_index != piece_block::invalid.piece_index);
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(block.piece_index < m_piece_map.end_index());
|
2003-11-05 00:27:06 +01:00
|
|
|
|
2013-10-16 10:29:12 +02:00
|
|
|
piece_pos const& p = m_piece_map[block.piece_index];
|
|
|
|
if (p.index == piece_pos::we_have_index) return true;
|
2018-01-08 23:34:24 +01:00
|
|
|
int const state = p.download_queue();
|
|
|
|
if (state == piece_pos::piece_open) return false;
|
|
|
|
auto const i = find_dl_piece(state, block.piece_index);
|
|
|
|
TORRENT_ASSERT(i != m_downloads[state].end());
|
2015-02-14 22:32:41 +01:00
|
|
|
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const info = blocks_for_piece(*i);
|
2015-02-14 22:32:41 +01:00
|
|
|
TORRENT_ASSERT(info[block.block_index].piece_index == block.piece_index);
|
|
|
|
return info[block.block_index].state == block_info::state_finished;
|
2003-11-05 00:27:06 +01:00
|
|
|
}
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
// options may be 0 or piece_picker::reverse
|
2016-08-07 22:05:20 +02:00
|
|
|
// returns false if the block could not be marked as downloading
|
2017-06-20 17:45:18 +02:00
|
|
|
bool piece_picker::mark_as_downloading(piece_block const block
|
2018-01-28 14:39:43 +01:00
|
|
|
, torrent_peer* peer, picker_options_t const options)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2015-01-26 03:04:58 +01:00
|
|
|
std::cerr << "[" << this << "] " << "mark_as_downloading( {"
|
|
|
|
<< block.piece_index << ", " << block.block_index << "} )" << std::endl;
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
TORRENT_ASSERT(peer == nullptr || peer->in_use);
|
2012-05-03 03:51:56 +02:00
|
|
|
TORRENT_ASSERT(block.block_index != piece_block::invalid.block_index);
|
|
|
|
TORRENT_ASSERT(block.piece_index != piece_block::invalid.piece_index);
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(block.piece_index < m_piece_map.end_index());
|
2016-11-27 14:46:53 +01:00
|
|
|
TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index));
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_piece_map[block.piece_index].have());
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
piece_pos& p = m_piece_map[block.piece_index];
|
2015-01-26 03:04:58 +01:00
|
|
|
if (p.download_queue() == piece_pos::piece_open)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2008-09-06 23:04:57 +02:00
|
|
|
#endif
|
2016-08-07 22:05:20 +02:00
|
|
|
int const prio = p.priority(this);
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(prio < int(m_priority_boundaries.size())
|
2008-01-31 18:52:29 +01:00
|
|
|
|| m_dirty);
|
2015-01-26 03:04:58 +01:00
|
|
|
|
|
|
|
p.download_state = (options & reverse)
|
|
|
|
? piece_pos::piece_downloading_reverse
|
|
|
|
: piece_pos::piece_downloading;
|
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
if (prio >= 0 && !m_dirty) update(prio, p.index);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
auto const dp = add_download_piece(block.piece_index);
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = mutable_blocks_for_piece(*dp);
|
2015-02-14 22:32:41 +01:00
|
|
|
block_info& info = binfo[block.block_index];
|
2012-04-12 07:00:20 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == block.piece_index);
|
2007-06-10 22:46:09 +02:00
|
|
|
info.state = block_info::state_requested;
|
2007-05-08 13:13:13 +02:00
|
|
|
info.peer = peer;
|
2007-07-06 19:15:35 +02:00
|
|
|
info.num_peers = 1;
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_ASSERTS
|
|
|
|
TORRENT_ASSERT(info.peers.count(peer) == 0);
|
|
|
|
info.peers.insert(peer);
|
|
|
|
#endif
|
|
|
|
++dp->requested;
|
|
|
|
// update_full may move the downloading piece to
|
|
|
|
// a different vector, so 'dp' may be invalid after
|
|
|
|
// this call
|
|
|
|
update_piece_state(dp);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2008-09-06 23:04:57 +02:00
|
|
|
#endif
|
2017-06-20 17:45:18 +02:00
|
|
|
auto i = find_dl_piece(p.download_queue(), block.piece_index);
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[p.download_queue()].end());
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = mutable_blocks_for_piece(*i);
|
2015-02-14 22:32:41 +01:00
|
|
|
block_info& info = binfo[block.block_index];
|
2012-04-12 07:00:20 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == block.piece_index);
|
2007-09-15 22:20:07 +02:00
|
|
|
if (info.state == block_info::state_writing
|
|
|
|
|| info.state == block_info::state_finished)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2007-09-15 22:20:07 +02:00
|
|
|
return false;
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2015-01-26 03:04:58 +01:00
|
|
|
|
|
|
|
if ((options & reverse) && !p.reverse() && i->requested == 0)
|
|
|
|
{
|
|
|
|
// this piece isn't reverse, but there's no other peer
|
|
|
|
// downloading from it and we just requested a block from a
|
|
|
|
// reverse peer. Make it reverse
|
|
|
|
int prio = p.priority(this);
|
|
|
|
p.make_reverse();
|
|
|
|
if (prio >= 0 && !m_dirty) update(prio, p.index);
|
|
|
|
}
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(info.state == block_info::state_none
|
2007-07-06 19:15:35 +02:00
|
|
|
|| (info.state == block_info::state_requested
|
|
|
|
&& (info.num_peers > 0)));
|
2007-05-08 13:13:13 +02:00
|
|
|
info.peer = peer;
|
2007-07-06 19:15:35 +02:00
|
|
|
if (info.state != block_info::state_requested)
|
|
|
|
{
|
|
|
|
info.state = block_info::state_requested;
|
|
|
|
++i->requested;
|
2014-07-06 21:18:00 +02:00
|
|
|
i = update_piece_state(i);
|
2007-07-06 19:15:35 +02:00
|
|
|
}
|
|
|
|
++info.num_peers;
|
2015-01-26 03:04:58 +01:00
|
|
|
|
|
|
|
// if we make a non-reverse request from a reversed piece,
|
|
|
|
// undo the reverse state
|
2018-01-28 14:39:43 +01:00
|
|
|
if (!(options & reverse) && p.reverse())
|
2015-01-26 03:04:58 +01:00
|
|
|
{
|
|
|
|
int prio = p.priority(this);
|
|
|
|
// make it non-reverse
|
|
|
|
p.unreverse();
|
|
|
|
if (prio >= 0 && !m_dirty) update(prio, p.index);
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_ASSERTS
|
|
|
|
TORRENT_ASSERT(info.peers.count(peer) == 0);
|
|
|
|
info.peers.insert(peer);
|
|
|
|
#endif
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2007-09-15 22:20:07 +02:00
|
|
|
return true;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
int piece_picker::num_peers(piece_block const block) const
|
2007-07-06 19:15:35 +02:00
|
|
|
{
|
2012-05-03 03:51:56 +02:00
|
|
|
TORRENT_ASSERT(block.block_index != piece_block::invalid.block_index);
|
|
|
|
TORRENT_ASSERT(block.piece_index != piece_block::invalid.piece_index);
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(block.piece_index < m_piece_map.end_index());
|
2016-09-05 00:24:20 +02:00
|
|
|
TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index));
|
2007-07-06 19:15:35 +02:00
|
|
|
|
|
|
|
piece_pos const& p = m_piece_map[block.piece_index];
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!p.downloading()) return 0;
|
2007-07-06 19:15:35 +02:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
auto const i = find_dl_piece(p.download_queue(), block.piece_index);
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[p.download_queue()].end());
|
2007-07-06 19:15:35 +02:00
|
|
|
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = blocks_for_piece(*i);
|
2015-02-14 22:32:41 +01:00
|
|
|
block_info const& info = binfo[block.block_index];
|
2013-10-06 19:00:07 +02:00
|
|
|
TORRENT_ASSERT(&info >= &m_block_info[0]);
|
|
|
|
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
|
2012-04-12 07:00:20 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == block.piece_index);
|
2007-07-06 19:15:35 +02:00
|
|
|
return info.num_peers;
|
|
|
|
}
|
2010-01-15 17:45:42 +01:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::get_availability(aux::vector<int, piece_index_t>& avail) const
|
2007-05-30 08:52:59 +02:00
|
|
|
{
|
2008-06-11 10:30:06 +02:00
|
|
|
TORRENT_ASSERT(m_seeds >= 0);
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2007-05-30 08:52:59 +02:00
|
|
|
avail.resize(m_piece_map.size());
|
2016-12-22 16:42:33 +01:00
|
|
|
auto j = avail.begin();
|
|
|
|
for (auto i = m_piece_map.begin(), end(m_piece_map.end()); i != end; ++i, ++j)
|
2008-01-31 18:52:29 +01:00
|
|
|
*j = i->peer_count + m_seeds;
|
2007-05-30 08:52:59 +02:00
|
|
|
}
|
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
int piece_picker::get_availability(piece_index_t const piece) const
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
return m_piece_map[piece].peer_count + m_seeds;
|
|
|
|
}
|
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
bool piece_picker::mark_as_writing(piece_block const block, torrent_peer* peer)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2008-09-06 23:04:57 +02:00
|
|
|
#endif
|
2006-07-16 02:08:50 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
std::cerr << "[" << this << "] " << "mark_as_writing( {" << block.piece_index << ", " << block.block_index << "} )" << std::endl;
|
|
|
|
#endif
|
|
|
|
|
2016-07-09 22:26:26 +02:00
|
|
|
TORRENT_ASSERT(peer == nullptr || static_cast<torrent_peer*>(peer)->in_use);
|
2012-04-12 19:10:22 +02:00
|
|
|
|
2012-05-03 03:51:56 +02:00
|
|
|
TORRENT_ASSERT(block.block_index != piece_block::invalid.block_index);
|
|
|
|
TORRENT_ASSERT(block.piece_index != piece_block::invalid.piece_index);
|
2016-12-22 16:42:33 +01:00
|
|
|
TORRENT_ASSERT(block.piece_index < m_piece_map.end_index());
|
2016-11-27 14:46:53 +01:00
|
|
|
TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index));
|
2014-07-06 21:18:00 +02:00
|
|
|
// this is not valid for web peers
|
|
|
|
// TORRENT_ASSERT(peer != 0);
|
2003-11-05 00:27:06 +01:00
|
|
|
|
2009-03-17 10:34:44 +01:00
|
|
|
piece_pos& p = m_piece_map[block.piece_index];
|
2014-07-06 21:18:00 +02:00
|
|
|
if (p.downloading() == 0)
|
2009-03-17 10:34:44 +01:00
|
|
|
{
|
2011-02-09 03:56:00 +01:00
|
|
|
// if we already have this piece, just ignore this
|
|
|
|
if (have_piece(block.piece_index)) return false;
|
|
|
|
|
2016-08-07 22:05:20 +02:00
|
|
|
int const prio = p.priority(this);
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(prio < int(m_priority_boundaries.size())
|
2009-03-17 10:34:44 +01:00
|
|
|
|| m_dirty);
|
2015-01-26 03:04:58 +01:00
|
|
|
p.download_state = piece_pos::piece_downloading;
|
2011-04-16 21:25:39 +02:00
|
|
|
// prio being -1 can happen if a block is requested before
|
|
|
|
// the piece priority was set to 0
|
2009-03-17 10:34:44 +01:00
|
|
|
if (prio >= 0 && !m_dirty) update(prio, p.index);
|
2007-06-10 22:46:09 +02:00
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
auto const dp = add_download_piece(block.piece_index);
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = mutable_blocks_for_piece(*dp);
|
2015-02-14 22:32:41 +01:00
|
|
|
block_info& info = binfo[block.block_index];
|
2013-10-06 19:00:07 +02:00
|
|
|
TORRENT_ASSERT(&info >= &m_block_info[0]);
|
|
|
|
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
|
2012-04-12 07:00:20 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == block.piece_index);
|
2009-03-17 10:34:44 +01:00
|
|
|
info.state = block_info::state_writing;
|
|
|
|
info.peer = peer;
|
|
|
|
info.num_peers = 0;
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_ASSERTS
|
|
|
|
info.peers.clear();
|
|
|
|
#endif
|
|
|
|
dp->writing = 1;
|
|
|
|
|
|
|
|
update_piece_state(dp);
|
2009-03-17 10:34:44 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-06-20 17:45:18 +02:00
|
|
|
auto i = find_dl_piece(p.download_queue(), block.piece_index);
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[p.download_queue()].end());
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = mutable_blocks_for_piece(*i);
|
2015-02-14 22:32:41 +01:00
|
|
|
block_info& info = binfo[block.block_index];
|
2008-06-23 15:02:41 +02:00
|
|
|
|
2013-10-06 19:00:07 +02:00
|
|
|
TORRENT_ASSERT(&info >= &m_block_info[0]);
|
|
|
|
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
|
2012-04-12 07:00:20 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == block.piece_index);
|
|
|
|
|
2009-03-17 10:34:44 +01:00
|
|
|
info.peer = peer;
|
|
|
|
if (info.state == block_info::state_requested) --i->requested;
|
2010-05-01 19:47:28 +02:00
|
|
|
if (info.state == block_info::state_writing
|
|
|
|
|| info.state == block_info::state_finished)
|
|
|
|
return false;
|
|
|
|
|
2009-03-17 10:34:44 +01:00
|
|
|
++i->writing;
|
|
|
|
info.state = block_info::state_writing;
|
2012-04-12 07:00:20 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == block.piece_index);
|
2008-09-06 23:04:57 +02:00
|
|
|
|
2009-03-17 10:34:44 +01:00
|
|
|
// all other requests for this block should have been
|
|
|
|
// cancelled now
|
|
|
|
info.num_peers = 0;
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_ASSERTS
|
|
|
|
info.peers.clear();
|
|
|
|
#endif
|
2007-07-07 03:26:30 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
update_piece_state(i);
|
2007-06-10 22:46:09 +02:00
|
|
|
}
|
2010-05-01 19:47:28 +02:00
|
|
|
return true;
|
2007-06-10 22:46:09 +02:00
|
|
|
}
|
2008-02-18 04:07:14 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// calling this function prevents this piece from being picked
|
|
|
|
// by the piece picker until the pieces is restored. This allow
|
|
|
|
// the disk thread to synchronize and flush any failed state
|
|
|
|
// (used for disk write failures and piece hash failures).
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::lock_piece(piece_index_t const piece)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
std::cerr << "[" << this << "] " << "lock_piece(" << piece << ")" << std::endl;
|
|
|
|
#endif
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
int state = m_piece_map[piece].download_queue();
|
2014-07-06 21:18:00 +02:00
|
|
|
if (state == piece_pos::piece_open) return;
|
2017-06-20 17:45:18 +02:00
|
|
|
auto const i = find_dl_piece(state, piece);
|
2015-01-26 03:04:58 +01:00
|
|
|
if (i == m_downloads[state].end()) return;
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
TORRENT_ASSERT(i->passed_hash_check == false);
|
|
|
|
if (i->passed_hash_check)
|
|
|
|
{
|
|
|
|
// it's not clear why this would happen,
|
|
|
|
// but it seems reasonable to not break the
|
|
|
|
// accounting over it.
|
|
|
|
i->passed_hash_check = false;
|
|
|
|
TORRENT_ASSERT(m_num_passed > 0);
|
|
|
|
--m_num_passed;
|
|
|
|
}
|
|
|
|
|
|
|
|
// prevent this piece from being picked until it's restored
|
|
|
|
i->locked = true;
|
|
|
|
}
|
|
|
|
|
2015-01-06 09:08:49 +01:00
|
|
|
// TODO: 2 it would be nice if this could be folded into lock_piece()
|
2014-07-06 21:18:00 +02:00
|
|
|
// the main distinction is that this also maintains the m_num_passed
|
|
|
|
// counter and the passed_hash_check member
|
2015-02-12 04:16:53 +01:00
|
|
|
// Is there ever a case where we call write filed without also locking
|
|
|
|
// the piece? Perhaps write_failed() should imply locking it.
|
2017-06-20 17:45:18 +02:00
|
|
|
void piece_picker::write_failed(piece_block const block)
|
2008-02-18 04:07:14 +01:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2008-02-18 04:07:14 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
std::cerr << "[" << this << "] " << "write_failed( {" << block.piece_index << ", " << block.block_index << "} )" << std::endl;
|
|
|
|
#endif
|
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
int const state = m_piece_map[block.piece_index].download_queue();
|
2014-07-06 21:18:00 +02:00
|
|
|
if (state == piece_pos::piece_open) return;
|
2017-06-20 17:45:18 +02:00
|
|
|
auto i = find_dl_piece(state, block.piece_index);
|
2015-01-26 03:04:58 +01:00
|
|
|
if (i == m_downloads[state].end()) return;
|
2008-02-18 04:07:14 +01:00
|
|
|
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = mutable_blocks_for_piece(*i);
|
2015-02-14 22:32:41 +01:00
|
|
|
block_info& info = binfo[block.block_index];
|
2013-10-06 19:00:07 +02:00
|
|
|
TORRENT_ASSERT(&info >= &m_block_info[0]);
|
|
|
|
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
|
2012-04-12 07:00:20 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == block.piece_index);
|
2009-06-10 10:30:55 +02:00
|
|
|
TORRENT_ASSERT(info.state == block_info::state_writing);
|
|
|
|
TORRENT_ASSERT(info.num_peers == 0);
|
|
|
|
|
|
|
|
TORRENT_ASSERT(i->writing > 0);
|
|
|
|
TORRENT_ASSERT(info.state == block_info::state_writing);
|
|
|
|
|
|
|
|
if (info.state == block_info::state_finished) return;
|
|
|
|
if (info.state == block_info::state_writing) --i->writing;
|
|
|
|
|
2016-07-09 22:26:26 +02:00
|
|
|
info.peer = nullptr;
|
2009-06-10 10:30:55 +02:00
|
|
|
info.state = block_info::state_none;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (i->passed_hash_check)
|
|
|
|
{
|
|
|
|
// the hash was good, but we failed to write
|
|
|
|
// some of the blocks to disk, which means we
|
|
|
|
// can't consider the piece complete
|
|
|
|
i->passed_hash_check = false;
|
|
|
|
TORRENT_ASSERT(m_num_passed > 0);
|
|
|
|
--m_num_passed;
|
|
|
|
}
|
2009-06-10 10:30:55 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// prevent this hash job from actually completing
|
|
|
|
// this piece, by setting the failure state.
|
|
|
|
// the piece is unlocked in the call to restore_piece()
|
|
|
|
i->locked = true;
|
|
|
|
|
|
|
|
i = update_piece_state(i);
|
2011-08-16 08:30:53 +02:00
|
|
|
|
2009-06-10 10:30:55 +02:00
|
|
|
if (i->finished + i->writing + i->requested == 0)
|
|
|
|
{
|
|
|
|
piece_pos& p = m_piece_map[block.piece_index];
|
2016-08-07 22:05:20 +02:00
|
|
|
int const prev_priority = p.priority(this);
|
2009-06-10 10:30:55 +02:00
|
|
|
erase_download_piece(i);
|
2016-08-07 22:05:20 +02:00
|
|
|
int const new_priority = p.priority(this);
|
2009-06-10 10:30:55 +02:00
|
|
|
|
|
|
|
if (m_dirty) return;
|
|
|
|
if (new_priority == prev_priority) return;
|
2011-11-07 05:31:48 +01:00
|
|
|
if (prev_priority == -1) add(block.piece_index);
|
2009-06-10 10:30:55 +02:00
|
|
|
else update(prev_priority, p.index);
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
void piece_picker::mark_as_canceled(piece_block const block, torrent_peer* peer)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2015-02-13 03:58:21 +01:00
|
|
|
std::cerr << "[" << this << "] " << "mark_as_cancelled( {"
|
|
|
|
<< block.piece_index << ", " << block.block_index
|
|
|
|
<< "} )" << std::endl;
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
|
|
|
TORRENT_ASSERT(block.block_index >= 0);
|
|
|
|
piece_pos& p = m_piece_map[block.piece_index];
|
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
if (p.download_queue() == piece_pos::piece_open) return;
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
auto i = find_dl_piece(p.download_queue(), block.piece_index);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[p.download_queue()].end());
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = mutable_blocks_for_piece(*i);
|
2015-02-14 22:32:41 +01:00
|
|
|
block_info& info = binfo[block.block_index];
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
if (info.state == block_info::state_finished) return;
|
|
|
|
|
|
|
|
TORRENT_ASSERT(info.num_peers == 0);
|
|
|
|
info.peer = peer;
|
|
|
|
TORRENT_ASSERT(info.state == block_info::state_writing
|
2016-07-09 22:26:26 +02:00
|
|
|
|| peer == nullptr);
|
2014-07-06 21:18:00 +02:00
|
|
|
if (info.state == block_info::state_writing)
|
|
|
|
{
|
|
|
|
--i->writing;
|
|
|
|
info.state = block_info::state_none;
|
2015-02-13 03:58:21 +01:00
|
|
|
// i may be invalid after this call
|
|
|
|
i = update_piece_state(i);
|
|
|
|
|
|
|
|
if (i->finished + i->writing + i->requested == 0)
|
|
|
|
{
|
2016-08-07 22:05:20 +02:00
|
|
|
int const prev_priority = p.priority(this);
|
2015-02-13 03:58:21 +01:00
|
|
|
erase_download_piece(i);
|
2016-08-07 22:05:20 +02:00
|
|
|
int const new_priority = p.priority(this);
|
2015-02-13 03:58:21 +01:00
|
|
|
|
|
|
|
if (m_dirty) return;
|
|
|
|
if (new_priority == prev_priority) return;
|
|
|
|
if (prev_priority == -1) add(block.piece_index);
|
|
|
|
else update(prev_priority, p.index);
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2009-06-10 10:30:55 +02:00
|
|
|
else
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(info.state == block_info::state_none);
|
2009-06-10 10:30:55 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
2008-02-18 04:07:14 +01:00
|
|
|
}
|
2008-09-06 23:04:57 +02:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
void piece_picker::mark_as_finished(piece_block const block, torrent_peer* peer)
|
2007-06-10 22:46:09 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef TORRENT_PICKER_LOG
|
2015-02-12 04:16:53 +01:00
|
|
|
std::cerr << "[" << this << "] " << "mark_as_finished( {"
|
|
|
|
<< block.piece_index << ", " << block.block_index << "} )" << std::endl;
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
|
2016-07-09 22:26:26 +02:00
|
|
|
TORRENT_ASSERT(peer == nullptr || static_cast<torrent_peer*>(peer)->in_use);
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(block.block_index >= 0);
|
2007-06-10 22:46:09 +02:00
|
|
|
|
|
|
|
piece_pos& p = m_piece_map[block.piece_index];
|
2005-05-25 12:01:01 +02:00
|
|
|
|
2015-01-26 03:04:58 +01:00
|
|
|
if (p.download_queue() == piece_pos::piece_open)
|
2003-11-05 00:27:06 +01:00
|
|
|
{
|
2011-02-09 03:56:00 +01:00
|
|
|
// if we already have this piece, just ignore this
|
|
|
|
if (have_piece(block.piece_index)) return;
|
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2008-09-06 23:04:57 +02:00
|
|
|
#endif
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2016-08-07 22:05:20 +02:00
|
|
|
int const prio = p.priority(this);
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(prio < int(m_priority_boundaries.size())
|
2008-01-31 18:52:29 +01:00
|
|
|
|| m_dirty);
|
2015-01-26 03:04:58 +01:00
|
|
|
p.download_state = piece_pos::piece_downloading;
|
2008-01-31 18:52:29 +01:00
|
|
|
if (prio >= 0 && !m_dirty) update(prio, p.index);
|
2003-11-05 00:27:06 +01:00
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
auto const dp = add_download_piece(block.piece_index);
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = mutable_blocks_for_piece(*dp);
|
2015-02-14 22:32:41 +01:00
|
|
|
block_info& info = binfo[block.block_index];
|
2013-10-06 19:00:07 +02:00
|
|
|
TORRENT_ASSERT(&info >= &m_block_info[0]);
|
|
|
|
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
|
2012-04-12 07:00:20 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == block.piece_index);
|
2007-06-10 22:46:09 +02:00
|
|
|
info.peer = peer;
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(info.state == block_info::state_none);
|
2008-02-18 04:07:14 +01:00
|
|
|
TORRENT_ASSERT(info.num_peers == 0);
|
2014-07-06 21:18:00 +02:00
|
|
|
++dp->finished;
|
2007-06-10 22:46:09 +02:00
|
|
|
info.state = block_info::state_finished;
|
2014-07-06 21:18:00 +02:00
|
|
|
// dp may be invalid after this call
|
|
|
|
update_piece_state(dp);
|
2003-11-05 00:27:06 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2008-09-06 23:04:57 +02:00
|
|
|
#endif
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
auto i = find_dl_piece(p.download_queue(), block.piece_index);
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[p.download_queue()].end());
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = mutable_blocks_for_piece(*i);
|
2015-02-14 22:32:41 +01:00
|
|
|
block_info& info = binfo[block.block_index];
|
2012-04-12 07:00:20 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == block.piece_index);
|
2009-01-14 08:41:25 +01:00
|
|
|
|
|
|
|
if (info.state == block_info::state_finished) return;
|
|
|
|
|
2008-02-18 04:07:14 +01:00
|
|
|
TORRENT_ASSERT(info.num_peers == 0);
|
2013-08-19 05:54:45 +02:00
|
|
|
|
|
|
|
// peers may have been disconnected in between mark_as_writing
|
|
|
|
// and mark_as_finished. When a peer disconnects, its m_peer_info
|
2016-06-20 17:32:06 +02:00
|
|
|
// pointer is set to nullptr. If so, preserve the previous peer
|
2013-08-19 05:54:45 +02:00
|
|
|
// pointer, instead of forgetting who we downloaded this block from
|
2016-07-09 22:26:26 +02:00
|
|
|
if (info.state != block_info::state_writing || peer != nullptr)
|
2013-08-19 05:54:45 +02:00
|
|
|
info.peer = peer;
|
|
|
|
|
2007-06-10 22:46:09 +02:00
|
|
|
++i->finished;
|
2007-07-15 17:41:55 +02:00
|
|
|
if (info.state == block_info::state_writing)
|
2007-08-22 20:40:31 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(i->writing > 0);
|
2007-07-15 17:41:55 +02:00
|
|
|
--i->writing;
|
2007-08-22 20:40:31 +02:00
|
|
|
info.state = block_info::state_finished;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-09-06 23:04:57 +02:00
|
|
|
TORRENT_ASSERT(info.state == block_info::state_none);
|
2007-08-22 20:40:31 +02:00
|
|
|
info.state = block_info::state_finished;
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
i = update_piece_state(i);
|
2015-06-30 02:40:32 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (i->finished < blocks_in_piece(i->index))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (i->passed_hash_check)
|
|
|
|
we_have(i->index);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
|
|
|
check_piece_state();
|
|
|
|
#endif
|
2003-11-05 00:27:06 +01:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2016-12-22 16:42:33 +01:00
|
|
|
void piece_picker::get_downloaders(std::vector<torrent_peer*>& d
|
|
|
|
, piece_index_t const index) const
|
2003-11-02 22:06:50 +01:00
|
|
|
{
|
|
|
|
d.clear();
|
2016-08-07 22:05:20 +02:00
|
|
|
int const state = m_piece_map[index].download_queue();
|
|
|
|
int const num_blocks = blocks_in_piece(index);
|
2017-02-08 16:54:55 +01:00
|
|
|
d.reserve(aux::numeric_cast<std::size_t>(num_blocks));
|
2015-02-13 03:58:21 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (state == piece_pos::piece_open)
|
|
|
|
{
|
2016-06-20 17:32:06 +02:00
|
|
|
for (int i = 0; i < num_blocks; ++i) d.push_back(nullptr);
|
2014-07-06 21:18:00 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
auto const i = find_dl_piece(state, index);
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[state].end());
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = blocks_for_piece(*i);
|
2015-02-13 03:58:21 +01:00
|
|
|
for (int j = 0; j != num_blocks; ++j)
|
2003-11-02 22:06:50 +01:00
|
|
|
{
|
2016-07-09 22:26:26 +02:00
|
|
|
TORRENT_ASSERT(binfo[j].peer == nullptr
|
2015-08-18 10:25:13 +02:00
|
|
|
|| binfo[j].peer->in_use);
|
2015-02-14 22:32:41 +01:00
|
|
|
d.push_back(binfo[j].peer);
|
2003-11-02 22:06:50 +01:00
|
|
|
}
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
torrent_peer* piece_picker::get_downloader(piece_block const block) const
|
2004-01-13 04:08:59 +01:00
|
|
|
{
|
2016-08-07 22:05:20 +02:00
|
|
|
int const state = m_piece_map[block.piece_index].download_queue();
|
2016-07-09 22:26:26 +02:00
|
|
|
if (state == piece_pos::piece_open) return nullptr;
|
2004-01-13 04:08:59 +01:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
auto const i = find_dl_piece(state, block.piece_index);
|
2004-01-13 04:08:59 +01:00
|
|
|
|
2012-05-03 03:51:56 +02:00
|
|
|
TORRENT_ASSERT(block.block_index != piece_block::invalid.block_index);
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = blocks_for_piece(*i);
|
2015-02-14 22:32:41 +01:00
|
|
|
TORRENT_ASSERT(binfo[block.block_index].piece_index == block.piece_index);
|
|
|
|
if (binfo[block.block_index].state == block_info::state_none)
|
2016-06-20 17:32:06 +02:00
|
|
|
return nullptr;
|
2004-01-13 04:08:59 +01:00
|
|
|
|
2015-08-18 10:25:13 +02:00
|
|
|
torrent_peer* peer = binfo[block.block_index].peer;
|
2016-07-09 22:26:26 +02:00
|
|
|
TORRENT_ASSERT(peer == nullptr || static_cast<torrent_peer*>(peer)->in_use);
|
2012-04-12 19:10:22 +02:00
|
|
|
return peer;
|
2004-01-13 04:08:59 +01:00
|
|
|
}
|
|
|
|
|
2008-02-18 21:55:03 +01:00
|
|
|
// this is called when a request is rejected or when
|
|
|
|
// a peer disconnects. The piece might be in any state
|
2017-06-20 17:45:18 +02:00
|
|
|
void piece_picker::abort_download(piece_block const block, torrent_peer* peer)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-10-10 09:08:46 +02:00
|
|
|
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
2016-08-02 13:20:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2008-10-10 09:08:46 +02:00
|
|
|
#endif
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifdef TORRENT_PICKER_LOG
|
|
|
|
std::cerr << "[" << this << "] " << "abort_download( {" << block.piece_index << ", " << block.block_index << "} )" << std::endl;
|
|
|
|
#endif
|
2016-07-09 22:26:26 +02:00
|
|
|
TORRENT_ASSERT(peer == nullptr || peer->in_use);
|
2012-04-12 19:10:22 +02:00
|
|
|
|
2012-05-03 03:51:56 +02:00
|
|
|
TORRENT_ASSERT(block.block_index != piece_block::invalid.block_index);
|
|
|
|
TORRENT_ASSERT(block.piece_index != piece_block::invalid.piece_index);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
int const state = m_piece_map[block.piece_index].download_queue();
|
2014-07-06 21:18:00 +02:00
|
|
|
if (state == piece_pos::piece_open) return;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
auto i = find_dl_piece(state, block.piece_index);
|
2015-01-26 03:04:58 +01:00
|
|
|
TORRENT_ASSERT(i != m_downloads[state].end());
|
2003-11-05 00:27:06 +01:00
|
|
|
|
2017-03-05 05:45:07 +01:00
|
|
|
auto const binfo = mutable_blocks_for_piece(*i);
|
2015-02-14 22:32:41 +01:00
|
|
|
block_info& info = binfo[block.block_index];
|
2016-07-09 22:26:26 +02:00
|
|
|
TORRENT_ASSERT(info.peer == nullptr || info.peer->in_use);
|
2012-04-12 07:00:20 +02:00
|
|
|
TORRENT_ASSERT(info.piece_index == block.piece_index);
|
2008-02-18 04:07:14 +01:00
|
|
|
|
2008-09-06 23:04:57 +02:00
|
|
|
TORRENT_ASSERT(info.state != block_info::state_none);
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (info.state != block_info::state_requested) return;
|
2008-02-18 21:55:03 +01:00
|
|
|
|
2017-06-20 17:45:18 +02:00
|
|
|
piece_pos const& p = m_piece_map[block.piece_index];
|
|
|
|
int const prev_prio = p.priority(this);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
#if TORRENT_USE_ASSERTS
|
|
|
|
TORRENT_ASSERT(info.peers.count(peer));
|
|
|
|
info.peers.erase(peer);
|
|
|
|
#endif
|
|
|
|
TORRENT_ASSERT(info.num_peers > 0);
|
|
|
|
if (info.num_peers > 0) --info.num_peers;
|
2016-07-09 22:26:26 +02:00
|
|
|
if (info.peer == peer) info.peer = nullptr;
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(info.peers.size() == info.num_peers);
|
2008-09-06 23:04:57 +02:00
|
|
|
|
2016-11-27 14:46:53 +01:00
|
|
|
TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index));
|
2008-02-18 04:07:14 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// if there are other peers, leave the block requested
|
|
|
|
if (info.num_peers > 0) return;
|
2007-07-06 19:15:35 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// clear the downloader of this block
|
2016-07-09 22:26:26 +02:00
|
|
|
info.peer = nullptr;
|
2007-03-30 21:18:03 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// clear this block as being downloaded
|
|
|
|
info.state = block_info::state_none;
|
|
|
|
TORRENT_ASSERT(i->requested > 0);
|
|
|
|
--i->requested;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2006-12-15 03:26:11 +01:00
|
|
|
// if there are no other blocks in this piece
|
2003-10-23 01:00:57 +02:00
|
|
|
// that's being downloaded, remove it from the list
|
2007-06-10 22:46:09 +02:00
|
|
|
if (i->requested + i->finished + i->writing == 0)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
TORRENT_ASSERT(prev_prio < int(m_priority_boundaries.size())
|
2008-01-31 18:52:29 +01:00
|
|
|
|| m_dirty);
|
2009-06-10 10:30:55 +02:00
|
|
|
erase_download_piece(i);
|
2016-08-07 22:05:20 +02:00
|
|
|
int const prio = p.priority(this);
|
2008-09-06 23:04:57 +02:00
|
|
|
if (!m_dirty)
|
2008-01-31 18:52:29 +01:00
|
|
|
{
|
|
|
|
if (prev_prio == -1 && prio >= 0) add(block.piece_index);
|
|
|
|
else if (prev_prio >= 0) update(prev_prio, p.index);
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
return;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
i = update_piece_state(i);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2003-10-30 00:28:09 +01:00
|
|
|
int piece_picker::unverified_blocks() const
|
|
|
|
{
|
|
|
|
int counter = 0;
|
2018-01-11 01:35:15 +01:00
|
|
|
for (auto const& c : m_downloads)
|
2003-10-30 00:28:09 +01:00
|
|
|
{
|
2018-01-11 01:35:15 +01:00
|
|
|
for (auto const& dp : c)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2016-08-02 13:20:13 +02:00
|
|
|
counter += int(dp.finished);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
2003-10-30 00:28:09 +01:00
|
|
|
}
|
|
|
|
return counter;
|
|
|
|
}
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|