Merge pull request #5297 from vector-im/feature/fga/fix_bad_realm_usages
Improve usage of realm
This commit is contained in:
commit
79b511b44d
1
changelog.d/5297.misc
Normal file
1
changelog.d/5297.misc
Normal file
@ -0,0 +1 @@
|
|||||||
|
Improve some internal realm usages.
|
@ -16,9 +16,7 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.api.session.room.model
|
package org.matrix.android.sdk.api.session.room.model
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.session.user.model.User
|
|
||||||
|
|
||||||
data class ReadReceipt(
|
data class ReadReceipt(
|
||||||
val user: User,
|
val roomMember: RoomMemberSummary,
|
||||||
val originServerTs: Long
|
val originServerTs: Long
|
||||||
)
|
)
|
||||||
|
@ -19,11 +19,9 @@ import com.zhuinden.monarchy.Monarchy
|
|||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.asCoroutineDispatcher
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Semaphore
|
|
||||||
import kotlinx.coroutines.sync.withPermit
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
@ -37,30 +35,26 @@ internal fun <T> CoroutineScope.asyncTransaction(realmConfiguration: RealmConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val realmSemaphore = Semaphore(1)
|
|
||||||
|
|
||||||
suspend fun <T> awaitTransaction(config: RealmConfiguration, transaction: suspend (realm: Realm) -> T): T {
|
suspend fun <T> awaitTransaction(config: RealmConfiguration, transaction: suspend (realm: Realm) -> T): T {
|
||||||
return realmSemaphore.withPermit {
|
return withContext(Realm.WRITE_EXECUTOR.asCoroutineDispatcher()) {
|
||||||
withContext(Dispatchers.IO) {
|
Realm.getInstance(config).use { bgRealm ->
|
||||||
Realm.getInstance(config).use { bgRealm ->
|
bgRealm.beginTransaction()
|
||||||
bgRealm.beginTransaction()
|
val result: T
|
||||||
val result: T
|
try {
|
||||||
try {
|
val start = System.currentTimeMillis()
|
||||||
val start = System.currentTimeMillis()
|
result = transaction(bgRealm)
|
||||||
result = transaction(bgRealm)
|
if (isActive) {
|
||||||
if (isActive) {
|
bgRealm.commitTransaction()
|
||||||
bgRealm.commitTransaction()
|
val end = System.currentTimeMillis()
|
||||||
val end = System.currentTimeMillis()
|
val time = end - start
|
||||||
val time = end - start
|
Timber.v("Execute transaction in $time millis")
|
||||||
Timber.v("Execute transaction in $time millis")
|
}
|
||||||
}
|
} finally {
|
||||||
} finally {
|
if (bgRealm.isInTransaction) {
|
||||||
if (bgRealm.isInTransaction) {
|
bgRealm.cancelTransaction()
|
||||||
bgRealm.cancelTransaction()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.database.mapper
|
|||||||
import org.matrix.android.sdk.api.session.room.model.ReadReceipt
|
import org.matrix.android.sdk.api.session.room.model.ReadReceipt
|
||||||
import org.matrix.android.sdk.internal.database.RealmSessionProvider
|
import org.matrix.android.sdk.internal.database.RealmSessionProvider
|
||||||
import org.matrix.android.sdk.internal.database.model.ReadReceiptsSummaryEntity
|
import org.matrix.android.sdk.internal.database.model.ReadReceiptsSummaryEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.UserEntity
|
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
|
||||||
import org.matrix.android.sdk.internal.database.query.where
|
import org.matrix.android.sdk.internal.database.query.where
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -29,14 +29,12 @@ internal class ReadReceiptsSummaryMapper @Inject constructor(private val realmSe
|
|||||||
if (readReceiptsSummaryEntity == null) {
|
if (readReceiptsSummaryEntity == null) {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
return realmSessionProvider.withRealm { realm ->
|
val readReceipts = readReceiptsSummaryEntity.readReceipts
|
||||||
val readReceipts = readReceiptsSummaryEntity.readReceipts
|
return readReceipts
|
||||||
readReceipts
|
.mapNotNull {
|
||||||
.mapNotNull {
|
val roomMember = RoomMemberSummaryEntity.where(readReceiptsSummaryEntity.realm, roomId = it.roomId, userId = it.userId).findFirst()
|
||||||
val user = UserEntity.where(realm, it.userId).findFirst()
|
?: return@mapNotNull null
|
||||||
?: return@mapNotNull null
|
ReadReceipt(roomMember.asDomain(), it.originServerTs.toLong())
|
||||||
ReadReceipt(user.asDomain(), it.originServerTs.toLong())
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ internal class TimelineEventMapper @Inject constructor(private val readReceiptsS
|
|||||||
),
|
),
|
||||||
readReceipts = readReceipts
|
readReceipts = readReceipts
|
||||||
?.distinctBy {
|
?.distinctBy {
|
||||||
it.user
|
it.roomMember
|
||||||
}?.sortedByDescending {
|
}?.sortedByDescending {
|
||||||
it.originServerTs
|
it.originServerTs
|
||||||
}.orEmpty()
|
}.orEmpty()
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
package org.matrix.android.sdk.internal.session.room.create
|
package org.matrix.android.sdk.internal.session.room.create
|
||||||
|
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
import io.realm.Realm
|
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
import kotlinx.coroutines.TimeoutCancellationException
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
import org.matrix.android.sdk.api.failure.Failure
|
import org.matrix.android.sdk.api.failure.Failure
|
||||||
@ -28,6 +27,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership
|
|||||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
||||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
||||||
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
|
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
|
||||||
|
import org.matrix.android.sdk.internal.database.awaitTransaction
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
import org.matrix.android.sdk.internal.database.query.where
|
import org.matrix.android.sdk.internal.database.query.where
|
||||||
@ -105,7 +105,7 @@ internal class DefaultCreateRoomTask @Inject constructor(
|
|||||||
throw CreateRoomFailure.CreatedWithTimeout(roomId)
|
throw CreateRoomFailure.CreatedWithTimeout(roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
Realm.getInstance(realmConfiguration).executeTransactionAsync {
|
awaitTransaction(realmConfiguration) {
|
||||||
RoomSummaryEntity.where(it, roomId).findFirst()?.lastActivityTime = System.currentTimeMillis()
|
RoomSummaryEntity.where(it, roomId).findFirst()?.lastActivityTime = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.room.membership.joining
|
package org.matrix.android.sdk.internal.session.room.membership.joining
|
||||||
|
|
||||||
import io.realm.Realm
|
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.RealmConfiguration
|
||||||
import kotlinx.coroutines.TimeoutCancellationException
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||||
@ -24,6 +23,7 @@ import org.matrix.android.sdk.api.session.room.failure.JoinRoomFailure
|
|||||||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
|
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
|
||||||
|
import org.matrix.android.sdk.internal.database.awaitTransaction
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
import org.matrix.android.sdk.internal.database.query.where
|
import org.matrix.android.sdk.internal.database.query.where
|
||||||
@ -89,11 +89,9 @@ internal class DefaultJoinRoomTask @Inject constructor(
|
|||||||
} catch (exception: TimeoutCancellationException) {
|
} catch (exception: TimeoutCancellationException) {
|
||||||
throw JoinRoomFailure.JoinedWithTimeout
|
throw JoinRoomFailure.JoinedWithTimeout
|
||||||
}
|
}
|
||||||
|
awaitTransaction(realmConfiguration) {
|
||||||
Realm.getInstance(realmConfiguration).executeTransactionAsync {
|
|
||||||
RoomSummaryEntity.where(it, roomId).findFirst()?.lastActivityTime = System.currentTimeMillis()
|
RoomSummaryEntity.where(it, roomId).findFirst()?.lastActivityTime = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
|
|
||||||
setReadMarkers(roomId)
|
setReadMarkers(roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,8 +90,7 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
private val timelineEventsChangeListener =
|
private val timelineEventsChangeListener =
|
||||||
OrderedRealmCollectionChangeListener { results: RealmResults<TimelineEventEntity>, changeSet: OrderedCollectionChangeSet ->
|
OrderedRealmCollectionChangeListener { results: RealmResults<TimelineEventEntity>, changeSet: OrderedCollectionChangeSet ->
|
||||||
Timber.v("on timeline events chunk update")
|
Timber.v("on timeline events chunk update")
|
||||||
val frozenResults = results.freeze()
|
handleDatabaseChangeSet(results, changeSet)
|
||||||
handleDatabaseChangeSet(frozenResults, changeSet)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var timelineEventEntities: RealmResults<TimelineEventEntity> = chunkEntity.sortedTimelineEvents(timelineSettings.rootThreadEventId)
|
private var timelineEventEntities: RealmResults<TimelineEventEntity> = chunkEntity.sortedTimelineEvents(timelineSettings.rootThreadEventId)
|
||||||
@ -287,7 +286,7 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
* @return the number of events loaded. If we are in a thread timeline it also returns
|
* @return the number of events loaded. If we are in a thread timeline it also returns
|
||||||
* whether or not we reached the end/root message
|
* whether or not we reached the end/root message
|
||||||
*/
|
*/
|
||||||
private suspend fun loadFromStorage(count: Int, direction: Timeline.Direction): LoadedFromStorage {
|
private fun loadFromStorage(count: Int, direction: Timeline.Direction): LoadedFromStorage {
|
||||||
val displayIndex = getNextDisplayIndex(direction) ?: return LoadedFromStorage()
|
val displayIndex = getNextDisplayIndex(direction) ?: return LoadedFromStorage()
|
||||||
val baseQuery = timelineEventEntities.where()
|
val baseQuery = timelineEventEntities.where()
|
||||||
|
|
||||||
@ -428,10 +427,10 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
* This method is responsible for managing insertions and updates of events on this chunk.
|
* This method is responsible for managing insertions and updates of events on this chunk.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private fun handleDatabaseChangeSet(frozenResults: RealmResults<TimelineEventEntity>, changeSet: OrderedCollectionChangeSet) {
|
private fun handleDatabaseChangeSet(results: RealmResults<TimelineEventEntity>, changeSet: OrderedCollectionChangeSet) {
|
||||||
val insertions = changeSet.insertionRanges
|
val insertions = changeSet.insertionRanges
|
||||||
for (range in insertions) {
|
for (range in insertions) {
|
||||||
val newItems = frozenResults
|
val newItems = results
|
||||||
.subList(range.startIndex, range.startIndex + range.length)
|
.subList(range.startIndex, range.startIndex + range.length)
|
||||||
.map { it.buildAndDecryptIfNeeded() }
|
.map { it.buildAndDecryptIfNeeded() }
|
||||||
builtEventsIndexes.entries.filter { it.value >= range.startIndex }.forEach { it.setValue(it.value + range.length) }
|
builtEventsIndexes.entries.filter { it.value >= range.startIndex }.forEach { it.setValue(it.value + range.length) }
|
||||||
@ -447,7 +446,7 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
val modifications = changeSet.changeRanges
|
val modifications = changeSet.changeRanges
|
||||||
for (range in modifications) {
|
for (range in modifications) {
|
||||||
for (modificationIndex in (range.startIndex until range.startIndex + range.length)) {
|
for (modificationIndex in (range.startIndex until range.startIndex + range.length)) {
|
||||||
val updatedEntity = frozenResults[modificationIndex] ?: continue
|
val updatedEntity = results[modificationIndex] ?: continue
|
||||||
try {
|
try {
|
||||||
builtEvents[modificationIndex] = updatedEntity.buildAndDecryptIfNeeded()
|
builtEvents[modificationIndex] = updatedEntity.buildAndDecryptIfNeeded()
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
@ -461,17 +460,16 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getNextDisplayIndex(direction: Timeline.Direction): Int? {
|
private fun getNextDisplayIndex(direction: Timeline.Direction): Int? {
|
||||||
val frozenTimelineEvents = timelineEventEntities.freeze()
|
if (timelineEventEntities.isEmpty()) {
|
||||||
if (frozenTimelineEvents.isEmpty()) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return if (builtEvents.isEmpty()) {
|
return if (builtEvents.isEmpty()) {
|
||||||
if (initialEventId != null) {
|
if (initialEventId != null) {
|
||||||
frozenTimelineEvents.where().equalTo(TimelineEventEntityFields.EVENT_ID, initialEventId).findFirst()?.displayIndex
|
timelineEventEntities.where().equalTo(TimelineEventEntityFields.EVENT_ID, initialEventId).findFirst()?.displayIndex
|
||||||
} else if (direction == Timeline.Direction.BACKWARDS) {
|
} else if (direction == Timeline.Direction.BACKWARDS) {
|
||||||
frozenTimelineEvents.first(null)?.displayIndex
|
timelineEventEntities.first(null)?.displayIndex
|
||||||
} else {
|
} else {
|
||||||
frozenTimelineEvents.last(null)?.displayIndex
|
timelineEventEntities.last(null)?.displayIndex
|
||||||
}
|
}
|
||||||
} else if (direction == Timeline.Direction.FORWARDS) {
|
} else if (direction == Timeline.Direction.FORWARDS) {
|
||||||
builtEvents.first().displayIndex + 1
|
builtEvents.first().displayIndex + 1
|
||||||
|
@ -516,7 +516,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec
|
|||||||
val event = itr.previous()
|
val event = itr.previous()
|
||||||
timelineEventsGroups.addOrIgnore(event)
|
timelineEventsGroups.addOrIgnore(event)
|
||||||
val currentReadReceipts = ArrayList(event.readReceipts).filter {
|
val currentReadReceipts = ArrayList(event.readReceipts).filter {
|
||||||
it.user.userId != session.myUserId
|
it.roomMember.userId != session.myUserId
|
||||||
}
|
}
|
||||||
if (timelineEventVisibilityHelper.shouldShowEvent(
|
if (timelineEventVisibilityHelper.shouldShowEvent(
|
||||||
timelineEvent = event,
|
timelineEvent = event,
|
||||||
|
@ -36,7 +36,7 @@ class ReadReceiptsItemFactory @Inject constructor(private val avatarRenderer: Av
|
|||||||
}
|
}
|
||||||
val readReceiptsData = readReceipts
|
val readReceiptsData = readReceipts
|
||||||
.map {
|
.map {
|
||||||
ReadReceiptData(it.user.userId, it.user.avatarUrl, it.user.displayName, it.originServerTs)
|
ReadReceiptData(it.roomMember.userId, it.roomMember.avatarUrl, it.roomMember.displayName, it.originServerTs)
|
||||||
}
|
}
|
||||||
.toList()
|
.toList()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user