From 93ce0cc5e95e0f39fe8e9888ab0503f99345ec7c Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 3 Jul 2019 14:48:45 +0200 Subject: [PATCH] Realm: avoid using monarchy thread for custom work --- .../database/RealmLiveEntityObserver.kt | 21 +++++++++++--- .../internal/session/DefaultSession.kt | 27 +++++++---------- .../session/group/GroupSummaryUpdater.kt | 4 ++- .../room/EventRelationsAggregationUpdater.kt | 6 ++-- .../session/room/prune/EventsPruner.kt | 6 ++-- .../session/room/timeline/DefaultTimeline.kt | 11 +++---- .../session/user/UserEntityUpdater.kt | 6 ++-- .../matrix/android/internal/util/Handler.kt | 29 +++++++++++++++++++ 8 files changed, 75 insertions(+), 35 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Handler.kt 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 3f3c9bde..8be0e697 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 @@ -17,7 +17,10 @@ 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.Realm +import io.realm.RealmConfiguration import io.realm.RealmObject import io.realm.RealmResults import java.util.concurrent.atomic.AtomicBoolean @@ -29,17 +32,24 @@ internal interface LiveEntityObserver { fun isStarted(): Boolean } -internal abstract class RealmLiveEntityObserver(protected val monarchy: Monarchy) +internal abstract class RealmLiveEntityObserver(protected val realmConfiguration: RealmConfiguration) : LiveEntityObserver { + private companion object { + val BACKGROUND_HANDLER = createBackgroundHandler("LIVE_ENTITY_BACKGROUND") + } + protected abstract val query: Monarchy.Query private val isStarted = AtomicBoolean(false) + private val backgroundRealm = AtomicReference() private lateinit var results: AtomicReference> override fun start() { if (isStarted.compareAndSet(false, true)) { - monarchy.postToMonarchyThread { - val queryResults = query.createQuery(it).findAll() + BACKGROUND_HANDLER.post { + val realm = Realm.getInstance(realmConfiguration) + backgroundRealm.set(realm) + val queryResults = query.createQuery(realm).findAll() queryResults.addChangeListener { t, changeSet -> onChanged(t, changeSet) } @@ -50,8 +60,11 @@ internal abstract class RealmLiveEntityObserver(protected val m override fun dispose() { if (isStarted.compareAndSet(true, false)) { - monarchy.postToMonarchyThread { + BACKGROUND_HANDLER.post { results.getAndSet(null).removeAllChangeListeners() + backgroundRealm.getAndSet(null).also { + it.close() + } } } } 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 e98b459a..32311853 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 @@ -50,7 +50,6 @@ import javax.inject.Inject internal class DefaultSession @Inject constructor(override val sessionParams: SessionParams, private val context: Context, private val liveEntityObservers: Set<@JvmSuppressWildcards LiveEntityObserver>, - private val monarchy: Monarchy, private val sessionListeners: SessionListeners, private val roomService: RoomService, private val roomDirectoryService: RoomDirectoryService, @@ -66,16 +65,16 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se private val contentUrlResolver: ContentUrlResolver, private val contentUploadProgressTracker: ContentUploadStateTracker) : 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 { + 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 { private var isOpen = false @@ -85,9 +84,6 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se assertMainThread() assert(!isOpen) isOpen = true - if (!monarchy.isMonarchyThreadOpen) { - monarchy.openManually() - } liveEntityObservers.forEach { it.start() } } @@ -123,9 +119,6 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se stopSync() liveEntityObservers.forEach { it.dispose() } cryptoService.close() - if (monarchy.isMonarchyThreadOpen) { - monarchy.closeManually() - } isOpen = false } 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 43bad2bc..a2ca8503 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 @@ -27,14 +27,16 @@ import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.internal.database.RealmLiveEntityObserver 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.worker.WorkerParamsFactory +import io.realm.RealmConfiguration import javax.inject.Inject private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER" internal class GroupSummaryUpdater @Inject constructor(private val context: Context, private val credentials: Credentials, - monarchy: Monarchy) : RealmLiveEntityObserver(monarchy) { + @SessionDatabase realmConfiguration: RealmConfiguration) : RealmLiveEntityObserver(realmConfiguration) { override val query = Monarchy.Query { GroupEntity.where(it) } 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 23318887..76fea187 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 @@ -22,8 +22,10 @@ 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.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.RealmConfiguration import timber.log.Timber import javax.inject.Inject @@ -33,11 +35,11 @@ import javax.inject.Inject * The summaries can then be extracted and added (as a decoration) to a TimelineEvent for final display. */ -internal class EventRelationsAggregationUpdater @Inject constructor(monarchy: Monarchy, +internal class EventRelationsAggregationUpdater @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration, private val credentials: Credentials, private val task: EventRelationsAggregationTask, private val taskExecutor: TaskExecutor) : - RealmLiveEntityObserver(monarchy) { + RealmLiveEntityObserver(realmConfiguration) { override val query = Monarchy.Query { EventEntity.types(it, listOf( 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 456cbde7..53b72fa4 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 @@ -23,9 +23,11 @@ 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.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.configureWith +import io.realm.RealmConfiguration import timber.log.Timber import javax.inject.Inject @@ -33,11 +35,11 @@ import javax.inject.Inject * Listens to the database for the insertion of any redaction event. * As it will actually delete the content, it should be called last in the list of listener. */ -internal class EventsPruner @Inject constructor(monarchy: Monarchy, +internal class EventsPruner @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration, private val credentials: Credentials, private val pruneEventTask: PruneEventTask, private val taskExecutor: TaskExecutor) : - RealmLiveEntityObserver(monarchy) { + RealmLiveEntityObserver(realmConfiguration) { override val query = Monarchy.Query { EventEntity.where(it, type = EventType.REDACTION) } 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 34de3708..8f5c62cd 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 @@ -16,9 +16,6 @@ package im.vector.matrix.android.internal.session.room.timeline -import android.os.Handler -import android.os.HandlerThread -import android.os.Looper import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.events.model.EventType @@ -43,6 +40,8 @@ import im.vector.matrix.android.internal.database.query.whereInRoom import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.util.Debouncer +import im.vector.matrix.android.internal.util.createBackgroundHandler +import im.vector.matrix.android.internal.util.createUIHandler import io.realm.OrderedCollectionChangeSet import io.realm.OrderedRealmCollectionChangeListener import io.realm.Realm @@ -75,9 +74,7 @@ internal class DefaultTimeline( ) : Timeline { private companion object { - val BACKGROUND_HANDLER = Handler( - HandlerThread("TIMELINE_DB_THREAD").apply { start() }.looper - ) + val BACKGROUND_HANDLER = createBackgroundHandler("TIMELINE_DB_THREAD") } override var listener: Timeline.Listener? = null @@ -90,7 +87,7 @@ internal class DefaultTimeline( private val isStarted = AtomicBoolean(false) private val isReady = AtomicBoolean(false) - private val mainHandler = Handler(Looper.getMainLooper()) + private val mainHandler = createUIHandler() private val backgroundRealm = AtomicReference() private val cancelableBag = CancelableBag() private val debouncer = Debouncer(mainHandler) 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 b1935e41..bfb9786d 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,17 +22,19 @@ 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.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.RealmConfiguration import io.realm.Sort import javax.inject.Inject -internal class UserEntityUpdater @Inject constructor(monarchy: Monarchy, +internal class UserEntityUpdater @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration, private val updateUserTask: UpdateUserTask, private val taskExecutor: TaskExecutor) - : RealmLiveEntityObserver(monarchy) { + : RealmLiveEntityObserver(realmConfiguration) { override val query = Monarchy.Query { EventEntity diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Handler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Handler.kt new file mode 100644 index 00000000..51fdbfe2 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/util/Handler.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.util + +import android.os.Handler +import android.os.HandlerThread +import android.os.Looper + +fun createBackgroundHandler(name: String): Handler = Handler( + HandlerThread(name).apply { start() }.looper +) + +fun createUIHandler(): Handler = Handler( + Looper.getMainLooper() +) \ No newline at end of file