From f038e54fa2b3e2fe379791e719555e7a038e1d89 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 24 Jun 2026 18:31:24 +0000 Subject: [PATCH] feat: scale LocalCache pruning aggressiveness to OS memory-pressure level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MemoryTrimmingService.doTrim() previously ran the full pruning suite regardless of how severe the OS signal was. Now it tiers the work by ComponentCallbacks2 level so low-pressure signals don't pay the cost of aggressive observer teardown: Tier 1 (always): cleanMemory + pruneExpiredEvents + prunePastVersionsOfReplaceables Tier 2 (>= RUNNING_LOW): + pruneOldMessages + pruneRepliesAndReactions Tier 3 (>= RUNNING_CRITICAL): + cleanObservers + pruneHiddenEvents/Messages The `level` is now threaded from Amethyst.onTrimMemory → AppModules.trim(level) → MemoryTrimmingService.run(…, level) → doTrim(…, level). The existing scheduled-trim call site (AppModules.trim) defaults to RUNNING_CRITICAL so its behaviour is unchanged. Co-Authored-By: Claude --- .../com/vitorpamplona/amethyst/Amethyst.kt | Bin 8130 -> 8135 bytes .../com/vitorpamplona/amethyst/AppModules.kt | 4 +- .../eventCache/MemoryTrimmingService.kt | 47 ++++++++++++++---- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt index 11c2371792c890f7e1981e97e46b308d4117f3b2..ca1de8490bc6e107dda7332ee9e32700d47d41e1 100644 GIT binary patch delta 18 acmX?Pf82h, otherAccounts: List, + level: Int, ) { + // Tier 1: always run — cheap housekeeping cache.cleanMemory() - cache.cleanObservers() + cache.pruneExpiredEvents() + cache.prunePastVersionsOfReplaceables() - account.forEach { - cache.pruneHiddenEvents(it) - cache.pruneHiddenMessages(it) + if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW) { + // Tier 2: medium pressure — drop messages and unobserved reactions + val accounts = otherAccounts.mapNotNull { decodePublicKeyAsHexOrNull(it.npub) }.toSet() + cache.pruneOldMessages() + cache.pruneRepliesAndReactions(accounts) } - val accounts = otherAccounts.mapNotNull { decodePublicKeyAsHexOrNull(it.npub) }.toSet() - cache.pruneOldMessages() - cache.pruneRepliesAndReactions(accounts) - cache.prunePastVersionsOfReplaceables() - cache.pruneExpiredEvents() + if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) { + // Tier 3: critical pressure — sever observer links and drop muted content + cache.cleanObservers() + account.forEach { + cache.pruneHiddenEvents(it) + cache.pruneHiddenMessages(it) + } + } } suspend fun run( account: Collection, otherAccounts: List, + level: Int = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL, ) { if (isTrimmingMemoryMutex.compareAndSet(false, true)) { - Log.d("ServiceManager", "Trimming Memory") + Log.d("ServiceManager", "Trimming Memory (level=$level)") try { - doTrim(account, otherAccounts) + doTrim(account, otherAccounts, level) } finally { isTrimmingMemoryMutex.getAndSet(false) }