From b8669d5ed2fdcc1691bf336b4ae6a577c43d804a Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 10 Jul 2019 15:55:30 +0200 Subject: [PATCH 1/5] Sync: use a single threaded executor to ensure we have only one sync at a time --- .../matrix/android/SingleThreadCoroutineDispatcher.kt | 2 +- .../im/vector/matrix/android/internal/di/MatrixModule.kt | 7 ++++--- .../android/internal/session/sync/job/SyncService.kt | 4 ++-- .../matrix/android/internal/session/sync/job/SyncThread.kt | 4 ++-- .../matrix/android/internal/session/sync/job/SyncWorker.kt | 4 ++-- .../im/vector/matrix/android/internal/task/TaskExecutor.kt | 1 + .../im/vector/matrix/android/internal/task/TaskThread.kt | 3 ++- .../android/internal/util/MatrixCoroutineDispatchers.kt | 3 ++- 8 files changed, 16 insertions(+), 12 deletions(-) diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/SingleThreadCoroutineDispatcher.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/SingleThreadCoroutineDispatcher.kt index dc6bc7193a..69803c5dc1 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/SingleThreadCoroutineDispatcher.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/SingleThreadCoroutineDispatcher.kt @@ -19,4 +19,4 @@ package im.vector.matrix.android import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import kotlinx.coroutines.Dispatchers.Main -internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main) \ No newline at end of file +internal val testCoroutineDispatchers = MatrixCoroutineDispatchers(Main, Main, Main, Main, Main) \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt index 260c80f14b..55b92ef89b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt @@ -18,15 +18,15 @@ package im.vector.matrix.android.internal.di import android.content.Context import android.content.res.Resources -import android.os.Handler -import android.os.HandlerThread import dagger.Module import dagger.Provides import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import im.vector.matrix.android.internal.util.createBackgroundHandler import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.android.asCoroutineDispatcher +import kotlinx.coroutines.asCoroutineDispatcher import org.matrix.olm.OlmManager +import java.util.concurrent.Executors @Module internal object MatrixModule { @@ -38,7 +38,8 @@ internal object MatrixModule { return MatrixCoroutineDispatchers(io = Dispatchers.IO, computation = Dispatchers.IO, main = Dispatchers.Main, - crypto = createBackgroundHandler("Crypto_Thread").asCoroutineDispatcher() + crypto = createBackgroundHandler("Crypto_Thread").asCoroutineDispatcher(), + sync = Executors.newSingleThreadExecutor().asCoroutineDispatcher() ) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncService.kt index 3fe850d675..1af5688b24 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncService.kt @@ -105,8 +105,8 @@ open class SyncService : Service() { Timber.v("Execute sync request with timeout 0") val params = SyncTask.Params(TIME_OUT) cancelableTask = syncTask.configureWith(params) - .callbackOn(TaskThread.CALLER) - .executeOn(TaskThread.CALLER) + .callbackOn(TaskThread.SYNC) + .executeOn(TaskThread.SYNC) .dispatchTo(object : MatrixCallback { override fun onSuccess(data: Unit) { cancelableTask = null diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt index 56d590d7ba..b6d236edbf 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncThread.kt @@ -97,8 +97,8 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, val latch = CountDownLatch(1) val params = SyncTask.Params(DEFAULT_LONG_POOL_TIMEOUT) cancelableTask = syncTask.configureWith(params) - .callbackOn(TaskThread.CALLER) - .executeOn(TaskThread.CALLER) + .callbackOn(TaskThread.SYNC) + .executeOn(TaskThread.SYNC) .dispatchTo(object : MatrixCallback { override fun onSuccess(data: Unit) { latch.countDown() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncWorker.kt index ff30dbbc52..570aa9c46e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncWorker.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/job/SyncWorker.kt @@ -62,8 +62,8 @@ internal class SyncWorker(context: Context, val latch = CountDownLatch(1) val taskParams = SyncTask.Params(0) cancelableTask = syncTask.configureWith(taskParams) - .callbackOn(TaskThread.CALLER) - .executeOn(TaskThread.CALLER) + .callbackOn(TaskThread.SYNC) + .executeOn(TaskThread.SYNC) .dispatchTo(object : MatrixCallback { override fun onSuccess(data: Unit) { latch.countDown() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt index c46b86bd70..31de5ae7f8 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskExecutor.kt @@ -77,6 +77,7 @@ internal class TaskExecutor @Inject constructor(private val coroutineDispatchers TaskThread.IO -> coroutineDispatchers.io TaskThread.CALLER -> EmptyCoroutineContext TaskThread.CRYPTO -> coroutineDispatchers.crypto + TaskThread.SYNC -> coroutineDispatchers.sync } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskThread.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskThread.kt index fc0180c953..659fd3dd9d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskThread.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/task/TaskThread.kt @@ -21,5 +21,6 @@ internal enum class TaskThread { COMPUTATION, IO, CALLER, - CRYPTO + CRYPTO, + SYNC } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/MatrixCoroutineDispatchers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/MatrixCoroutineDispatchers.kt index f58b4313fc..ef0c91a327 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/MatrixCoroutineDispatchers.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/MatrixCoroutineDispatchers.kt @@ -22,5 +22,6 @@ internal data class MatrixCoroutineDispatchers( val io: CoroutineDispatcher, val computation: CoroutineDispatcher, val main: CoroutineDispatcher, - val crypto: CoroutineDispatcher + val crypto: CoroutineDispatcher, + val sync: CoroutineDispatcher ) \ No newline at end of file From 141434e8f87b45a809e2fda8c330130f3eb7f3a5 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 10 Jul 2019 19:01:15 +0200 Subject: [PATCH 2/5] Try getting things off the main thread --- .../internal/session/DefaultSession.kt | 57 ++++++++++--------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt index ed7e5021e0..6a1cda534a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt @@ -20,6 +20,7 @@ import android.content.Context import android.os.Looper import androidx.annotation.MainThread import androidx.lifecycle.LiveData +import dagger.Lazy import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.pushrules.PushRuleService @@ -52,34 +53,34 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se private val context: Context, private val liveEntityObservers: Set<@JvmSuppressWildcards LiveEntityObserver>, private val sessionListeners: SessionListeners, - private val roomService: RoomService, - private val roomDirectoryService: RoomDirectoryService, - private val groupService: GroupService, - private val userService: UserService, - private val filterService: FilterService, - private val cacheService: CacheService, - private val signOutService: SignOutService, - private val pushRuleService: PushRuleService, - private val pushersService: PushersService, - private val cryptoService: CryptoManager, - private val fileService: FileService, + private val roomService: Lazy, + private val roomDirectoryService: Lazy, + private val groupService: Lazy, + private val userService: Lazy, + private val filterService: Lazy, + private val cacheService: Lazy, + private val signOutService: Lazy, + private val pushRuleService: Lazy, + private val pushersService: Lazy, + private val cryptoService: Lazy, + private val fileService: Lazy, private val syncThread: SyncThread, private val contentUrlResolver: ContentUrlResolver, private val contentUploadProgressTracker: ContentUploadStateTracker, - private val initialSyncProgressService: InitialSyncProgressService) + private val initialSyncProgressService: Lazy) : Session, - RoomService by roomService, - RoomDirectoryService by roomDirectoryService, - GroupService by groupService, - UserService by userService, - CryptoService by cryptoService, - CacheService by cacheService, - SignOutService by signOutService, - FilterService by filterService, - PushRuleService by pushRuleService, - PushersService by pushersService, - FileService by fileService, - InitialSyncProgressService by initialSyncProgressService { + RoomService by roomService.get(), + RoomDirectoryService by roomDirectoryService.get(), + GroupService by groupService.get(), + UserService by userService.get(), + CryptoService by cryptoService.get(), + CacheService by cacheService.get(), + SignOutService by signOutService.get(), + FilterService by filterService.get(), + PushRuleService by pushRuleService.get(), + PushersService by pushersService.get(), + FileService by fileService.get(), + InitialSyncProgressService by initialSyncProgressService.get() { private var isOpen = false @@ -123,7 +124,7 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se assert(isOpen) stopSync() liveEntityObservers.forEach { it.dispose() } - cryptoService.close() + cryptoService.get().close() isOpen = false } @@ -140,15 +141,15 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se //syncThread.kill() Timber.w("SIGN_OUT: call webservice") - return signOutService.signOut(object : MatrixCallback { + return signOutService.get().signOut(object : MatrixCallback { override fun onSuccess(data: Unit) { Timber.w("SIGN_OUT: call webservice -> SUCCESS: clear cache") // Clear the cache - cacheService.clearCache(object : MatrixCallback { + cacheService.get().clearCache(object : MatrixCallback { override fun onSuccess(data: Unit) { Timber.w("SIGN_OUT: clear cache -> SUCCESS: clear crypto cache") - cryptoService.clearCryptoCache(MatrixCallbackDelegate(callback)) + cryptoService.get().clearCryptoCache(MatrixCallbackDelegate(callback)) WorkManagerUtil.cancelAllWorks(context) } From f007fb04b8f54abb7f0276f41453da93838ed0ad Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 10 Jul 2019 16:40:32 +0200 Subject: [PATCH 3/5] Timeline: clean listeners --- .../internal/session/room/timeline/DefaultTimeline.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt index 3925adf190..87f78224cd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt @@ -43,7 +43,7 @@ import kotlin.collections.ArrayList import kotlin.collections.HashMap -private const val INITIAL_LOAD_SIZE = 20 +private const val INITIAL_LOAD_SIZE = 10 private const val MIN_FETCHING_COUNT = 30 private const val DISPLAY_INDEX_UNKNOWN = Int.MIN_VALUE @@ -216,6 +216,7 @@ internal class DefaultTimeline( backgroundRealm.set(realm) clearUnlinkedEvents(realm) + roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst()?.also { it.sendingTimelineEvents.addChangeListener { _ -> postSnapshot() @@ -242,6 +243,8 @@ internal class DefaultTimeline( Timber.v("Dispose timeline for roomId: $roomId and eventId: $initialEventId") BACKGROUND_HANDLER.post { cancelableBag.cancel() + roomEntity?.sendingTimelineEvents?.removeAllChangeListeners() + eventRelations.removeAllChangeListeners() liveEvents.removeAllChangeListeners() backgroundRealm.getAndSet(null).also { it.close() From 1b95336ad3f9031b15d3b2d8f7014b79df65ecf0 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 10 Jul 2019 19:14:06 +0200 Subject: [PATCH 4/5] EventEntity|TimelineEventEntity : remove UUID as primary key and use auto-incremented Long --- .../api/session/room/timeline/TimelineEvent.kt | 2 +- .../internal/database/helper/ChunkEntityHelper.kt | 3 ++- .../internal/database/helper/RoomEntityHelper.kt | 4 ++-- .../database/helper/TimelineEventEntityHelper.kt | 11 +++++++++++ .../android/internal/database/mapper/EventMapper.kt | 2 +- .../internal/database/mapper/TimelineEventMapper.kt | 13 ------------- .../android/internal/database/model/EventEntity.kt | 3 +-- .../internal/database/model/TimelineEventEntity.kt | 6 +----- .../room/detail/timeline/TimelineEventController.kt | 9 +++++---- .../room/detail/timeline/item/MergedHeaderItem.kt | 2 +- 10 files changed, 25 insertions(+), 30 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt index 3341d87ebd..c56b4f4de5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt @@ -28,7 +28,7 @@ import im.vector.matrix.android.api.session.room.send.SendState */ data class TimelineEvent( val root: Event, - val localId: String, + val localId: Long, val displayIndex: Int, val senderName: String?, val isUniqueDisplayName: Boolean, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt index af8317aaa7..706152931c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt @@ -134,7 +134,8 @@ internal fun ChunkEntity.add(roomId: String, } } - val eventEntity = TimelineEventEntity().also { + val localId = TimelineEventEntity.nextId(realm) + val eventEntity = TimelineEventEntity(localId).also { it.root = event.toEntity(roomId).apply { this.stateIndex = currentStateIndex this.isUnlinked = isUnlinked diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt index c0d01ded2a..01d95eb289 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt @@ -26,7 +26,6 @@ import im.vector.matrix.android.internal.database.query.fastContains import im.vector.matrix.android.internal.extensions.assertIsManaged import im.vector.matrix.android.internal.session.room.membership.RoomMembers - internal fun RoomEntity.deleteOnCascade(chunkEntity: ChunkEntity) { chunks.remove(chunkEntity) chunkEntity.deleteOnCascade() @@ -65,7 +64,8 @@ internal fun RoomEntity.addSendingEvent(event: Event) { } val roomMembers = RoomMembers(realm, roomId) val myUser = roomMembers.get(senderId) - val timelineEventEntity = TimelineEventEntity().also { + val localId = TimelineEventEntity.nextId(realm) + val timelineEventEntity = TimelineEventEntity(localId).also { it.root = eventEntity it.eventId = event.eventId ?: "" it.roomId = roomId diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt index 16a815b4cf..d700fdf37c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/TimelineEventEntityHelper.kt @@ -30,9 +30,11 @@ import im.vector.matrix.android.internal.database.query.prev import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.extensions.assertIsManaged import im.vector.matrix.android.internal.session.room.membership.RoomMembers +import io.realm.Realm import io.realm.RealmList import io.realm.RealmQuery + internal fun TimelineEventEntity.updateSenderData() { assertIsManaged() val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst() ?: return @@ -69,6 +71,15 @@ internal fun TimelineEventEntity.updateSenderData() { this.senderMembershipEvent = senderMembershipEvent } +internal fun TimelineEventEntity.Companion.nextId(realm: Realm): Long{ + val currentIdNum = realm.where(TimelineEventEntity::class.java).max(TimelineEventEntityFields.LOCAL_ID) + return if (currentIdNum == null) { + 1 + } else { + currentIdNum.toLong() + 1 + } +} + private fun RealmList.buildQuery(sender: String, isUnlinked: Boolean): RealmQuery { return where() .equalTo(TimelineEventEntityFields.ROOT.STATE_KEY, sender) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt index 2d0aa9e118..30346f789e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt @@ -35,7 +35,7 @@ internal object EventMapper { val uds = if (event.unsignedData == null) null else MoshiProvider.providesMoshi().adapter(UnsignedData::class.java).toJson(event.unsignedData) val eventEntity = EventEntity() - eventEntity.eventId = event.eventId ?: UUID.randomUUID().toString() + eventEntity.eventId = event.eventId ?: "" eventEntity.roomId = event.roomId ?: roomId eventEntity.content = ContentMapper.map(event.content) val resolvedPrevContent = event.prevContent ?: event.unsignedData?.prevContent diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/TimelineEventMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/TimelineEventMapper.kt index c890436ff8..92cbd4be82 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/TimelineEventMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/TimelineEventMapper.kt @@ -23,15 +23,6 @@ import im.vector.matrix.android.internal.database.model.TimelineEventEntity internal object TimelineEventMapper { - fun map(timelineEvent: TimelineEvent, roomId: String): TimelineEventEntity { - val timelineEventEntity = TimelineEventEntity() - timelineEventEntity.root = timelineEvent.root.toEntity(roomId) - timelineEventEntity.eventId = timelineEvent.root.eventId ?: "" - timelineEventEntity.roomId = roomId - timelineEventEntity.annotations = timelineEvent.annotations?.let { EventAnnotationsSummaryMapper.map(it, roomId) } - return timelineEventEntity - } - fun map(timelineEventEntity: TimelineEventEntity): TimelineEvent { return TimelineEvent( @@ -53,8 +44,4 @@ internal fun TimelineEventEntity.asDomain(): TimelineEvent { return TimelineEventMapper.map(this) } -internal fun TimelineEvent.toEntity(roomId: String): TimelineEventEntity { - return TimelineEventMapper.map(this, roomId) -} - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventEntity.kt index 65ee5aab37..ab10297fe6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventEntity.kt @@ -27,8 +27,7 @@ import io.realm.annotations.LinkingObjects import io.realm.annotations.PrimaryKey import java.util.* -internal open class EventEntity(@PrimaryKey var localId: String = UUID.randomUUID().toString(), - @Index var eventId: String = "", +internal open class EventEntity(@Index var eventId: String = "", @Index var roomId: String = "", @Index var type: String = "", var content: String? = null, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt index 9a467f724e..c811ece154 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt @@ -16,10 +16,6 @@ package im.vector.matrix.android.internal.database.model -import com.squareup.moshi.Types -import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult -import im.vector.matrix.android.internal.database.mapper.ContentMapper -import im.vector.matrix.android.internal.di.MoshiProvider import io.realm.RealmObject import io.realm.RealmResults import io.realm.annotations.Index @@ -28,7 +24,7 @@ import io.realm.annotations.PrimaryKey import java.util.* -internal open class TimelineEventEntity(@PrimaryKey var localId: String = UUID.randomUUID().toString(), +internal open class TimelineEventEntity(var localId: Long = 0, @Index var eventId: String = "", @Index var roomId: String = "", var root: EventEntity? = null, diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineEventController.kt index 0ecfa21639..b6cf00a3c6 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/TimelineEventController.kt @@ -18,6 +18,7 @@ package im.vector.riotx.features.home.room.detail.timeline import android.os.Handler import android.os.Looper +import android.util.LongSparseArray import android.view.View import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListUpdateCallback @@ -82,8 +83,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim fun onUrlLongClicked(url: String): Boolean } - private val collapsedEventIds = linkedSetOf() - private val mergeItemCollapseStates = HashMap() + private val collapsedEventIds = linkedSetOf() + private val mergeItemCollapseStates = HashMap() private val modelCache = arrayListOf() private var currentSnapshot: List = emptyList() @@ -298,7 +299,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim } else { collapsedEventIds.removeAll(mergedEventIds) } - val mergeId = mergedEventIds.joinToString(separator = "_") { it } + val mergeId = mergedEventIds.joinToString(separator = "_") { it.toString() } MergedHeaderItem(isCollapsed, mergeId, mergedData, avatarRenderer) { mergeItemCollapseStates[event.localId] = it requestModelBuild() @@ -329,7 +330,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim } private data class CacheItemData( - val localId: String, + val localId: Long, val eventId: String?, val eventModel: EpoxyModel<*>? = null, val mergedHeaderModel: MergedHeaderItem? = null, diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedHeaderItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedHeaderItem.kt index 8a6c8683ed..0ad13fcfb6 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedHeaderItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/item/MergedHeaderItem.kt @@ -78,7 +78,7 @@ data class MergedHeaderItem(private val isCollapsed: Boolean, } data class Data( - val eventId: String, + val eventId: Long, val userId: String, val memberName: String, val avatarUrl: String? From f493ce44f21f3d2c0826f55ac5d5bc2c93ddffca Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 11 Jul 2019 15:30:01 +0200 Subject: [PATCH 5/5] RealmLiveEntity: passes the results and changeSet instead of filtering as it's more efficient --- .../database/RealmLiveEntityObserver.kt | 22 +++---------------- .../session/group/GroupSummaryUpdater.kt | 16 +++++++++++--- .../room/EventRelationsAggregationUpdater.kt | 19 ++++++++-------- .../session/room/prune/EventsPruner.kt | 20 ++++++++++------- .../session/user/UserEntityUpdater.kt | 14 +++++++----- 5 files changed, 47 insertions(+), 44 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveEntityObserver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveEntityObserver.kt index 8be0e697fb..af842c67da 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveEntityObserver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/RealmLiveEntityObserver.kt @@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.database import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.internal.util.createBackgroundHandler import io.realm.OrderedCollectionChangeSet +import io.realm.OrderedRealmCollectionChangeListener import io.realm.Realm import io.realm.RealmConfiguration import io.realm.RealmObject @@ -33,7 +34,7 @@ internal interface LiveEntityObserver { } internal abstract class RealmLiveEntityObserver(protected val realmConfiguration: RealmConfiguration) - : LiveEntityObserver { + : LiveEntityObserver, OrderedRealmCollectionChangeListener> { private companion object { val BACKGROUND_HANDLER = createBackgroundHandler("LIVE_ENTITY_BACKGROUND") @@ -50,9 +51,7 @@ internal abstract class RealmLiveEntityObserver(protected val r val realm = Realm.getInstance(realmConfiguration) backgroundRealm.set(realm) val queryResults = query.createQuery(realm).findAll() - queryResults.addChangeListener { t, changeSet -> - onChanged(t, changeSet) - } + queryResults.addChangeListener(this) results = AtomicReference(queryResults) } } @@ -73,19 +72,4 @@ internal abstract class RealmLiveEntityObserver(protected val r return isStarted.get() } - private fun onChanged(realmResults: RealmResults, changeSet: OrderedCollectionChangeSet) { - val insertionIndexes = changeSet.insertions - val updateIndexes = changeSet.changes - val deletionIndexes = changeSet.deletions - val inserted = realmResults.filterIndexed { index, _ -> insertionIndexes.contains(index) } - val updated = realmResults.filterIndexed { index, _ -> updateIndexes.contains(index) } - val deleted = realmResults.filterIndexed { index, _ -> deletionIndexes.contains(index) } - processChanges(inserted, updated, deleted) - } - - /** - * Do quick treatment or delegate on a task - */ - protected abstract fun processChanges(inserted: List, updated: List, deleted: List) - } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt index 5418448019..fcfe9f0ade 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt @@ -22,13 +22,20 @@ import androidx.work.WorkManager import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.database.RealmLiveEntityObserver +import im.vector.matrix.android.internal.database.mapper.asDomain +import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.model.GroupEntity import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.di.SessionDatabase +import im.vector.matrix.android.internal.session.room.prune.PruneEventTask +import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.worker.WorkManagerUtil import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder import im.vector.matrix.android.internal.worker.WorkerParamsFactory +import io.realm.OrderedCollectionChangeSet import io.realm.RealmConfiguration +import io.realm.RealmResults +import timber.log.Timber import javax.inject.Inject private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER" @@ -40,8 +47,12 @@ internal class GroupSummaryUpdater @Inject constructor(private val context: Cont override val query = Monarchy.Query { GroupEntity.where(it) } - override fun processChanges(inserted: List, updated: List, deleted: List) { - val newGroupIds = inserted.map { it.groupId } + override fun onChange(results: RealmResults, changeSet: OrderedCollectionChangeSet) { + val newGroupIds = changeSet.insertions + .asSequence() + .mapNotNull { results[it]?.groupId} + .toList() + val getGroupDataWorkerParams = GetGroupDataWorker.Params(credentials.userId, newGroupIds) val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams) @@ -55,5 +66,4 @@ internal class GroupSummaryUpdater @Inject constructor(private val context: Cont .enqueue() } - } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt index 76fea187b3..9d642d3a89 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/EventRelationsAggregationUpdater.kt @@ -25,7 +25,9 @@ import im.vector.matrix.android.internal.database.query.types import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith +import io.realm.OrderedCollectionChangeSet import io.realm.RealmConfiguration +import io.realm.RealmResults import timber.log.Timber import javax.inject.Inject @@ -50,19 +52,18 @@ internal class EventRelationsAggregationUpdater @Inject constructor(@SessionData ) } - override fun processChanges(inserted: List, updated: List, deleted: List) { - Timber.v("EventRelationsAggregationUpdater called with ${inserted.size} insertions") - val domainInserted = inserted - .map { it.asDomain() } + override fun onChange(results: RealmResults, changeSet: OrderedCollectionChangeSet) { + Timber.v("EventRelationsAggregationUpdater called with ${changeSet.insertions.size} insertions") + val insertedDomains = changeSet.insertions + .asSequence() + .mapNotNull { results[it]?.asDomain() } + .toList() val params = EventRelationsAggregationTask.Params( - domainInserted, + insertedDomains, credentials.userId ) - - task.configureWith(params) - .executeBy(taskExecutor) - + task.configureWith(params).executeBy(taskExecutor) } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/EventsPruner.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/EventsPruner.kt index 630332874d..91d3c4e7c8 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/EventsPruner.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/prune/EventsPruner.kt @@ -26,9 +26,12 @@ import im.vector.matrix.android.internal.database.query.types import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.session.SessionScope +import im.vector.matrix.android.internal.session.room.EventRelationsAggregationTask import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith +import io.realm.OrderedCollectionChangeSet import io.realm.RealmConfiguration +import io.realm.RealmResults import timber.log.Timber import javax.inject.Inject @@ -44,18 +47,19 @@ internal class EventsPruner @Inject constructor(@SessionDatabase realmConfigurat override val query = Monarchy.Query { EventEntity.types(it, listOf(EventType.REDACTION)) } - override fun processChanges(inserted: List, updated: List, deleted: List) { - Timber.v("Event pruner called with ${inserted.size} insertions") - val redactionEvents = inserted.map { it.asDomain() } + override fun onChange(results: RealmResults, changeSet: OrderedCollectionChangeSet) { + Timber.v("Event pruner called with ${changeSet.insertions.size} insertions") + + val insertedDomains = changeSet.insertions + .asSequence() + .mapNotNull { results[it]?.asDomain() } + .toList() val params = PruneEventTask.Params( - redactionEvents, + insertedDomains, credentials.userId ) - - pruneEventTask.configureWith(params) - .executeBy(taskExecutor) - + pruneEventTask.configureWith(params).executeBy(taskExecutor) } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityUpdater.kt index 254381f6ac..5c722863c9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityUpdater.kt @@ -22,13 +22,13 @@ import im.vector.matrix.android.internal.database.RealmLiveEntityObserver import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.model.EventEntityFields import im.vector.matrix.android.internal.database.query.types -import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.di.SessionDatabase -import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskThread import im.vector.matrix.android.internal.task.configureWith +import io.realm.OrderedCollectionChangeSet import io.realm.RealmConfiguration +import io.realm.RealmResults import io.realm.Sort import javax.inject.Inject @@ -42,15 +42,19 @@ internal class UserEntityUpdater @Inject constructor(@SessionDatabase realmConfi .types(it, listOf(EventType.STATE_ROOM_MEMBER)) .sort(EventEntityFields.STATE_INDEX, Sort.DESCENDING) .distinct(EventEntityFields.STATE_KEY) - } - override fun processChanges(inserted: List, updated: List, deleted: List) { - val roomMembersEvents = inserted.map { it.eventId } + override fun onChange(results: RealmResults, changeSet: OrderedCollectionChangeSet) { + val roomMembersEvents = changeSet.insertions + .asSequence() + .mapNotNull { results[it]?.eventId } + .toList() + val taskParams = UpdateUserTask.Params(roomMembersEvents) updateUserTask .configureWith(taskParams) .executeOn(TaskThread.IO) .executeBy(taskExecutor) } + } \ No newline at end of file