forked from GitHub-Mirror/riotX-android
Adding events to chunk is now faster by using query to check contains and no primary key
This commit is contained in:
parent
7ba67d6c2b
commit
e942b54b56
@ -0,0 +1,18 @@
|
||||
package im.vector.matrix.android.internal.database.helper
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.internal.database.mapper.asEntity
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.query.fastContains
|
||||
|
||||
fun List<Event>.addManagedToChunk(chunkEntity: ChunkEntity) {
|
||||
if (!chunkEntity.isManaged) {
|
||||
throw IllegalStateException("Chunk entity should be managed to use fast contains")
|
||||
}
|
||||
this.forEach { event ->
|
||||
val eventEntity = event.asEntity()
|
||||
if (!chunkEntity.events.fastContains(eventEntity)) {
|
||||
chunkEntity.events.add(eventEntity)
|
||||
}
|
||||
}
|
||||
}
|
@ -2,10 +2,10 @@ package im.vector.matrix.android.internal.database.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.RealmResults
|
||||
import io.realm.annotations.Index
|
||||
import io.realm.annotations.LinkingObjects
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
open class EventEntity(@PrimaryKey var eventId: String = "",
|
||||
open class EventEntity(@Index var eventId: String = "",
|
||||
var type: String = "",
|
||||
var content: String = "",
|
||||
var prevContent: String? = null,
|
||||
|
@ -5,6 +5,7 @@ import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.Sort
|
||||
|
||||
@ -37,6 +38,10 @@ fun RealmQuery<EventEntity>.last(from: Long? = null): EventEntity? {
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
fun RealmList<EventEntity>.fastContains(eventEntity: EventEntity): Boolean {
|
||||
return this.where().equalTo("eventId", eventEntity.eventId).findFirst() != null
|
||||
}
|
||||
|
||||
fun EventEntity.Companion.findAllRoomMembers(realm: Realm, roomId: String): Map<String, RoomMember> {
|
||||
return EventEntity
|
||||
.where(realm, roomId, EventType.STATE_ROOM_MEMBER)
|
||||
|
@ -14,6 +14,7 @@ import im.vector.matrix.android.internal.database.query.last
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.room.members.RoomDisplayNameResolver
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
@ -46,28 +47,28 @@ internal class RoomSummaryUpdater(private val monarchy: Monarchy,
|
||||
val rooms = changeSet.realmResults.map { it.asDomain() }
|
||||
val indexesToUpdate = changeSet.orderedCollectionChangeSet.changes + changeSet.orderedCollectionChangeSet.insertions
|
||||
monarchy.writeAsync { realm ->
|
||||
manageRoomList(realm, rooms, indexesToUpdate)
|
||||
insertRoomList(realm, rooms, indexesToUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun manageRoomList(realm: Realm, rooms: List<Room>, indexes: IntArray) {
|
||||
private fun insertRoomList(realm: Realm, rooms: List<Room>, indexes: IntArray) {
|
||||
indexes.forEach {
|
||||
val room = rooms[it]
|
||||
try {
|
||||
manageRoom(realm, room)
|
||||
insertRoom(realm, room)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "An error occured when updating room summaries")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun manageRoom(realm: Realm, room: Room?) {
|
||||
private fun insertRoom(realm: Realm, room: Room?) {
|
||||
if (room == null) {
|
||||
return
|
||||
}
|
||||
val roomSummary = RoomSummaryEntity.where(realm, room.roomId).findFirst()
|
||||
?: RoomSummaryEntity(room.roomId)
|
||||
?: realm.createObject(room.roomId)
|
||||
|
||||
val lastMessageEvent = EventEntity.where(realm, room.roomId, EventType.MESSAGE).last()
|
||||
val lastTopicEvent = EventEntity.where(realm, room.roomId, EventType.STATE_ROOM_TOPIC).last()?.asDomain()
|
||||
|
@ -61,13 +61,17 @@ internal class LoadRoomMembersRequest(private val roomAPI: RoomAPI,
|
||||
private fun insertInDb(response: RoomMembersResponse, roomId: String) {
|
||||
monarchy.runTransactionSync { realm ->
|
||||
// We ignore all the already known members
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||
?: throw IllegalStateException("You shouldn't use this method without a room")
|
||||
|
||||
val roomMembers = EventEntity.findAllRoomMembers(realm, roomId)
|
||||
val eventsToInsert = response.roomMemberEvents.filter { !roomMembers.containsKey(it.stateKey) }
|
||||
stateEventsChunkHandler.handle(realm, roomId, eventsToInsert)
|
||||
|
||||
RoomEntity
|
||||
.where(realm, roomId).findFirst()
|
||||
?.let { it.areAllMembersLoaded = true }
|
||||
val chunk = stateEventsChunkHandler.handle(realm, roomId, eventsToInsert)
|
||||
if (!roomEntity.chunks.contains(chunk)) {
|
||||
roomEntity.chunks.add(chunk)
|
||||
}
|
||||
roomEntity.areAllMembersLoaded = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,6 @@ import im.vector.matrix.android.api.session.events.model.Event
|
||||
data class TokenChunkEvent(
|
||||
@Json(name = "start") val nextToken: String? = null,
|
||||
@Json(name = "end") val prevToken: String? = null,
|
||||
@Json(name = "chunk") val chunk: List<Event> = emptyList(),
|
||||
@Json(name = "chunk") val events: List<Event> = emptyList(),
|
||||
@Json(name = "state") val stateEvents: List<Event> = emptyList()
|
||||
)
|
@ -7,9 +7,10 @@ import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.database.mapper.asEntity
|
||||
import im.vector.matrix.android.internal.database.helper.addManagedToChunk
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.query.fastContains
|
||||
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
|
||||
import im.vector.matrix.android.internal.database.query.findWithNextToken
|
||||
import im.vector.matrix.android.internal.database.query.findWithPrevToken
|
||||
@ -22,6 +23,7 @@ import im.vector.matrix.android.internal.session.room.model.TokenChunkEvent
|
||||
import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
|
||||
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import io.realm.kotlin.createObject
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -73,15 +75,16 @@ class PaginationRequest(private val roomAPI: RoomAPI,
|
||||
private fun insertInDb(receivedChunk: TokenChunkEvent, roomId: String) {
|
||||
monarchy.runTransactionSync { realm ->
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||
?: return@runTransactionSync
|
||||
?: throw IllegalStateException("You shouldn't use this method without a room")
|
||||
|
||||
val currentChunk = ChunkEntity.findWithPrevToken(realm, roomId, receivedChunk.nextToken)
|
||||
?: ChunkEntity()
|
||||
?: realm.createObject()
|
||||
|
||||
currentChunk.prevToken = receivedChunk.prevToken
|
||||
|
||||
val prevChunk = ChunkEntity.findWithNextToken(realm, roomId, receivedChunk.prevToken)
|
||||
|
||||
val eventIds = receivedChunk.chunk.filter { it.eventId != null }.map { it.eventId!! }
|
||||
val eventIds = receivedChunk.events.filter { it.eventId != null }.map { it.eventId!! }
|
||||
val chunksOverlapped = ChunkEntity.findAllIncludingEvents(realm, eventIds)
|
||||
val hasOverlapped = chunksOverlapped.isNotEmpty()
|
||||
|
||||
@ -90,14 +93,7 @@ class PaginationRequest(private val roomAPI: RoomAPI,
|
||||
roomEntity.chunks.add(stateEventsChunk)
|
||||
}
|
||||
|
||||
receivedChunk.chunk.forEach { event ->
|
||||
val eventEntity = event.asEntity().let {
|
||||
realm.copyToRealmOrUpdate(it)
|
||||
}
|
||||
if (!currentChunk.events.contains(eventEntity)) {
|
||||
currentChunk.events.add(eventEntity)
|
||||
}
|
||||
}
|
||||
receivedChunk.events.addManagedToChunk(currentChunk)
|
||||
|
||||
if (prevChunk != null) {
|
||||
currentChunk.events.addAll(prevChunk.events)
|
||||
@ -106,7 +102,7 @@ class PaginationRequest(private val roomAPI: RoomAPI,
|
||||
} else if (hasOverlapped) {
|
||||
chunksOverlapped.forEach { overlapped ->
|
||||
overlapped.events.forEach { event ->
|
||||
if (!currentChunk.events.contains(event)) {
|
||||
if (!currentChunk.events.fastContains(event)) {
|
||||
currentChunk.events.add(event)
|
||||
}
|
||||
}
|
||||
|
@ -17,21 +17,22 @@ class ReadReceiptHandler {
|
||||
if (content == null) {
|
||||
return emptyList()
|
||||
}
|
||||
return content
|
||||
val readReceipts = content
|
||||
.flatMap { (eventId, receiptDict) ->
|
||||
receiptDict
|
||||
.filterKeys { it == "m.read" }
|
||||
.flatMap { (_, userIdsDict) ->
|
||||
userIdsDict.map { (userId, paramsDict) ->
|
||||
val ts = paramsDict.filterKeys { it == "ts" }
|
||||
.values
|
||||
.firstOrNull() ?: 0.0
|
||||
.values
|
||||
.firstOrNull() ?: 0.0
|
||||
val primaryKey = roomId + userId
|
||||
ReadReceiptEntity(primaryKey, userId, eventId, roomId, ts)
|
||||
}
|
||||
}
|
||||
}
|
||||
.apply { realm.insertOrUpdate(this) }
|
||||
realm.insertOrUpdate(readReceipts)
|
||||
return readReceipts
|
||||
}
|
||||
|
||||
}
|
@ -4,7 +4,7 @@ import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
import im.vector.matrix.android.internal.database.mapper.asEntity
|
||||
import im.vector.matrix.android.internal.database.helper.addManagedToChunk
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
@ -16,6 +16,7 @@ import im.vector.matrix.android.internal.session.sync.model.RoomSync
|
||||
import im.vector.matrix.android.internal.session.sync.model.RoomSyncEphemeral
|
||||
import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
|
||||
|
||||
internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
@ -30,12 +31,12 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
|
||||
fun handleRoomSync(handlingStrategy: HandlingStrategy) {
|
||||
monarchy.runTransactionSync { realm ->
|
||||
val roomEntities = when (handlingStrategy) {
|
||||
is HandlingStrategy.JOINED -> handlingStrategy.data.map { handleJoinedRoom(realm, it.key, it.value) }
|
||||
val rooms = when (handlingStrategy) {
|
||||
is HandlingStrategy.JOINED -> handlingStrategy.data.map { handleJoinedRoom(realm, it.key, it.value) }
|
||||
is HandlingStrategy.INVITED -> handlingStrategy.data.map { handleInvitedRoom(realm, it.key, it.value) }
|
||||
is HandlingStrategy.LEFT -> handlingStrategy.data.map { handleLeftRoom(it.key, it.value) }
|
||||
is HandlingStrategy.LEFT -> handlingStrategy.data.map { handleLeftRoom(it.key, it.value) }
|
||||
}
|
||||
realm.insertOrUpdate(roomEntities)
|
||||
realm.insertOrUpdate(rooms)
|
||||
}
|
||||
|
||||
if (handlingStrategy is HandlingStrategy.JOINED) {
|
||||
@ -53,13 +54,13 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
roomId: String,
|
||||
roomSync: RoomSync): RoomEntity {
|
||||
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: RoomEntity(roomId)
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||
?: RoomEntity(roomId)
|
||||
|
||||
if (roomEntity.membership == MyMembership.INVITED) {
|
||||
roomEntity.chunks.deleteAllFromRealm()
|
||||
}
|
||||
|
||||
|
||||
roomEntity.membership = MyMembership.JOINED
|
||||
|
||||
if (roomSync.summary != null) {
|
||||
@ -72,7 +73,7 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
}
|
||||
}
|
||||
if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) {
|
||||
val chunkEntity = handleListOfEvent(realm, roomId, roomSync.timeline.events, roomSync.timeline.prevToken, isLimited = roomSync.timeline.limited)
|
||||
val chunkEntity = handleTimelineEvents(realm, roomId, roomSync.timeline.events, roomSync.timeline.prevToken, isLimited = roomSync.timeline.limited)
|
||||
if (!roomEntity.chunks.contains(chunkEntity)) {
|
||||
roomEntity.chunks.add(chunkEntity)
|
||||
}
|
||||
@ -88,7 +89,7 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
roomEntity.roomId = roomId
|
||||
roomEntity.membership = MyMembership.INVITED
|
||||
if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) {
|
||||
val chunkEntity = handleListOfEvent(realm, roomId, roomSync.inviteState.events)
|
||||
val chunkEntity = handleTimelineEvents(realm, roomId, roomSync.inviteState.events)
|
||||
if (!roomEntity.chunks.contains(chunkEntity)) {
|
||||
roomEntity.chunks.add(chunkEntity)
|
||||
}
|
||||
@ -110,7 +111,7 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
roomSummary: RoomSyncSummary) {
|
||||
|
||||
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst()
|
||||
?: RoomSummaryEntity(roomId)
|
||||
?: RoomSummaryEntity(roomId)
|
||||
|
||||
if (roomSummary.heroes.isNotEmpty()) {
|
||||
roomSummaryEntity.heroes.clear()
|
||||
@ -125,30 +126,22 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
realm.insertOrUpdate(roomSummaryEntity)
|
||||
}
|
||||
|
||||
private fun handleListOfEvent(realm: Realm,
|
||||
roomId: String,
|
||||
eventList: List<Event>,
|
||||
prevToken: String? = null,
|
||||
nextToken: String? = null,
|
||||
isLimited: Boolean = true): ChunkEntity {
|
||||
private fun handleTimelineEvents(realm: Realm,
|
||||
roomId: String,
|
||||
eventList: List<Event>,
|
||||
prevToken: String? = null,
|
||||
nextToken: String? = null,
|
||||
isLimited: Boolean = true): ChunkEntity {
|
||||
|
||||
val chunkEntity = if (!isLimited) {
|
||||
ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
|
||||
} else {
|
||||
val eventIds = eventList.filter { it.eventId != null }.map { it.eventId!! }
|
||||
ChunkEntity.findAllIncludingEvents(realm, eventIds).firstOrNull()
|
||||
} ?: ChunkEntity().apply { this.prevToken = prevToken }
|
||||
} ?: realm.createObject<ChunkEntity>().apply { this.prevToken = prevToken }
|
||||
|
||||
chunkEntity.nextToken = nextToken
|
||||
|
||||
eventList.forEach { event ->
|
||||
val eventEntity = event.asEntity().let {
|
||||
realm.copyToRealmOrUpdate(it)
|
||||
}
|
||||
if (!chunkEntity.events.contains(eventEntity)) {
|
||||
chunkEntity.events.add(eventEntity)
|
||||
}
|
||||
}
|
||||
eventList.addManagedToChunk(chunkEntity)
|
||||
return chunkEntity
|
||||
}
|
||||
|
||||
|
@ -2,27 +2,27 @@ package im.vector.matrix.android.internal.session.sync
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.internal.database.DBConstants
|
||||
import im.vector.matrix.android.internal.database.mapper.asEntity
|
||||
import im.vector.matrix.android.internal.database.helper.addManagedToChunk
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.query.findWithNextToken
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
|
||||
class StateEventsChunkHandler {
|
||||
|
||||
fun handle(realm: Realm, roomId: String, stateEvents: List<Event>): ChunkEntity {
|
||||
val chunkEntity = ChunkEntity.findWithNextToken(realm, roomId, DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||
?: ChunkEntity(prevToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN, nextToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||
?: realm.createObject<ChunkEntity>()
|
||||
.apply {
|
||||
prevToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN
|
||||
nextToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN
|
||||
}
|
||||
|
||||
stateEvents.forEach { event ->
|
||||
val eventEntity = event.asEntity().let {
|
||||
realm.copyToRealmOrUpdate(it)
|
||||
}
|
||||
if (!chunkEntity.events.contains(eventEntity)) {
|
||||
chunkEntity.events.add(eventEntity)
|
||||
}
|
||||
}
|
||||
stateEvents.addManagedToChunk(chunkEntity)
|
||||
return chunkEntity
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user