From 7780bd7e1198a3e3c4420267f33d0279c93c0dbc Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 2 Oct 2024 17:52:06 +0200 Subject: [PATCH] timeline : add synchronisation around timelineItemIndexer --- .../impl/timeline/TimelineItemIndexer.kt | 28 ++++++++++++++----- .../impl/timeline/TimelineItemIndexerTest.kt | 3 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineItemIndexer.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineItemIndexer.kt index 877b4ea385..2db5003f4a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineItemIndexer.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineItemIndexer.kt @@ -11,26 +11,39 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.SingleIn import io.element.android.libraries.matrix.api.core.EventId +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import timber.log.Timber import javax.inject.Inject @SingleIn(RoomScope::class) class TimelineItemIndexer @Inject constructor() { + // This is a latch to wait for the first process call + private val firstProcessLatch = CompletableDeferred() private val timelineEventsIndexes = mutableMapOf() - fun isKnown(eventId: EventId): Boolean { - return timelineEventsIndexes.containsKey(eventId).also { - Timber.d("$eventId isKnown = $it") + private val mutex = Mutex() + + suspend fun isKnown(eventId: EventId): Boolean { + firstProcessLatch.await() + return mutex.withLock { + timelineEventsIndexes.containsKey(eventId).also { + Timber.d("$eventId isKnown = $it") + } } } - fun indexOf(eventId: EventId): Int { - return (timelineEventsIndexes[eventId] ?: -1).also { - Timber.d("indexOf $eventId= $it") + suspend fun indexOf(eventId: EventId): Int { + firstProcessLatch.await() + return mutex.withLock { + (timelineEventsIndexes[eventId] ?: -1).also { + Timber.d("indexOf $eventId= $it") + } } } - fun process(timelineItems: List) { + suspend fun process(timelineItems: List) = mutex.withLock { Timber.d("process ${timelineItems.size} items") timelineEventsIndexes.clear() timelineItems.forEachIndexed { index, timelineItem -> @@ -46,6 +59,7 @@ class TimelineItemIndexer @Inject constructor() { else -> Unit } } + firstProcessLatch.complete(Unit) } private fun processEvent(event: TimelineItem.Event, index: Int) { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineItemIndexerTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineItemIndexerTest.kt index 3e20250910..2e3687b74e 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineItemIndexerTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineItemIndexerTest.kt @@ -13,11 +13,12 @@ import io.element.android.features.messages.impl.timeline.model.virtual.Timeline import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.test.AN_EVENT_ID +import kotlinx.coroutines.test.runTest import org.junit.Test class TimelineItemIndexerTest { @Test - fun `test TimelineItemIndexer`() { + fun `test TimelineItemIndexer`() = runTest { val eventIds = mutableListOf() val data = listOf( aTimelineItemEvent().also { eventIds.add(it.eventId!!) },