https://bugs.kde.org/show_bug.cgi?id=521757
[email protected] changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |[email protected] --- Comment #5 from [email protected] --- Answering the request in comment for dbus-monitor / bustle output showing why resultRemoved() fires so often. The signal storm has a specific cause: DeleteStatsForResource can never delete a resource whose path contains a backslash, so the caller retries it forever. SOFTWARE/OS VERSIONS Operating System: Arch Linux KDE Plasma Version: 6.7.4 plasma-workspace: 6.7.4-3 kactivitymanagerd: 6.7.4-1 plasma-activities: 6.7.4-1 plasma-activities-stats: 6.7.4-1 Qt Version: 6.11.2 SQLite: 3.53.4 Kernel: 7.0.3-arch1-2 Graphics Platform: Wayland THE DBUS EVIDENCE dbus-monitor --session captured for 10 seconds while one core was pegged: 1345 member=ResourceScoreDeleted 1344 member=DeleteStatsForResource 13277 session bus messages in 10 seconds, of which 2689 are this loop. That is roughly 134 delete attempts per second, sustained. All 1344 calls carried an identical argument set: method call sender=:1.31 -> destination=org.kde.ActivityManager path=/ActivityManager/Resources/Scoring; interface=org.kde.ActivityManager.ResourcesScoring; member=DeleteStatsForResource string ":current" string ":any" string "/home/too/SharedRDP/temp/cypress\snapshots/3879-swa-question-text.snap.png" signal sender=:1.29 -> destination=(null destination) interface=org.kde.ActivityManager.ResourcesScoring; member=ResourceScoreDeleted :1.31 is plasmashell, :1.29 is kactivitymanagerd. The file does not exist on disk. The row for it was still in ResourceScoreCache after 37 days of this. ROOT CAUSE Note the backslash in the path. In /usr/lib/qt6/plugins/kactivitymanagerd1/org.kde.ActivityManager.ResourceScoring.so: DELETE FROM ResourceInfo WHERE targettedResource LIKE :targettedResource ESCAPE '\' and the same predicate: targettedResource LIKE :targettedResource ESCAPE '\' is reused for the other resource tables. ESCAPE '\' is presumably there so callers can pass wildcard patterns. The side effect is that a backslash occurring literally inside a stored path is reinterpreted as an escape introducer: cypress\snapshots is matched as cypresssnapshots, and the statement affects zero rows. Verified against a copy of the live database: sqlite> select count(*) from ResourceScoreCache ...> where targettedResource = '/home/too/SharedRDP/temp/cypress\snapshots/3879-swa-question-text.snap.png'; 1 sqlite> select count(*) from ResourceScoreCache ...> where targettedResource LIKE '/home/too/SharedRDP/temp/cypress\snapshots/3879-swa-question-text.snap.png' ESCAPE '\'; 0 The row is reachable by equality and unreachable by the predicate the service actually uses. WHY IT NEVER TERMINATES 1. The consumer in plasmashell holds a resource entry for a file that no longer exists and calls DeleteStatsForResource on it. 2. kactivitymanagerd runs the LIKE ... ESCAPE delete. Zero rows affected, but ResourceScoreDeleted is emitted unconditionally. 3. The consumer treats the signal as a change notification, re-reads, finds the entry still present, and returns to step 1. Neither side checks the affected row count, and neither has a retry limit or backoff, so this does not converge. This is why KActivities::Stats::ResultWatcher::resultRemoved() re-runs its full SQLite query millions of times and produces the allocation profile reported in this bug. The 139051509 allocation calls are the symptom, not the cause. MEASURED COST (before clearing the database) kactivitymanagerd plasmashell read syscalls/sec 202,702 72,457 read throughput 790 MB/s 280 MB/s lifetime rchar 18.3 TB 6.7 TB lifetime syscr 4.49 billion 1.64 billion CPU consumed in 37 day boot 3h 44m 2h 13m hot thread The database is 9 MB, so 790 MB/s means it was being re-scanned from page cache roughly 85 times per second. read_bytes was only 225 MB, so almost none of it reached the disk. Two secondary effects: - The SQLite WAL grew to 12 MB, larger than the 9 MB database itself, because continuous reader traffic prevented checkpointing. - plasmashell had written 27.5 GB to disk over the boot. An earlier boot shows the same signature in the journal: plasma-kactivitymanagerd.service: Consumed 15h 42min 42.473s CPU time over 2w 3d 5h 42min 59.973s wall clock time, 55.4M memory peak So it survives reboots, because the offending rows are persistent. CONFIRMATION 199 rows contained a literal backslash: 54 in ResourceScoreCache, 84 in ResourceEvent, 61 in ResourceInfo, all recorded on 2026-05-12. After deleting them and restarting both services: before after loop messages per 10s 2689 0 total session DBus messages per 10s 13277 301 kactivitymanagerd read syscalls/sec 202,702 0 plasmashell read syscalls/sec 72,457 28 kactivitymanagerd CPU 60.6% 0.1% WAL size 12 MB 0 kactivitymanagerd used 0 seconds of CPU in its first 95 seconds after restart. PRAGMA integrity_check returned ok. This explains why "clear the resources directory" works as a workaround for everyone in this bug: it removes the undeletable rows. HOW THE ROWS GOT THERE Cypress and Playwright runs on Windows wrote output to a Linux filesystem over an RDP share, so the Windows path separator ended up inside the Linux filename, for example ~/SharedRDP/temp/cypress\snapshots/foo.snap.png. Any path containing a literal backslash should reproduce it. Paths containing % or _ are likely affected the same way, since those are also LIKE metacharacters. Minimal reproducer, without needing Windows: 1. touch 'foo\bar.txt' somewhere in $HOME and open it in a Plasma application so it is recorded as a resource. 2. rm 'foo\bar.txt' 3. Log out and back in, then leave the session idle. SUGGESTED FIX Any one of these breaks the livelock. The first is the actual defect. 1. Do not use LIKE ... ESCAPE for what is an exact-identity delete. Match with = on the resource path. If wildcard deletion is a required feature, keep it on a separate explicit code path rather than applying pattern semantics to every caller-supplied path. 2. If LIKE must stay, escape the bound value before binding, so a literal \, % or _ in a stored path is passed through as itself. 3. Defensively, emit ResourceScoreDeleted only when the statement actually affected rows. That alone would stop the feedback loop even where a delete legitimately matches nothing. 4. Defensively, have the consumer in plasma-activities-stats stop re-requesting deletion of a resource whose deletion it has already requested without effect. POSSIBLY RELATED Bug 508766 (database not cleared by "Clear History" in Security and Privacy) may share this root cause, since a backslash row would resist that path too. Bug 470026 and its duplicate bug 484837 blame an oversized recently-used.xbel. That is a different trigger and does not apply here: this system's xbel is 41 KB with 305 entries. However comment 14 of bug 470026 suspects a regression affecting DeleteStatsForResource calls, which may be this same defect surfacing by another route. ------------------------------- CUT HERE -------------------------------------- ================================================================================ FALLBACK Only if bug 521757 is judged to be a different issue and a fresh report is wanted. Uses the standard KDE bug entry template. ================================================================================ Field values for the New Bug form: Product: plasmashell Component: The Activities subsystem in general Version: 6.7.4 Severity: major (permanent 100% CPU on one core, never recovers) Platform: Archlinux Packages OS: Linux ------------------------------- CUT HERE -------------------------------------- SUMMARY DeleteStatsForResource can never delete a resource whose path contains a backslash, because the delete matches with LIKE :targettedResource ESCAPE '\' and the backslash in the stored path is consumed as an escape character. The statement affects zero rows, ResourceScoreDeleted is emitted anyway, the consumer in plasmashell re-reads, finds the resource still present and requests deletion again. plasmashell and kactivitymanagerd then livelock at roughly 134 iterations per second indefinitely. STEPS TO REPRODUCE 1. Create a file whose name contains a literal backslash, for example touch 'foo\bar.txt' in $HOME, and open it in a Plasma application so it is recorded as a resource in the activity database. 2. Delete the file so the recorded resource no longer resolves. 3. Log out, log back in, and leave the session idle. OBSERVED RESULT kactivitymanagerd and plasmashell each begin consuming CPU continuously and never stop. dbus-monitor --session shows the pair exchanging DeleteStatsForResource and ResourceScoreDeleted about 134 times per second, all referring to the same single resource. The row is never removed. The condition persists across reboots because the row is persistent. Measured on the affected system: 202,702 read syscalls/sec in kactivitymanagerd and 72,457/sec in plasmashell, 790 MB/s and 280 MB/s of page-cache re-reads against a 9 MB database, 18.3 TB lifetime rchar, and 3h44m plus 2h13m of CPU consumed in a single 37 day boot. EXPECTED RESULT DeleteStatsForResource removes the named resource, whatever characters its path contains, and the loop terminates. SOFTWARE/OS VERSIONS Operating System: Arch Linux KDE Plasma Version: 6.7.4 KDE Frameworks Version: 6.7.4 Qt Version: 6.11.2 Kernel Version: 7.0.3-arch1-2 Graphics Platform: Wayland ADDITIONAL INFORMATION The offending SQL is in /usr/lib/qt6/plugins/kactivitymanagerd1/org.kde.ActivityManager.ResourceScoring.so: DELETE FROM ResourceInfo WHERE targettedResource LIKE :targettedResource ESCAPE '\' Demonstrated against a copy of the live database, the row is reachable by equality and unreachable by the predicate the service uses: select count(*) from ResourceScoreCache where targettedResource = '/home/too/SharedRDP/temp/cypress\snapshots/3879-swa-question-text.snap.png'; 1 select count(*) from ResourceScoreCache where targettedResource LIKE '/home/too/SharedRDP/temp/cypress\snapshots/3879-swa-question-text.snap.png' ESCAPE '\'; 0 Workaround, which also confirms the diagnosis: cp -r ~/.local/share/kactivitymanagerd/resources \ ~/.local/share/kactivitymanagerd/resources.bak-$(date +%F) systemctl --user stop plasma-kactivitymanagerd sqlite3 ~/.local/share/kactivitymanagerd/resources/database \ "DELETE FROM ResourceScoreCache WHERE instr(targettedResource,char(92))>0; DELETE FROM ResourceEvent WHERE instr(targettedResource,char(92))>0; DELETE FROM ResourceInfo WHERE instr(targettedResource,char(92))>0; PRAGMA wal_checkpoint(TRUNCATE); VACUUM; PRAGMA wal_checkpoint(TRUNCATE);" systemctl --user start plasma-kactivitymanagerd systemctl --user restart plasma-plasmashell plasmashell must be restarted too, otherwise it keeps its in-memory copy of the stale entry and restarts the loop against the now-clean database. After this the loop messages drop from 2689 per 10s to 0, kactivitymanagerd read syscalls drop from 202,702/sec to 0, and it uses 0 seconds of CPU in its first 95 seconds. PRAGMA integrity_check returns ok. See bug 521757, which reports the same symptom and workaround on 6.7.0 through 6.7.4 and identifies the resultRemoved() allocation storm that this explains. -- You are receiving this mail because: You are watching all bug changes.
