mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-11-10 04:57:20 +01:00
Merge pull request #1550 from davotoula/reduce-errors-ConcurrentModificationException
Reduce errors in log: concurrent modification exception
This commit is contained in:
@@ -46,7 +46,6 @@ import kotlinx.coroutines.flow.onStart
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.flow.transformLatest
|
import kotlinx.coroutines.flow.transformLatest
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlin.collections.map
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintains several stateflows for each step in processing PeopleLists
|
* Maintains several stateflows for each step in processing PeopleLists
|
||||||
|
|||||||
@@ -186,11 +186,11 @@ class AccountFollowsLoaderSubAssembler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// removes accounts that are not being subscribed anymore.
|
// removes accounts that are not being subscribed anymore.
|
||||||
accountUpdatesJobMap.forEach {
|
// Cancel watchers for accounts no longer observed using a snapshot to avoid CME
|
||||||
if (it.key !in uniqueSubscribedAccounts.keys) {
|
accountUpdatesJobMap.keys
|
||||||
endWatcher(it.key)
|
.toList()
|
||||||
}
|
.filter { it !in uniqueSubscribedAccounts.keys }
|
||||||
}
|
.forEach { endWatcher(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val accountUpdatesJobMap = mutableMapOf<User, Job>()
|
private val accountUpdatesJobMap = mutableMapOf<User, Job>()
|
||||||
|
|||||||
@@ -90,19 +90,30 @@ class UserReportsSubAssembler(
|
|||||||
users: Iterable<User>,
|
users: Iterable<User>,
|
||||||
eoseCache: EOSEAccountFast<User>,
|
eoseCache: EOSEAccountFast<User>,
|
||||||
inRelays: Set<NormalizedRelayUrl>,
|
inRelays: Set<NormalizedRelayUrl>,
|
||||||
): Collection<List<User>> =
|
): Collection<List<User>> {
|
||||||
users
|
if (users.none()) return emptyList()
|
||||||
.groupBy {
|
|
||||||
eoseCache
|
val relaySnapshot = inRelays.toSet()
|
||||||
.since(it)
|
|
||||||
?.keys
|
return users
|
||||||
?.intersect(inRelays)
|
.groupBy { user ->
|
||||||
?.hashCode()
|
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
|
}.values
|
||||||
.map {
|
.map {
|
||||||
// important to keep in order otherwise the Relay thinks the filter has changed and we REQ again
|
// important to keep in order otherwise the Relay thinks the filter has changed and we REQ again
|
||||||
it.sortedBy { it.pubkeyHex }
|
it.sortedBy { it.pubkeyHex }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun findMinimumEOSEsForUsers(
|
fun findMinimumEOSEsForUsers(
|
||||||
users: List<User>,
|
users: List<User>,
|
||||||
|
|||||||
@@ -125,36 +125,51 @@ class EOSEAccountFast<T : Any>(
|
|||||||
cacheSize: Int = 20,
|
cacheSize: Int = 20,
|
||||||
) {
|
) {
|
||||||
private val users: LruCache<T, EOSERelayList> = LruCache<T, EOSERelayList>(cacheSize)
|
private val users: LruCache<T, EOSERelayList> = LruCache<T, EOSERelayList>(cacheSize)
|
||||||
|
private val lock = Any()
|
||||||
|
|
||||||
fun addOrUpdate(
|
fun addOrUpdate(
|
||||||
user: T,
|
user: T,
|
||||||
relayUrl: NormalizedRelayUrl,
|
relayUrl: NormalizedRelayUrl,
|
||||||
time: Long,
|
time: Long,
|
||||||
) {
|
) {
|
||||||
val relayList = users[user]
|
synchronized(lock) {
|
||||||
if (relayList == null) {
|
val relayList = users[user]
|
||||||
val newList = EOSERelayList()
|
if (relayList == null) {
|
||||||
users.put(user, newList)
|
val newList = EOSERelayList()
|
||||||
|
users.put(user, newList)
|
||||||
|
|
||||||
newList.addOrUpdate(relayUrl, time)
|
newList.addOrUpdate(relayUrl, time)
|
||||||
} else {
|
} else {
|
||||||
relayList.addOrUpdate(relayUrl, time)
|
relayList.addOrUpdate(relayUrl, time)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeEveryoneBut(list: Set<T>) {
|
fun removeEveryoneBut(list: Set<T>) {
|
||||||
users.snapshot().forEach {
|
synchronized(lock) {
|
||||||
if (it.key !in list) {
|
users.snapshot().forEach {
|
||||||
users.remove(it.key)
|
if (it.key !in list) {
|
||||||
|
users.remove(it.key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeDataFor(user: T) {
|
fun removeDataFor(user: T) {
|
||||||
users.remove(user)
|
synchronized(lock) {
|
||||||
|
users.remove(user)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun since(key: T) = users[key]?.relayList
|
fun since(key: T): SincePerRelayMap? =
|
||||||
|
synchronized(lock) {
|
||||||
|
users[key]?.relayList?.toMutableMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sinceRelaySet(key: T): Set<NormalizedRelayUrl>? =
|
||||||
|
synchronized(lock) {
|
||||||
|
users[key]?.relayList?.keys?.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
fun newEose(
|
fun newEose(
|
||||||
user: T,
|
user: T,
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import com.vitorpamplona.amethyst.R
|
|||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenUser
|
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenUser
|
||||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowing
|
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowing
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav.nav
|
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ import com.vitorpamplona.amethyst.model.User
|
|||||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||||
import com.vitorpamplona.amethyst.ui.note.UserComposeNoAction
|
import com.vitorpamplona.amethyst.ui.note.UserComposeNoAction
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.list.PeopleListItem
|
|
||||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||||
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||||
import com.vitorpamplona.amethyst.ui.theme.HalfHalfHorzModifier
|
import com.vitorpamplona.amethyst.ui.theme.HalfHalfHorzModifier
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import androidx.compose.foundation.layout.Row
|
|||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.offset
|
import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Groups
|
import androidx.compose.material.icons.outlined.Groups
|
||||||
import androidx.compose.material.icons.outlined.Lock
|
import androidx.compose.material.icons.outlined.Lock
|
||||||
|
|||||||
Reference in New Issue
Block a user