merged RC_1_1 into master

This commit is contained in:
Arvid Norberg 2018-07-04 17:49:22 +02:00
commit c7e705e158
5 changed files with 113 additions and 75 deletions

View File

@ -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

View 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])

View File

@ -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()

View File

@ -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);

View File

@ -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);