fix issue of rapid calls to file_priority() clobbering each other
This commit is contained in:
parent
b5e717ffe0
commit
b5790b982b
|
@ -1,3 +1,4 @@
|
||||||
|
* fix issue of rapid calls to file_priority() clobbering each other
|
||||||
* clear tracker errors on success
|
* clear tracker errors on success
|
||||||
* optimize setting with unlimited unchoke slots
|
* optimize setting with unlimited unchoke slots
|
||||||
* fixed restoring of trackers, comment, creation date and created-by in resume data
|
* fixed restoring of trackers, comment, creation date and created-by in resume data
|
||||||
|
|
|
@ -575,7 +575,7 @@ namespace libtorrent {
|
||||||
download_priority_t file_priority(file_index_t index) const;
|
download_priority_t file_priority(file_index_t index) const;
|
||||||
|
|
||||||
void on_file_priority(storage_error const& err, aux::vector<download_priority_t, file_index_t> prios);
|
void on_file_priority(storage_error const& err, aux::vector<download_priority_t, file_index_t> prios);
|
||||||
void prioritize_files(aux::vector<download_priority_t, file_index_t> const& files);
|
void prioritize_files(aux::vector<download_priority_t, file_index_t> files);
|
||||||
void file_priorities(aux::vector<download_priority_t, file_index_t>*) const;
|
void file_priorities(aux::vector<download_priority_t, file_index_t>*) const;
|
||||||
|
|
||||||
void cancel_non_critical();
|
void cancel_non_critical();
|
||||||
|
@ -1273,6 +1273,12 @@ namespace libtorrent {
|
||||||
// TODO: this wastes 5 bits per file
|
// TODO: this wastes 5 bits per file
|
||||||
aux::vector<download_priority_t, file_index_t> m_file_priority;
|
aux::vector<download_priority_t, file_index_t> m_file_priority;
|
||||||
|
|
||||||
|
// any file priority updateds attempted while another file priority update
|
||||||
|
// in in-progress/outstanding with the disk I/O thread, are queued up in
|
||||||
|
// this dictionary. Once the outstanding update comes back, all of these
|
||||||
|
// are applied in one batch
|
||||||
|
std::map<file_index_t, download_priority_t> m_deferred_file_priorities;
|
||||||
|
|
||||||
// this object is used to track download progress of individual files
|
// this object is used to track download progress of individual files
|
||||||
aux::file_progress m_file_progress;
|
aux::file_progress m_file_progress;
|
||||||
|
|
||||||
|
@ -1704,6 +1710,9 @@ namespace libtorrent {
|
||||||
// the torrent error
|
// the torrent error
|
||||||
bool m_torrent_initialized:1;
|
bool m_torrent_initialized:1;
|
||||||
|
|
||||||
|
// this is set to true while waiting for an async_set_file_priority
|
||||||
|
bool m_outstanding_file_priority:1;
|
||||||
|
|
||||||
#if TORRENT_USE_ASSERTS
|
#if TORRENT_USE_ASSERTS
|
||||||
// set to true when torrent is start()ed. It may only be started once
|
// set to true when torrent is start()ed. It may only be started once
|
||||||
bool m_was_started = false;
|
bool m_was_started = false;
|
||||||
|
|
|
@ -227,6 +227,7 @@ bool is_downloading_state(int const st)
|
||||||
, m_downloaded(0xffffff)
|
, m_downloaded(0xffffff)
|
||||||
, m_progress_ppm(0)
|
, m_progress_ppm(0)
|
||||||
, m_torrent_initialized(false)
|
, m_torrent_initialized(false)
|
||||||
|
, m_outstanding_file_priority(false)
|
||||||
{
|
{
|
||||||
// we cannot log in the constructor, because it relies on shared_from_this
|
// we cannot log in the constructor, because it relies on shared_from_this
|
||||||
// being initialized, which happens after the constructor returns.
|
// being initialized, which happens after the constructor returns.
|
||||||
|
@ -4963,29 +4964,28 @@ bool is_downloading_state(int const st)
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
aux::vector<download_priority_t, file_index_t> fix_priorities(
|
aux::vector<download_priority_t, file_index_t> fix_priorities(
|
||||||
aux::vector<download_priority_t, file_index_t> const& input
|
aux::vector<download_priority_t, file_index_t> input
|
||||||
, file_storage const* fs)
|
, file_storage const* fs)
|
||||||
{
|
{
|
||||||
aux::vector<download_priority_t, file_index_t> files(input.begin(), input.end());
|
if (fs) input.resize(fs->num_files(), default_priority);
|
||||||
|
|
||||||
if (fs) files.resize(fs->num_files(), default_priority);
|
for (file_index_t i : input.range())
|
||||||
|
|
||||||
for (file_index_t i : files.range())
|
|
||||||
{
|
{
|
||||||
// initialize pad files to priority 0
|
// initialize pad files to priority 0
|
||||||
if (files[i] > dont_download && fs && fs->pad_file_at(i))
|
if (input[i] > dont_download && fs && fs->pad_file_at(i))
|
||||||
files[i] = dont_download;
|
input[i] = dont_download;
|
||||||
else if (files[i] > top_priority)
|
else if (input[i] > top_priority)
|
||||||
files[i] = top_priority;
|
input[i] = top_priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
return files;
|
return input;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void torrent::on_file_priority(storage_error const& err
|
void torrent::on_file_priority(storage_error const& err
|
||||||
, aux::vector<download_priority_t, file_index_t> prios)
|
, aux::vector<download_priority_t, file_index_t> prios)
|
||||||
{
|
{
|
||||||
|
m_outstanding_file_priority = false;
|
||||||
COMPLETE_ASYNC("file_priority");
|
COMPLETE_ASYNC("file_priority");
|
||||||
if (m_file_priority != prios)
|
if (m_file_priority != prios)
|
||||||
{
|
{
|
||||||
|
@ -4994,23 +4994,43 @@ bool is_downloading_state(int const st)
|
||||||
recalc_share_mode();
|
recalc_share_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!err) return;
|
if (err)
|
||||||
|
{
|
||||||
|
// in this case, some file priorities failed to get set
|
||||||
|
if (alerts().should_post<file_error_alert>())
|
||||||
|
alerts().emplace_alert<file_error_alert>(err.ec
|
||||||
|
, resolve_filename(err.file()), err.operation, get_handle());
|
||||||
|
|
||||||
// in this case, some file priorities failed to get set
|
set_error(err.ec, err.file());
|
||||||
|
pause();
|
||||||
if (alerts().should_post<file_error_alert>())
|
}
|
||||||
alerts().emplace_alert<file_error_alert>(err.ec
|
else if (!m_deferred_file_priorities.empty() && !m_abort)
|
||||||
, resolve_filename(err.file()), err.operation, get_handle());
|
{
|
||||||
|
auto new_priority = m_file_priority;
|
||||||
set_error(err.ec, err.file());
|
// resize the vector if we have to. The last item in the map has the
|
||||||
pause();
|
// highest file index.
|
||||||
|
auto const max_idx = std::prev(m_deferred_file_priorities.end())->first;
|
||||||
|
if (new_priority.end_index() <= max_idx)
|
||||||
|
{
|
||||||
|
// any unallocated slot is assumed to have the default priority
|
||||||
|
new_priority.resize(static_cast<int>(max_idx) + 1, default_priority);
|
||||||
|
}
|
||||||
|
for (auto const& p : m_deferred_file_priorities)
|
||||||
|
{
|
||||||
|
file_index_t const index = p.first;
|
||||||
|
download_priority_t const prio = p.second;
|
||||||
|
new_priority[index] = prio;
|
||||||
|
}
|
||||||
|
m_deferred_file_priorities.clear();
|
||||||
|
prioritize_files(std::move(new_priority));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void torrent::prioritize_files(aux::vector<download_priority_t, file_index_t> const& files)
|
void torrent::prioritize_files(aux::vector<download_priority_t, file_index_t> files)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
auto new_priority = fix_priorities(files
|
auto new_priority = fix_priorities(std::move(files)
|
||||||
, valid_metadata() ? &m_torrent_file->files() : nullptr);
|
, valid_metadata() ? &m_torrent_file->files() : nullptr);
|
||||||
|
|
||||||
// storage may be NULL during shutdown
|
// storage may be NULL during shutdown
|
||||||
|
@ -5023,6 +5043,7 @@ bool is_downloading_state(int const st)
|
||||||
// possibly not fully updated.
|
// possibly not fully updated.
|
||||||
update_piece_priorities(new_priority);
|
update_piece_priorities(new_priority);
|
||||||
|
|
||||||
|
m_outstanding_file_priority = true;
|
||||||
ADD_OUTSTANDING_ASYNC("file_priority");
|
ADD_OUTSTANDING_ASYNC("file_priority");
|
||||||
m_ses.disk_thread().async_set_file_priority(m_storage
|
m_ses.disk_thread().async_set_file_priority(m_storage
|
||||||
, std::move(new_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));
|
||||||
|
@ -5048,6 +5069,13 @@ bool is_downloading_state(int const st)
|
||||||
}
|
}
|
||||||
|
|
||||||
prio = aux::clamp(prio, dont_download, top_priority);
|
prio = aux::clamp(prio, dont_download, top_priority);
|
||||||
|
|
||||||
|
if (m_outstanding_file_priority)
|
||||||
|
{
|
||||||
|
m_deferred_file_priorities[index] = prio;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto new_priority = m_file_priority;
|
auto new_priority = m_file_priority;
|
||||||
if (new_priority.end_index() <= index)
|
if (new_priority.end_index() <= index)
|
||||||
{
|
{
|
||||||
|
@ -5066,6 +5094,7 @@ bool is_downloading_state(int const st)
|
||||||
// piece priorities still stay the same, but the file priorities are
|
// piece priorities still stay the same, but the file priorities are
|
||||||
// possibly not fully updated.
|
// possibly not fully updated.
|
||||||
update_piece_priorities(new_priority);
|
update_piece_priorities(new_priority);
|
||||||
|
m_outstanding_file_priority = true;
|
||||||
ADD_OUTSTANDING_ASYNC("file_priority");
|
ADD_OUTSTANDING_ASYNC("file_priority");
|
||||||
m_ses.disk_thread().async_set_file_priority(m_storage
|
m_ses.disk_thread().async_set_file_priority(m_storage
|
||||||
, std::move(new_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));
|
||||||
|
|
|
@ -520,6 +520,7 @@ namespace libtorrent {
|
||||||
return sync_call_ret<download_priority_t>(dont_download, &torrent::file_priority, index);
|
return sync_call_ret<download_priority_t>(dont_download, &torrent::file_priority, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: support moving files into this call
|
||||||
void torrent_handle::prioritize_files(std::vector<download_priority_t> const& files) const
|
void torrent_handle::prioritize_files(std::vector<download_priority_t> const& files) const
|
||||||
{
|
{
|
||||||
async_call(&torrent::prioritize_files
|
async_call(&torrent::prioritize_files
|
||||||
|
|
|
@ -484,6 +484,35 @@ TORRENT_TEST(no_metadata_piece_prio)
|
||||||
ses.remove_torrent(h);
|
ses.remove_torrent(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(file_priority_multiple_calls)
|
||||||
|
{
|
||||||
|
settings_pack pack = settings();
|
||||||
|
lt::session ses(pack);
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
auto t = ::generate_torrent(true);
|
||||||
|
|
||||||
|
add_torrent_params addp;
|
||||||
|
addp.flags &= ~torrent_flags::paused;
|
||||||
|
addp.flags &= ~torrent_flags::auto_managed;
|
||||||
|
addp.save_path = ".";
|
||||||
|
addp.ti = t;
|
||||||
|
torrent_handle h = ses.add_torrent(addp);
|
||||||
|
|
||||||
|
for (file_index_t const i : t->files().file_range())
|
||||||
|
h.file_priority(i, lt::low_priority);
|
||||||
|
|
||||||
|
std::vector<download_priority_t> const expected(
|
||||||
|
std::size_t(t->files().num_files()), lt::low_priority);
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
{
|
||||||
|
auto const p = h.get_file_priorities();
|
||||||
|
if (p == expected) return;
|
||||||
|
std::this_thread::sleep_for(milliseconds(500));
|
||||||
|
}
|
||||||
|
TEST_CHECK(false);
|
||||||
|
}
|
||||||
|
|
||||||
TORRENT_TEST(export_file_while_seed)
|
TORRENT_TEST(export_file_while_seed)
|
||||||
{
|
{
|
||||||
settings_pack pack = settings();
|
settings_pack pack = settings();
|
||||||
|
|
|
@ -254,7 +254,6 @@ TORRENT_TEST(total_wanted)
|
||||||
// the last set priority
|
// the last set priority
|
||||||
h.file_priority(file_index_t{1}, default_priority);
|
h.file_priority(file_index_t{1}, default_priority);
|
||||||
h.file_priority(file_index_t{1}, dont_download);
|
h.file_priority(file_index_t{1}, dont_download);
|
||||||
TEST_EQUAL(h.status({}).total_wanted, 0);
|
|
||||||
TEST_CHECK(wait_priority(h, aux::vector<download_priority_t, file_index_t>(static_cast<std::size_t>(fs.num_files()))));
|
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);
|
TEST_EQUAL(h.status({}).total_wanted, 0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue