From ad6c7b140cecd1623861d5aef32195094d6fd267 Mon Sep 17 00:00:00 2001 From: nephros Date: Sat, 7 Dec 2024 21:46:49 +0100 Subject: [PATCH 01/39] Hotcache: Add a cache object to track nonexisting files --- .../patchmanagerobject.cpp | 38 ++++++++++++++----- .../patchmanager-daemon/patchmanagerobject.h | 3 ++ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index fa046250..c4bff637 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -147,6 +147,8 @@ static const QString SILICA_CODE = QStringLiteral("silica"); static const QString SETTINGS_CODE = QStringLiteral("settings"); static const QString KEYBOARD_CODE = QStringLiteral("keyboard"); +static const int HOTCACHE_MAXCOST = 5000; + /*! \class PatchManagerObject \inmodule PatchManagerDaemon @@ -508,6 +510,8 @@ PatchManagerObject::PatchManagerObject(QObject *parent) : QObject(parent) , m_sbus(s_sessionBusConnection) { + // set up cache + m_hotcache.setMaxCost(HOTCACHE_MAXCOST); } PatchManagerObject::~PatchManagerObject() @@ -1862,20 +1866,36 @@ void PatchManagerObject::startReadingLocalServer() const QByteArray request = clientConnection->readAll(); QByteArray payload; const QString fakePath = QStringLiteral("%1%2").arg(s_patchmanagerCacheRoot, QString::fromLatin1(request)); - if (!m_failed && QFileInfo::exists(fakePath)) { - payload = fakePath.toLatin1(); - if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { - qDebug() << Q_FUNC_INFO << "Requested:" << request << "Sending:" << payload; - } - } else { - payload = request; - if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { - qDebug() << Q_FUNC_INFO << "Requested:" << request << "is sent unaltered."; + payload = request; + if (!m_failed) { + /* Hot cache: cache the most often-used missed paths, and return early if they are in the cache */ + if (!m_hotcache.contains(request)) { // not in the cache. do all the lookups + if (Q_UNLIKELY(QFileInfo::exists(fakePath))) { + payload = fakePath.toLatin1(); + if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { + qDebug() << Q_FUNC_INFO << "Requested:" << request << "Sending:" << payload; + } + } else { + if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { + qDebug() << Q_FUNC_INFO << "Requested:" << request << "is sent unaltered."; + } + } + } else { //hotcache hit, i.e. file does not exist + qDebug() << Q_FUNC_INFO << "Hot cache: hit:" << request; + if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { + qDebug() << Q_FUNC_INFO << "Requested:" << request << "is sent unaltered."; + } } } clientConnection->write(payload); clientConnection->flush(); // clientConnection->waitForBytesWritten(); + + // manage the cache after writing the data: + if (payload == request) { // didn't exist + m_hotcache.insert(request, nullptr); // TODO: do we want a cost here? + qDebug() << Q_FUNC_INFO << "Hot cache: now has" << m_hotcache.size() << "entries"; + } }, Qt::DirectConnection); } diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index 4f85b50b..4bff5393 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -48,6 +48,7 @@ #include #include #include +#include #include @@ -267,6 +268,8 @@ private slots: QTimer *m_sessionBusConnector = nullptr; QDBusConnection m_sbus; + + QCache m_hotcache; }; #endif // PATCHMANAGEROBJECT_H From 37d44e990b603a0c9ad38ce9df5a5f72736b6518 Mon Sep 17 00:00:00 2001 From: nephros Date: Sat, 7 Dec 2024 21:52:12 +0100 Subject: [PATCH 02/39] Hotcache: remove entry if it existed --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index c4bff637..c26af826 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -1895,6 +1895,10 @@ void PatchManagerObject::startReadingLocalServer() if (payload == request) { // didn't exist m_hotcache.insert(request, nullptr); // TODO: do we want a cost here? qDebug() << Q_FUNC_INFO << "Hot cache: now has" << m_hotcache.size() << "entries"; + } else { + if (m_hotcache.remove(request)) { + qWarning() << Q_FUNC_INFO << "Hot cache: contained a patched file!"; + } } }, Qt::DirectConnection); } From e2fddc35e0f1ab6b7cc86e52a7850c3c80e335c8 Mon Sep 17 00:00:00 2001 From: nephros Date: Sat, 7 Dec 2024 23:06:15 +0100 Subject: [PATCH 03/39] Hotcache: simplify logic --- .../patchmanagerobject.cpp | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index c26af826..05f4b90b 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -1867,24 +1867,19 @@ void PatchManagerObject::startReadingLocalServer() QByteArray payload; const QString fakePath = QStringLiteral("%1%2").arg(s_patchmanagerCacheRoot, QString::fromLatin1(request)); payload = request; - if (!m_failed) { - /* Hot cache: cache the most often-used missed paths, and return early if they are in the cache */ - if (!m_hotcache.contains(request)) { // not in the cache. do all the lookups - if (Q_UNLIKELY(QFileInfo::exists(fakePath))) { - payload = fakePath.toLatin1(); - if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { - qDebug() << Q_FUNC_INFO << "Requested:" << request << "Sending:" << payload; - } - } else { - if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { - qDebug() << Q_FUNC_INFO << "Requested:" << request << "is sent unaltered."; - } - } - } else { //hotcache hit, i.e. file does not exist - qDebug() << Q_FUNC_INFO << "Hot cache: hit:" << request; - if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { - qDebug() << Q_FUNC_INFO << "Requested:" << request << "is sent unaltered."; - } + if ( + (!m_failed) // return unaltered for failed + && (!m_hotcache.contains(request)) // hotcache has the most often asked unpatched files + && (Q_UNLIKELY(QFileInfo::exists(fakePath))) // file is patched + ) + { + payload = fakePath.toLatin1(); + if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { + qDebug() << Q_FUNC_INFO << "Requested:" << request << "Sending:" << payload; + } + } else { // failed state or file is unpatched + if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { + qDebug() << Q_FUNC_INFO << "Requested:" << request << "is sent unaltered."; } } clientConnection->write(payload); From bb975f41466ed0f01b5c9b24eb5156f897b6e6e7 Mon Sep 17 00:00:00 2001 From: nephros Date: Sun, 8 Dec 2024 14:37:20 +0100 Subject: [PATCH 04/39] Hotcache: store Object, retrieve one on lookup --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 05f4b90b..86677583 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -1869,7 +1869,8 @@ void PatchManagerObject::startReadingLocalServer() payload = request; if ( (!m_failed) // return unaltered for failed - && (!m_hotcache.contains(request)) // hotcache has the most often asked unpatched files + //&& (!m_hotcache.contains(request)) // hotcache has the most often asked unpatched files + && (m_hotcache.take(request) == nullptr) // like contains(), but request the object so its use count goes up && (Q_UNLIKELY(QFileInfo::exists(fakePath))) // file is patched ) { @@ -1888,7 +1889,8 @@ void PatchManagerObject::startReadingLocalServer() // manage the cache after writing the data: if (payload == request) { // didn't exist - m_hotcache.insert(request, nullptr); // TODO: do we want a cost here? + QObject *dummy = new QObject(); // the cache will own it later + m_hotcache.insert(request, dummy); // TODO: do we want a cost here? qDebug() << Q_FUNC_INFO << "Hot cache: now has" << m_hotcache.size() << "entries"; } else { if (m_hotcache.remove(request)) { From 5fb9b3f16b808025a96d311841cb8f80914c361d Mon Sep 17 00:00:00 2001 From: nephros Date: Sun, 8 Dec 2024 20:54:26 +0100 Subject: [PATCH 05/39] Hotcache: remove log line --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 86677583..7b866592 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -1891,7 +1891,6 @@ void PatchManagerObject::startReadingLocalServer() if (payload == request) { // didn't exist QObject *dummy = new QObject(); // the cache will own it later m_hotcache.insert(request, dummy); // TODO: do we want a cost here? - qDebug() << Q_FUNC_INFO << "Hot cache: now has" << m_hotcache.size() << "entries"; } else { if (m_hotcache.remove(request)) { qWarning() << Q_FUNC_INFO << "Hot cache: contained a patched file!"; From 59516713146e655595d0dfd7fa92efc615d5f960 Mon Sep 17 00:00:00 2001 From: nephros Date: Mon, 9 Dec 2024 08:17:01 +0100 Subject: [PATCH 06/39] Hotcache: use object() not take() take() gives ownership to the caller. object() does not. --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 7b866592..557b7fd1 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -1869,8 +1869,12 @@ void PatchManagerObject::startReadingLocalServer() payload = request; if ( (!m_failed) // return unaltered for failed - //&& (!m_hotcache.contains(request)) // hotcache has the most often asked unpatched files - && (m_hotcache.take(request) == nullptr) // like contains(), but request the object so its use count goes up + /* Note: contains() is not enough, we want the cache to notice the access so the entry counts as "used". + * Also, it returns 0 in qt5.6, nullptr in qt5.15 + * See https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/qcache.h?h=5.6#n68 + * vs. https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/qcache.h?h=5.15#n74 + */ + && (m_hotcache[request] == 0) // it is not in the list of unpatched files && (Q_UNLIKELY(QFileInfo::exists(fakePath))) // file is patched ) { From de94ed13c18ff445b87d83ae5b79b6c60f0354d4 Mon Sep 17 00:00:00 2001 From: nephros Date: Mon, 9 Dec 2024 16:14:27 +0100 Subject: [PATCH 07/39] Hotcache: move debugging messages after writing to the connection --- .../patchmanagerobject.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 557b7fd1..d5ed498b 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -1879,23 +1879,24 @@ void PatchManagerObject::startReadingLocalServer() ) { payload = fakePath.toLatin1(); - if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { - qDebug() << Q_FUNC_INFO << "Requested:" << request << "Sending:" << payload; - } - } else { // failed state or file is unpatched - if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { - qDebug() << Q_FUNC_INFO << "Requested:" << request << "is sent unaltered."; - } + } else { + // failed state or file is unpatched } clientConnection->write(payload); clientConnection->flush(); // clientConnection->waitForBytesWritten(); - // manage the cache after writing the data: - if (payload == request) { // didn't exist + // print debug and manage the cache after writing the data: + if (payload == request) { // file didn't exist + if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { + qDebug() << Q_FUNC_INFO << "Requested:" << request << "was sent unaltered."; + } QObject *dummy = new QObject(); // the cache will own it later m_hotcache.insert(request, dummy); // TODO: do we want a cost here? } else { + if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { + qDebug() << Q_FUNC_INFO << "Requested:" << request << "Sent:" << payload; + } if (m_hotcache.remove(request)) { qWarning() << Q_FUNC_INFO << "Hot cache: contained a patched file!"; } From 20925c1fa49f454542c6198f138f0f2aca72b964 Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 10 Dec 2024 11:52:30 +0100 Subject: [PATCH 08/39] Hotcache: set up the filter with some initial contents --- .../patchmanagerobject.cpp | 74 ++++++++++++++++++- .../patchmanager-daemon/patchmanagerobject.h | 1 + 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index d5ed498b..fe5d7927 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -147,7 +147,10 @@ static const QString SILICA_CODE = QStringLiteral("silica"); static const QString SETTINGS_CODE = QStringLiteral("settings"); static const QString KEYBOARD_CODE = QStringLiteral("keyboard"); -static const int HOTCACHE_MAXCOST = 5000; +static const int HOTCACHE_COST_MAX = 5000; +static const int HOTCACHE_COST_STRONG = 1; +static const int HOTCACHE_COST_WEAK = 3; +static const int HOTCACHE_COST = 2; /*! \class PatchManagerObject @@ -510,8 +513,6 @@ PatchManagerObject::PatchManagerObject(QObject *parent) : QObject(parent) , m_sbus(s_sessionBusConnection) { - // set up cache - m_hotcache.setMaxCost(HOTCACHE_MAXCOST); } PatchManagerObject::~PatchManagerObject() @@ -814,6 +815,9 @@ void PatchManagerObject::initialize() qWarning() << Q_FUNC_INFO << "Failed to find ld.so.preload!"; } + // prepare the hotcache + setupFilter(); + qDebug() << Q_FUNC_INFO << PM_APPLY; QFileInfo pa(PM_APPLY); if (pa.exists()) { @@ -1892,7 +1896,7 @@ void PatchManagerObject::startReadingLocalServer() qDebug() << Q_FUNC_INFO << "Requested:" << request << "was sent unaltered."; } QObject *dummy = new QObject(); // the cache will own it later - m_hotcache.insert(request, dummy); // TODO: do we want a cost here? + m_hotcache.insert(request, dummy, HOTCACHE_COST); // cost: see setupFilter, use middle ground here } else { if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { qDebug() << Q_FUNC_INFO << "Requested:" << request << "Sent:" << payload; @@ -2994,3 +2998,65 @@ QString PatchManagerObject::pathToMangledPath(const QString &path, const QString qDebug() << Q_FUNC_INFO << "Path after mangle" << newpath; return newpath; } + +/*! Set up the filter parameters and fill it with some initial contents. + * + * The current implementation of the filter is a QCache, whole Object contents are not actually used, only the keys are. + * Once a file path has been identified as non-existing, it is added to the cache. + * + * Checking for presence is done using QCache::object() (or + * QCache::operator[]), not QCache::contains() in order to have the cache + * notice "usage" of th cached object. + * + * \sa m_hotcache + */ +void PatchManagerObject::setupFilter() +{ + if (!m_hotcache.isEmpty()) return; + + static const char *etcList[] = { + "/etc/passwd", + "/etc/group", + "/etc/shadow", + "/etc/localtime", + "/etc/ld.so.preload", + "/etc/ld.so.cache", + "/usr/share/locale/locale.alias" + }; + + /* only use relatively stable sonames here. No symlinks! */ + static const char *libList[] = { + "/usr/lib64/libtls-padding.so", + "/usr/lib64/libpreloadpatchmanager.so", + "/lib64/libc.so.6", + "/lib64/libdl.so.2", + "/lib64/librt.so.1", + "/lib64/libpthread.so.0", + "/lib64/libgcc_s.so.1", + "/usr/lib64/libsystemd.so.0", + "/usr/lib64/libcap.so.2", + "/usr/lib64/libmount.so.1", + "/usr/lib64/libblkid.so.1", + "/usr/lib64/libgpg-error.so.0" + }; + + // set up cache + m_hotcache.setMaxCost(HOTCACHE_COST_MAX); + + // use a cost of 1 here so they have less chance to be evicted + foreach( const char* entry, etcList) { + if (QFileInfo::exists(entry)) + m_hotcache.insert(QString(entry), new QObject(), HOTCACHE_COST_STRONG); + } + } + // they may be wrong, so use a higher cost than default + foreach( const char* entry, libList) { + QString libentry(entry); + if (Q_PROCESSOR_WORDSIZE == 4) { // 32 bit + libentry.replace("lib64", "lib"); + } + if (QFileInfo::exists(libentry)) { + m_hotcache.insert(libentry, new QObject(), HOTCACHE_COST_WEAK); + } + } +} diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index 4bff5393..da84e0ec 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -270,6 +270,7 @@ private slots: QDBusConnection m_sbus; QCache m_hotcache; + void setupFilter(); }; #endif // PATCHMANAGEROBJECT_H From 4ba2081b9876f4675e18a330740656bf14cf6688 Mon Sep 17 00:00:00 2001 From: nephros Date: Thu, 5 Dec 2024 02:11:48 +0100 Subject: [PATCH 09/39] Hotcache: Add a Settings switch --- src/qml/SettingsPage.qml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/qml/SettingsPage.qml b/src/qml/SettingsPage.qml index 158b16ef..7eec3697 100644 --- a/src/qml/SettingsPage.qml +++ b/src/qml/SettingsPage.qml @@ -249,6 +249,18 @@ Page { text: PatchManager.mangleCandidates.join("\n") enabled: fixBitSwitch.checked } + + TextSwitch { + id: filterSwitch + text: qsTranslate("", "Use advanced file existence filtering") + description: qsTranslate("", "Cache file existence checks.") + + " " + qsTranslate("", "Depending on many factors like memory, type of device, and others, this may have a positive or detrimental effect on overall performance.") + + "\n" +qsTranslate("", "If unsure, say N.") + checked: PatchManager.enableFSFilter + onClicked: PatchManager.enableFSFilter = !PatchManager.enableFSFilter + automaticCheck: false + } + } } } From bb422cad222ac3282de0375ad8bdba8d6c2ba1c5 Mon Sep 17 00:00:00 2001 From: nephros Date: Thu, 5 Dec 2024 02:31:45 +0100 Subject: [PATCH 10/39] Hotcache: wire up settings switch --- src/qml/patchmanager.cpp | 16 ++++++++++++++++ src/qml/patchmanager.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/src/qml/patchmanager.cpp b/src/qml/patchmanager.cpp index f82c00a8..305de732 100644 --- a/src/qml/patchmanager.cpp +++ b/src/qml/patchmanager.cpp @@ -313,6 +313,22 @@ void PatchManager::setBitnessMangle(bool bitnessMangle) } } +/*! \property PatchManager::enableFSFilter +*/ +/*! \qmlproperty bool PatchManager::enableFSFilter +*/ +bool PatchManager::enableFSFilter() const +{ + return getSettingsSync(QStringLiteral("enableFSFilter"), false).toBool(); +} + +void PatchManager::setEnableFSFilter(bool enableFSFilter) +{ + if (putSettingsSync(QStringLiteral("enableFSFilter"), enableFSFilter)) { + emit enableFSFilterChanged(enableFSFilter); + } +} + PatchManagerModel *PatchManager::installedModel() { return m_installedModel; diff --git a/src/qml/patchmanager.h b/src/qml/patchmanager.h index 3527df74..0fed819d 100644 --- a/src/qml/patchmanager.h +++ b/src/qml/patchmanager.h @@ -86,6 +86,7 @@ class PatchManager: public QObject Q_PROPERTY(bool applyOnBoot READ applyOnBoot WRITE setApplyOnBoot NOTIFY applyOnBootChanged) Q_PROPERTY(bool notifyOnSuccess READ notifyOnSuccess WRITE setNotifyOnSuccess NOTIFY notifyOnSuccessChanged) Q_PROPERTY(bool bitnessMangle READ bitnessMangle WRITE setBitnessMangle NOTIFY bitnessMangleChanged) + Q_PROPERTY(bool enableFSFilter READ enableFSFilter WRITE setEnableFSFilter NOTIFY enableFSFilterChanged) Q_PROPERTY(QStringList mangleCandidates READ mangleCandidates NOTIFY mangleCandidatesChanged) Q_PROPERTY(PatchManagerModel *installedModel READ installedModel CONSTANT) Q_PROPERTY(QVariantMap updates READ getUpdates NOTIFY updatesChanged) @@ -113,6 +114,8 @@ class PatchManager: public QObject void setNotifyOnSuccess(bool notifyOnSuccess); bool bitnessMangle() const; void setBitnessMangle(bool bitnessMangle); + bool enableFSFilter() const; + void setEnableFSFilter (bool enableFSFilter); QStringList mangleCandidates() const; PatchManagerModel *installedModel(); QString trCategory(const QString &category) const; @@ -194,6 +197,7 @@ public slots: void applyOnBootChanged(bool applyOnBoot); void notifyOnSuccessChanged(bool notifyOnSuccess); void bitnessMangleChanged(bool bitnessMangle); + void enableFSFilterChanged(bool enableFSFilter); void mangleCandidatesChanged(const QStringList &mangleCandidates); void updatesChanged(); void toggleServicesChanged(bool toggleServices); From a1826a4090124476da2076467a152405d2c413c4 Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 10 Dec 2024 13:40:56 +0100 Subject: [PATCH 11/39] Hotcache: move into a class, rename to m_filter --- .../patchmanagerobject.cpp | 44 +++++++++++-------- .../patchmanager-daemon/patchmanagerobject.h | 33 +++++++++++++- 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index fe5d7927..5e7c37e9 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -1872,13 +1872,8 @@ void PatchManagerObject::startReadingLocalServer() const QString fakePath = QStringLiteral("%1%2").arg(s_patchmanagerCacheRoot, QString::fromLatin1(request)); payload = request; if ( - (!m_failed) // return unaltered for failed - /* Note: contains() is not enough, we want the cache to notice the access so the entry counts as "used". - * Also, it returns 0 in qt5.6, nullptr in qt5.15 - * See https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/qcache.h?h=5.6#n68 - * vs. https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/tools/qcache.h?h=5.15#n74 - */ - && (m_hotcache[request] == 0) // it is not in the list of unpatched files + (!m_failed) // return unaltered for failed + && (!m_filter.contains(request)) // it is not in the list of unpatched files && (Q_UNLIKELY(QFileInfo::exists(fakePath))) // file is patched ) { @@ -1896,12 +1891,12 @@ void PatchManagerObject::startReadingLocalServer() qDebug() << Q_FUNC_INFO << "Requested:" << request << "was sent unaltered."; } QObject *dummy = new QObject(); // the cache will own it later - m_hotcache.insert(request, dummy, HOTCACHE_COST); // cost: see setupFilter, use middle ground here + m_filter.insert(request, dummy, HOTCACHE_COST); // cost: see setupFilter, use middle ground here } else { if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { qDebug() << Q_FUNC_INFO << "Requested:" << request << "Sent:" << payload; } - if (m_hotcache.remove(request)) { + if (m_filter.remove(request)) { qWarning() << Q_FUNC_INFO << "Hot cache: contained a patched file!"; } } @@ -3001,19 +2996,32 @@ QString PatchManagerObject::pathToMangledPath(const QString &path, const QString /*! Set up the filter parameters and fill it with some initial contents. * - * The current implementation of the filter is a QCache, whole Object contents are not actually used, only the keys are. - * Once a file path has been identified as non-existing, it is added to the cache. + * \sa PatchManagerFilter::setup() +*/ +void PatchManagerObject::setupFilter() +{ + if (!getSettings(QStringLiteral("enableFSFilter"), false).toBool()) { + m_filter.setActive(false); + return; + } else { + m_filter.setup(); + m_filter.setActive(true); + } +} + +/*! + * The current implementation of the filter is a QCache, whole Object contents + * are not actually used, only the keys are. Once a file path has been + * identified as non-existing, it is added to the cache. * * Checking for presence is done using QCache::object() (or * QCache::operator[]), not QCache::contains() in order to have the cache * notice "usage" of th cached object. * - * \sa m_hotcache + * \sa m_filter */ -void PatchManagerObject::setupFilter() +void PatchManagerFilter::setup() { - if (!m_hotcache.isEmpty()) return; - static const char *etcList[] = { "/etc/passwd", "/etc/group", @@ -3041,12 +3049,12 @@ void PatchManagerObject::setupFilter() }; // set up cache - m_hotcache.setMaxCost(HOTCACHE_COST_MAX); + setMaxCost(HOTCACHE_COST_MAX); // use a cost of 1 here so they have less chance to be evicted foreach( const char* entry, etcList) { if (QFileInfo::exists(entry)) - m_hotcache.insert(QString(entry), new QObject(), HOTCACHE_COST_STRONG); + insert(QString(entry), new QObject(), HOTCACHE_COST_STRONG); } } // they may be wrong, so use a higher cost than default @@ -3056,7 +3064,7 @@ void PatchManagerObject::setupFilter() libentry.replace("lib64", "lib"); } if (QFileInfo::exists(libentry)) { - m_hotcache.insert(libentry, new QObject(), HOTCACHE_COST_WEAK); + insert(libentry, new QObject(), HOTCACHE_COST_WEAK); } } } diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index da84e0ec..a5b5d760 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -74,6 +74,37 @@ class QSettings; class QNetworkAccessManager; class PatchManagerAdaptor; class QLocalServer; + +template +class PatchManagerFilter : public QCache +{ + //Q_OBJECT + //Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) +public: + //PatchManagerFilter(quint maxCost = 100) : QCache(maxCost) + //~PatchManagerFilter(); + + void setup(); + // override QCache::contains() + bool contains(const Key &key) const + { + if (m_active) { + return false; + } else { + return (object(key) == 0); + }; + }; + + void setActive(bool active) { m_active = active; emit activeChanged(active); }; + bool active() const { return m_active; }; + +signals: + void activeChanged(bool); + +private: + bool m_active; +}; + class PatchManagerObject : public QObject, public QDBusContext { Q_OBJECT @@ -269,7 +300,7 @@ private slots: QTimer *m_sessionBusConnector = nullptr; QDBusConnection m_sbus; - QCache m_hotcache; + PatchManagerFilter m_filter; void setupFilter(); }; From 3fd441c735f20bdab14dc1bc88b014e646e5a656 Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 10 Dec 2024 14:09:56 +0100 Subject: [PATCH 12/39] Hotcache: Don't be a template class - Try a Q_OBJECT macro for a template class... - Don't be a template class - Become Object-based, add contructor - Implement a constructor --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 7 +++++++ src/bin/patchmanager-daemon/patchmanagerobject.h | 13 ++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 5e7c37e9..39094261 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -3020,6 +3020,13 @@ void PatchManagerObject::setupFilter() * * \sa m_filter */ + +PatchManagerFilter::PatchManagerFilter(QObject *parent, int maxCost ) + : QObject(parent) + , QCache(maxCost) +{ +} + void PatchManagerFilter::setup() { static const char *etcList[] = { diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index a5b5d760..63982f2b 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -75,18 +75,17 @@ class QNetworkAccessManager; class PatchManagerAdaptor; class QLocalServer; -template -class PatchManagerFilter : public QCache +class PatchManagerFilter : public QObject, public QCache { - //Q_OBJECT - //Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) + Q_OBJECT + Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) public: - //PatchManagerFilter(quint maxCost = 100) : QCache(maxCost) + PatchManagerFilter(QObject *parent = nullptr, int maxCost = 100); //~PatchManagerFilter(); void setup(); // override QCache::contains() - bool contains(const Key &key) const + bool contains(const QString &key) const { if (m_active) { return false; @@ -300,7 +299,7 @@ private slots: QTimer *m_sessionBusConnector = nullptr; QDBusConnection m_sbus; - PatchManagerFilter m_filter; + PatchManagerFilter m_filter; void setupFilter(); }; From 6884b817ef1b70ae021b9de100501ad54101ec38 Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 10 Dec 2024 15:40:01 +0100 Subject: [PATCH 13/39] Hotcache: Prepare for stats collecting --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 4 ++++ src/bin/patchmanager-daemon/patchmanagerobject.h | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 39094261..def69437 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -3075,3 +3075,7 @@ void PatchManagerFilter::setup() } } } + +QList> PatchManagerFilter::stats() const +{ +} diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index 63982f2b..522e2338 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -79,6 +79,8 @@ class PatchManagerFilter : public QObject, public QCache { Q_OBJECT Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) + Q_PROPERTY(unsigned int hits READ hits) + Q_PROPERTY(unsigned int misses READ misses) public: PatchManagerFilter(QObject *parent = nullptr, int maxCost = 100); //~PatchManagerFilter(); @@ -97,11 +99,20 @@ class PatchManagerFilter : public QObject, public QCache void setActive(bool active) { m_active = active; emit activeChanged(active); }; bool active() const { return m_active; }; + void hit() { m_hits++; }; + void miss() { m_misses++; }; + unsigned int hits() const { return m_hits; }; + unsigned int misses() const { return m_misses; }; + + QList> stats() const; + signals: void activeChanged(bool); private: bool m_active; + unsigned int m_hits = 0; + unsigned int m_misses = 0; }; class PatchManagerObject : public QObject, public QDBusContext From b0c54792b9073adfbf2af940d8a084372d9bb5f9 Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 10 Dec 2024 15:40:59 +0100 Subject: [PATCH 14/39] Hotcache: Static initializer lists --- .../patchmanagerobject.cpp | 35 +++++++++---------- .../patchmanager-daemon/patchmanagerobject.h | 3 ++ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index def69437..ffa836a2 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -3027,20 +3027,8 @@ PatchManagerFilter::PatchManagerFilter(QObject *parent, int maxCost ) { } -void PatchManagerFilter::setup() -{ - static const char *etcList[] = { - "/etc/passwd", - "/etc/group", - "/etc/shadow", - "/etc/localtime", - "/etc/ld.so.preload", - "/etc/ld.so.cache", - "/usr/share/locale/locale.alias" - }; - - /* only use relatively stable sonames here. No symlinks! */ - static const char *libList[] = { +/* only use relatively stable sonames here. No symlinks! */ +const PatchManagerFilter::libList = QStringList({ "/usr/lib64/libtls-padding.so", "/usr/lib64/libpreloadpatchmanager.so", "/lib64/libc.so.6", @@ -3053,19 +3041,30 @@ void PatchManagerFilter::setup() "/usr/lib64/libmount.so.1", "/usr/lib64/libblkid.so.1", "/usr/lib64/libgpg-error.so.0" - }; +}); +const PatchManagerFilter::etcList = QStringList({ + "/etc/passwd", + "/etc/group", + "/etc/shadow", + "/etc/localtime", + "/etc/ld.so.preload", + "/etc/ld.so.cache", + "/usr/share/locale/locale.alias" +}); +void PatchManagerFilter::setup() +{ // set up cache setMaxCost(HOTCACHE_COST_MAX); // use a cost of 1 here so they have less chance to be evicted - foreach( const char* entry, etcList) { + for(const QString &entry : etcList) { if (QFileInfo::exists(entry)) - insert(QString(entry), new QObject(), HOTCACHE_COST_STRONG); + insert(entry, new QObject(), HOTCACHE_COST_STRONG); } } // they may be wrong, so use a higher cost than default - foreach( const char* entry, libList) { + for( const QString &entry : libList) { QString libentry(entry); if (Q_PROCESSOR_WORDSIZE == 4) { // 32 bit libentry.replace("lib64", "lib"); diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index 522e2338..ce15c91a 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -113,6 +113,9 @@ class PatchManagerFilter : public QObject, public QCache bool m_active; unsigned int m_hits = 0; unsigned int m_misses = 0; + + static const QStringList etcList; + static const QStringList libList; }; class PatchManagerObject : public QObject, public QDBusContext From bdedbeb6c1e063b286c393ef9b0dc6dee57dbfc8 Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 10 Dec 2024 16:01:14 +0100 Subject: [PATCH 15/39] Hotcache: Implement a simpler stats method --- .../patchmanagerobject.cpp | 22 +++++++++++++++++-- .../patchmanager-daemon/patchmanagerobject.h | 3 ++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index ffa836a2..56c0430c 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -3075,6 +3075,24 @@ void PatchManagerFilter::setup() } } -QList> PatchManagerFilter::stats() const -{ +//QList> PatchManagerFilter::stats() const +QString PatchManagerFilter::stats() const +{ + QStringList topTen; + const int ttmax = qEnvironmentVariableIsSet("PM_DEBUG_HOTCACHE") ? size() : 10; + foreach(const QString &key, keys() ) { + topTen << key; + if (topTen.size() >= ttmax) + break; + } + + //QList> list; + QTextStream list; + list << "Filter Stats:" + << "\n===========================" + << "\n Hotcache entries:: .............." << size() + << "\n Hotcache cost: .................." << totalCost() << "/" << maxCost() + << "\n Hotcache top entries: ..........." << "\n " << topTen.join("\n ") + << "\n==========================="; + return list.readAll(); } diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index ce15c91a..5ef4682e 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -104,7 +104,8 @@ class PatchManagerFilter : public QObject, public QCache unsigned int hits() const { return m_hits; }; unsigned int misses() const { return m_misses; }; - QList> stats() const; + //QList> stats() const; + QString stats() const; signals: void activeChanged(bool); From 969a7637da29e2fed6fe9c549798df1149fa06e1 Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 10 Dec 2024 16:34:17 +0100 Subject: [PATCH 16/39] Hotcache: Make the lists public --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 4 ++-- src/bin/patchmanager-daemon/patchmanagerobject.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 56c0430c..d25d38aa 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -3028,7 +3028,7 @@ PatchManagerFilter::PatchManagerFilter(QObject *parent, int maxCost ) } /* only use relatively stable sonames here. No symlinks! */ -const PatchManagerFilter::libList = QStringList({ +const QStringList PatchManagerFilter::libList = QStringList({ "/usr/lib64/libtls-padding.so", "/usr/lib64/libpreloadpatchmanager.so", "/lib64/libc.so.6", @@ -3042,7 +3042,7 @@ const PatchManagerFilter::libList = QStringList({ "/usr/lib64/libblkid.so.1", "/usr/lib64/libgpg-error.so.0" }); -const PatchManagerFilter::etcList = QStringList({ +const QStringList PatchManagerFilter::etcList = QStringList({ "/etc/passwd", "/etc/group", "/etc/shadow", diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index 5ef4682e..f6f63571 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -107,6 +107,9 @@ class PatchManagerFilter : public QObject, public QCache //QList> stats() const; QString stats() const; + static const QStringList etcList; + static const QStringList libList; + signals: void activeChanged(bool); @@ -115,8 +118,6 @@ class PatchManagerFilter : public QObject, public QCache unsigned int m_hits = 0; unsigned int m_misses = 0; - static const QStringList etcList; - static const QStringList libList; }; class PatchManagerObject : public QObject, public QDBusContext From 9cb13214624fc2673f6f3566c27df09e0fd1d880 Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 10 Dec 2024 16:45:30 +0100 Subject: [PATCH 17/39] Hotcache: Use foreach again. --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index d25d38aa..8dfd4c12 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -3058,13 +3058,13 @@ void PatchManagerFilter::setup() setMaxCost(HOTCACHE_COST_MAX); // use a cost of 1 here so they have less chance to be evicted - for(const QString &entry : etcList) { + foreach(const QString &entry, etcList) { if (QFileInfo::exists(entry)) insert(entry, new QObject(), HOTCACHE_COST_STRONG); } } // they may be wrong, so use a higher cost than default - for( const QString &entry : libList) { + foreach(const QString &entry, libList) { QString libentry(entry); if (Q_PROCESSOR_WORDSIZE == 4) { // 32 bit libentry.replace("lib64", "lib"); From 82c3901a3f585a00cab5d10f12f824ab6accf5cd Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 10 Dec 2024 16:48:16 +0100 Subject: [PATCH 18/39] Hotcache: Missing braces --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 8dfd4c12..be7396b9 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -3059,7 +3059,7 @@ void PatchManagerFilter::setup() // use a cost of 1 here so they have less chance to be evicted foreach(const QString &entry, etcList) { - if (QFileInfo::exists(entry)) + if (QFileInfo::exists(entry)) { insert(entry, new QObject(), HOTCACHE_COST_STRONG); } } From b33ecff6b0bb17f5bb99b91a6b19c7a4827f5d5b Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 10 Dec 2024 17:08:17 +0100 Subject: [PATCH 19/39] Hotcache: check for active filter in startReadingLocalServer --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 3 ++- src/bin/patchmanager-daemon/patchmanagerobject.h | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index be7396b9..1abd3d27 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -1873,7 +1873,7 @@ void PatchManagerObject::startReadingLocalServer() payload = request; if ( (!m_failed) // return unaltered for failed - && (!m_filter.contains(request)) // it is not in the list of unpatched files + && (!m_filter.active() || !m_filter.contains(request)) // filter inactive or not in the list of unpatched files && (Q_UNLIKELY(QFileInfo::exists(fakePath))) // file is patched ) { @@ -3027,6 +3027,7 @@ PatchManagerFilter::PatchManagerFilter(QObject *parent, int maxCost ) { } +/* initialize the static members */ /* only use relatively stable sonames here. No symlinks! */ const QStringList PatchManagerFilter::libList = QStringList({ "/usr/lib64/libtls-padding.so", diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index f6f63571..5599abf2 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -117,7 +117,6 @@ class PatchManagerFilter : public QObject, public QCache bool m_active; unsigned int m_hits = 0; unsigned int m_misses = 0; - }; class PatchManagerObject : public QObject, public QDBusContext From b65f653b4814811cd8991edf5bb1adc4d4e3da16 Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 10 Dec 2024 18:46:55 +0100 Subject: [PATCH 20/39] Hotcache: Use plain qstring for stats --- .../patchmanager-daemon/patchmanagerobject.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 1abd3d27..1607aef2 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -3088,12 +3088,12 @@ QString PatchManagerFilter::stats() const } //QList> list; - QTextStream list; - list << "Filter Stats:" - << "\n===========================" - << "\n Hotcache entries:: .............." << size() - << "\n Hotcache cost: .................." << totalCost() << "/" << maxCost() - << "\n Hotcache top entries: ..........." << "\n " << topTen.join("\n ") - << "\n==========================="; - return list.readAll(); + QString list; + list + "Filter Stats:" + + "\n===========================" + + "\n Hotcache entries:: .............." + size() + + "\n Hotcache cost: .................." + totalCost() + "/" + maxCost() + + "\n Hotcache top entries: ..........." + "\n " + topTen.join("\n ") + + "\n==========================="; + return list; } From 8a3787d6544758c01cb6966097dc2bd0878344a2 Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 10 Dec 2024 18:49:32 +0100 Subject: [PATCH 21/39] Hotcache: Add some debug prints --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 1607aef2..a8cabe71 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -3055,6 +3055,7 @@ const QStringList PatchManagerFilter::etcList = QStringList({ void PatchManagerFilter::setup() { + qDebug() << Q_FUNC_INFO; // set up cache setMaxCost(HOTCACHE_COST_MAX); @@ -3079,6 +3080,7 @@ void PatchManagerFilter::setup() //QList> PatchManagerFilter::stats() const QString PatchManagerFilter::stats() const { + qDebug() << Q_FUNC_INFO; QStringList topTen; const int ttmax = qEnvironmentVariableIsSet("PM_DEBUG_HOTCACHE") ? size() : 10; foreach(const QString &key, keys() ) { From 7df9ddb5bea2eb44a4309457265452ae65c8bf1f Mon Sep 17 00:00:00 2001 From: nephros Date: Mon, 31 Mar 2025 11:30:28 +0200 Subject: [PATCH 22/39] Hotcache: Don't copy around strings, us a bool. --- .../patchmanagerobject.cpp | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index a8cabe71..94f1eed2 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -148,9 +148,9 @@ static const QString SETTINGS_CODE = QStringLiteral("settings"); static const QString KEYBOARD_CODE = QStringLiteral("keyboard"); static const int HOTCACHE_COST_MAX = 5000; -static const int HOTCACHE_COST_STRONG = 1; -static const int HOTCACHE_COST_WEAK = 3; -static const int HOTCACHE_COST = 2; +static const int HOTCACHE_COST_STRONG = 1; +static const int HOTCACHE_COST_DEFAULT = 2; +static const int HOTCACHE_COST_WEAK = 3; /*! \class PatchManagerObject @@ -1868,33 +1868,44 @@ void PatchManagerObject::startReadingLocalServer() return; } const QByteArray request = clientConnection->readAll(); - QByteArray payload; const QString fakePath = QStringLiteral("%1%2").arg(s_patchmanagerCacheRoot, QString::fromLatin1(request)); - payload = request; + bool passAsIs = true; if ( (!m_failed) // return unaltered for failed && (!m_filter.active() || !m_filter.contains(request)) // filter inactive or not in the list of unpatched files && (Q_UNLIKELY(QFileInfo::exists(fakePath))) // file is patched ) { - payload = fakePath.toLatin1(); + passAsIs = false; } else { // failed state or file is unpatched + passAsIs = true; + } + /* write the result back to the library as soon as possible */ + if (passAsIs) { + clientConnection->write(request); + } else { + clientConnection->write(fakePath.toLatin1()); } - clientConnection->write(payload); clientConnection->flush(); // clientConnection->waitForBytesWritten(); - // print debug and manage the cache after writing the data: - if (payload == request) { // file didn't exist + /* print debug and manage the cache after writing the data: + * if the file didn't exist, we add it to the cache. + * otherwise, we so nothing, but check that it wasn't wrongly in the + * cache, which shouldn't happen. + * Note that we don't actually store anything in the cache, we're only + * interested in the key and the cost management. + */ + if (passAsIs) { // file didn't exist if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { qDebug() << Q_FUNC_INFO << "Requested:" << request << "was sent unaltered."; } QObject *dummy = new QObject(); // the cache will own it later - m_filter.insert(request, dummy, HOTCACHE_COST); // cost: see setupFilter, use middle ground here + m_filter.insert(request, dummy, HOTCACHE_COST_DEFAULT); // cost: see setupFilter, use middle ground here } else { if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { - qDebug() << Q_FUNC_INFO << "Requested:" << request << "Sent:" << payload; + qDebug() << Q_FUNC_INFO << "Requested:" << request << "Sent:" << fakePath; } if (m_filter.remove(request)) { qWarning() << Q_FUNC_INFO << "Hot cache: contained a patched file!"; From 475ac37ec97a8b7aff8109a47aca9da6bccf7ad2 Mon Sep 17 00:00:00 2001 From: nephros Date: Mon, 31 Mar 2025 12:52:26 +0200 Subject: [PATCH 23/39] Print hotcache stats on PM exit --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 94f1eed2..4ac6e3d2 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -522,6 +522,9 @@ PatchManagerObject::~PatchManagerObject() connection.unregisterService(DBUS_SERVICE_NAME); connection.unregisterObject(DBUS_PATH_NAME); } + if (m_filter.active()) { + qDebug() << m_filter.stats(); + } } void PatchManagerObject::registerDBus() @@ -3027,7 +3030,7 @@ void PatchManagerObject::setupFilter() * * Checking for presence is done using QCache::object() (or * QCache::operator[]), not QCache::contains() in order to have the cache - * notice "usage" of th cached object. + * notice "usage" of the cached object. * * \sa m_filter */ @@ -3038,7 +3041,7 @@ PatchManagerFilter::PatchManagerFilter(QObject *parent, int maxCost ) { } -/* initialize the static members */ +/* initialize the "static members", i.e. a list of very frequesntly accessed files. */ /* only use relatively stable sonames here. No symlinks! */ const QStringList PatchManagerFilter::libList = QStringList({ "/usr/lib64/libtls-padding.so", From 5f9e2c960a62249ac5d9cb83af824b71866098a6 Mon Sep 17 00:00:00 2001 From: nephros Date: Mon, 31 Mar 2025 13:14:29 +0200 Subject: [PATCH 24/39] Resolve symlinks before adding to primed cache --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 4ac6e3d2..da307ce0 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -3042,15 +3042,17 @@ PatchManagerFilter::PatchManagerFilter(QObject *parent, int maxCost ) } /* initialize the "static members", i.e. a list of very frequesntly accessed files. */ -/* only use relatively stable sonames here. No symlinks! */ +/* only use relatively stable sonames here. */ const QStringList PatchManagerFilter::libList = QStringList({ - "/usr/lib64/libtls-padding.so", "/usr/lib64/libpreloadpatchmanager.so", + "/lib/ld-linux-aarch64.so.1", + "/lib/ld-linux-armhf.so.3", "/lib64/libc.so.6", "/lib64/libdl.so.2", "/lib64/librt.so.1", "/lib64/libpthread.so.0", "/lib64/libgcc_s.so.1", + "/usr/lib64/libtls-padding.so", "/usr/lib64/libsystemd.so.0", "/usr/lib64/libcap.so.2", "/usr/lib64/libmount.so.1", @@ -3085,8 +3087,10 @@ void PatchManagerFilter::setup() if (Q_PROCESSOR_WORDSIZE == 4) { // 32 bit libentry.replace("lib64", "lib"); } + if (QFileInfo::exists(libentry)) { - insert(libentry, new QObject(), HOTCACHE_COST_WEAK); + QFileInfo fi(libentry); + insert(fi.canonicalFilePath(), new QObject(), HOTCACHE_COST_WEAK); } } } From 1a6e64f34d51e92fc015a26658f508ccd60a011c Mon Sep 17 00:00:00 2001 From: nephros Date: Sun, 2 Nov 2025 00:34:20 +0100 Subject: [PATCH 25/39] Fix cache returning false the false way. --- src/bin/patchmanager-daemon/patchmanagerobject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index 5599abf2..d0d83870 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -89,7 +89,7 @@ class PatchManagerFilter : public QObject, public QCache // override QCache::contains() bool contains(const QString &key) const { - if (m_active) { + if (!m_active) { return false; } else { return (object(key) == 0); From 18a3c4445e2dc7517339e14a75c34a37f2e13b64 Mon Sep 17 00:00:00 2001 From: "Peter G." Date: Sat, 1 Nov 2025 23:38:33 +0000 Subject: [PATCH 26/39] Update src/bin/patchmanager-daemon/patchmanagerobject.cpp Co-authored-by: Vlad G. --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index da307ce0..e8a7158b 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -1904,7 +1904,7 @@ void PatchManagerObject::startReadingLocalServer() if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { qDebug() << Q_FUNC_INFO << "Requested:" << request << "was sent unaltered."; } - QObject *dummy = new QObject(); // the cache will own it later + QObject *dummy = new QObject(); // the cache will own it the next line m_filter.insert(request, dummy, HOTCACHE_COST_DEFAULT); // cost: see setupFilter, use middle ground here } else { if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { From 64eb096f9fb82b3983c3ee071667403b37a905c5 Mon Sep 17 00:00:00 2001 From: nephros Date: Sun, 2 Nov 2025 00:43:21 +0100 Subject: [PATCH 27/39] Promote stat output to info level --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index e8a7158b..5d0578d0 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -523,7 +523,7 @@ PatchManagerObject::~PatchManagerObject() connection.unregisterObject(DBUS_PATH_NAME); } if (m_filter.active()) { - qDebug() << m_filter.stats(); + qInfo() << m_filter.stats(); } } From ec2aae2da96432153638b558ed26a3eaa296923f Mon Sep 17 00:00:00 2001 From: nephros Date: Sun, 2 Nov 2025 01:13:19 +0100 Subject: [PATCH 28/39] Split out Filter into .h --- .../patchmanager-daemon.pro | 1 + .../patchmanager-daemon/patchmanagerfilter.h | 85 +++++++++++++++++++ .../patchmanager-daemon/patchmanagerobject.h | 46 +--------- 3 files changed, 87 insertions(+), 45 deletions(-) create mode 100644 src/bin/patchmanager-daemon/patchmanagerfilter.h diff --git a/src/bin/patchmanager-daemon/patchmanager-daemon.pro b/src/bin/patchmanager-daemon/patchmanager-daemon.pro index c1eff9a4..730e88d7 100644 --- a/src/bin/patchmanager-daemon/patchmanager-daemon.pro +++ b/src/bin/patchmanager-daemon/patchmanager-daemon.pro @@ -26,6 +26,7 @@ DEFINES += BUILD_VERSION=\\\"$$BUILD_VERSION\\\" HEADERS += \ patchmanagerobject.h \ patchmanager_include.h \ + patchmanagerfilter.h inotifywatcher.h \ journal.h diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.h b/src/bin/patchmanager-daemon/patchmanagerfilter.h new file mode 100644 index 00000000..0dc2ae28 --- /dev/null +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2025 Patchmanager for SailfishOS contributors: + * - olf "Olf0" + * - Peter G. "nephros" + * - Vlad G. "b100dian" + * + * You may use this file under the terms of the BSD license as follows: + * + * "Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + */ + +#ifndef PATCHMANAGERFILTER_H +#define PATCHMANAGERFILTER_H + +#include +#include + +class PatchManagerFilter : public QObject, public QCache +{ + Q_OBJECT + Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) + Q_PROPERTY(unsigned int hits READ hits) + Q_PROPERTY(unsigned int misses READ misses) +public: + PatchManagerFilter(QObject *parent = nullptr, int maxCost = 100); + //~PatchManagerFilter(); + + void setup(); + // override QCache::contains() + bool contains(const QString &key) const + { + if (!m_active) { + return false; + } else { + return (object(key) == 0); + }; + }; + + void setActive(bool active) { m_active = active; emit activeChanged(active); }; + bool active() const { return m_active; }; + + void hit() { m_hits++; }; + void miss() { m_misses++; }; + unsigned int hits() const { return m_hits; }; + unsigned int misses() const { return m_misses; }; + + //QList> stats() const; + QString stats() const; + + static const QStringList etcList; + static const QStringList libList; + +signals: + void activeChanged(bool); + +private: + bool m_active; + unsigned int m_hits = 0; + unsigned int m_misses = 0; +}; + +#endif // PATCHMANAGERFILTER_H diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index d0d83870..55e6e14f 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -48,7 +48,6 @@ #include #include #include -#include #include @@ -74,50 +73,7 @@ class QSettings; class QNetworkAccessManager; class PatchManagerAdaptor; class QLocalServer; - -class PatchManagerFilter : public QObject, public QCache -{ - Q_OBJECT - Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) - Q_PROPERTY(unsigned int hits READ hits) - Q_PROPERTY(unsigned int misses READ misses) -public: - PatchManagerFilter(QObject *parent = nullptr, int maxCost = 100); - //~PatchManagerFilter(); - - void setup(); - // override QCache::contains() - bool contains(const QString &key) const - { - if (!m_active) { - return false; - } else { - return (object(key) == 0); - }; - }; - - void setActive(bool active) { m_active = active; emit activeChanged(active); }; - bool active() const { return m_active; }; - - void hit() { m_hits++; }; - void miss() { m_misses++; }; - unsigned int hits() const { return m_hits; }; - unsigned int misses() const { return m_misses; }; - - //QList> stats() const; - QString stats() const; - - static const QStringList etcList; - static const QStringList libList; - -signals: - void activeChanged(bool); - -private: - bool m_active; - unsigned int m_hits = 0; - unsigned int m_misses = 0; -}; +class PatchManagerFilter; class PatchManagerObject : public QObject, public QDBusContext { From 8b70747c3a688539b67fd3fabda747ee1f4f52cc Mon Sep 17 00:00:00 2001 From: nephros Date: Sun, 2 Nov 2025 01:28:34 +0100 Subject: [PATCH 29/39] Split out Filter into .cpp --- .../patchmanager-daemon.pro | 1 + .../patchmanagerfilter.cpp | 137 ++++++++++++++++++ .../patchmanagerobject.cpp | 95 +----------- 3 files changed, 139 insertions(+), 94 deletions(-) create mode 100644 src/bin/patchmanager-daemon/patchmanagerfilter.cpp diff --git a/src/bin/patchmanager-daemon/patchmanager-daemon.pro b/src/bin/patchmanager-daemon/patchmanager-daemon.pro index 730e88d7..3011998d 100644 --- a/src/bin/patchmanager-daemon/patchmanager-daemon.pro +++ b/src/bin/patchmanager-daemon/patchmanager-daemon.pro @@ -33,6 +33,7 @@ HEADERS += \ SOURCES += \ main.cpp \ patchmanagerobject.cpp \ + patchmanagerfilter.cpp \ inotifywatcher.cpp \ journal.cpp diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.cpp b/src/bin/patchmanager-daemon/patchmanagerfilter.cpp new file mode 100644 index 00000000..c2e9c89b --- /dev/null +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2025 Patchmanager for SailfishOS contributors: + * - olf "Olf0" + * - Peter G. "nephros" + * - Vlad G. "b100dian" + * + * You may use this file under the terms of the BSD license as follows: + * + * "Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + */ + + +/*! + * The current implementation of the filter is a QCache, whole Object contents + * are not actually used, only the keys are. Once a file path has been + * identified as non-existing, it is added to the cache. + * + * Checking for presence is done using QCache::object() (or + * QCache::operator[]), not QCache::contains() in order to have the cache + * notice "usage" of the cached object. + * + * \sa m_filter + */ + +#include "patchmanagerfilter.h" + +#include +#include +#include +#include +#include + +PatchManagerFilter::PatchManagerFilter(QObject *parent, int maxCost ) + : QObject(parent) + , QCache(maxCost) +{ +} + +/* initialize the "static members", i.e. a list of very frequesntly accessed files. */ +/* only use relatively stable sonames here. */ +const QStringList PatchManagerFilter::libList = QStringList({ + "/usr/lib64/libpreloadpatchmanager.so", + "/lib/ld-linux-aarch64.so.1", + "/lib/ld-linux-armhf.so.3", + "/lib64/libc.so.6", + "/lib64/libdl.so.2", + "/lib64/librt.so.1", + "/lib64/libpthread.so.0", + "/lib64/libgcc_s.so.1", + "/usr/lib64/libtls-padding.so", + "/usr/lib64/libsystemd.so.0", + "/usr/lib64/libcap.so.2", + "/usr/lib64/libmount.so.1", + "/usr/lib64/libblkid.so.1", + "/usr/lib64/libgpg-error.so.0" +}); +const QStringList PatchManagerFilter::etcList = QStringList({ + "/etc/passwd", + "/etc/group", + "/etc/shadow", + "/etc/localtime", + "/etc/ld.so.preload", + "/etc/ld.so.cache", + "/usr/share/locale/locale.alias" +}); + +void PatchManagerFilter::setup() +{ + qDebug() << Q_FUNC_INFO; + // set up cache + setMaxCost(HOTCACHE_COST_MAX); + + // use a cost of 1 here so they have less chance to be evicted + foreach(const QString &entry, etcList) { + if (QFileInfo::exists(entry)) { + insert(entry, new QObject(), HOTCACHE_COST_STRONG); + } + } + // they may be wrong, so use a higher cost than default + foreach(const QString &entry, libList) { + QString libentry(entry); + if (Q_PROCESSOR_WORDSIZE == 4) { // 32 bit + libentry.replace("lib64", "lib"); + } + + if (QFileInfo::exists(libentry)) { + QFileInfo fi(libentry); + insert(fi.canonicalFilePath(), new QObject(), HOTCACHE_COST_WEAK); + } + } +} + +//QList> PatchManagerFilter::stats() const +QString PatchManagerFilter::stats() const +{ + qDebug() << Q_FUNC_INFO; + QStringList topTen; + const int ttmax = qEnvironmentVariableIsSet("PM_DEBUG_HOTCACHE") ? size() : 10; + foreach(const QString &key, keys() ) { + topTen << key; + if (topTen.size() >= ttmax) + break; + } + + // % instead of + for QStringBuilder + QString list; + list % "Filter Stats:" + % "\n===========================" + % "\n Hotcache entries:: .............." % size() + % "\n Hotcache cost: .................." % totalCost() + "/" + maxCost() + % "\n Hotcache top entries: ..........." % "\n " + topTen.join("\n ") + % "\n==========================="; + return list; +} diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 5d0578d0..9cf45800 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -37,6 +37,7 @@ #include "patchmanagerobject.h" #include "patchmanager_adaptor.h" +#include "patchmanagerfilter.h" #include #include @@ -3023,97 +3024,3 @@ void PatchManagerObject::setupFilter() } } -/*! - * The current implementation of the filter is a QCache, whole Object contents - * are not actually used, only the keys are. Once a file path has been - * identified as non-existing, it is added to the cache. - * - * Checking for presence is done using QCache::object() (or - * QCache::operator[]), not QCache::contains() in order to have the cache - * notice "usage" of the cached object. - * - * \sa m_filter - */ - -PatchManagerFilter::PatchManagerFilter(QObject *parent, int maxCost ) - : QObject(parent) - , QCache(maxCost) -{ -} - -/* initialize the "static members", i.e. a list of very frequesntly accessed files. */ -/* only use relatively stable sonames here. */ -const QStringList PatchManagerFilter::libList = QStringList({ - "/usr/lib64/libpreloadpatchmanager.so", - "/lib/ld-linux-aarch64.so.1", - "/lib/ld-linux-armhf.so.3", - "/lib64/libc.so.6", - "/lib64/libdl.so.2", - "/lib64/librt.so.1", - "/lib64/libpthread.so.0", - "/lib64/libgcc_s.so.1", - "/usr/lib64/libtls-padding.so", - "/usr/lib64/libsystemd.so.0", - "/usr/lib64/libcap.so.2", - "/usr/lib64/libmount.so.1", - "/usr/lib64/libblkid.so.1", - "/usr/lib64/libgpg-error.so.0" -}); -const QStringList PatchManagerFilter::etcList = QStringList({ - "/etc/passwd", - "/etc/group", - "/etc/shadow", - "/etc/localtime", - "/etc/ld.so.preload", - "/etc/ld.so.cache", - "/usr/share/locale/locale.alias" -}); - -void PatchManagerFilter::setup() -{ - qDebug() << Q_FUNC_INFO; - // set up cache - setMaxCost(HOTCACHE_COST_MAX); - - // use a cost of 1 here so they have less chance to be evicted - foreach(const QString &entry, etcList) { - if (QFileInfo::exists(entry)) { - insert(entry, new QObject(), HOTCACHE_COST_STRONG); - } - } - // they may be wrong, so use a higher cost than default - foreach(const QString &entry, libList) { - QString libentry(entry); - if (Q_PROCESSOR_WORDSIZE == 4) { // 32 bit - libentry.replace("lib64", "lib"); - } - - if (QFileInfo::exists(libentry)) { - QFileInfo fi(libentry); - insert(fi.canonicalFilePath(), new QObject(), HOTCACHE_COST_WEAK); - } - } -} - -//QList> PatchManagerFilter::stats() const -QString PatchManagerFilter::stats() const -{ - qDebug() << Q_FUNC_INFO; - QStringList topTen; - const int ttmax = qEnvironmentVariableIsSet("PM_DEBUG_HOTCACHE") ? size() : 10; - foreach(const QString &key, keys() ) { - topTen << key; - if (topTen.size() >= ttmax) - break; - } - - //QList> list; - QString list; - list + "Filter Stats:" - + "\n===========================" - + "\n Hotcache entries:: .............." + size() - + "\n Hotcache cost: .................." + totalCost() + "/" + maxCost() - + "\n Hotcache top entries: ..........." + "\n " + topTen.join("\n ") - + "\n==========================="; - return list; -} From 29cd51e9bd8999834ec4f46c8509e182f2d66219 Mon Sep 17 00:00:00 2001 From: nephros Date: Sun, 2 Nov 2025 01:30:07 +0100 Subject: [PATCH 30/39] fixup! Split out Filter into .h --- src/bin/patchmanager-daemon/patchmanager-daemon.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/patchmanager-daemon/patchmanager-daemon.pro b/src/bin/patchmanager-daemon/patchmanager-daemon.pro index 3011998d..41145493 100644 --- a/src/bin/patchmanager-daemon/patchmanager-daemon.pro +++ b/src/bin/patchmanager-daemon/patchmanager-daemon.pro @@ -26,7 +26,7 @@ DEFINES += BUILD_VERSION=\\\"$$BUILD_VERSION\\\" HEADERS += \ patchmanagerobject.h \ patchmanager_include.h \ - patchmanagerfilter.h + patchmanagerfilter.h \ inotifywatcher.h \ journal.h From b995f3039db35f1412c68079f1bab645c8e2d7da Mon Sep 17 00:00:00 2001 From: nephros Date: Mon, 3 Nov 2025 10:36:29 +0100 Subject: [PATCH 31/39] Rework PM Filter class sources --- .../patchmanagerfilter.cpp | 93 ++++++++++++------- .../patchmanager-daemon/patchmanagerfilter.h | 34 +++---- .../patchmanagerobject.cpp | 5 - .../patchmanager-daemon/patchmanagerobject.h | 3 +- 4 files changed, 78 insertions(+), 57 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.cpp b/src/bin/patchmanager-daemon/patchmanagerfilter.cpp index c2e9c89b..a22880ab 100644 --- a/src/bin/patchmanager-daemon/patchmanagerfilter.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.cpp @@ -48,36 +48,30 @@ #include "patchmanagerfilter.h" #include -#include #include #include #include -PatchManagerFilter::PatchManagerFilter(QObject *parent, int maxCost ) - : QObject(parent) - , QCache(maxCost) -{ -} - /* initialize the "static members", i.e. a list of very frequesntly accessed files. */ /* only use relatively stable sonames here. */ -const QStringList PatchManagerFilter::libList = QStringList({ - "/usr/lib64/libpreloadpatchmanager.so", - "/lib/ld-linux-aarch64.so.1", - "/lib/ld-linux-armhf.so.3", - "/lib64/libc.so.6", - "/lib64/libdl.so.2", - "/lib64/librt.so.1", - "/lib64/libpthread.so.0", - "/lib64/libgcc_s.so.1", - "/usr/lib64/libtls-padding.so", - "/usr/lib64/libsystemd.so.0", - "/usr/lib64/libcap.so.2", - "/usr/lib64/libmount.so.1", - "/usr/lib64/libblkid.so.1", - "/usr/lib64/libgpg-error.so.0" +const QStringList libList = QStringList({ + "/usr/lib64/libpreloadpatchmanager.so", + "/lib/ld-linux-aarch64.so.1", + "/lib/ld-linux-armhf.so.3", + "/lib64/libc.so.6", + "/lib64/libdl.so.2", + "/lib64/librt.so.1", + "/lib64/libpthread.so.0", + "/lib64/libgcc_s.so.1", + "/usr/lib64/libtls-padding.so", + "/usr/lib64/libsystemd.so.0", + "/usr/lib64/libcap.so.2", + "/usr/lib64/libmount.so.1", + "/usr/lib64/libblkid.so.1", + "/usr/lib64/libgpg-error.so.0" }); -const QStringList PatchManagerFilter::etcList = QStringList({ + +const QStringList etcList = QStringList({ "/etc/passwd", "/etc/group", "/etc/shadow", @@ -87,6 +81,12 @@ const QStringList PatchManagerFilter::etcList = QStringList({ "/usr/share/locale/locale.alias" }); +PatchManagerFilter::PatchManagerFilter(QObject *parent, int maxCost) + : QObject(parent) + , QCache(maxCost) +{ +} + void PatchManagerFilter::setup() { qDebug() << Q_FUNC_INFO; @@ -113,25 +113,50 @@ void PatchManagerFilter::setup() } } -//QList> PatchManagerFilter::stats() const +// override QCache::contains() +bool PatchManagerFilter::contains(const QString &key) const +{ + if (!m_active) + return false; + + // we do not use QCache::contains here, because ::object() will make the cache notice usage of the object + bool ret = (QCache::object(key) != 0); // NB: returns 0 in Qt < 5.13, nullptr in later versions + + if(ret) { m_hits+=1; } else { m_misses+=1; } + + return ret; +}; + + QString PatchManagerFilter::stats() const { qDebug() << Q_FUNC_INFO; QStringList topTen; - const int ttmax = qEnvironmentVariableIsSet("PM_DEBUG_HOTCACHE") ? size() : 10; + int ttmax = qEnvironmentVariableIsSet("PM_DEBUG_HOTCACHE") ? size() : 10; foreach(const QString &key, keys() ) { topTen << key; if (topTen.size() >= ttmax) break; } - // % instead of + for QStringBuilder - QString list; - list % "Filter Stats:" - % "\n===========================" - % "\n Hotcache entries:: .............." % size() - % "\n Hotcache cost: .................." % totalCost() + "/" + maxCost() - % "\n Hotcache top entries: ..........." % "\n " + topTen.join("\n ") - % "\n==========================="; - return list; + QStringList stats; + stats << QStringLiteral("Filter Stats:") + << QStringLiteral("===========================") + << QStringLiteral(" Hotcache entries:: ..............%1").arg(size()) + << QStringLiteral(" Hotcache cost: ..................%1/%2").arg(totalCost()).arg(maxCost()); + if (qEnvironmentVariableIsSet("PM_DEBUG_HOTCACHE")) { + unsigned int sum = hits()+misses(); + if (sum > 0) { + QString ratio; + float ratf = (hits() / sum); + ratio.setNum( ratf, 'f', 2); + stats << QStringLiteral(" Hotcache hit/miss: ..............%1/%2 (%3%%)").arg(hits()).arg(misses()).arg(ratio); + } + } + stats << QStringLiteral("===========================") + << QStringLiteral(" Hotcache top entries: ...........") + << topTen + << QStringLiteral("==========================="); + + return stats.join("\n"); } diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.h b/src/bin/patchmanager-daemon/patchmanagerfilter.h index 0dc2ae28..cc1a878e 100644 --- a/src/bin/patchmanager-daemon/patchmanagerfilter.h +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.h @@ -38,6 +38,11 @@ #include #include +static const int HOTCACHE_COST_MAX = 5000; +static const int HOTCACHE_COST_STRONG = 1; +static const int HOTCACHE_COST_DEFAULT = 2; +static const int HOTCACHE_COST_WEAK = 3; + class PatchManagerFilter : public QObject, public QCache { Q_OBJECT @@ -45,41 +50,36 @@ class PatchManagerFilter : public QObject, public QCache Q_PROPERTY(unsigned int hits READ hits) Q_PROPERTY(unsigned int misses READ misses) public: - PatchManagerFilter(QObject *parent = nullptr, int maxCost = 100); + PatchManagerFilter(QObject *parent = nullptr, int maxCost = HOTCACHE_COST_MAX); //~PatchManagerFilter(); void setup(); + // override QCache::contains() - bool contains(const QString &key) const - { - if (!m_active) { - return false; - } else { - return (object(key) == 0); - }; - }; + bool contains(const QString &key) const; - void setActive(bool active) { m_active = active; emit activeChanged(active); }; + void setActive(bool active) { + if (m_active != active) { + m_active = active; + emit activeChanged(active); + } + }; bool active() const { return m_active; }; - void hit() { m_hits++; }; - void miss() { m_misses++; }; unsigned int hits() const { return m_hits; }; unsigned int misses() const { return m_misses; }; //QList> stats() const; QString stats() const; - static const QStringList etcList; - static const QStringList libList; - signals: void activeChanged(bool); private: bool m_active; - unsigned int m_hits = 0; - unsigned int m_misses = 0; + // need to be mutable so we can count from const method. + mutable unsigned int m_hits = 0; + mutable unsigned int m_misses = 0; }; #endif // PATCHMANAGERFILTER_H diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 9cf45800..50453a06 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -148,11 +148,6 @@ static const QString SILICA_CODE = QStringLiteral("silica"); static const QString SETTINGS_CODE = QStringLiteral("settings"); static const QString KEYBOARD_CODE = QStringLiteral("keyboard"); -static const int HOTCACHE_COST_MAX = 5000; -static const int HOTCACHE_COST_STRONG = 1; -static const int HOTCACHE_COST_DEFAULT = 2; -static const int HOTCACHE_COST_WEAK = 3; - /*! \class PatchManagerObject \inmodule PatchManagerDaemon diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index 55e6e14f..57aba357 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -51,6 +51,8 @@ #include +#include "patchmanagerfilter.h" + #ifndef SERVER_URL #define SERVER_URL "https://coderus.openrepos.net" #endif @@ -73,7 +75,6 @@ class QSettings; class QNetworkAccessManager; class PatchManagerAdaptor; class QLocalServer; -class PatchManagerFilter; class PatchManagerObject : public QObject, public QDBusContext { From 59348ece54f2dd9ac5daa48b444a1eea3e171424 Mon Sep 17 00:00:00 2001 From: nephros Date: Mon, 3 Nov 2025 10:39:13 +0100 Subject: [PATCH 32/39] Print statistics on demand --- .../dbus/org.SfietKonstantin.patchmanager.xml | 4 ++ .../patchmanagerobject.cpp | 45 ++++++++++++++++++- .../patchmanager-daemon/patchmanagerobject.h | 2 + 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/bin/patchmanager-daemon/dbus/org.SfietKonstantin.patchmanager.xml b/src/bin/patchmanager-daemon/dbus/org.SfietKonstantin.patchmanager.xml index b024cc97..1d4c9df6 100644 --- a/src/bin/patchmanager-daemon/dbus/org.SfietKonstantin.patchmanager.xml +++ b/src/bin/patchmanager-daemon/dbus/org.SfietKonstantin.patchmanager.xml @@ -1,6 +1,10 @@ + + + + diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 50453a06..ffc68e8a 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -1197,6 +1197,15 @@ void PatchManagerObject::process() } +/*! Retrieves some statistics via D-Bus. */ +QString PatchManagerObject::statistics() +{ + DBUS_GUARD(QString()) + qDebug() << Q_FUNC_INFO; + setDelayedReply(true); + QMetaObject::invokeMethod(this, NAME(doStatistics), Qt::QueuedConnection, Q_ARG(QDBusMessage, message())); + return QString(); +} /*! Retrieves a list of Patches via D-Bus. */ QVariantList PatchManagerObject::listPatches() @@ -1907,7 +1916,7 @@ void PatchManagerObject::startReadingLocalServer() qDebug() << Q_FUNC_INFO << "Requested:" << request << "Sent:" << fakePath; } if (m_filter.remove(request)) { - qWarning() << Q_FUNC_INFO << "Hot cache: contained a patched file!"; + qWarning() << Q_FUNC_INFO << "Hot cache: contained a patched file:" << request << "/" << fakePath; } } }, Qt::DirectConnection); @@ -2171,6 +2180,35 @@ void PatchManagerObject::doRefreshPatchList() } } +void PatchManagerObject::doStatistics(const QDBusMessage &message) +{ + qDebug() << Q_FUNC_INFO; + QStringList result; + + result << QStringLiteral("Patchmanager version: %1").arg(getPatchmanagerVersion()) + << QStringLiteral("Applied Patches: %1").arg(m_appliedPatches.count()) + << QStringLiteral("Patched files: %1").arg(m_patchedFiles.count()); + + if (m_originalWatcher) + result << QStringLiteral("Watched files: %1").arg(m_originalWatcher->files().count()); + + if (m_filter.active()) { + result << m_filter.stats(); + } else { + result << QStringLiteral("Advanced filtering is not active."); + } + + qInfo() << "=================================="; + qInfo() << "======== STATISTICS BEGIN ========"; + qInfo() << "=================================="; + qInfo() << qPrintable(result.join("\n")); + qInfo() << "=================================="; + qInfo() << "======== STATISTICS END =========="; + qInfo() << "=================================="; + + sendMessageReply(message, result.join("\n")); +} + void PatchManagerObject::doListPatches(const QDBusMessage &message) { qDebug() << Q_FUNC_INFO; @@ -2869,6 +2907,11 @@ void PatchManagerObject::requestCheckForUpdates() }); } }); + + if (m_filter.active()) { + qInfo() << m_filter.stats(); + } + } void PatchManagerObject::sendMessageReply(const QDBusMessage &message, const QVariant &result) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index 57aba357..baf32891 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -97,6 +97,7 @@ public slots: QVariantList listPatches(); QVariantMap listVersions(); + QString statistics(); bool isPatchApplied(const QString &patch); QVariantMap applyPatch(const QString &patch); QVariantMap unapplyPatch(const QString &patch); @@ -161,6 +162,7 @@ private slots: void doRefreshPatchList(); void doListPatches(const QDBusMessage &message); + void doStatistics(const QDBusMessage &message); bool doPatch(const QString &patchName, bool apply, QString *patchLog = nullptr); void doPatch(const QVariantMap ¶ms, const QDBusMessage &message, bool apply); From 0d2fd91e6741dabc42c384cbf47b1d2205c3edd0 Mon Sep 17 00:00:00 2001 From: nephros Date: Mon, 3 Nov 2025 11:40:27 +0100 Subject: [PATCH 33/39] Rework Stats yet again --- .../dbus/org.SfietKonstantin.patchmanager.xml | 1 + .../patchmanagerfilter.cpp | 29 +++++++------------ .../patchmanager-daemon/patchmanagerfilter.h | 2 +- .../patchmanagerobject.cpp | 25 ++++++++-------- .../patchmanager-daemon/patchmanagerobject.h | 4 +-- 5 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/bin/patchmanager-daemon/dbus/org.SfietKonstantin.patchmanager.xml b/src/bin/patchmanager-daemon/dbus/org.SfietKonstantin.patchmanager.xml index 1d4c9df6..e2cb22aa 100644 --- a/src/bin/patchmanager-daemon/dbus/org.SfietKonstantin.patchmanager.xml +++ b/src/bin/patchmanager-daemon/dbus/org.SfietKonstantin.patchmanager.xml @@ -3,6 +3,7 @@ + diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.cpp b/src/bin/patchmanager-daemon/patchmanagerfilter.cpp index a22880ab..f7547ae7 100644 --- a/src/bin/patchmanager-daemon/patchmanagerfilter.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.cpp @@ -128,35 +128,28 @@ bool PatchManagerFilter::contains(const QString &key) const }; -QString PatchManagerFilter::stats() const +QString PatchManagerFilter::stats(bool verbose=false) const { qDebug() << Q_FUNC_INFO; - QStringList topTen; - int ttmax = qEnvironmentVariableIsSet("PM_DEBUG_HOTCACHE") ? size() : 10; - foreach(const QString &key, keys() ) { - topTen << key; - if (topTen.size() >= ttmax) - break; - } - QStringList stats; stats << QStringLiteral("Filter Stats:") << QStringLiteral("===========================") << QStringLiteral(" Hotcache entries:: ..............%1").arg(size()) << QStringLiteral(" Hotcache cost: ..................%1/%2").arg(totalCost()).arg(maxCost()); - if (qEnvironmentVariableIsSet("PM_DEBUG_HOTCACHE")) { - unsigned int sum = hits()+misses(); + if (verbose) { + unsigned int sum = m_hits + m_misses; if (sum > 0) { QString ratio; - float ratf = (hits() / sum); - ratio.setNum( ratf, 'f', 2); - stats << QStringLiteral(" Hotcache hit/miss: ..............%1/%2 (%3%%)").arg(hits()).arg(misses()).arg(ratio); + float ratf = (static_cast(m_hits) / sum); + ratio.setNum(ratf, 'f', 2); + stats << QStringLiteral(" Hotcache hit/miss: ..............%1/%2 (%3%)").arg(m_hits).arg(m_misses).arg(ratio); } + + stats << QStringLiteral("===========================") + << QStringLiteral(" Hotcache entries:") + << keys(); } - stats << QStringLiteral("===========================") - << QStringLiteral(" Hotcache top entries: ...........") - << topTen - << QStringLiteral("==========================="); + stats << QStringLiteral("==========================="); return stats.join("\n"); } diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.h b/src/bin/patchmanager-daemon/patchmanagerfilter.h index cc1a878e..164f761c 100644 --- a/src/bin/patchmanager-daemon/patchmanagerfilter.h +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.h @@ -70,7 +70,7 @@ class PatchManagerFilter : public QObject, public QCache unsigned int misses() const { return m_misses; }; //QList> stats() const; - QString stats() const; + QString stats(bool verbose) const; signals: void activeChanged(bool); diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index ffc68e8a..e011f802 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -519,7 +519,7 @@ PatchManagerObject::~PatchManagerObject() connection.unregisterObject(DBUS_PATH_NAME); } if (m_filter.active()) { - qInfo() << m_filter.stats(); + qInfo() << m_filter.stats(false); } } @@ -1198,12 +1198,14 @@ void PatchManagerObject::process() } /*! Retrieves some statistics via D-Bus. */ -QString PatchManagerObject::statistics() +QString PatchManagerObject::statistics(bool verbose=false) { DBUS_GUARD(QString()) qDebug() << Q_FUNC_INFO; setDelayedReply(true); - QMetaObject::invokeMethod(this, NAME(doStatistics), Qt::QueuedConnection, Q_ARG(QDBusMessage, message())); + QMetaObject::invokeMethod(this, NAME(doStatistics), Qt::QueuedConnection, + Q_ARG(QVariantMap, QVariantMap({{QStringLiteral("verbose"), verbose}})), + Q_ARG(QDBusMessage, message())); return QString(); } @@ -1850,6 +1852,7 @@ void PatchManagerObject::onTimerAction() { qDebug() << Q_FUNC_INFO; checkForUpdates(); + statistics(false); } void PatchManagerObject::startReadingLocalServer() @@ -2180,20 +2183,23 @@ void PatchManagerObject::doRefreshPatchList() } } -void PatchManagerObject::doStatistics(const QDBusMessage &message) +void PatchManagerObject::doStatistics(const QVariantMap ¶ms, const QDBusMessage &message) { qDebug() << Q_FUNC_INFO; - QStringList result; + bool verbose = params.value(QStringLiteral("verbose")).toBool(); + + QStringList result; result << QStringLiteral("Patchmanager version: %1").arg(getPatchmanagerVersion()) << QStringLiteral("Applied Patches: %1").arg(m_appliedPatches.count()) - << QStringLiteral("Patched files: %1").arg(m_patchedFiles.count()); + //<< QStringLiteral("Patched files: %1").arg(m_patchedFiles.count()); + << QStringLiteral("Patched files: %1").arg(m_fileToPatch.values().count()); if (m_originalWatcher) result << QStringLiteral("Watched files: %1").arg(m_originalWatcher->files().count()); if (m_filter.active()) { - result << m_filter.stats(); + result << m_filter.stats(verbose); } else { result << QStringLiteral("Advanced filtering is not active."); } @@ -2907,11 +2913,6 @@ void PatchManagerObject::requestCheckForUpdates() }); } }); - - if (m_filter.active()) { - qInfo() << m_filter.stats(); - } - } void PatchManagerObject::sendMessageReply(const QDBusMessage &message, const QVariant &result) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.h b/src/bin/patchmanager-daemon/patchmanagerobject.h index baf32891..2c57e49a 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.h +++ b/src/bin/patchmanager-daemon/patchmanagerobject.h @@ -97,7 +97,7 @@ public slots: QVariantList listPatches(); QVariantMap listVersions(); - QString statistics(); + QString statistics(bool verbose); bool isPatchApplied(const QString &patch); QVariantMap applyPatch(const QString &patch); QVariantMap unapplyPatch(const QString &patch); @@ -162,7 +162,7 @@ private slots: void doRefreshPatchList(); void doListPatches(const QDBusMessage &message); - void doStatistics(const QDBusMessage &message); + void doStatistics(const QVariantMap ¶ms, const QDBusMessage &message); bool doPatch(const QString &patchName, bool apply, QString *patchLog = nullptr); void doPatch(const QVariantMap ¶ms, const QDBusMessage &message, bool apply); From 213b50820f31f1143a411211e4e7e4aa249d34f3 Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 4 Nov 2025 09:37:59 +0100 Subject: [PATCH 34/39] Remove stats call from destructor --- src/bin/patchmanager-daemon/patchmanagerobject.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index e011f802..4260f5ce 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -518,9 +518,6 @@ PatchManagerObject::~PatchManagerObject() connection.unregisterService(DBUS_SERVICE_NAME); connection.unregisterObject(DBUS_PATH_NAME); } - if (m_filter.active()) { - qInfo() << m_filter.stats(false); - } } void PatchManagerObject::registerDBus() From 59ea81800258f8e2c161a77f244c006d2c5ca88f Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 4 Nov 2025 08:43:32 +0100 Subject: [PATCH 35/39] Stats: limit max output size --- src/bin/patchmanager-daemon/patchmanagerfilter.cpp | 12 ++++++++++-- src/bin/patchmanager-daemon/patchmanagerfilter.h | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.cpp b/src/bin/patchmanager-daemon/patchmanagerfilter.cpp index f7547ae7..c88d46b8 100644 --- a/src/bin/patchmanager-daemon/patchmanagerfilter.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.cpp @@ -146,8 +146,16 @@ QString PatchManagerFilter::stats(bool verbose=false) const } stats << QStringLiteral("===========================") - << QStringLiteral(" Hotcache entries:") - << keys(); + << QStringLiteral(" Hotcache entries:"); + if (count() > HOTCACHE_LOG_MAX) { + stats << QStringLiteral("showing %1/%2").arg(HOTCACHE_LOG_MAX).arg(count()); + auto beg = keys().begin(); auto end = beg + HOTCACHE_LOG_MAX; + for (auto it = beg; it != end; ++it) { + stats << *it; + } + } else { + stats << keys(); + } } stats << QStringLiteral("==========================="); diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.h b/src/bin/patchmanager-daemon/patchmanagerfilter.h index 164f761c..ab4dd846 100644 --- a/src/bin/patchmanager-daemon/patchmanagerfilter.h +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.h @@ -43,6 +43,9 @@ static const int HOTCACHE_COST_STRONG = 1; static const int HOTCACHE_COST_DEFAULT = 2; static const int HOTCACHE_COST_WEAK = 3; +// output will be a dbus message. Don't make it too long. +static const int HOTCACHE_LOG_MAX = 4096; + class PatchManagerFilter : public QObject, public QCache { Q_OBJECT From 7421efff43d453c0280c0d97f73088e05af1964e Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 4 Nov 2025 08:43:55 +0100 Subject: [PATCH 36/39] Stats: lower max cost --- src/bin/patchmanager-daemon/patchmanagerfilter.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.h b/src/bin/patchmanager-daemon/patchmanagerfilter.h index ab4dd846..a44a2bcd 100644 --- a/src/bin/patchmanager-daemon/patchmanagerfilter.h +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.h @@ -38,7 +38,9 @@ #include #include -static const int HOTCACHE_COST_MAX = 5000; +// df -i / on SFOS 5.0 gives about 100k used inodes. +// must be chosen so that lookup times do not eat any benefits. +static const int HOTCACHE_COST_MAX = 2500; static const int HOTCACHE_COST_STRONG = 1; static const int HOTCACHE_COST_DEFAULT = 2; static const int HOTCACHE_COST_WEAK = 3; From 48ccda6f57974b556c561d0b23972d8dfe6dbeb5 Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 4 Nov 2025 09:30:21 +0100 Subject: [PATCH 37/39] Default values go into header --- src/bin/patchmanager-daemon/patchmanagerfilter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.cpp b/src/bin/patchmanager-daemon/patchmanagerfilter.cpp index c88d46b8..c75e9eaa 100644 --- a/src/bin/patchmanager-daemon/patchmanagerfilter.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.cpp @@ -128,7 +128,7 @@ bool PatchManagerFilter::contains(const QString &key) const }; -QString PatchManagerFilter::stats(bool verbose=false) const +QString PatchManagerFilter::stats(bool verbose) const { qDebug() << Q_FUNC_INFO; QStringList stats; From ebb671f396f14f29fd1dd63e68338cba03a4a0ef Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 4 Nov 2025 09:32:25 +0100 Subject: [PATCH 38/39] Cache: Use small data type for cache entries --- .../patchmanagerfilter.cpp | 20 +++++++++++++++++-- .../patchmanager-daemon/patchmanagerfilter.h | 8 +++++++- .../patchmanagerobject.cpp | 3 +-- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.cpp b/src/bin/patchmanager-daemon/patchmanagerfilter.cpp index c75e9eaa..5102ebc7 100644 --- a/src/bin/patchmanager-daemon/patchmanagerfilter.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.cpp @@ -96,7 +96,7 @@ void PatchManagerFilter::setup() // use a cost of 1 here so they have less chance to be evicted foreach(const QString &entry, etcList) { if (QFileInfo::exists(entry)) { - insert(entry, new QObject(), HOTCACHE_COST_STRONG); + insert(entry, 1, HOTCACHE_COST_STRONG); } } // they may be wrong, so use a higher cost than default @@ -108,11 +108,27 @@ void PatchManagerFilter::setup() if (QFileInfo::exists(libentry)) { QFileInfo fi(libentry); - insert(fi.canonicalFilePath(), new QObject(), HOTCACHE_COST_WEAK); + insert(fi.canonicalFilePath(), 1, HOTCACHE_COST_WEAK); } } } +// override QCache::insert(). +bool PatchManagerFilter::insert(const QString &key, quint8 value, int cost) +{ + quint8* data; + // In Qt 5.6 (up to and including 5.12), QCache::object() returns 0 for "not found", + // we cannot accept a zero value here. + if (value == 0) { + qCritical() << "PatchManagerFilter::insert: Inserting zero will lead to wrong results!" + << "Forcing value to 1!"; + data = new quint8(1); + } else { + data = new quint8(value); + } + return QCache::insert(key, data, cost); +} + // override QCache::contains() bool PatchManagerFilter::contains(const QString &key) const { diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.h b/src/bin/patchmanager-daemon/patchmanagerfilter.h index a44a2bcd..47a1627f 100644 --- a/src/bin/patchmanager-daemon/patchmanagerfilter.h +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.h @@ -48,7 +48,9 @@ static const int HOTCACHE_COST_WEAK = 3; // output will be a dbus message. Don't make it too long. static const int HOTCACHE_LOG_MAX = 4096; -class PatchManagerFilter : public QObject, public QCache +// As we do not care about the actual cached object, try to use a small one. +// quint8 should be one byte or so +class PatchManagerFilter : public QObject, public QCache { Q_OBJECT Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) @@ -60,6 +62,9 @@ class PatchManagerFilter : public QObject, public QCache void setup(); + // override QCache::insert() + bool insert(const QString &key, quint8 value = 1, int cost = HOTCACHE_COST_DEFAULT); + // override QCache::contains() bool contains(const QString &key) const; @@ -82,6 +87,7 @@ class PatchManagerFilter : public QObject, public QCache private: bool m_active; + // need to be mutable so we can count from const method. mutable unsigned int m_hits = 0; mutable unsigned int m_misses = 0; diff --git a/src/bin/patchmanager-daemon/patchmanagerobject.cpp b/src/bin/patchmanager-daemon/patchmanagerobject.cpp index 4260f5ce..4607a503 100644 --- a/src/bin/patchmanager-daemon/patchmanagerobject.cpp +++ b/src/bin/patchmanager-daemon/patchmanagerobject.cpp @@ -1909,8 +1909,7 @@ void PatchManagerObject::startReadingLocalServer() if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { qDebug() << Q_FUNC_INFO << "Requested:" << request << "was sent unaltered."; } - QObject *dummy = new QObject(); // the cache will own it the next line - m_filter.insert(request, dummy, HOTCACHE_COST_DEFAULT); // cost: see setupFilter, use middle ground here + m_filter.insert(request); } else { if (qEnvironmentVariableIsSet("PM_DEBUG_SOCKET")) { qDebug() << Q_FUNC_INFO << "Requested:" << request << "Sent:" << fakePath; From e31d6bf4341c7e63aaa01e693a0ade8b522396ad Mon Sep 17 00:00:00 2001 From: nephros Date: Tue, 4 Nov 2025 12:27:06 +0100 Subject: [PATCH 39/39] Add a comment about sizing the cache --- .../patchmanager-daemon/patchmanagerfilter.h | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/bin/patchmanager-daemon/patchmanagerfilter.h b/src/bin/patchmanager-daemon/patchmanagerfilter.h index 47a1627f..db560db8 100644 --- a/src/bin/patchmanager-daemon/patchmanagerfilter.h +++ b/src/bin/patchmanager-daemon/patchmanagerfilter.h @@ -38,8 +38,27 @@ #include #include -// df -i / on SFOS 5.0 gives about 100k used inodes. -// must be chosen so that lookup times do not eat any benefits. +/* choosing the right cost obviously is critical and difficult ;) + we want lookup times to be faster than the cost of a QFileInfo::exists() + --> smaller is better. + + We also want it to not hold "stale" entries, i.e. files once added and + never accessed again. + --> smaller is also better + + But we also want it to hold the most commonly accessed files, and not rotate + the entries all the time. ideally after some time, it stays somewhat + stable. + --> too small is bad + + Some observations: + + df -i / on SFOS 5.0 gives about 100k used inodes. + On a system with about 100 patched files, running find /usr -exec head -n 1 {} >/dev/null \; + the cost() seems to not go over 3600 or so when maxCost is 5000. + +*/ + static const int HOTCACHE_COST_MAX = 2500; static const int HOTCACHE_COST_STRONG = 1; static const int HOTCACHE_COST_DEFAULT = 2;