merged RC_1_1 into master
This commit is contained in:
commit
c7e705e158
|
@ -85,6 +85,10 @@
|
|||
* resume data no longer has timestamps of files
|
||||
* require C++11 to build libtorrent
|
||||
|
||||
* fix issue when subsequent file priority updates cause torrent to stop
|
||||
|
||||
1.1.8 release
|
||||
|
||||
* coalesce reads and writes by default on windows
|
||||
* fixed disk I/O performance of checking hashes and creating torrents
|
||||
* fix race condition in part_file
|
||||
|
|
|
@ -71,6 +71,8 @@ class test_torrent_handle(unittest.TestCase):
|
|||
self.assertEqual(self.h.get_piece_priorities(), [4])
|
||||
|
||||
self.h.prioritize_files([0, 1])
|
||||
# workaround for asynchronous priority update
|
||||
time.sleep(1)
|
||||
self.assertEqual(self.h.get_file_priorities(), [0, 1])
|
||||
|
||||
self.h.prioritize_pieces([0])
|
||||
|
|
114
src/torrent.cpp
114
src/torrent.cpp
|
@ -92,6 +92,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_manager.hpp"
|
||||
#include "libtorrent/disk_interface.hpp"
|
||||
#include "libtorrent/broadcast_socket.hpp" // for is_ip_address
|
||||
#include "libtorrent/download_priority.hpp"
|
||||
#include "libtorrent/hex.hpp" // to_hex
|
||||
#include "libtorrent/aux_/range.hpp"
|
||||
// TODO: factor out cache_status to its own header
|
||||
|
@ -979,17 +980,15 @@ bool is_downloading_state(int const st)
|
|||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
debug_log("*** set-share-mode: %d", s);
|
||||
#endif
|
||||
|
||||
// in share mode, all pieces have their priorities initialized to 0
|
||||
if (m_share_mode && valid_metadata())
|
||||
if (m_share_mode)
|
||||
{
|
||||
m_file_priority.clear();
|
||||
m_file_priority.resize(m_torrent_file->num_files(), dont_download);
|
||||
std::size_t const num_files = valid_metadata()
|
||||
? std::size_t(m_torrent_file->num_files())
|
||||
: m_file_priority.size();
|
||||
// in share mode, all pieces have their priorities initialized to
|
||||
// dont_download
|
||||
prioritize_files(aux::vector<download_priority_t, file_index_t>(num_files, dont_download));
|
||||
}
|
||||
|
||||
update_piece_priorities();
|
||||
|
||||
if (m_share_mode) recalc_share_mode();
|
||||
}
|
||||
|
||||
void torrent::set_upload_mode(bool b)
|
||||
|
@ -5017,15 +5016,47 @@ bool is_downloading_state(int const st)
|
|||
m_picker->piece_priorities(*pieces);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
aux::vector<download_priority_t, file_index_t> fix_priorities(
|
||||
aux::vector<download_priority_t, file_index_t> const& input
|
||||
, file_storage const* fs)
|
||||
{
|
||||
aux::vector<download_priority_t, file_index_t> files(input.begin(), input.end());
|
||||
|
||||
if (fs)
|
||||
{
|
||||
files.resize(fs->num_files(), default_priority);
|
||||
}
|
||||
|
||||
for (file_index_t i : index_range<file_index_t>{file_index_t{}, files.end_index()})
|
||||
{
|
||||
// initialize pad files to priority 0
|
||||
if (files[i] > dont_download && fs && fs->pad_file_at(i))
|
||||
files[i] = dont_download;
|
||||
else if (files[i] > top_priority)
|
||||
files[i] = top_priority;
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
||||
|
||||
void torrent::on_file_priority(storage_error const& err
|
||||
, aux::vector<download_priority_t, file_index_t> const& prios)
|
||||
{
|
||||
COMPLETE_ASYNC("file_priority");
|
||||
if (m_file_priority == prios) return;
|
||||
if (m_file_priority != prios)
|
||||
{
|
||||
m_file_priority = prios;
|
||||
update_piece_priorities();
|
||||
if (m_share_mode)
|
||||
recalc_share_mode();
|
||||
}
|
||||
|
||||
if (!err) return;
|
||||
|
||||
// in this case, some file priorities failed to get set
|
||||
m_file_priority = prios;
|
||||
update_piece_priorities();
|
||||
|
||||
if (alerts().should_post<file_error_alert>())
|
||||
alerts().emplace_alert<file_error_alert>(err.ec
|
||||
|
@ -5039,33 +5070,21 @@ bool is_downloading_state(int const st)
|
|||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
// this call is only valid on torrents with metadata
|
||||
if (!valid_metadata() || is_seed()) return;
|
||||
if (is_seed()) return;
|
||||
|
||||
file_storage const& fs = m_torrent_file->files();
|
||||
file_index_t const limit = std::min(files.end_index(), fs.end_file());
|
||||
auto new_priority = fix_priorities(files, valid_metadata() ? &m_torrent_file->files() : nullptr);
|
||||
|
||||
if (m_file_priority.end_index() < limit)
|
||||
m_file_priority.resize(static_cast<int>(limit), default_priority);
|
||||
|
||||
auto si = files.begin();
|
||||
for (file_index_t i(0); i < limit; ++i, ++si)
|
||||
{
|
||||
// initialize pad files to priority 0
|
||||
m_file_priority[i] = fs.pad_file_at(i)
|
||||
? dont_download
|
||||
: aux::clamp(*si, dont_download, top_priority);
|
||||
}
|
||||
|
||||
// storage may be nullptr during construction and shutdown
|
||||
if (m_torrent_file->num_pieces() > 0 && m_storage)
|
||||
// storage may be NULL during shutdown
|
||||
if (m_storage)
|
||||
{
|
||||
ADD_OUTSTANDING_ASYNC("file_priority");
|
||||
m_ses.disk_thread().async_set_file_priority(m_storage
|
||||
, m_file_priority, std::bind(&torrent::on_file_priority, shared_from_this(), _1, _2));
|
||||
, std::move(new_priority), std::bind(&torrent::on_file_priority, shared_from_this(), _1, _2));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_file_priority = std::move(new_priority);
|
||||
}
|
||||
|
||||
update_piece_priorities();
|
||||
}
|
||||
|
||||
void torrent::set_file_priority(file_index_t const index
|
||||
|
@ -5078,33 +5097,33 @@ bool is_downloading_state(int const st)
|
|||
// setting file priority on a torrent that doesn't have metadata yet is
|
||||
// similar to having passed in file priorities through add_torrent_params.
|
||||
// we store the priorities in m_file_priority until we get the metadata
|
||||
file_storage const& fs = m_torrent_file->files();
|
||||
if (index < file_index_t(0) || (valid_metadata() && index >= fs.end_file()))
|
||||
if (index < file_index_t(0)
|
||||
|| (valid_metadata() && index >= m_torrent_file->files().end_file()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
prio = aux::clamp(prio, dont_download, top_priority);
|
||||
if (m_file_priority.end_index() <= index)
|
||||
auto new_priority = m_file_priority;
|
||||
if (new_priority.end_index() <= index)
|
||||
{
|
||||
// any unallocated slot is assumed to have the default priority
|
||||
if (prio == default_priority) return;
|
||||
m_file_priority.resize(static_cast<int>(index) + 1, default_priority);
|
||||
new_priority.resize(static_cast<int>(index) + 1, default_priority);
|
||||
}
|
||||
|
||||
if (m_file_priority[index] == prio) return;
|
||||
m_file_priority[index] = prio;
|
||||
|
||||
if (!valid_metadata()) return;
|
||||
new_priority[index] = prio;
|
||||
|
||||
// storage may be nullptr during shutdown
|
||||
if (m_storage)
|
||||
{
|
||||
ADD_OUTSTANDING_ASYNC("file_priority");
|
||||
m_ses.disk_thread().async_set_file_priority(m_storage
|
||||
, m_file_priority, std::bind(&torrent::on_file_priority, shared_from_this(), _1, _2));
|
||||
, std::move(new_priority), std::bind(&torrent::on_file_priority, shared_from_this(), _1, _2));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_file_priority = std::move(new_priority);
|
||||
}
|
||||
update_piece_priorities();
|
||||
}
|
||||
|
||||
download_priority_t torrent::file_priority(file_index_t const index) const
|
||||
|
@ -5133,17 +5152,14 @@ bool is_downloading_state(int const st)
|
|||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
files->assign(m_file_priority.begin(), m_file_priority.end());
|
||||
|
||||
if (!valid_metadata())
|
||||
{
|
||||
files->resize(m_file_priority.size());
|
||||
std::copy(m_file_priority.begin(), m_file_priority.end(), files->begin());
|
||||
return;
|
||||
}
|
||||
|
||||
files->clear();
|
||||
files->resize(m_torrent_file->num_files(), default_priority);
|
||||
TORRENT_ASSERT(int(m_file_priority.size()) <= m_torrent_file->num_files());
|
||||
std::copy(m_file_priority.begin(), m_file_priority.end(), files->begin());
|
||||
}
|
||||
|
||||
void torrent::update_piece_priorities()
|
||||
|
|
|
@ -424,8 +424,11 @@ TORRENT_TEST(no_metadata_file_prio)
|
|||
torrent_handle h = ses.add_torrent(addp);
|
||||
|
||||
h.file_priority(file_index_t(0), 0_pri);
|
||||
// TODO 2: this should wait for an alert instead of just sleeping
|
||||
std::this_thread::sleep_for(lt::milliseconds(100));
|
||||
TEST_EQUAL(h.file_priority(file_index_t(0)), 0_pri);
|
||||
h.file_priority(file_index_t(0), 1_pri);
|
||||
std::this_thread::sleep_for(lt::milliseconds(100));
|
||||
TEST_EQUAL(h.file_priority(file_index_t(0)), 1_pri);
|
||||
|
||||
ses.remove_torrent(h);
|
||||
|
|
|
@ -53,10 +53,32 @@ using namespace lt;
|
|||
|
||||
namespace {
|
||||
|
||||
bool wait_priority(torrent_handle const& h, aux::vector<download_priority_t, file_index_t> const& prio)
|
||||
{
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
if (h.get_file_priorities() == prio) return true;
|
||||
|
||||
#ifdef NDEBUG
|
||||
std::this_thread::sleep_for(lt::milliseconds(100));
|
||||
#else
|
||||
std::this_thread::sleep_for(lt::milliseconds(300));
|
||||
#endif
|
||||
}
|
||||
|
||||
return h.get_file_priorities() == prio;
|
||||
}
|
||||
|
||||
bool prioritize_files(torrent_handle const& h, aux::vector<download_priority_t, file_index_t> const& prio)
|
||||
{
|
||||
h.prioritize_files(prio);
|
||||
return wait_priority(h, prio);
|
||||
}
|
||||
|
||||
void test_running_torrent(std::shared_ptr<torrent_info> info, std::int64_t file_size)
|
||||
{
|
||||
settings_pack pack = settings();
|
||||
pack.set_int(settings_pack::alert_mask, alert::storage_notification);
|
||||
pack.set_int(settings_pack::alert_mask, alert::file_progress_notification | alert::storage_notification);
|
||||
pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:48130");
|
||||
pack.set_int(settings_pack::max_retry_port_bind, 10);
|
||||
lt::session ses(pack);
|
||||
|
@ -82,7 +104,7 @@ void test_running_torrent(std::shared_ptr<torrent_info> info, std::int64_t file_
|
|||
}
|
||||
|
||||
aux::vector<download_priority_t, file_index_t> ones(std::size_t(info->num_files()), 1_pri);
|
||||
h.prioritize_files(ones);
|
||||
TEST_CHECK(prioritize_files(h, ones))
|
||||
|
||||
torrent_status st = h.status();
|
||||
|
||||
|
@ -91,38 +113,22 @@ void test_running_torrent(std::shared_ptr<torrent_info> info, std::int64_t file_
|
|||
|
||||
aux::vector<download_priority_t, file_index_t> prio(std::size_t(info->num_files()), 1_pri);
|
||||
prio[file_index_t(0)] = 0_pri;
|
||||
h.prioritize_files(prio);
|
||||
TEST_CHECK(prioritize_files(h, prio))
|
||||
st = h.status();
|
||||
|
||||
st = h.status();
|
||||
TEST_EQUAL(st.total_wanted, 0); // we don't want anything
|
||||
TEST_EQUAL(st.total_wanted_done, 0);
|
||||
TEST_EQUAL(int(h.get_file_priorities().size()), info->num_files());
|
||||
if (!st.is_seeding)
|
||||
{
|
||||
TEST_EQUAL(h.get_file_priorities()[0], 0_pri);
|
||||
if (info->num_files() > 1)
|
||||
TEST_EQUAL(h.get_file_priorities()[1], 1_pri);
|
||||
if (info->num_files() > 2)
|
||||
TEST_EQUAL(h.get_file_priorities()[2], 1_pri);
|
||||
}
|
||||
|
||||
if (info->num_files() > 1)
|
||||
{
|
||||
prio[file_index_t(1)] = 0_pri;
|
||||
h.prioritize_files(prio);
|
||||
st = h.status();
|
||||
prio[file_index_t{1}] = 0_pri;
|
||||
TEST_CHECK(prioritize_files(h, prio))
|
||||
|
||||
st = h.status();
|
||||
TEST_EQUAL(st.total_wanted, file_size);
|
||||
TEST_EQUAL(st.total_wanted_done, 0);
|
||||
if (!st.is_seeding)
|
||||
{
|
||||
TEST_EQUAL(int(h.get_file_priorities().size()), info->num_files());
|
||||
TEST_EQUAL(h.get_file_priorities()[0], 0_pri);
|
||||
if (info->num_files() > 1)
|
||||
TEST_EQUAL(h.get_file_priorities()[1], 0_pri);
|
||||
if (info->num_files() > 2)
|
||||
TEST_EQUAL(h.get_file_priorities()[2], 1_pri);
|
||||
}
|
||||
}
|
||||
|
||||
if (info->num_pieces() > 0)
|
||||
|
@ -156,6 +162,8 @@ void test_running_torrent(std::shared_ptr<torrent_info> info, std::int64_t file_
|
|||
TEST_CHECK(hasher(piece).final() == info->hash_for_piece(piece_index_t(0)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CHECK(h.get_file_priorities() == prio);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
@ -221,6 +229,11 @@ TORRENT_TEST(total_wanted)
|
|||
TEST_EQUAL(st.total_wanted, 1024);
|
||||
std::cout << "total_wanted_done: " << st.total_wanted_done << " : 0" << std::endl;
|
||||
TEST_EQUAL(st.total_wanted_done, 0);
|
||||
|
||||
h.file_priority(file_index_t{1}, default_priority);
|
||||
h.file_priority(file_index_t{1}, dont_download);
|
||||
TEST_CHECK(wait_priority(h, aux::vector<download_priority_t, file_index_t>(static_cast<std::size_t>(fs.num_files()))));
|
||||
TEST_EQUAL(h.status({}).total_wanted, 0);
|
||||
}
|
||||
|
||||
TORRENT_TEST(added_peers)
|
||||
|
@ -298,14 +311,14 @@ TORRENT_TEST(torrent)
|
|||
file_storage fs;
|
||||
|
||||
fs.add_file("test_torrent_dir2/tmp1", 1024);
|
||||
lt::create_torrent t(fs, 128 * 1024, 6);
|
||||
lt::create_torrent t(fs, 1024, 6);
|
||||
|
||||
std::vector<char> piece(128 * 1024);
|
||||
std::vector<char> piece(1024);
|
||||
for (int i = 0; i < int(piece.size()); ++i)
|
||||
piece[std::size_t(i)] = (i % 26) + 'A';
|
||||
|
||||
// calculate the hash for all pieces
|
||||
sha1_hash ph = hasher(piece).final();
|
||||
sha1_hash const ph = hasher(piece).final();
|
||||
TEST_CHECK(t.num_pieces() > 0);
|
||||
for (auto const i : fs.piece_range())
|
||||
t.set_hash(i, ph);
|
||||
|
|
Loading…
Reference in New Issue