fix race condition in storage tick handling in disk_io_thread

This commit is contained in:
arvidn 2017-05-18 08:50:22 -04:00 committed by Arvid Norberg
parent a9044e4d97
commit e79a7a08b9
2 changed files with 24 additions and 9 deletions

View File

@ -571,6 +571,7 @@ namespace aux {
// storages that have had write activity recently and will get ticked
// soon, for deferred actions (say, flushing partfile metadata)
std::vector<std::pair<time_point, std::weak_ptr<storage_interface>>> m_need_tick;
std::mutex m_need_tick_mutex;
// this is protected by the completed_jobs_mutex. It's true whenever
// there's a call_job_handlers message in-flight to the network thread. We

View File

@ -689,8 +689,11 @@ namespace libtorrent {
m_stats_counters.inc_stats_counter(counters::num_writing_threads, -1);
if (!pe->storage->set_need_tick())
m_need_tick.push_back({aux::time_now() + minutes(2), pe->storage});
{
std::lock_guard<std::mutex> l(m_need_tick_mutex);
if (!pe->storage->set_need_tick())
m_need_tick.push_back({aux::time_now() + minutes(2), pe->storage});
}
if (!failed)
{
@ -1128,7 +1131,7 @@ namespace libtorrent {
std::shared_ptr<storage_interface> storage = j->storage;
// TODO: instead of doing this. pass in the settings to each storage_interface
// TODO: 4 instead of doing this. pass in the settings to each storage_interface
// call. Each disk thread could hold its most recent understanding of the settings
// in a shared_ptr, and update it every time it wakes up from a job. That way
// each access to the settings won't require a std::mutex to be held.
@ -1493,8 +1496,11 @@ namespace libtorrent {
m_stats_counters.inc_stats_counter(counters::disk_job_time, write_time);
}
if (!j->storage->set_need_tick())
m_need_tick.push_back({aux::time_now() + minutes(2), j->storage});
{
std::lock_guard<std::mutex> l(m_need_tick_mutex);
if (!j->storage->set_need_tick())
m_need_tick.push_back({aux::time_now() + minutes(2), j->storage});
}
return ret != j->d.io.buffer_size
? status_t::fatal_disk_error : status_t::no_error;
@ -3100,11 +3106,19 @@ namespace libtorrent {
maybe_flush_write_blocks();
time_point const now = aux::time_now();
while (!m_need_tick.empty() && m_need_tick.front().first < now)
{
std::shared_ptr<storage_interface> st = m_need_tick.front().second.lock();
m_need_tick.erase(m_need_tick.begin());
if (st) st->tick();
std::unique_lock<std::mutex> l2(m_need_tick_mutex);
while (!m_need_tick.empty() && m_need_tick.front().first < now)
{
std::shared_ptr<storage_interface> st = m_need_tick.front().second.lock();
m_need_tick.erase(m_need_tick.begin());
if (st)
{
l2.unlock();
st->tick();
l2.lock();
}
}
}
if (now > m_next_close_oldest_file)