diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index 8d98e6d9c..fc0c6da77 100644 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -836,6 +836,11 @@ namespace libtorrent void queue_position_top() const; void queue_position_bottom() const; + // updates the position in the queue for this torrent. The relative order + // of all other torrents remain intact but their numerical queue position + // shifts to make space for this torrent's new position + void queue_position_set(int p) const; + #ifndef TORRENT_NO_DEPRECATE // deprecated in 1.1 diff --git a/src/torrent.cpp b/src/torrent.cpp index 18529bac4..8fdc0cead 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -9228,6 +9228,9 @@ namespace libtorrent void torrent::queue_up() { + // fix race conditions on async position change calls (from handler) + if(!m_auto_managed || m_abort || is_finished()) return; + set_queue_position(queue_position() == 0 ? queue_position() : queue_position() - 1); } @@ -9240,10 +9243,13 @@ namespace libtorrent void torrent::set_queue_position(int p) { TORRENT_ASSERT(is_single_thread()); + + // fix race conditions on async position change calls (from handler) + if ((!m_auto_managed || m_abort || is_finished()) && p != -1) return; + TORRENT_ASSERT((p == -1) == is_finished() || (!m_auto_managed && p == -1) || (m_abort && p == -1)); - if (is_finished() && p != -1) return; if (p == m_sequence_number) return; TORRENT_ASSERT(p >= -1); diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 0e72528fd..b5f72cfbc 100644 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -361,6 +361,13 @@ namespace libtorrent TORRENT_ASYNC_CALL(queue_down); } + void torrent_handle::queue_position_set(int p) const + { + TORRENT_ASSERT_PRECOND(p >= 0); + if (p < 0) return; + TORRENT_ASYNC_CALL1(set_queue_position, p); + } + void torrent_handle::queue_position_top() const { TORRENT_ASYNC_CALL1(set_queue_position, 0); diff --git a/test/test_torrent.cpp b/test/test_torrent.cpp index e4df23a39..2e8926b58 100644 --- a/test/test_torrent.cpp +++ b/test/test_torrent.cpp @@ -392,4 +392,113 @@ TORRENT_TEST(torrent_total_size_zero) TEST_CHECK(ec); } +TORRENT_TEST(queue) +{ + lt::settings_pack pack = settings(); + // we're not testing the hash check, just accept the data we write + pack.set_bool(settings_pack::disable_hash_checks, true); + lt::session ses(pack); + + std::vector torrents; + for(int i = 0; i < 6; i++) + { + file_storage fs; + std::stringstream file_path; + file_path << "test_torrent_dir4/queue" << i; + fs.add_file(file_path.str(), 1024); + libtorrent::create_torrent t(fs, 128 * 1024, 6); + + std::vector buf; + bencode(std::back_inserter(buf), t.generate()); + boost::shared_ptr ti = boost::make_shared(&buf[0], buf.size()); + add_torrent_params p; + p.ti = ti; + p.save_path = "."; + torrents.push_back(ses.add_torrent(p)); + } + + std::vector pieces = torrents[5].piece_priorities(); + std::vector > piece_prios; + for (int i = 0; i < int(pieces.size()); ++i) { + piece_prios.push_back(std::make_pair(i,0)); + } + torrents[5].prioritize_pieces(piece_prios); + torrent_handle finished = torrents[5]; + + // add_torrent should be ordered + TEST_EQUAL(finished.queue_position(), -1); + TEST_EQUAL(torrents[0].queue_position(), 0); + TEST_EQUAL(torrents[1].queue_position(), 1); + TEST_EQUAL(torrents[2].queue_position(), 2); + TEST_EQUAL(torrents[3].queue_position(), 3); + TEST_EQUAL(torrents[4].queue_position(), 4); + + // test top and bottom + torrents[2].queue_position_top(); + torrents[1].queue_position_bottom(); + + TEST_EQUAL(finished.queue_position(), -1); + TEST_EQUAL(torrents[2].queue_position(), 0); + TEST_EQUAL(torrents[0].queue_position(), 1); + TEST_EQUAL(torrents[3].queue_position(), 2); + TEST_EQUAL(torrents[4].queue_position(), 3); + TEST_EQUAL(torrents[1].queue_position(), 4); + + // test set pos + torrents[0].queue_position_set(0); + torrents[1].queue_position_set(1); + // torrent 2 should be get moved down by 0 and 1 to pos 2 + + TEST_EQUAL(finished.queue_position(), -1); + TEST_EQUAL(torrents[0].queue_position(), 0); + TEST_EQUAL(torrents[1].queue_position(), 1); + TEST_EQUAL(torrents[2].queue_position(), 2); + TEST_EQUAL(torrents[3].queue_position(), 3); + TEST_EQUAL(torrents[4].queue_position(), 4); + + //test strange up and down commands + torrents[0].queue_position_up(); + torrents[4].queue_position_down(); + + TEST_EQUAL(finished.queue_position(), -1); + TEST_EQUAL(torrents[0].queue_position(), 0); + TEST_EQUAL(torrents[1].queue_position(), 1); + TEST_EQUAL(torrents[2].queue_position(), 2); + TEST_EQUAL(torrents[3].queue_position(), 3); + TEST_EQUAL(torrents[4].queue_position(), 4); + + torrents[1].queue_position_up(); + torrents[3].queue_position_down(); + finished.queue_position_up(); + + TEST_EQUAL(finished.queue_position(), -1); + TEST_EQUAL(torrents[1].queue_position(), 0); + TEST_EQUAL(torrents[0].queue_position(), 1); + TEST_EQUAL(torrents[2].queue_position(), 2); + TEST_EQUAL(torrents[4].queue_position(), 3); + TEST_EQUAL(torrents[3].queue_position(), 4); + + torrents[1].queue_position_down(); + torrents[3].queue_position_up(); + finished.queue_position_down(); + + + TEST_EQUAL(finished.queue_position(), -1); + TEST_EQUAL(torrents[0].queue_position(), 0); + TEST_EQUAL(torrents[1].queue_position(), 1); + TEST_EQUAL(torrents[2].queue_position(), 2); + TEST_EQUAL(torrents[3].queue_position(), 3); + TEST_EQUAL(torrents[4].queue_position(), 4); + + // test set pos on not existing pos + torrents[3].queue_position_set(10); + finished.queue_position_set(10); + + TEST_EQUAL(finished.queue_position(), -1); + TEST_EQUAL(torrents[0].queue_position(), 0); + TEST_EQUAL(torrents[1].queue_position(), 1); + TEST_EQUAL(torrents[2].queue_position(), 2); + TEST_EQUAL(torrents[4].queue_position(), 3); + TEST_EQUAL(torrents[3].queue_position(), 4); +}