From e698c092985b8f2f889a8af853d7f8603fee58eb Mon Sep 17 00:00:00 2001 From: Coda Date: Wed, 11 May 2022 11:28:06 -0700 Subject: [PATCH] Allow to use POSIX-compliant disk IO type This patch allows user to switch disk IO type between memory mapped files based type (default in libtorrent 2, and seems causing memory issues) and POSIX-compliant type which is more conservative on memory usage. Co-authored-by: Chocobo1 Co-authored-by: Vladimir Golovnev (Glassez) PR #16895. --- src/base/bittorrent/customstorage.cpp | 14 ++++++++++ src/base/bittorrent/customstorage.h | 4 +++ src/base/bittorrent/session.cpp | 27 +++++++++++++++++++- src/base/bittorrent/session.h | 11 ++++++++ src/gui/advancedsettings.cpp | 15 +++++++++++ src/gui/advancedsettings.h | 1 + src/webui/api/appcontroller.cpp | 5 ++++ src/webui/www/private/views/preferences.html | 14 ++++++++++ 8 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/base/bittorrent/customstorage.cpp b/src/base/bittorrent/customstorage.cpp index c2934421d..308bc41ac 100644 --- a/src/base/bittorrent/customstorage.cpp +++ b/src/base/bittorrent/customstorage.cpp @@ -34,6 +34,8 @@ #include "common.h" #ifdef QBT_USES_LIBTORRENT2 +#include +#include #include std::unique_ptr customDiskIOConstructor( @@ -42,6 +44,18 @@ std::unique_ptr customDiskIOConstructor( return std::make_unique(lt::default_disk_io_constructor(ioContext, settings, counters)); } +std::unique_ptr customPosixDiskIOConstructor( + lt::io_context &ioContext, const lt::settings_interface &settings, lt::counters &counters) +{ + return std::make_unique(lt::posix_disk_io_constructor(ioContext, settings, counters)); +} + +std::unique_ptr customMMapDiskIOConstructor( + lt::io_context &ioContext, const lt::settings_interface &settings, lt::counters &counters) +{ + return std::make_unique(lt::mmap_disk_io_constructor(ioContext, settings, counters)); +} + CustomDiskIOThread::CustomDiskIOThread(std::unique_ptr nativeDiskIOThread) : m_nativeDiskIO {std::move(nativeDiskIOThread)} { diff --git a/src/base/bittorrent/customstorage.h b/src/base/bittorrent/customstorage.h index 13e162251..facbea6df 100644 --- a/src/base/bittorrent/customstorage.h +++ b/src/base/bittorrent/customstorage.h @@ -50,6 +50,10 @@ #ifdef QBT_USES_LIBTORRENT2 std::unique_ptr customDiskIOConstructor( lt::io_context &ioContext, lt::settings_interface const &settings, lt::counters &counters); +std::unique_ptr customPosixDiskIOConstructor( + lt::io_context &ioContext, lt::settings_interface const &settings, lt::counters &counters); +std::unique_ptr customMMapDiskIOConstructor( + lt::io_context &ioContext, lt::settings_interface const &settings, lt::counters &counters); class CustomDiskIOThread final : public lt::disk_interface { diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index afde3ef7a..57cb2e399 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -381,6 +381,7 @@ Session::Session(QObject *parent) , m_diskCacheSize(BITTORRENT_SESSION_KEY(u"DiskCacheSize"_qs), -1) , m_diskCacheTTL(BITTORRENT_SESSION_KEY(u"DiskCacheTTL"_qs), 60) , m_diskQueueSize(BITTORRENT_SESSION_KEY(u"DiskQueueSize"_qs), (1024 * 1024)) + , m_diskIOType(BITTORRENT_SESSION_KEY(u"DiskIOType"_qs), DiskIOType::Default) , m_useOSCache(BITTORRENT_SESSION_KEY(u"UseOSCache"_qs), true) #ifdef Q_OS_WIN , m_coalesceReadWriteEnabled(BITTORRENT_SESSION_KEY(u"CoalesceReadWrite"_qs), true) @@ -1149,7 +1150,18 @@ void Session::initializeNativeSession() loadLTSettings(pack); lt::session_params sessionParams {pack, {}}; #ifdef QBT_USES_LIBTORRENT2 - sessionParams.disk_io_constructor = customDiskIOConstructor; + switch (diskIOType()) + { + case DiskIOType::Posix: + sessionParams.disk_io_constructor = customPosixDiskIOConstructor; + break; + case DiskIOType::MMap: + sessionParams.disk_io_constructor = customMMapDiskIOConstructor; + break; + default: + sessionParams.disk_io_constructor = customDiskIOConstructor; + break; + } #endif m_nativeSession = new lt::session {sessionParams}; @@ -3363,6 +3375,19 @@ void Session::setPeerTurnoverInterval(const int val) configureDeferred(); } +DiskIOType Session::diskIOType() const +{ + return m_diskIOType; +} + +void Session::setDiskIOType(const DiskIOType type) +{ + if (type != m_diskIOType) + { + m_diskIOType = type; + } +} + int Session::requestQueueSize() const { return m_requestQueueSize; diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index c99471239..f7ecb7cc2 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -122,6 +122,14 @@ namespace BitTorrent }; Q_ENUM_NS(ChokingAlgorithm) + enum class DiskIOType : int + { + Default = 0, + MMap = 1, + Posix = 2 + }; + Q_ENUM_NS(DiskIOType) + enum class MixedModeAlgorithm : int { TCP = 0, @@ -368,6 +376,8 @@ namespace BitTorrent void setDiskCacheTTL(int ttl); qint64 diskQueueSize() const; void setDiskQueueSize(qint64 size); + DiskIOType diskIOType() const; + void setDiskIOType(DiskIOType type); bool useOSCache() const; void setUseOSCache(bool use); bool isCoalesceReadWriteEnabled() const; @@ -689,6 +699,7 @@ namespace BitTorrent CachedSettingValue m_diskCacheSize; CachedSettingValue m_diskCacheTTL; CachedSettingValue m_diskQueueSize; + CachedSettingValue m_diskIOType; CachedSettingValue m_useOSCache; CachedSettingValue m_coalesceReadWriteEnabled; CachedSettingValue m_usePieceExtentAffinity; diff --git a/src/gui/advancedsettings.cpp b/src/gui/advancedsettings.cpp index 5121e0e46..e737dcdff 100644 --- a/src/gui/advancedsettings.cpp +++ b/src/gui/advancedsettings.cpp @@ -108,6 +108,9 @@ namespace DISK_CACHE_TTL, #endif DISK_QUEUE_SIZE, +#ifdef QBT_USES_LIBTORRENT2 + DISK_IO_TYPE, +#endif OS_CACHE, #ifndef QBT_USES_LIBTORRENT2 COALESCE_RW, @@ -219,6 +222,9 @@ void AdvancedSettings::saveAdvancedSettings() #endif // Disk queue size session->setDiskQueueSize(m_spinBoxDiskQueueSize.value() * 1024); +#ifdef QBT_USES_LIBTORRENT2 + session->setDiskIOType(m_comboBoxDiskIOType.currentData().value()); +#endif // Enable OS cache session->setUseOSCache(m_checkBoxOsCache.isChecked()); #ifndef QBT_USES_LIBTORRENT2 @@ -521,6 +527,15 @@ void AdvancedSettings::loadAdvancedSettings() m_spinBoxDiskQueueSize.setSuffix(tr(" KiB")); addRow(DISK_QUEUE_SIZE, (tr("Disk queue size") + u' ' + makeLink(u"https://www.libtorrent.org/reference-Settings.html#max_queued_disk_bytes", u"(?)")) , &m_spinBoxDiskQueueSize); +#ifdef QBT_USES_LIBTORRENT2 + // Disk IO type + m_comboBoxDiskIOType.addItem(tr("Default"), QVariant::fromValue(BitTorrent::DiskIOType::Default)); + m_comboBoxDiskIOType.addItem(tr("Memory mapped files"), QVariant::fromValue(BitTorrent::DiskIOType::MMap)); + m_comboBoxDiskIOType.addItem(tr("POSIX-compliant"), QVariant::fromValue(BitTorrent::DiskIOType::Posix)); + m_comboBoxDiskIOType.setCurrentIndex(m_comboBoxDiskIOType.findData(QVariant::fromValue(session->diskIOType()))); + addRow(DISK_IO_TYPE, tr("Disk IO type (requires restart)") + u' ' + makeLink(u"https://www.libtorrent.org/single-page-ref.html#default-disk-io-constructor", u"(?)") + , &m_comboBoxDiskIOType); +#endif // Enable OS cache m_checkBoxOsCache.setChecked(session->useOSCache()); addRow(OS_CACHE, (tr("Enable OS cache") + u' ' + makeLink(u"https://www.libtorrent.org/reference-Settings.html#disk_io_write_mode", u"(?)")) diff --git a/src/gui/advancedsettings.h b/src/gui/advancedsettings.h index 34f48b672..1dc52ebc6 100644 --- a/src/gui/advancedsettings.h +++ b/src/gui/advancedsettings.h @@ -76,6 +76,7 @@ private: QSpinBox m_spinBoxCache, m_spinBoxCacheTTL; QCheckBox m_checkBoxCoalesceRW; #else + QComboBox m_comboBoxDiskIOType; QSpinBox m_spinBoxHashingThreads; #endif diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index 06c2c9343..987769eed 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -315,6 +315,8 @@ void AppController::preferencesAction() data[u"disk_cache_ttl"_qs] = session->diskCacheTTL(); // Disk queue size data[u"disk_queue_size"_qs] = session->diskQueueSize(); + // Disk IO Type + data[u"disk_io_type"_qs] = static_cast(session->diskIOType()); // Enable OS cache data[u"enable_os_cache"_qs] = session->useOSCache(); // Coalesce reads & writes @@ -799,6 +801,9 @@ void AppController::setPreferencesAction() // Disk queue size if (hasKey(u"disk_queue_size"_qs)) session->setDiskQueueSize(it.value().toLongLong()); + // Disk IO Type + if (hasKey(u"disk_io_type"_qs)) + session->setDiskIOType(static_cast(it.value().toInt())); // Enable OS cache if (hasKey(u"enable_os_cache"_qs)) session->setUseOSCache(it.value().toBool()); diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index 6804c0fe9..36c53ab6f 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -1038,6 +1038,18 @@   QBT_TR(KiB)QBT_TR[CONTEXT=OptionsDialog] + + + + + + + + @@ -1970,6 +1982,7 @@ $('diskCache').setProperty('value', pref.disk_cache); $('diskCacheExpiryInterval').setProperty('value', pref.disk_cache_ttl); $('diskQueueSize').setProperty('value', (pref.disk_queue_size / 1024)); + $('diskIOType').setProperty('value', pref.disk_io_type); $('enableOSCache').setProperty('checked', pref.enable_os_cache); $('coalesceReadsAndWrites').setProperty('checked', pref.enable_coalesce_read_write); $('pieceExtentAffinity').setProperty('checked', pref.enable_piece_extent_affinity); @@ -2371,6 +2384,7 @@ settings.set('disk_cache', $('diskCache').getProperty('value')); settings.set('disk_cache_ttl', $('diskCacheExpiryInterval').getProperty('value')); settings.set('disk_queue_size', ($('diskQueueSize').getProperty('value') * 1024)); + settings.set('disk_io_type', $('diskIOType').getProperty('value')); settings.set('enable_os_cache', $('enableOSCache').getProperty('checked')); settings.set('enable_coalesce_read_write', $('coalesceReadsAndWrites').getProperty('checked')); settings.set('enable_piece_extent_affinity', $('pieceExtentAffinity').getProperty('checked'));