diff --git a/ChangeLog b/ChangeLog index 8b675f034..954b3d911 100644 --- a/ChangeLog +++ b/ChangeLog @@ -95,6 +95,7 @@ * added support for storing per-peer rate limits across reconnects * improved fallocate support * fixed magnet link issue when using resume data + * support disk I/O priority settings release 0.14.9 diff --git a/bindings/python/src/session_settings.cpp b/bindings/python/src/session_settings.cpp index 7b857723c..677b0ae24 100644 --- a/bindings/python/src/session_settings.cpp +++ b/bindings/python/src/session_settings.cpp @@ -99,6 +99,13 @@ void bind_session_settings() .def_readwrite("disk_cache_algorithm", &session_settings::disk_cache_algorithm) .def_readwrite("read_cache_line_size", &session_settings::read_cache_line_size) .def_readwrite("write_cache_line_size", &session_settings::write_cache_line_size) + .def_readwrite("optimistic_disk_retry", &session_settings::optimistic_disk_retry) + .def_readwrite("disable_hash_checks", &session_settings::disable_hash_checks) + .def_readwrite("allow_reordered_disk_operations", &session_settings::allow_reordered_disk_operations) + .def_readwrite("allow_i2p_mixed", &session_settings::allow_i2p_mixed) + .def_readwrite("max_suggest_pieces", &session_settings::max_suggest_pieces) + .def_readwrite("drop_skipped_requests", &session_settings::drop_skipped_requests) + .def_readwrite("low_prio_disk", &session_settings::low_prio_disk) ; enum_("proxy_type") diff --git a/docs/manual.rst b/docs/manual.rst index 23974f458..f25bcb165 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -3718,6 +3718,8 @@ session_settings int max_suggest_pieces; bool drop_skipped_requests; + + bool low_prio_disk; }; ``user_agent`` this is the client identification to the tracker. @@ -4180,6 +4182,13 @@ BitComet peers silently ignoring some requests. It may cause problems at high rates, and high level of reordering in the uploading peer, that's why it's disabled by default. +``low_prio_disk`` determines if the disk I/O should use a normal +or low priority policy. This defaults to true, which means that +it's low priority by default. Other processes doing disk I/O will +normally take priority in this mode. This is meant to improve the +overall responsiveness of the system while downloading in the +background. For high-performance server setups, this might not +be desirable. pe_settings =========== diff --git a/include/libtorrent/disk_io_thread.hpp b/include/libtorrent/disk_io_thread.hpp index 4169e1527..602477c6d 100644 --- a/include/libtorrent/disk_io_thread.hpp +++ b/include/libtorrent/disk_io_thread.hpp @@ -253,6 +253,7 @@ namespace libtorrent { disk_io_thread(io_service& ios , boost::function const& queue_callback + , file_pool& fp , int block_size = 16 * 1024); ~disk_io_thread(); @@ -399,6 +400,10 @@ namespace libtorrent // exist anymore, and crash. This prevents that. boost::optional m_work; + // reference to the file_pool which is a member of + // the session_impl object + file_pool& m_file_pool; + // thread for performing blocking disk io operations thread m_disk_io_thread; }; diff --git a/include/libtorrent/file.hpp b/include/libtorrent/file.hpp index 44d7bf80a..b92668a85 100644 --- a/include/libtorrent/file.hpp +++ b/include/libtorrent/file.hpp @@ -241,6 +241,12 @@ namespace libtorrent size_type phys_offset(size_type offset); +#ifdef TORRENT_WINDOWS + HANDLE native_handle() const { return m_file_handle; } +#else + int native_handle() const { return m_fd; } +#endif + private: #ifdef TORRENT_WINDOWS diff --git a/include/libtorrent/file_pool.hpp b/include/libtorrent/file_pool.hpp index 6dc1d4c26..0e1a6aae2 100644 --- a/include/libtorrent/file_pool.hpp +++ b/include/libtorrent/file_pool.hpp @@ -52,7 +52,7 @@ namespace libtorrent { struct TORRENT_EXPORT file_pool : boost::noncopyable { - file_pool(int size = 40): m_size(size) {} + file_pool(int size = 40): m_size(size), m_low_prio_io(true) {} boost::shared_ptr open_file(void* st, std::string const& p , int m, error_code& ec); @@ -60,12 +60,15 @@ namespace libtorrent void release(std::string const& p); void resize(int size); int size_limit() const { return m_size; } + void set_low_prio_io(bool b) { m_low_prio_io = b; } private: + file_pool(file_pool const&); void remove_oldest(); int m_size; + bool m_low_prio_io; struct lru_file_entry { diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index 41d2c6d45..ead0fe48e 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -185,6 +185,7 @@ namespace libtorrent , allow_i2p_mixed(false) , max_suggest_pieces(10) , drop_skipped_requests(false) + , low_prio_disk(true) {} // this is the user agent that will be sent to the tracker @@ -675,6 +676,13 @@ namespace libtorrent // satisfied after the equivalence of the entire // request queue has been received, will be considered lost bool drop_skipped_requests; + + // if this is set to true, the disk I/O will be + // run at lower-than-normal priority. This is + // intended to make the machine more responsive + // to foreground tasks, while bittorrent runs + // in the background + bool low_prio_disk; }; #ifndef TORRENT_DISABLE_DHT diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index b30c800b6..25a4f34e9 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/invariant_check.hpp" #include "libtorrent/error_code.hpp" #include "libtorrent/error.hpp" +#include "libtorrent/file_pool.hpp" #include #include @@ -280,6 +281,7 @@ namespace libtorrent disk_io_thread::disk_io_thread(io_service& ios , boost::function const& queue_callback + , file_pool& fp , int block_size) : disk_buffer_pool(block_size) , m_abort(false) @@ -289,6 +291,7 @@ namespace libtorrent , m_ios(ios) , m_queue_callback(queue_callback) , m_work(io_service::work(m_ios)) + , m_file_pool(fp) , m_disk_io_thread(boost::bind(&disk_io_thread::thread_fun, this)) { #ifdef TORRENT_DISK_STATS @@ -1570,7 +1573,21 @@ namespace libtorrent TORRENT_ASSERT(s.cache_size >= 0); TORRENT_ASSERT(s.cache_expiry > 0); +#if defined TORRENT_WINDOWS + if (m_settings.low_prio_disk != s.low_prio_disk) + { + m_file_pool.set_low_prio_io(s.low_prio_disk); + // we need to close all files, since the prio + // only takes affect when files are opened + m_file_pool.release(0); + } +#endif m_settings = s; + m_file_pool.resize(m_settings.file_pool_size); +#if defined __APPLE__ && defined __MACH__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 + setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD + , m_settings.low_prio_disk ? IOPOL_THROTTLE : IOPOL_DEFAULT); +#endif break; } case disk_io_job::abort_torrent: diff --git a/src/file_pool.cpp b/src/file_pool.cpp index 635653ff9..31a7f930f 100644 --- a/src/file_pool.cpp +++ b/src/file_pool.cpp @@ -80,6 +80,15 @@ namespace libtorrent m_files.erase(i); return boost::shared_ptr(); } +#ifdef TORRENT_WINDOWS + if (m_low_prio_io) + { + FILE_IO_PRIORITY_HINT_INFO priorityHint; + priorityHint.PriorityHint = IoPriorityHintLow; + result = SetFileInformationByHandle(e.file_ptr->native_handle(), + FileIoPriorityHintInfo, &priorityHint, sizeof(PriorityHint)); + } +#endif TORRENT_ASSERT(e.file_ptr->is_open()); e.mode = m; } @@ -126,10 +135,16 @@ namespace libtorrent if (i != m_files.end()) m_files.erase(i); } + // closes files belonging to the specified + // storage. If 0 is passed, all files are closed void file_pool::release(void* st) { mutex::scoped_lock l(m_mutex); - TORRENT_ASSERT(st != 0); + if (st == 0) + { + m_files.clear(); + return; + } for (file_set::iterator i = m_files.begin(); i != m_files.end();) diff --git a/src/session.cpp b/src/session.cpp index 70c57597c..19d1765f7 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -175,6 +175,7 @@ namespace libtorrent set.cache_buffer_chunk_size = 128; set.read_cache_line_size = 512; set.write_cache_line_size = 512; + set.low_prio_disk = false; // one hour expiration set.cache_expiry = 60 * 60; diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 57bf29411..59c427f40 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -403,7 +403,7 @@ namespace aux { , m_files(40) , m_io_service() , m_alerts(m_io_service) - , m_disk_thread(m_io_service, boost::bind(&session_impl::on_disk_queue, this)) + , m_disk_thread(m_io_service, boost::bind(&session_impl::on_disk_queue, this), m_files) , m_half_open(m_io_service) , m_download_rate(peer_connection::download_channel) #ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT @@ -1016,7 +1016,10 @@ namespace aux { #ifndef TORRENT_DISABLE_MLOCK || m_settings.lock_disk_cache != s.lock_disk_cache #endif - || m_settings.use_read_cache != s.use_read_cache) + || m_settings.use_read_cache != s.use_read_cache + || m_settings.allow_reordered_disk_operations != s.allow_reordered_disk_operations + || m_settings.file_pool_size != s.file_pool_size + || m_settings.low_prio_disk != s.low_prio_disk) update_disk_io_thread = true; // if queuing settings were changed, recalculate @@ -1037,7 +1040,6 @@ namespace aux { m_disk_thread.add_job(j); } - m_files.resize(m_settings.file_pool_size); if (!s.auto_upload_slots) m_allowed_upload_slots = m_max_uploads; // replace all occurances of '\n' with ' '. std::string::iterator i = m_settings.user_agent.begin(); diff --git a/test/test_storage.cpp b/test/test_storage.cpp index 017a27735..25579eefb 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -243,7 +243,7 @@ void run_elevator_test() { error_code ec; - disk_io_thread dio(ios, &nop); + disk_io_thread dio(ios, &nop, fp); boost::intrusive_ptr pm(new piece_manager(boost::shared_ptr(), ti, "" , fp, dio, &create_test_storage, storage_mode_sparse)); @@ -379,7 +379,7 @@ void run_storage_tests(boost::intrusive_ptr info { file_pool fp; libtorrent::asio::io_service ios; - disk_io_thread io(ios, boost::function()); + disk_io_thread io(ios, boost::function(), fp); boost::shared_ptr dummy(new int); boost::intrusive_ptr pm = new piece_manager(dummy, info , test_path, fp, io, default_storage_constructor, storage_mode); @@ -601,7 +601,7 @@ void test_check_files(std::string const& test_path file_pool fp; libtorrent::asio::io_service ios; - disk_io_thread io(ios, boost::function()); + disk_io_thread io(ios, boost::function(), fp); boost::shared_ptr dummy(new int); boost::intrusive_ptr pm = new piece_manager(dummy, info , test_path, fp, io, default_storage_constructor, storage_mode);