Timeline: remove use of isUnlinked method as it slows down the insertion a lot

This commit is contained in:
ganfra 2019-12-31 12:57:45 +01:00
parent 787908287c
commit e32d242e38
7 changed files with 25 additions and 29 deletions

View file

@ -30,15 +30,6 @@ import im.vector.matrix.android.internal.session.room.timeline.PaginationDirecti
import io.realm.Sort
import io.realm.kotlin.createObject
// By default if a chunk is empty we consider it unlinked
internal fun ChunkEntity.isUnlinked(): Boolean {
assertIsManaged()
return timelineEvents.where()
.equalTo(TimelineEventEntityFields.ROOT.IS_UNLINKED, false)
.findAll()
.isEmpty()
}
internal fun ChunkEntity.deleteOnCascade() {
assertIsManaged()
this.timelineEvents.deleteAllFromRealm()
@ -49,9 +40,8 @@ internal fun ChunkEntity.merge(roomId: String,
chunkToMerge: ChunkEntity,
direction: PaginationDirection): List<TimelineEventEntity> {
assertIsManaged()
val isChunkToMergeUnlinked = chunkToMerge.isUnlinked()
val isCurrentChunkUnlinked = this.isUnlinked()
val isUnlinked = isCurrentChunkUnlinked && isChunkToMergeUnlinked
val isChunkToMergeUnlinked = chunkToMerge.isUnlinked
val isCurrentChunkUnlinked = isUnlinked
if (isCurrentChunkUnlinked && !isChunkToMergeUnlinked) {
this.timelineEvents.forEach { it.root?.isUnlinked = false }
@ -69,15 +59,15 @@ internal fun ChunkEntity.merge(roomId: String,
return eventsToMerge
.mapNotNull {
val event = it.root?.asDomain() ?: return@mapNotNull null
add(roomId, event, direction, isUnlinked = isUnlinked)
add(roomId, event, direction)
}
}
internal fun ChunkEntity.add(roomId: String,
event: Event,
direction: PaginationDirection,
stateIndexOffset: Int = 0,
isUnlinked: Boolean = false): TimelineEventEntity? {
stateIndexOffset: Int = 0
): TimelineEventEntity? {
assertIsManaged()
if (event.eventId != null && timelineEvents.find(event.eventId) != null) {
return null
@ -102,6 +92,7 @@ internal fun ChunkEntity.add(roomId: String,
}
}
val isUnlinked = isUnlinked
val localId = TimelineEventEntity.nextId(realm)
val eventId = event.eventId ?: ""
val senderId = event.senderId ?: ""
@ -128,9 +119,9 @@ internal fun ChunkEntity.add(roomId: String,
val rootEvent = event.toEntity(roomId).apply {
this.stateIndex = currentStateIndex
this.isUnlinked = isUnlinked
this.displayIndex = currentDisplayIndex
this.sendState = SendState.SYNCED
this.isUnlinked = isUnlinked
}
val eventEntity = realm.createObject<TimelineEventEntity>().also {
it.localId = localId

View file

@ -66,6 +66,9 @@ internal class TimelineEventSenderVisitor @Inject constructor() {
fun visit(timelineEventEntities: List<TimelineEventEntity>) = timelineEventEntities.forEach { visit(it) }
fun visit(timelineEventEntity: TimelineEventEntity) {
if (!timelineEventEntity.isValid) {
return
}
val key = Key(
roomId = timelineEventEntity.roomId,
stateIndex = timelineEventEntity.root?.stateIndex ?: 0,
@ -96,7 +99,7 @@ internal class TimelineEventSenderVisitor @Inject constructor() {
val stateIndex = root?.stateIndex ?: return result
val senderId = root?.sender ?: return result
val chunkEntity = chunk?.firstOrNull() ?: return result
val isUnlinked = chunkEntity.isUnlinked()
val isUnlinked = chunkEntity.isUnlinked
var senderMembershipEvent: EventEntity?
var senderRoomMemberContent: String?
var senderRoomMemberPrevContent: String?
@ -142,5 +145,4 @@ internal class TimelineEventSenderVisitor @Inject constructor() {
result.senderMembershipEventId = senderMembershipEvent?.eventId
return result
}
}

View file

@ -30,7 +30,8 @@ internal open class ChunkEntity(@Index var prevToken: String? = null,
var backwardsDisplayIndex: Int? = null,
var forwardsDisplayIndex: Int? = null,
var backwardsStateIndex: Int? = null,
var forwardsStateIndex: Int? = null
var forwardsStateIndex: Int? = null,
var isUnlinked: Boolean = false
) : RealmObject() {
fun identifier() = "${prevToken}_$nextToken"

View file

@ -57,9 +57,15 @@ internal fun ChunkEntity.Companion.findIncludingEvent(realm: Realm, eventId: Str
return findAllIncludingEvents(realm, listOf(eventId)).firstOrNull()
}
internal fun ChunkEntity.Companion.create(realm: Realm, prevToken: String?, nextToken: String?): ChunkEntity {
internal fun ChunkEntity.Companion.create(
realm: Realm,
prevToken: String?,
nextToken: String?,
isUnlinked: Boolean
): ChunkEntity {
return realm.createObject<ChunkEntity>().apply {
this.prevToken = prevToken
this.nextToken = nextToken
this.isUnlinked = isUnlinked
}
}

View file

@ -18,10 +18,6 @@ package im.vector.matrix.android.internal.session.room.timeline
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.helper.*
import im.vector.matrix.android.internal.database.helper.add
import im.vector.matrix.android.internal.database.helper.addOrUpdate
import im.vector.matrix.android.internal.database.helper.addStateEvent
import im.vector.matrix.android.internal.database.helper.deleteOnCascade
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.create
@ -136,14 +132,14 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
// The current chunk is the one we will keep all along the merge processChanges.
// We try to look for a chunk next to the token,
// otherwise we create a whole new one
// otherwise we create a whole new one which is unlinked (not live)
var currentChunk = if (direction == PaginationDirection.FORWARDS) {
prevChunk?.apply { this.nextToken = nextToken }
} else {
nextChunk?.apply { this.prevToken = prevToken }
}
?: ChunkEntity.create(realm, prevToken, nextToken)
?: ChunkEntity.create(realm, prevToken, nextToken, isUnlinked = true)
if (receivedChunk.events.isEmpty() && receivedChunk.end == receivedChunk.start) {
Timber.v("Reach end of $roomId")
@ -151,7 +147,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
} else if (!shouldSkip) {
Timber.v("Add ${receivedChunk.events.size} events in chunk(${currentChunk.nextToken} | ${currentChunk.prevToken}")
val timelineEvents = receivedChunk.events.mapNotNull {
currentChunk.add(roomId, it, direction, isUnlinked = currentChunk.isUnlinked())
currentChunk.add(roomId, it, direction)
}
// Then we merge chunks if needed
if (currentChunk != prevChunk && prevChunk != null) {
@ -169,7 +165,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
}
roomEntity.addOrUpdate(currentChunk)
for (stateEvent in receivedChunk.stateEvents) {
roomEntity.addStateEvent(stateEvent, isUnlinked = currentChunk.isUnlinked())
roomEntity.addStateEvent(stateEvent, isUnlinked = currentChunk.isUnlinked)
}
timelineEventSenderVisitor.visit(timelineEvents)
}

View file

@ -190,6 +190,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
}
lastChunk?.isLastForward = false
chunkEntity.isLastForward = true
chunkEntity.isUnlinked = false
val timelineEvents = ArrayList<TimelineEventEntity>(eventList.size)
for (event in eventList) {

View file

@ -198,5 +198,4 @@ class HomeDetailFragment @Inject constructor(
RoomListDisplayMode.ROOMS -> R.id.bottom_action_rooms
else -> R.id.bottom_action_home
}
}