2003-10-23 01:00:57 +02:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (c) 2003, Arvid Norberg
|
|
|
|
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>
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
#include "libtorrent/piece_picker.hpp"
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
#include "libtorrent/torrent.hpp"
|
|
|
|
#include "libtorrent/peer_connection.hpp"
|
|
|
|
#endif
|
|
|
|
|
2003-12-01 06:01:40 +01:00
|
|
|
#if defined(_MSC_VER) && _MSC_VER < 1300
|
2003-10-23 01:00:57 +02:00
|
|
|
#define for if (false) {} else for
|
2003-12-01 06:01:40 +01:00
|
|
|
namespace std
|
|
|
|
{
|
|
|
|
template<class T>
|
|
|
|
inline T min(T a, T b) { return a<b?a:b; }
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace libtorrent
|
|
|
|
{
|
|
|
|
|
|
|
|
piece_picker::piece_picker(int blocks_per_piece, int total_num_blocks)
|
|
|
|
: m_piece_info(2)
|
|
|
|
, m_downloading_piece_info(2)
|
2005-05-25 12:01:01 +02:00
|
|
|
, m_filtered_piece_info(2)
|
2003-10-23 01:00:57 +02:00
|
|
|
, m_piece_map((total_num_blocks + blocks_per_piece-1) / blocks_per_piece)
|
2005-05-30 19:43:03 +02:00
|
|
|
, m_num_filtered(0)
|
|
|
|
, m_num_have_filtered(0)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2004-01-26 01:21:12 +01:00
|
|
|
assert(blocks_per_piece > 0);
|
|
|
|
assert(total_num_blocks > 0);
|
2004-01-25 23:41:55 +01:00
|
|
|
|
2005-03-19 13:22:40 +01:00
|
|
|
// the piece index is stored in 20 bits, which limits the allowed
|
|
|
|
// number of pieces somewhat
|
2005-08-12 14:40:58 +02:00
|
|
|
if (m_piece_map.size() >= piece_pos::we_have_index)
|
|
|
|
throw std::runtime_error("too many pieces in torrent");
|
2005-03-19 13:22:40 +01:00
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
m_blocks_per_piece = blocks_per_piece;
|
|
|
|
m_blocks_in_last_piece = total_num_blocks % blocks_per_piece;
|
|
|
|
if (m_blocks_in_last_piece == 0) m_blocks_in_last_piece = blocks_per_piece;
|
|
|
|
|
|
|
|
assert(m_blocks_per_piece <= max_blocks_per_piece);
|
|
|
|
assert(m_blocks_in_last_piece <= m_blocks_per_piece);
|
|
|
|
assert(m_blocks_in_last_piece <= max_blocks_per_piece);
|
|
|
|
|
|
|
|
// allocate the piece_map to cover all pieces
|
|
|
|
// and make them invalid (as if though we already had every piece)
|
2005-08-12 14:40:58 +02:00
|
|
|
std::fill(m_piece_map.begin(), m_piece_map.end()
|
|
|
|
, piece_pos(0, piece_pos::we_have_index));
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2005-05-30 19:43:03 +02:00
|
|
|
// pieces is a bitmask with the pieces we have
|
2004-01-03 03:10:11 +01:00
|
|
|
void piece_picker::files_checked(
|
|
|
|
const std::vector<bool>& pieces
|
|
|
|
, const std::vector<downloading_piece>& unfinished)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2003-12-17 20:03:23 +01:00
|
|
|
// build a vector of all the pieces we don't have
|
|
|
|
std::vector<int> piece_list;
|
2005-05-29 19:25:13 +02:00
|
|
|
piece_list.reserve(std::count(pieces.begin(), pieces.end(), false));
|
2003-12-17 20:03:23 +01:00
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
for (std::vector<bool>::const_iterator i = pieces.begin();
|
2005-05-13 02:39:39 +02:00
|
|
|
i != pieces.end(); ++i)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
|
|
|
if (*i) continue;
|
2004-01-25 19:18:36 +01:00
|
|
|
int index = static_cast<int>(i - pieces.begin());
|
2005-05-30 19:43:03 +02:00
|
|
|
if (m_piece_map[index].filtered)
|
|
|
|
{
|
|
|
|
++m_num_filtered;
|
|
|
|
--m_num_have_filtered;
|
|
|
|
}
|
2003-12-17 20:03:23 +01:00
|
|
|
piece_list.push_back(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
// random shuffle the list
|
|
|
|
std::random_shuffle(piece_list.begin(), piece_list.end());
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2003-12-17 20:03:23 +01:00
|
|
|
// add the pieces to the piece_picker
|
|
|
|
for (std::vector<int>::iterator i = piece_list.begin();
|
2005-05-13 02:39:39 +02:00
|
|
|
i != piece_list.end(); ++i)
|
2003-12-17 20:03:23 +01:00
|
|
|
{
|
|
|
|
int index = *i;
|
2004-01-26 01:21:12 +01:00
|
|
|
assert(index >= 0);
|
|
|
|
assert(index < (int)m_piece_map.size());
|
2005-05-25 12:01:01 +02:00
|
|
|
assert(m_piece_map[index].index == piece_pos::we_have_index);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
int peer_count = m_piece_map[index].peer_count;
|
|
|
|
assert(peer_count == 0);
|
|
|
|
assert(m_piece_info.size() == 2);
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
piece_pos& p = m_piece_map[index];
|
2005-05-29 19:25:13 +02:00
|
|
|
std::vector<std::vector<int> >& dst_vec = pick_piece_info_vector(
|
|
|
|
p.downloading, p.filtered);
|
2005-05-25 12:01:01 +02:00
|
|
|
assert((int)dst_vec.size() > peer_count);
|
|
|
|
p.index = (int)dst_vec[peer_count].size();
|
|
|
|
dst_vec[peer_count].push_back(index);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2004-01-03 03:10:11 +01:00
|
|
|
|
|
|
|
// if we have fast resume info
|
|
|
|
// use it
|
|
|
|
if (!unfinished.empty())
|
|
|
|
{
|
|
|
|
for (std::vector<downloading_piece>::const_iterator i
|
2005-05-13 02:39:39 +02:00
|
|
|
= unfinished.begin(); i != unfinished.end(); ++i)
|
2004-01-03 03:10:11 +01:00
|
|
|
{
|
2004-01-12 21:31:27 +01:00
|
|
|
address peer;
|
2004-01-03 03:10:11 +01:00
|
|
|
for (int j = 0; j < m_blocks_per_piece; ++j)
|
|
|
|
{
|
|
|
|
if (i->finished_blocks[j])
|
|
|
|
mark_as_finished(piece_block(i->index, j), peer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
#ifndef NDEBUG
|
2005-05-29 19:25:13 +02:00
|
|
|
integrity_check();
|
2003-10-23 01:00:57 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
|
|
|
void piece_picker::integrity_check(const torrent* t) const
|
|
|
|
{
|
|
|
|
assert(sizeof(piece_pos) == 4);
|
|
|
|
|
|
|
|
if (t != 0)
|
2004-01-26 11:29:00 +01:00
|
|
|
assert((int)m_piece_map.size() == t->torrent_file().num_pieces());
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-05-30 19:43:03 +02:00
|
|
|
int num_filtered = 0;
|
|
|
|
int num_have_filtered = 0;
|
2003-10-23 01:00:57 +02:00
|
|
|
for (std::vector<piece_pos>::const_iterator i = m_piece_map.begin();
|
2005-05-13 02:39:39 +02:00
|
|
|
i != m_piece_map.end(); ++i)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2004-01-25 19:18:36 +01:00
|
|
|
int index = static_cast<int>(i - m_piece_map.begin());
|
2005-05-30 19:43:03 +02:00
|
|
|
if (i->filtered)
|
|
|
|
{
|
|
|
|
if (i->index != piece_pos::we_have_index)
|
|
|
|
++num_filtered;
|
|
|
|
else
|
|
|
|
++num_have_filtered;
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
if (t != 0)
|
|
|
|
{
|
|
|
|
int actual_peer_count = 0;
|
2004-01-13 04:08:59 +01:00
|
|
|
for (torrent::const_peer_iterator peer = t->begin();
|
2005-05-13 02:39:39 +02:00
|
|
|
peer != t->end(); ++peer)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2004-01-13 04:08:59 +01:00
|
|
|
if (peer->second->has_piece(index)) actual_peer_count++;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2004-01-26 11:29:00 +01:00
|
|
|
assert((int)i->peer_count == actual_peer_count);
|
2003-10-23 01:00:57 +02:00
|
|
|
/*
|
|
|
|
int num_downloaders = 0;
|
|
|
|
for (std::vector<peer_connection*>::const_iterator peer = t->begin();
|
|
|
|
peer != t->end();
|
|
|
|
++peer)
|
|
|
|
{
|
|
|
|
const std::vector<piece_block>& queue = (*peer)->download_queue();
|
|
|
|
if (std::find_if(queue.begin(), queue.end(), has_index(index)) == queue.end()) continue;
|
|
|
|
|
|
|
|
++num_downloaders;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i->downloading)
|
|
|
|
{
|
|
|
|
assert(num_downloaders == 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(num_downloaders == 0);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
if (i->index == piece_pos::we_have_index)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
|
|
|
assert(t == 0 || t->have_piece(index));
|
|
|
|
assert(i->downloading == 0);
|
|
|
|
|
|
|
|
// make sure there's no entry
|
|
|
|
// with this index. (there shouldn't
|
2005-05-25 12:01:01 +02:00
|
|
|
// be since the piece_map is piece_pos::we_have_index)
|
2003-10-23 01:00:57 +02:00
|
|
|
for (std::vector<std::vector<int> >::const_iterator i = m_piece_info.begin();
|
2005-05-13 02:39:39 +02:00
|
|
|
i != m_piece_info.end(); ++i)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
|
|
|
for (std::vector<int>::const_iterator j= i->begin();
|
2005-05-13 02:39:39 +02:00
|
|
|
j != i->end(); ++j)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
|
|
|
assert(*j != index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (std::vector<std::vector<int> >::const_iterator i = m_downloading_piece_info.begin();
|
2005-05-25 12:01:01 +02:00
|
|
|
i != m_downloading_piece_info.end(); ++i)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
|
|
|
for (std::vector<int>::const_iterator j = i->begin();
|
2005-05-13 02:39:39 +02:00
|
|
|
j != i->end(); ++j)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
|
|
|
assert(*j != index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (t != 0)
|
|
|
|
assert(!t->have_piece(index));
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
const std::vector<std::vector<int> >& c_vec = pick_piece_info_vector(i->downloading, i->filtered);
|
2003-10-23 01:00:57 +02:00
|
|
|
assert(i->peer_count < c_vec.size());
|
|
|
|
const std::vector<int>& vec = c_vec[i->peer_count];
|
|
|
|
assert(i->index < vec.size());
|
|
|
|
assert(vec[i->index] == index);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<downloading_piece>::const_iterator down
|
|
|
|
= std::find_if(m_downloads.begin(),
|
|
|
|
m_downloads.end(),
|
|
|
|
has_index(index));
|
|
|
|
if (i->downloading == 1)
|
|
|
|
{
|
|
|
|
assert(down != m_downloads.end());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(down == m_downloads.end());
|
|
|
|
}
|
|
|
|
}
|
2005-05-30 19:43:03 +02:00
|
|
|
assert(num_filtered == m_num_filtered);
|
|
|
|
assert(num_have_filtered == m_num_have_filtered);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2004-09-08 01:16:11 +02:00
|
|
|
#endif
|
|
|
|
|
2004-08-05 15:56:26 +02:00
|
|
|
float piece_picker::distributed_copies() const
|
|
|
|
{
|
2004-09-08 01:16:11 +02:00
|
|
|
const float num_pieces = static_cast<float>(m_piece_map.size());
|
|
|
|
|
|
|
|
for (int i = 0; i < (int)m_piece_info.size(); ++i)
|
2004-08-05 15:56:26 +02:00
|
|
|
{
|
2004-09-08 01:16:11 +02:00
|
|
|
int p = (int)m_piece_info[i].size();
|
|
|
|
assert(float(p) / num_pieces <= 1.f);
|
|
|
|
if (p > 0)
|
|
|
|
{
|
2004-08-05 15:56:26 +02:00
|
|
|
float fraction_above_count =
|
2004-09-08 01:16:11 +02:00
|
|
|
1.f - float(p) / num_pieces;
|
|
|
|
return i + fraction_above_count;
|
2004-08-05 15:56:26 +02:00
|
|
|
}
|
|
|
|
}
|
2004-09-08 01:16:11 +02:00
|
|
|
return 1.f;
|
2004-08-05 15:56:26 +02:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
std::vector<std::vector<int> >& piece_picker::pick_piece_info_vector(
|
|
|
|
bool downloading, bool filtered)
|
|
|
|
{
|
|
|
|
return filtered
|
|
|
|
?m_filtered_piece_info
|
|
|
|
:(downloading?m_downloading_piece_info:m_piece_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::vector<int> > const& piece_picker::pick_piece_info_vector(
|
|
|
|
bool downloading, bool filtered) const
|
|
|
|
{
|
|
|
|
return filtered
|
|
|
|
?m_filtered_piece_info
|
|
|
|
:(downloading?m_downloading_piece_info:m_piece_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// will update the piece with the given properties (downloading, filtered, peer_count, elem_index)
|
|
|
|
// to place it at the correct position in the vectors.
|
|
|
|
void piece_picker::move(bool downloading, bool filtered, int peer_count, int elem_index)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(peer_count >= 0);
|
|
|
|
assert(elem_index >= 0);
|
2005-05-25 12:01:01 +02:00
|
|
|
std::vector<std::vector<int> >& src_vec(pick_piece_info_vector(downloading, filtered));
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
assert((int)src_vec.size() > peer_count);
|
|
|
|
assert((int)src_vec[peer_count].size() > elem_index);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
int index = src_vec[peer_count][elem_index];
|
|
|
|
// update the piece_map
|
|
|
|
piece_pos& p = m_piece_map[index];
|
|
|
|
|
2005-05-29 10:58:21 +02:00
|
|
|
assert(p.downloading != downloading
|
|
|
|
|| p.filtered != filtered
|
|
|
|
|| (int)p.peer_count != peer_count);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
std::vector<std::vector<int> >& dst_vec(pick_piece_info_vector(p.downloading, p.filtered));
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
if (dst_vec.size() <= p.peer_count)
|
|
|
|
{
|
|
|
|
dst_vec.resize(p.peer_count+1);
|
|
|
|
assert(dst_vec.size() > p.peer_count);
|
|
|
|
}
|
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
p.index = (int)dst_vec[p.peer_count].size();
|
2003-10-23 01:00:57 +02:00
|
|
|
dst_vec[p.peer_count].push_back(index);
|
|
|
|
assert(p.index < dst_vec[p.peer_count].size());
|
|
|
|
assert(dst_vec[p.peer_count][p.index] == index);
|
|
|
|
|
|
|
|
// this will remove elem from the source vector without
|
2005-02-23 17:56:32 +01:00
|
|
|
// preserving order, but the order is random any way
|
2003-10-23 01:00:57 +02:00
|
|
|
int replace_index = src_vec[peer_count][elem_index] = src_vec[peer_count].back();
|
|
|
|
if (index != replace_index)
|
|
|
|
{
|
|
|
|
// update the entry we moved from the back
|
|
|
|
m_piece_map[replace_index].index = elem_index;
|
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
assert((int)src_vec[peer_count].size() > elem_index);
|
2004-01-26 11:29:00 +01:00
|
|
|
assert((int)m_piece_map[replace_index].peer_count == peer_count);
|
|
|
|
assert((int)m_piece_map[replace_index].index == elem_index);
|
2003-10-23 01:00:57 +02:00
|
|
|
assert(src_vec[peer_count][elem_index] == replace_index);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-01-26 11:29:00 +01:00
|
|
|
assert((int)src_vec[peer_count].size() == elem_index+1);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
src_vec[peer_count].pop_back();
|
|
|
|
}
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
void piece_picker::remove(bool downloading, bool filtered, int peer_count, int elem_index)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(peer_count >= 0);
|
|
|
|
assert(elem_index >= 0);
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
std::vector<std::vector<int> >& src_vec(pick_piece_info_vector(downloading, filtered));
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
assert((int)src_vec.size() > peer_count);
|
|
|
|
assert((int)src_vec[peer_count].size() > elem_index);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
int index = src_vec[peer_count][elem_index];
|
2005-05-25 12:01:01 +02:00
|
|
|
m_piece_map[index].index = piece_pos::we_have_index;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
if (downloading)
|
|
|
|
{
|
|
|
|
std::vector<downloading_piece>::iterator i
|
|
|
|
= std::find_if(m_downloads.begin(),
|
|
|
|
m_downloads.end(),
|
|
|
|
has_index(index));
|
|
|
|
assert(i != m_downloads.end());
|
|
|
|
m_downloads.erase(i);
|
|
|
|
}
|
|
|
|
m_piece_map[index].downloading = 0;
|
|
|
|
|
|
|
|
// this will remove elem from the vector without
|
|
|
|
// preserving order
|
|
|
|
index = src_vec[peer_count][elem_index] = src_vec[peer_count].back();
|
|
|
|
// update the entry we moved from the back
|
2004-01-25 19:18:36 +01:00
|
|
|
if ((int)src_vec[peer_count].size() > elem_index+1)
|
2003-10-23 01:00:57 +02:00
|
|
|
m_piece_map[index].index = elem_index;
|
|
|
|
src_vec[peer_count].pop_back();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void piece_picker::restore_piece(int index)
|
|
|
|
{
|
|
|
|
assert(index >= 0);
|
2004-01-25 19:18:36 +01:00
|
|
|
assert(index < (int)m_piece_map.size());
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
assert(m_piece_map[index].downloading == 1);
|
|
|
|
|
|
|
|
std::vector<downloading_piece>::iterator i
|
|
|
|
= std::find_if(m_downloads.begin(),
|
|
|
|
m_downloads.end(),
|
|
|
|
has_index(index));
|
|
|
|
assert(i != m_downloads.end());
|
|
|
|
m_downloads.erase(i);
|
|
|
|
|
|
|
|
m_piece_map[index].downloading = 0;
|
2005-05-25 12:01:01 +02:00
|
|
|
piece_pos& p = m_piece_map[index];
|
|
|
|
move(true, p.filtered, p.peer_count, p.index);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2004-11-21 11:49:02 +01:00
|
|
|
// integrity_check();
|
2003-10-23 01:00:57 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2003-12-18 04:30:41 +01:00
|
|
|
void piece_picker::inc_refcount(int i)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
|
|
|
assert(i >= 0);
|
2004-01-25 19:18:36 +01:00
|
|
|
assert(i < (int)m_piece_map.size());
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
int peer_count = m_piece_map[i].peer_count;
|
|
|
|
int index = m_piece_map[i].index;
|
|
|
|
|
2005-03-19 13:22:40 +01:00
|
|
|
assert(peer_count < 2048);
|
2003-10-23 01:00:57 +02:00
|
|
|
m_piece_map[i].peer_count++;
|
2005-05-12 01:03:12 +02:00
|
|
|
assert(m_piece_map[i].peer_count != 0);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2003-12-18 04:30:41 +01:00
|
|
|
// if we have the piece, we don't have to move
|
|
|
|
// any entries in the piece_info vector
|
2005-05-25 12:01:01 +02:00
|
|
|
if (index == piece_pos::we_have_index) return;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
piece_pos& p = m_piece_map[i];
|
|
|
|
move(p.downloading, p.filtered, peer_count, index);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2004-11-21 11:49:02 +01:00
|
|
|
// integrity_check();
|
2003-10-23 01:00:57 +02:00
|
|
|
#endif
|
2003-12-18 04:30:41 +01:00
|
|
|
return;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void piece_picker::dec_refcount(int i)
|
|
|
|
{
|
2004-12-21 13:30:09 +01:00
|
|
|
#ifndef NDEBUG
|
|
|
|
// integrity_check();
|
|
|
|
#endif
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
assert(i >= 0);
|
2004-01-25 19:18:36 +01:00
|
|
|
assert(i < (int)m_piece_map.size());
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
int peer_count = m_piece_map[i].peer_count;
|
|
|
|
int index = m_piece_map[i].index;
|
2005-03-19 13:22:40 +01:00
|
|
|
assert(peer_count > 0);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-11-18 23:33:50 +01:00
|
|
|
if (m_piece_map[i].peer_count > 0)
|
|
|
|
m_piece_map[i].peer_count--;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
if (index == piece_pos::we_have_index) return;
|
|
|
|
piece_pos& p = m_piece_map[i];
|
|
|
|
move(p.downloading, p.filtered, peer_count, index);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
// this is used to indicate that we succesfully have
|
|
|
|
// 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.
|
2003-10-23 01:00:57 +02:00
|
|
|
void piece_picker::we_have(int index)
|
|
|
|
{
|
2004-01-26 01:21:12 +01:00
|
|
|
assert(index >= 0);
|
|
|
|
assert(index < (int)m_piece_map.size());
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
int info_index = m_piece_map[index].index;
|
|
|
|
int peer_count = m_piece_map[index].peer_count;
|
|
|
|
|
|
|
|
assert(m_piece_map[index].downloading == 1);
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
assert(info_index != piece_pos::we_have_index);
|
|
|
|
piece_pos& p = m_piece_map[index];
|
2005-05-30 19:43:03 +02:00
|
|
|
if (p.filtered)
|
|
|
|
{
|
|
|
|
--m_num_filtered;
|
|
|
|
++m_num_have_filtered;
|
|
|
|
}
|
2005-05-25 12:01:01 +02:00
|
|
|
remove(p.downloading, p.filtered, peer_count, info_index);
|
2003-10-23 01:00:57 +02:00
|
|
|
#ifndef NDEBUG
|
2005-05-29 19:25:13 +02:00
|
|
|
integrity_check();
|
2003-10-23 01:00:57 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
|
|
|
|
void piece_picker::mark_as_filtered(int index)
|
|
|
|
{
|
|
|
|
assert(index >= 0);
|
|
|
|
assert(index < (int)m_piece_map.size());
|
|
|
|
|
2005-05-29 19:25:13 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
integrity_check();
|
|
|
|
#endif
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
piece_pos& p = m_piece_map[index];
|
|
|
|
if (p.filtered == 1) return;
|
|
|
|
p.filtered = 1;
|
|
|
|
if (p.index != piece_pos::we_have_index)
|
2005-05-30 19:43:03 +02:00
|
|
|
{
|
|
|
|
++m_num_filtered;
|
2005-05-25 12:01:01 +02:00
|
|
|
move(p.downloading, false, p.peer_count, p.index);
|
2005-05-30 19:43:03 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++m_num_have_filtered;
|
|
|
|
}
|
2005-05-25 12:01:01 +02:00
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
integrity_check();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// this function can be used for pieces that we don't
|
|
|
|
// have, but have marked as filtered (so we didn't
|
|
|
|
// want to download them) but later want to enable for
|
|
|
|
// downloading, then we call this function and it will
|
|
|
|
// be inserted in the available piece list again
|
|
|
|
void piece_picker::mark_as_unfiltered(int index)
|
|
|
|
{
|
|
|
|
assert(index >= 0);
|
|
|
|
assert(index < (int)m_piece_map.size());
|
|
|
|
|
|
|
|
piece_pos& p = m_piece_map[index];
|
|
|
|
if (p.filtered == 0) return;
|
|
|
|
p.filtered = 0;
|
|
|
|
if (p.index != piece_pos::we_have_index)
|
2005-05-30 19:43:03 +02:00
|
|
|
{
|
|
|
|
--m_num_filtered;
|
|
|
|
assert(m_num_filtered >= 0);
|
2005-05-25 12:01:01 +02:00
|
|
|
move(p.downloading, true, p.peer_count, p.index);
|
2005-05-30 19:43:03 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
--m_num_have_filtered;
|
|
|
|
assert(m_num_have_filtered >= 0);
|
|
|
|
}
|
2005-05-25 12:01:01 +02:00
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
integrity_check();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool piece_picker::is_filtered(int index) const
|
|
|
|
{
|
|
|
|
assert(index >= 0);
|
|
|
|
assert(index < (int)m_piece_map.size());
|
|
|
|
|
|
|
|
return m_piece_map[index].filtered == 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void piece_picker::filtered_pieces(std::vector<bool>& mask) const
|
|
|
|
{
|
|
|
|
mask.resize(m_piece_map.size());
|
|
|
|
std::vector<bool>::iterator j = mask.begin();
|
|
|
|
for (std::vector<piece_pos>::const_iterator i = m_piece_map.begin(),
|
|
|
|
end(m_piece_map.end()); i != end; ++i, ++j)
|
|
|
|
{
|
|
|
|
*j = i->filtered == 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void piece_picker::pick_pieces(const std::vector<bool>& pieces
|
|
|
|
, std::vector<piece_block>& interesting_pieces
|
|
|
|
, int num_blocks) const
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2004-01-26 01:21:12 +01:00
|
|
|
assert(num_blocks > 0);
|
2003-10-23 01:00:57 +02:00
|
|
|
assert(pieces.size() == m_piece_map.size());
|
|
|
|
|
2003-11-02 22:06:50 +01:00
|
|
|
#ifndef NDEBUG
|
2004-11-21 11:49:02 +01:00
|
|
|
// integrity_check();
|
2003-11-02 22:06:50 +01:00
|
|
|
#endif
|
|
|
|
|
2005-02-23 17:56:32 +01:00
|
|
|
// free refers to pieces that are free to download, no one else
|
2003-10-23 01:00:57 +02:00
|
|
|
// is downloading them.
|
|
|
|
// partial is pieces that are partially being downloaded, and
|
|
|
|
// parts of them may be free for download as well, the
|
2005-06-23 01:04:37 +02:00
|
|
|
// partially downloaded pieces will be prioritized
|
2005-02-23 17:56:32 +01:00
|
|
|
assert(m_piece_info.begin() != m_piece_info.end());
|
2005-05-25 12:01:01 +02:00
|
|
|
// +1 is to ignore pieces that no peer has. The bucket with index 0 contains
|
|
|
|
// pieces that 0 other peers has.
|
2003-10-23 01:00:57 +02:00
|
|
|
std::vector<std::vector<int> >::const_iterator free = m_piece_info.begin()+1;
|
2005-05-25 12:01:01 +02:00
|
|
|
assert(m_downloading_piece_info.begin() != m_downloading_piece_info.end());
|
2003-10-23 01:00:57 +02:00
|
|
|
std::vector<std::vector<int> >::const_iterator partial = m_downloading_piece_info.begin()+1;
|
|
|
|
|
|
|
|
while((free != m_piece_info.end()) || (partial != m_downloading_piece_info.end()))
|
|
|
|
{
|
|
|
|
if (partial != m_downloading_piece_info.end())
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 2; ++i)
|
|
|
|
{
|
2005-02-23 17:56:32 +01:00
|
|
|
num_blocks = add_interesting_blocks(*partial, pieces
|
|
|
|
, interesting_pieces, num_blocks);
|
2005-08-12 14:40:58 +02:00
|
|
|
assert(num_blocks >= 0);
|
2003-11-02 22:06:50 +01:00
|
|
|
if (num_blocks == 0) return;
|
2003-10-23 01:00:57 +02:00
|
|
|
++partial;
|
|
|
|
if (partial == m_downloading_piece_info.end()) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (free != m_piece_info.end())
|
|
|
|
{
|
2003-11-02 22:06:50 +01:00
|
|
|
num_blocks = add_interesting_blocks(*free, pieces, interesting_pieces, num_blocks);
|
2005-08-12 14:40:58 +02:00
|
|
|
assert(num_blocks >= 0);
|
2003-11-02 22:06:50 +01:00
|
|
|
if (num_blocks == 0) return;
|
2003-10-23 01:00:57 +02:00
|
|
|
++free;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
int piece_picker::add_interesting_blocks(const std::vector<int>& piece_list
|
|
|
|
, const std::vector<bool>& pieces
|
|
|
|
, std::vector<piece_block>& interesting_blocks
|
|
|
|
, int num_blocks) const
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2004-01-26 01:21:12 +01:00
|
|
|
assert(num_blocks > 0);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
for (std::vector<int>::const_iterator i = piece_list.begin();
|
2005-05-13 02:39:39 +02:00
|
|
|
i != piece_list.end(); ++i)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(*i >= 0);
|
2004-01-25 19:18:36 +01:00
|
|
|
assert(*i < (int)m_piece_map.size());
|
2003-10-23 01:00:57 +02:00
|
|
|
// if the peer doesn't have the piece
|
|
|
|
// skip it
|
|
|
|
if (!pieces[*i]) continue;
|
|
|
|
|
|
|
|
// if there's at least one block that
|
|
|
|
// we can request from this peer
|
|
|
|
// we can break our search (return)
|
|
|
|
|
|
|
|
if (m_piece_map[*i].downloading == 0)
|
|
|
|
{
|
2003-11-02 22:06:50 +01:00
|
|
|
int piece_blocks = std::min(blocks_in_piece(*i), num_blocks);
|
|
|
|
for (int j = 0; j < piece_blocks; ++j)
|
|
|
|
{
|
2003-11-05 00:27:06 +01:00
|
|
|
interesting_blocks.push_back(piece_block(*i, j));
|
2003-11-02 22:06:50 +01:00
|
|
|
}
|
|
|
|
num_blocks -= piece_blocks;
|
2005-08-12 14:40:58 +02:00
|
|
|
assert(num_blocks >= 0);
|
2003-11-02 22:06:50 +01:00
|
|
|
if (num_blocks == 0) return num_blocks;
|
|
|
|
continue;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// calculate the number of blocks in this
|
|
|
|
// piece. It's always m_blocks_per_piece, except
|
|
|
|
// in the last piece.
|
2003-11-02 22:06:50 +01:00
|
|
|
int num_blocks_in_piece = blocks_in_piece(*i);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
std::vector<downloading_piece>::const_iterator p
|
|
|
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(*i));
|
|
|
|
assert(p != m_downloads.end());
|
|
|
|
|
|
|
|
for (int j = 0; j < num_blocks_in_piece; ++j)
|
|
|
|
{
|
2003-11-05 00:27:06 +01:00
|
|
|
if (p->finished_blocks[j] == 1) continue;
|
|
|
|
|
2005-08-12 14:40:58 +02:00
|
|
|
// this block is interesting (we don't have it
|
|
|
|
// yet). But it may already have been requested
|
|
|
|
// from another peer. We have to add it anyway
|
|
|
|
// to allow the requester to determine if the
|
|
|
|
// block should be requested from more than one
|
|
|
|
// peer. If it is being downloaded, we continue
|
|
|
|
// to look for blocks until we have num_blocks
|
|
|
|
// blocks that have not been requested from any
|
|
|
|
// other peer.
|
2003-10-23 01:00:57 +02:00
|
|
|
interesting_blocks.push_back(piece_block(*i, j));
|
|
|
|
if (p->requested_blocks[j] == 0)
|
2003-11-02 22:06:50 +01:00
|
|
|
{
|
|
|
|
// we have found a piece that's free to download
|
|
|
|
num_blocks--;
|
2005-08-12 14:40:58 +02:00
|
|
|
assert(num_blocks >= 0);
|
2003-11-02 22:06:50 +01:00
|
|
|
if (num_blocks == 0) return num_blocks;
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
}
|
2005-08-12 14:40:58 +02:00
|
|
|
assert(num_blocks >= 0);
|
2003-11-02 22:06:50 +01:00
|
|
|
return num_blocks;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool piece_picker::is_piece_finished(int index) const
|
|
|
|
{
|
2004-01-25 19:18:36 +01:00
|
|
|
assert(index < (int)m_piece_map.size());
|
2003-10-23 01:00:57 +02:00
|
|
|
assert(index >= 0);
|
|
|
|
|
|
|
|
if (m_piece_map[index].downloading == 0) return false;
|
|
|
|
std::vector<downloading_piece>::const_iterator i
|
|
|
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index));
|
|
|
|
assert(i != m_downloads.end());
|
2004-01-25 19:18:36 +01:00
|
|
|
assert((int)i->finished_blocks.count() <= m_blocks_per_piece);
|
2003-10-30 00:28:09 +01:00
|
|
|
int max_blocks = blocks_in_piece(index);
|
2004-01-26 11:29:00 +01:00
|
|
|
if ((int)i->finished_blocks.count() != max_blocks) return false;
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-01-26 11:29:00 +01:00
|
|
|
assert((int)i->requested_blocks.count() == max_blocks);
|
2003-10-23 01:00:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool piece_picker::is_downloading(piece_block block) const
|
|
|
|
{
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(block.piece_index >= 0);
|
|
|
|
assert(block.block_index >= 0);
|
2004-01-25 19:18:36 +01:00
|
|
|
assert(block.piece_index < (int)m_piece_map.size());
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(block.block_index < (int)max_blocks_per_piece);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
if (m_piece_map[block.piece_index].downloading == 0) return false;
|
|
|
|
std::vector<downloading_piece>::const_iterator i
|
2004-01-13 04:08:59 +01:00
|
|
|
= std::find_if(
|
|
|
|
m_downloads.begin()
|
|
|
|
, m_downloads.end()
|
|
|
|
, has_index(block.piece_index));
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
assert(i != m_downloads.end());
|
|
|
|
return i->requested_blocks[block.block_index];
|
|
|
|
}
|
|
|
|
|
2003-11-05 00:27:06 +01:00
|
|
|
bool piece_picker::is_finished(piece_block block) const
|
|
|
|
{
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(block.piece_index >= 0);
|
|
|
|
assert(block.block_index >= 0);
|
2004-01-25 19:18:36 +01:00
|
|
|
assert(block.piece_index < (int)m_piece_map.size());
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(block.block_index < (int)max_blocks_per_piece);
|
2003-11-05 00:27:06 +01:00
|
|
|
|
2005-05-25 12:01:01 +02:00
|
|
|
if (m_piece_map[block.piece_index].index == piece_pos::we_have_index) return true;
|
2003-11-05 00:27:06 +01:00
|
|
|
if (m_piece_map[block.piece_index].downloading == 0) return false;
|
|
|
|
std::vector<downloading_piece>::const_iterator i
|
|
|
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
|
|
|
assert(i != m_downloads.end());
|
|
|
|
return i->finished_blocks[block.block_index];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-01-12 21:31:27 +01:00
|
|
|
void piece_picker::mark_as_downloading(piece_block block, const address& peer)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
2004-11-21 11:49:02 +01:00
|
|
|
// integrity_check();
|
2003-10-23 01:00:57 +02:00
|
|
|
#endif
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(block.piece_index >= 0);
|
|
|
|
assert(block.block_index >= 0);
|
2004-01-25 19:18:36 +01:00
|
|
|
assert(block.piece_index < (int)m_piece_map.size());
|
2003-11-05 00:27:06 +01:00
|
|
|
assert(block.block_index < blocks_in_piece(block.piece_index));
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
piece_pos& p = m_piece_map[block.piece_index];
|
|
|
|
if (p.downloading == 0)
|
|
|
|
{
|
|
|
|
p.downloading = 1;
|
2005-05-25 12:01:01 +02:00
|
|
|
move(false, p.filtered, p.peer_count, p.index);
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
downloading_piece dp;
|
|
|
|
dp.index = block.piece_index;
|
|
|
|
dp.requested_blocks[block.block_index] = 1;
|
2003-11-02 22:06:50 +01:00
|
|
|
dp.info[block.block_index].peer = peer;
|
2003-10-23 01:00:57 +02:00
|
|
|
m_downloads.push_back(dp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::vector<downloading_piece>::iterator i
|
|
|
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
|
|
|
assert(i != m_downloads.end());
|
|
|
|
assert(i->requested_blocks[block.block_index] == 0);
|
2003-11-02 22:06:50 +01:00
|
|
|
i->info[block.block_index].peer = peer;
|
2003-10-23 01:00:57 +02:00
|
|
|
i->requested_blocks[block.block_index] = 1;
|
|
|
|
}
|
|
|
|
#ifndef NDEBUG
|
2004-11-21 11:49:02 +01:00
|
|
|
// integrity_check();
|
2003-10-23 01:00:57 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2004-01-12 21:31:27 +01:00
|
|
|
void piece_picker::mark_as_finished(piece_block block, const address& peer)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
2004-11-21 11:49:02 +01:00
|
|
|
// integrity_check();
|
2003-10-23 01:00:57 +02:00
|
|
|
#endif
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(block.piece_index >= 0);
|
|
|
|
assert(block.block_index >= 0);
|
2004-01-25 19:18:36 +01:00
|
|
|
assert(block.piece_index < (int)m_piece_map.size());
|
2003-11-05 00:27:06 +01:00
|
|
|
assert(block.block_index < blocks_in_piece(block.piece_index));
|
|
|
|
|
|
|
|
piece_pos& p = m_piece_map[block.piece_index];
|
2005-05-25 12:01:01 +02:00
|
|
|
if (p.index == piece_pos::we_have_index) return;
|
|
|
|
|
2003-11-05 00:27:06 +01:00
|
|
|
if (p.downloading == 0)
|
|
|
|
{
|
|
|
|
p.downloading = 1;
|
2005-05-25 12:01:01 +02:00
|
|
|
move(false, p.filtered, p.peer_count, p.index);
|
2003-11-05 00:27:06 +01:00
|
|
|
|
|
|
|
downloading_piece dp;
|
|
|
|
dp.index = block.piece_index;
|
|
|
|
dp.requested_blocks[block.block_index] = 1;
|
|
|
|
dp.finished_blocks[block.block_index] = 1;
|
|
|
|
dp.info[block.block_index].peer = peer;
|
|
|
|
m_downloads.push_back(dp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::vector<downloading_piece>::iterator i
|
|
|
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
|
|
|
assert(i != m_downloads.end());
|
|
|
|
i->info[block.block_index].peer = peer;
|
|
|
|
i->requested_blocks[block.block_index] = 1;
|
|
|
|
i->finished_blocks[block.block_index] = 1;
|
|
|
|
}
|
|
|
|
#ifndef NDEBUG
|
2004-11-21 11:49:02 +01:00
|
|
|
// integrity_check();
|
2003-11-05 00:27:06 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
void piece_picker::mark_as_finished(piece_block block, const peer_id& peer)
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
|
|
|
integrity_check();
|
|
|
|
#endif
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(block.piece_index >= 0);
|
|
|
|
assert(block.block_index >= 0);
|
2003-11-05 00:27:06 +01:00
|
|
|
assert(block.piece_index < m_piece_map.size());
|
|
|
|
assert(block.block_index < blocks_in_piece(block.piece_index));
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
assert(m_piece_map[block.piece_index].downloading == 1);
|
|
|
|
|
|
|
|
std::vector<downloading_piece>::iterator i
|
|
|
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
|
|
|
assert(i != m_downloads.end());
|
|
|
|
i->finished_blocks[block.block_index] = 1;
|
2003-11-05 00:27:06 +01:00
|
|
|
// the block may have been requested, then cancled
|
|
|
|
// and requested by a peer that disconnects
|
|
|
|
// that way we can actually receive the piece
|
|
|
|
// without the requested bit is set.
|
|
|
|
i->requested_blocks[block.block_index] = 1;
|
2003-11-02 22:06:50 +01:00
|
|
|
i->info[block.block_index].num_downloads++;
|
2003-11-05 00:27:06 +01:00
|
|
|
i->info[block.block_index].peer = peer;
|
2003-10-23 01:00:57 +02:00
|
|
|
#ifndef NDEBUG
|
|
|
|
integrity_check();
|
|
|
|
#endif
|
|
|
|
}
|
2003-11-05 00:27:06 +01:00
|
|
|
*/
|
2004-01-13 04:08:59 +01:00
|
|
|
void piece_picker::get_downloaders(std::vector<address>& d, int index) const
|
2003-11-02 22:06:50 +01:00
|
|
|
{
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(index >= 0 && index <= (int)m_piece_map.size());
|
2004-01-13 04:08:59 +01:00
|
|
|
std::vector<downloading_piece>::const_iterator i
|
2003-11-02 22:06:50 +01:00
|
|
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index));
|
|
|
|
assert(i != m_downloads.end());
|
|
|
|
|
|
|
|
d.clear();
|
|
|
|
for (int j = 0; j < blocks_in_piece(index); ++j)
|
|
|
|
{
|
|
|
|
d.push_back(i->info[j].peer);
|
|
|
|
}
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-01-13 04:08:59 +01:00
|
|
|
boost::optional<address> piece_picker::get_downloader(piece_block block) const
|
|
|
|
{
|
|
|
|
std::vector<downloading_piece>::const_iterator i = std::find_if(
|
|
|
|
m_downloads.begin()
|
|
|
|
, m_downloads.end()
|
|
|
|
, has_index(block.piece_index));
|
|
|
|
|
|
|
|
if (i == m_downloads.end())
|
|
|
|
return boost::optional<address>();
|
|
|
|
|
|
|
|
assert(block.block_index < max_blocks_per_piece);
|
|
|
|
assert(block.block_index >= 0);
|
|
|
|
|
|
|
|
if (i->requested_blocks[block.block_index] == false
|
|
|
|
|| i->finished_blocks[block.block_index] == true)
|
|
|
|
return boost::optional<address>();
|
|
|
|
|
|
|
|
return boost::optional<address>(i->info[block.block_index].peer);
|
|
|
|
}
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
void piece_picker::abort_download(piece_block block)
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
2004-11-21 11:49:02 +01:00
|
|
|
// integrity_check();
|
2003-10-23 01:00:57 +02:00
|
|
|
#endif
|
|
|
|
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(block.piece_index >= 0);
|
|
|
|
assert(block.block_index >= 0);
|
2004-01-25 19:18:36 +01:00
|
|
|
assert(block.piece_index < (int)m_piece_map.size());
|
2004-01-25 23:41:55 +01:00
|
|
|
assert(block.block_index < blocks_in_piece(block.piece_index));
|
2003-10-23 01:00:57 +02:00
|
|
|
|
|
|
|
if (m_piece_map[block.piece_index].downloading == 0)
|
|
|
|
{
|
|
|
|
assert(std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)) == m_downloads.end());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<downloading_piece>::iterator i
|
|
|
|
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
|
|
|
|
assert(i != m_downloads.end());
|
2003-11-05 00:27:06 +01:00
|
|
|
|
|
|
|
if (i->finished_blocks[block.block_index]) return;
|
|
|
|
|
|
|
|
assert(block.block_index < blocks_in_piece(block.piece_index));
|
2003-10-23 01:00:57 +02:00
|
|
|
assert(i->requested_blocks[block.block_index] == 1);
|
|
|
|
|
|
|
|
// clear this block as being downloaded
|
|
|
|
i->requested_blocks[block.block_index] = 0;
|
|
|
|
|
|
|
|
// if there are no other blocks in this pieces
|
|
|
|
// that's being downloaded, remove it from the list
|
|
|
|
if (i->requested_blocks.count() == 0)
|
|
|
|
{
|
|
|
|
m_downloads.erase(i);
|
|
|
|
m_piece_map[block.piece_index].downloading = 0;
|
2005-05-25 12:01:01 +02:00
|
|
|
piece_pos& p = m_piece_map[block.piece_index];
|
|
|
|
move(true, p.filtered, p.peer_count, p.index);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
#ifndef NDEBUG
|
2004-11-21 11:49:02 +01:00
|
|
|
// integrity_check();
|
2003-10-23 01:00:57 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2003-10-30 00:28:09 +01:00
|
|
|
int piece_picker::unverified_blocks() const
|
|
|
|
{
|
|
|
|
int counter = 0;
|
|
|
|
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin();
|
2005-05-13 02:39:39 +02:00
|
|
|
i != m_downloads.end(); ++i)
|
2003-10-30 00:28:09 +01:00
|
|
|
{
|
2004-01-25 19:18:36 +01:00
|
|
|
counter += (int)i->finished_blocks.count();
|
2003-10-30 00:28:09 +01:00
|
|
|
}
|
|
|
|
return counter;
|
|
|
|
}
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2005-05-13 02:39:39 +02:00
|
|
|
|