introduced a non-rarest-first option to the piece picker that is used to pick the very first pieces in a torrent

This commit is contained in:
Arvid Norberg 2007-07-07 01:26:30 +00:00
parent 4d912eddf4
commit 82e1160214
5 changed files with 72 additions and 57 deletions

View File

@ -192,7 +192,8 @@ namespace libtorrent
void pick_pieces(const std::vector<bool>& pieces
, std::vector<piece_block>& interesting_blocks
, int num_pieces, bool prefer_whole_pieces
, void* peer, piece_state_t speed) const;
, void* peer, piece_state_t speed
, bool rarest_first) const;
// clears the peer pointer in all downloading pieces with this
// peer pointer

View File

@ -107,6 +107,7 @@ namespace libtorrent
, inactivity_timeout(600)
, unchoke_interval(20)
, num_want(200)
, initial_picker_threshold(4)
#ifndef TORRENT_DISABLE_DHT
, use_dht_as_fallback(true)
#endif
@ -246,6 +247,10 @@ namespace libtorrent
// the num want sent to trackers
int num_want;
// while we have fewer pieces than this, pick
// random pieces instead of rarest first.
int initial_picker_threshold;
#ifndef TORRENT_DISABLE_DHT
// while this is true, the dht will note be used unless the
// tracker is online

View File

@ -48,8 +48,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/torrent.hpp"
#endif
#define TORRENT_PIECE_PICKER_INVARIANT_CHECK INVARIANT_CHECK
//#define TORRENT_PIECE_PICKER_INVARIANT_CHECK
//#define TORRENT_PIECE_PICKER_INVARIANT_CHECK INVARIANT_CHECK
#define TORRENT_PIECE_PICKER_INVARIANT_CHECK
namespace libtorrent
{
@ -1011,7 +1011,7 @@ namespace libtorrent
void piece_picker::pick_pieces(const std::vector<bool>& pieces
, std::vector<piece_block>& interesting_blocks
, int num_blocks, bool prefer_whole_pieces
, void* peer, piece_state_t speed) const
, void* peer, piece_state_t speed, bool rarest_first) const
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
assert(num_blocks > 0);
@ -1052,6 +1052,37 @@ namespace libtorrent
, prefer_whole_pieces, peer, speed);
assert(num_blocks >= 0);
if (num_blocks == 0) return;
if (rarest_first) continue;
// we're not using rarest first (only for the first
// bucket, since that's where the currently downloading
// pieces are)
while (num_blocks > 0)
{
int start_piece = rand() % m_piece_map.size();
int piece = start_piece;
while (!pieces[piece]
|| m_piece_map[piece].index == piece_pos::we_have_index
|| m_piece_map[piece].priority(m_sequenced_download_threshold) < 2)
{
++piece;
// could not find any more pieces
if (piece == start_piece) return;
if (piece == int(m_piece_map.size())) piece = 0;
}
assert(m_piece_map[piece].downloading == false);
int num_blocks_in_piece = blocks_in_piece(piece);
if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks)
num_blocks_in_piece = num_blocks;
for (int j = 0; j < num_blocks_in_piece; ++j)
interesting_blocks.push_back(piece_block(piece, j));
num_blocks -= (std::min)(num_blocks_in_piece, num_blocks);
}
if (num_blocks == 0) return;
break;
}
assert(num_blocks > 0);
@ -1212,9 +1243,7 @@ namespace libtorrent
if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks)
num_blocks_in_piece = num_blocks;
for (int j = 0; j < num_blocks_in_piece; ++j)
{
interesting_blocks.push_back(piece_block(*i, j));
}
num_blocks -= (std::min)(num_blocks_in_piece, num_blocks);
}
assert(num_blocks >= 0);
@ -1383,50 +1412,27 @@ namespace libtorrent
assert(block.piece_index < (int)m_piece_map.size());
assert(block.block_index < blocks_in_piece(block.piece_index));
piece_pos& p = m_piece_map[block.piece_index];
assert(p.downloading);
assert(m_piece_map[block.piece_index].downloading);
/* if (p.downloading == 0)
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());
block_info& info = i->info[block.block_index];
info.peer = peer;
assert(info.state == block_info::state_requested);
if (info.state == block_info::state_requested) --i->requested;
assert(i->requested >= 0);
assert (info.state != block_info::state_writing);
++i->writing;
info.state = block_info::state_writing;
if (info.num_peers > 0) --info.num_peers;
assert(info.num_peers >= 0);
if (i->requested == 0)
{
int prio = p.priority(m_sequenced_download_threshold);
p.downloading = 1;
if (prio > 0) move(prio, p.index);
else assert(p.priority(m_sequenced_download_threshold) == 0);
downloading_piece& dp = add_download_piece();
dp.state = none;
dp.index = block.piece_index;
block_info& info = dp.info[block.block_index];
info.peer = peer;
if (info.state == block_info::state_requested) --dp.requested;
assert(dp.requested >= 0);
assert (info.state != block_info::state_finished);
assert (info.state != block_info::state_writing);
if (info.state != block_info::state_requested) ++dp.writing;
info.state = block_info::state_writing;
}
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());
block_info& info = i->info[block.block_index];
info.peer = peer;
assert(info.state == block_info::state_requested);
if (info.state == block_info::state_requested) --i->requested;
assert(i->requested >= 0);
assert (info.state != block_info::state_writing);
++i->writing;
info.state = block_info::state_writing;
if (info.num_peers > 0) --info.num_peers;
assert(info.num_peers >= 0);
if (i->requested == 0)
{
// there are no blocks requested in this piece.
// remove the fast/slow state from it
i->state = none;
}
// there are no blocks requested in this piece.
// remove the fast/slow state from it
i->state = none;
}
}

View File

@ -210,6 +210,8 @@ namespace libtorrent
bool prefer_whole_pieces = c.prefer_whole_pieces()
|| (c.peer_info_struct() && c.peer_info_struct()->on_parole);
bool rarest_first = t.num_pieces() >= t.settings().initial_picker_threshold;
if (!prefer_whole_pieces)
{
prefer_whole_pieces = c.statistics().download_payload_rate()
@ -238,7 +240,8 @@ namespace libtorrent
// for this peer. If we're downloading one piece in 20 seconds
// then use this mode.
p.pick_pieces(c.get_bitfield(), interesting_pieces
, num_requests, prefer_whole_pieces, c.peer_info_struct(), state);
, num_requests, prefer_whole_pieces, c.peer_info_struct()
, state, rarest_first);
// this vector is filled with the interesting pieces
// that some other peer is currently downloading

View File

@ -95,21 +95,21 @@ int test_main()
std::vector<piece_block> picked;
picked.clear();
p.pick_pieces(peer1, picked, 1, false, 0, piece_picker::fast);
p.pick_pieces(peer1, picked, 1, false, 0, piece_picker::fast, true);
TEST_CHECK(picked.size() == 1);
TEST_CHECK(picked.front().piece_index == 2);
// now pick a piece from peer2. The block is supposed to be
// from piece 3, since it is the rarest piece that peer has.
picked.clear();
p.pick_pieces(peer2, picked, 1, false, 0, piece_picker::fast);
p.pick_pieces(peer2, picked, 1, false, 0, piece_picker::fast, true);
TEST_CHECK(picked.size() == 1);
TEST_CHECK(picked.front().piece_index == 3);
// same thing for peer3.
picked.clear();
p.pick_pieces(peer3, picked, 1, false, 0, piece_picker::fast);
p.pick_pieces(peer3, picked, 1, false, 0, piece_picker::fast, true);
TEST_CHECK(picked.size() == 1);
TEST_CHECK(picked.front().piece_index == 5);
@ -119,7 +119,7 @@ int test_main()
p.inc_refcount(1);
picked.clear();
p.pick_pieces(peer3, picked, 1, false, 0, piece_picker::fast);
p.pick_pieces(peer3, picked, 1, false, 0, piece_picker::fast, true);
TEST_CHECK(picked.size() == 1);
TEST_CHECK(picked.front().piece_index == 1);
// and the block picked should not be 0 or 2
@ -167,7 +167,7 @@ int test_main()
TEST_CHECK(!p.is_requested(piece_block(2, 1)));
picked.clear();
p.pick_pieces(peer1, picked, 1, false, 0, piece_picker::fast);
p.pick_pieces(peer1, picked, 1, false, 0, piece_picker::fast, true);
TEST_CHECK(picked.size() == 2);
piece_block expected3[] = { piece_block(2, 0), piece_block(2, 1) };
@ -180,7 +180,7 @@ int test_main()
// partially selected)
picked.clear();
p.pick_pieces(peer1, picked, 1, true, 0, piece_picker::fast);
p.pick_pieces(peer1, picked, 1, true, 0, piece_picker::fast, true);
// it will pick 4 blocks, since we said we
// wanted whole pieces.
@ -199,7 +199,7 @@ int test_main()
// to make sure it can still fall back on partial pieces
picked.clear();
p.pick_pieces(peer1, picked, 100, true, 0, piece_picker::fast);
p.pick_pieces(peer1, picked, 100, true, 0, piece_picker::fast, true);
TEST_CHECK(picked.size() == 12);
@ -220,7 +220,7 @@ int test_main()
// to make sure it can still fall back on partial pieces
picked.clear();
p.pick_pieces(peer1, picked, 100, true, &peer_struct, piece_picker::fast);
p.pick_pieces(peer1, picked, 100, true, &peer_struct, piece_picker::fast, true);
TEST_CHECK(picked.size() == 11);