From 545cd2ff6df93a57ba6e6ea7a4600243657ab9ad Mon Sep 17 00:00:00 2001 From: davotoula Date: Wed, 5 Nov 2025 19:02:53 +0100 Subject: [PATCH] synchronize all cache mutations and supply sinceRelaySet so callers get snapshot copies rework groupByRelayPresence to build relay snapshots via sinceRelaySet, filtering with immutable lists to prevent ConcurrentModificationException when relays update mid-iteration --- .../user/watchers/UserReportsSubAssembler.kt | 27 +++++++++++++------ .../amethyst/service/relays/EOSE.kt | 5 ++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserReportsSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserReportsSubAssembler.kt index 651077a71..157187c06 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserReportsSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserReportsSubAssembler.kt @@ -90,19 +90,30 @@ class UserReportsSubAssembler( users: Iterable, eoseCache: EOSEAccountFast, inRelays: Set, - ): Collection> = - users - .groupBy { - eoseCache - .since(it) - ?.keys - ?.intersect(inRelays) - ?.hashCode() + ): Collection> { + if (users.none()) return emptyList() + + val relaySnapshot = inRelays.toSet() + + return users + .groupBy { user -> + val relaysForUser = eoseCache.sinceRelaySet(user) + if (relaysForUser.isNullOrEmpty() || relaySnapshot.isEmpty()) { + null + } else { + val intersection = relaysForUser.filter { it in relaySnapshot }.sorted() + if (intersection.isEmpty()) { + null + } else { + intersection.hashCode() + } + } }.values .map { // important to keep in order otherwise the Relay thinks the filter has changed and we REQ again it.sortedBy { it.pubkeyHex } } + } fun findMinimumEOSEsForUsers( users: List, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt index dfa5b2db4..9229450da 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt @@ -166,6 +166,11 @@ class EOSEAccountFast( users[key]?.relayList?.toMutableMap() } + fun sinceRelaySet(key: T): Set? = + synchronized(lock) { + users[key]?.relayList?.keys?.toSet() + } + fun newEose( user: T, relayUrl: NormalizedRelayUrl,