more piece_picker unit tests and some fixes

This commit is contained in:
Arvid Norberg 2015-02-13 02:58:21 +00:00
parent 01ee9cd9af
commit 51f1a61d2d
6 changed files with 104 additions and 49 deletions

10
Jamfile
View File

@ -28,14 +28,10 @@ VERSION = 1.1.0 ;
rule coverage ( properties * ) rule coverage ( properties * )
{ {
local result ; local result ;
if ! <test-coverage>on if <test-coverage>on in $(properties)
{ && ( <toolset>gcc in $(properties)
return $(result) ;
}
if <toolset>gcc in $(properties)
|| <toolset>darwin in $(properties) || <toolset>darwin in $(properties)
|| <toolset>clang in $(properties) || <toolset>clang in $(properties) )
{ {
result += <cxxflags>-fprofile-arcs <cxxflags>-ftest-coverage ; result += <cxxflags>-fprofile-arcs <cxxflags>-ftest-coverage ;

View File

@ -173,6 +173,8 @@ namespace libtorrent
// info about each block // info about each block
// this is a pointer into the m_block_info // this is a pointer into the m_block_info
// vector owned by the piece_picker // vector owned by the piece_picker
// TODO: 2 if we could make this an index into m_block_info instead
// we would save at least 4 or 5 bytes
block_info* info; block_info* info;
// the index of the piece // the index of the piece
@ -366,8 +368,8 @@ namespace libtorrent
void piece_passed(int index); void piece_passed(int index);
void mark_as_checking(int index); // void mark_as_checking(int index);
void mark_as_done_checking(int index); // void mark_as_done_checking(int index);
// returns information about the given piece // returns information about the given piece
void piece_info(int index, piece_picker::downloading_piece& st) const; void piece_info(int index, piece_picker::downloading_piece& st) const;
@ -405,10 +407,6 @@ namespace libtorrent
// the hash-check yet // the hash-check yet
int unverified_blocks() const; int unverified_blocks() const;
// return the peer pointers for all blocks that are currently
// in requested state (i.e. requested but not received)
void get_requestors(std::vector<void*>& d, int index) const;
// return the peer pointers to all peers that participated in // return the peer pointers to all peers that participated in
// this piece // this piece
void get_downloaders(std::vector<void*>& d, int index) const; void get_downloaders(std::vector<void*>& d, int index) const;

View File

@ -2790,7 +2790,7 @@ namespace libtorrent
if (st.requested > 0 && st.writing + st.finished + st.requested == num_blocks) if (st.requested > 0 && st.writing + st.finished + st.requested == num_blocks)
{ {
std::vector<void*> d; std::vector<void*> d;
t->picker().get_requestors(d, piece); t->picker().get_downloaders(d, piece);
if (d.size() == 1) if (d.size() == 1)
{ {
// only make predictions if all remaining // only make predictions if all remaining

View File

@ -3425,7 +3425,9 @@ get_out:
void piece_picker::mark_as_canceled(piece_block block, void* peer) void piece_picker::mark_as_canceled(piece_block block, void* peer)
{ {
#ifdef TORRENT_PICKER_LOG #ifdef TORRENT_PICKER_LOG
std::cerr << "[" << this << "] " << "mark_as_cancelled( {" << block.piece_index << ", " << block.block_index << "} )" << std::endl; std::cerr << "[" << this << "] " << "mark_as_cancelled( {"
<< block.piece_index << ", " << block.block_index
<< "} )" << std::endl;
#endif #endif
#if TORRENT_USE_INVARIANT_CHECKS #if TORRENT_USE_INVARIANT_CHECKS
@ -3458,6 +3460,21 @@ get_out:
{ {
--i->writing; --i->writing;
info.state = block_info::state_none; info.state = block_info::state_none;
// i may be invalid after this call
i = update_piece_state(i);
if (i->finished + i->writing + i->requested == 0)
{
piece_pos& p = m_piece_map[block.piece_index];
int prev_priority = p.priority(this);
erase_download_piece(i);
int new_priority = p.priority(this);
if (m_dirty) return;
if (new_priority == prev_priority) return;
if (prev_priority == -1) add(block.piece_index);
else update(prev_priority, p.index);
}
} }
else else
{ {
@ -3569,48 +3586,26 @@ get_out:
} }
// TODO: 3 this doesn't appear to be used for anything. Can it be removed /*
// or should it be used to plug some race when requesting and checking pieces?
void piece_picker::mark_as_checking(int index) void piece_picker::mark_as_checking(int index)
{ {
/*
int state = m_piece_map[index].download_queue(); int state = m_piece_map[index].download_queue();
if (state == piece_pos::piece_open) return; if (state == piece_pos::piece_open) return;
std::vector<downloading_piece>::iterator i = find_dl_piece(state, index); std::vector<downloading_piece>::iterator i = find_dl_piece(state, index);
if (i == m_downloads[state].end()) return; if (i == m_downloads[state].end()) return;
TORRENT_ASSERT(i->outstanding_hash_check == false); TORRENT_ASSERT(i->outstanding_hash_check == false);
i->outstanding_hash_check = true; i->outstanding_hash_check = true;
*/
} }
void piece_picker::mark_as_done_checking(int index) void piece_picker::mark_as_done_checking(int index)
{ {
/*
int state = m_piece_map[index].download_queue(); int state = m_piece_map[index].download_queue();
if (state == piece_pos::piece_open) return; if (state == piece_pos::piece_open) return;
std::vector<downloading_piece>::iterator i = find_dl_piece(state, index); std::vector<downloading_piece>::iterator i = find_dl_piece(state, index);
if (i == m_downloads[state].end()) return; if (i == m_downloads[state].end()) return;
i->outstanding_hash_check = false; i->outstanding_hash_check = false;
}
*/ */
}
void piece_picker::get_requestors(std::vector<void*>& d, int index) const
{
TORRENT_ASSERT(index >= 0 && index <= (int)m_piece_map.size());
int state = m_piece_map[index].download_queue();
TORRENT_ASSERT(state != piece_pos::piece_open);
std::vector<downloading_piece>::const_iterator i = find_dl_piece(state, index);
TORRENT_ASSERT(i != m_downloads[state].end());
d.clear();
for (int j = 0, end(blocks_in_piece(index)); j != end; ++j)
{
if (i->info[j].state != block_info::state_requested) continue;
if (i->info[j].peer == 0) continue;
d.push_back(i->info[j].peer);
}
}
void piece_picker::get_downloaders(std::vector<void*>& d, int index) const void piece_picker::get_downloaders(std::vector<void*>& d, int index) const
{ {
@ -3618,18 +3613,21 @@ get_out:
d.clear(); d.clear();
int state = m_piece_map[index].download_queue(); int state = m_piece_map[index].download_queue();
int num_blocks = blocks_in_piece(index);
d.reserve(num_blocks);
if (state == piece_pos::piece_open) if (state == piece_pos::piece_open)
{ {
int num_blocks = blocks_in_piece(index);
for (int i = 0; i < num_blocks; ++i) d.push_back(0); for (int i = 0; i < num_blocks; ++i) d.push_back(0);
return; return;
} }
std::vector<downloading_piece>::const_iterator i = find_dl_piece(state, index); std::vector<downloading_piece>::const_iterator i
= find_dl_piece(state, index);
TORRENT_ASSERT(i != m_downloads[state].end()); TORRENT_ASSERT(i != m_downloads[state].end());
TORRENT_ASSERT(i->info >= &m_block_info[0] TORRENT_ASSERT(i->info >= &m_block_info[0]
&& i->info < &m_block_info[0] + m_block_info.size()); && i->info < &m_block_info[0] + m_block_info.size());
for (int j = 0, end(blocks_in_piece(index)); j != end; ++j) for (int j = 0; j != num_blocks; ++j)
{ {
TORRENT_ASSERT(i->info[j].peer == 0 || static_cast<torrent_peer*>(i->info[j].peer)->in_use); TORRENT_ASSERT(i->info[j].peer == 0 || static_cast<torrent_peer*>(i->info[j].peer)->in_use);
d.push_back(i->info[j].peer); d.push_back(i->info[j].peer);

View File

@ -3897,7 +3897,7 @@ namespace libtorrent
TORRENT_ASSERT(!m_picker->have_piece(j->piece)); TORRENT_ASSERT(!m_picker->have_piece(j->piece));
picker().mark_as_done_checking(j->piece); // picker().mark_as_done_checking(j->piece);
state_updated(); state_updated();
@ -10824,7 +10824,7 @@ namespace libtorrent
// adds a piece // adds a piece
void torrent::verify_piece(int piece) void torrent::verify_piece(int piece)
{ {
picker().mark_as_checking(piece); // picker().mark_as_checking(piece);
inc_refcount("verify_piece"); inc_refcount("verify_piece");
m_ses.disk_thread().async_hash(m_storage.get(), piece, 0 m_ses.disk_thread().async_hash(m_storage.get(), piece, 0

View File

@ -1550,18 +1550,81 @@ int test_main()
TEST_EQUAL(p->has_piece_passed(1), false); TEST_EQUAL(p->has_piece_passed(1), false);
TEST_EQUAL(p->have_piece(1), false); TEST_EQUAL(p->have_piece(1), false);
// ========================================================
// make sure write_failed() and lock_piece() actually // make sure write_failed() and lock_piece() actually
// locks the piece, and that it won't be picked. // locks the piece, and that it won't be picked.
// also make sure restore_piece() unlocks it and makes // also make sure restore_piece() unlocks it and makes
// it available for picking again. // it available for picking again.
// test mark_as_canceled() picked = pick_pieces(p, " * ", 1, blocks_per_piece, 0);
TEST_EQUAL(picked.size(), 0);
// test get_download_queue() p->restore_piece(1);
// test get_requestors() (similar to get_downloaders()) picked = pick_pieces(p, " * ", 1, blocks_per_piece, 0);
TEST_EQUAL(picked.size(), blocks_per_piece);
// locking pieces only works on partial pieces
p->mark_as_writing(piece_block(1, 0), &tmp1);
p->lock_piece(1);
picked = pick_pieces(p, " * ", 1, blocks_per_piece, 0);
TEST_EQUAL(picked.size(), 0);
// ========================================================
print_title("test write_failed (clear piece)");
p = setup_picker("1111111", "* * ", "1101111", "");
stat = p->piece_stats(1);
TEST_EQUAL(stat.downloading, 0);
p->mark_as_writing(piece_block(1, 0), &tmp1);
stat = p->piece_stats(1);
TEST_EQUAL(stat.downloading, 1);
p->write_failed(piece_block(1, 0));
stat = p->piece_stats(1);
TEST_EQUAL(stat.downloading, 0);
// ========================================================
print_title("test mark_as_canceled");
p = setup_picker("1111111", "* * ", "1101111", "");
stat = p->piece_stats(1);
TEST_EQUAL(stat.downloading, 0);
p->mark_as_writing(piece_block(1, 0), &tmp1);
stat = p->piece_stats(1);
TEST_EQUAL(stat.downloading, 1);
p->mark_as_canceled(piece_block(1, 0), &tmp1);
stat = p->piece_stats(1);
TEST_EQUAL(stat.downloading, 0);
// ========================================================
print_title("test get_download_queue");
p = setup_picker("1111111", " ", "1101111", "0327000");
std::vector<piece_picker::downloading_piece> downloads
= p->get_download_queue();
// the download queue should have piece 1, 2 and 3 in it
TEST_EQUAL(downloads.size(), 3);
TEST_CHECK(std::find_if(downloads.begin(), downloads.end()
, boost::bind(&piece_picker::downloading_piece::index, _1) == 1) != downloads.end());
TEST_CHECK(std::find_if(downloads.begin(), downloads.end()
, boost::bind(&piece_picker::downloading_piece::index, _1) == 2) != downloads.end());
TEST_CHECK(std::find_if(downloads.begin(), downloads.end()
, boost::bind(&piece_picker::downloading_piece::index, _1) == 3) != downloads.end());
/* /*