diff --git a/docs/manual.rst b/docs/manual.rst index 2b8f6c267..1d63d730a 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -4381,6 +4381,7 @@ session_settings bool smooth_connects; bool always_send_user_agent; bool apply_ip_filter_to_trackers; + int read_job_every; }; ``version`` is automatically set to the libtorrent version you're using @@ -5238,6 +5239,13 @@ IP filter applies to trackers as well as peers. If this is set to false, trackers are exempt from the IP filter (if there is one). If no IP filter is set, this setting is irrelevant. +``read_job_every`` is used to avoid starvation of read jobs in the disk I/O +thread. By default, read jobs are deferred, sorted by physical disk location +and serviced once all write jobs have been issued. In scenarios where the +download rate is enough to saturate the disk, there's a risk the read jobs will +never be serviced. With this setting, every *x* write job, issued in a row, will +instead pick one read job off of the sorted queue, where *x* is ``read_job_every``. + pe_settings =========== diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index 025a207e7..b67b349be 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -267,6 +267,7 @@ namespace libtorrent , smooth_connects(true) , always_send_user_agent(false) , apply_ip_filter_to_trackers(true) + , read_job_every(10) {} // libtorrent version. Used for forward binary compatibility @@ -1064,6 +1065,11 @@ namespace libtorrent // if true, trackers will also be filtered by the IP // filter, otherwise they are exempt bool apply_ip_filter_to_trackers; + + // to avoid write jobs starving read jobs, if this many + // write jobs have been taking priority in a row, service + // one read job + int read_job_every; }; #ifndef TORRENT_DISABLE_DHT diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index adfa52931..37a956191 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -1559,6 +1559,7 @@ namespace libtorrent read_jobs_t::iterator elevator_job_pos = m_sorted_read_jobs.begin(); size_type last_elevator_pos = 0; bool need_update_elevator_pos = false; + int immediate_jobs_in_row = 0; for (;;) { @@ -1618,7 +1619,14 @@ namespace libtorrent m_queue_time.add_sample(total_microseconds(now - j.start_time)); ptime operation_start = now; - if (!m_jobs.empty()) + // make sure we don't starve out the read queue by just issuing + // write jobs constantly, mix in a read job every now and then + // with a configurable ratio + bool pick_read_job = m_jobs.empty() + || (immediate_jobs_in_row >= m_settings.read_job_every + && !m_sorted_read_jobs.empty()); + + if (!pick_read_job) { // we have a job in the job queue. If it's // a read operation and we are allowed to @@ -1702,6 +1710,8 @@ namespace libtorrent m_cache_stats.cumulative_job_time += total_milliseconds(now - operation_start); continue; } + + ++immediate_jobs_in_row; } else { @@ -1710,6 +1720,8 @@ namespace libtorrent // job queue lock anymore jl.unlock(); + immediate_jobs_in_row = 0; + TORRENT_ASSERT(!m_sorted_read_jobs.empty()); // if m_sorted_read_jobs used to be empty, diff --git a/src/session_impl.cpp b/src/session_impl.cpp index c5caa16af..f1286f603 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -363,6 +363,7 @@ namespace aux { TORRENT_SETTING(integer, smooth_connects) TORRENT_SETTING(boolean, always_send_user_agent) TORRENT_SETTING(boolean, apply_ip_filter_to_trackers) + TORRENT_SETTING(integer, read_job_every) }; #undef TORRENT_SETTING