Add roomId to EventEntity as it makes queries a lot faster and fixes performance issues.

This commit is contained in:
ganfra 2019-01-03 17:10:02 +01:00 committed by ganfra
parent 51000c4711
commit e9737dff75
11 changed files with 52 additions and 69 deletions

View File

@ -10,6 +10,10 @@ fun Fragment.replaceFragment(fragment: Fragment, frameId: Int) {
fragmentManager?.inTransaction { replace(frameId, fragment) }
}

fun Fragment.addFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) {
fragmentManager?.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
}

fun Fragment.addChildFragment(fragment: Fragment, frameId: Int) {
childFragmentManager.inTransaction { add(frameId, fragment) }
}
@ -18,10 +22,6 @@ fun Fragment.replaceChildFragment(fragment: Fragment, frameId: Int) {
childFragmentManager.inTransaction { replace(frameId, fragment) }
}

fun Fragment.addFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) {
fragmentManager?.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
}

fun Fragment.addChildFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) {
childFragmentManager.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
}

View File

@ -5,7 +5,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import im.vector.riotredesign.R
import im.vector.riotredesign.core.extensions.replaceFragment
import im.vector.riotredesign.core.extensions.replaceChildFragment
import im.vector.riotredesign.core.platform.RiotFragment
import im.vector.riotredesign.features.home.group.GroupListFragment
import im.vector.riotredesign.features.home.room.list.RoomListFragment
@ -27,9 +27,9 @@ class HomeDrawerFragment : RiotFragment() {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState == null) {
val groupListFragment = GroupListFragment.newInstance()
replaceFragment(groupListFragment, R.id.groupListFragmentContainer)
replaceChildFragment(groupListFragment, R.id.groupListFragmentContainer)
val roomListFragment = RoomListFragment.newInstance()
replaceFragment(roomListFragment, R.id.roomListFragmentContainer)
replaceChildFragment(roomListFragment, R.id.roomListFragmentContainer)
}
}


View File

@ -5,7 +5,6 @@ import im.vector.matrix.android.api.session.events.model.EnrichedEvent
import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.api.session.room.model.RoomSummary
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers

class RxRoom(private val room: Room) {

@ -15,7 +14,6 @@ class RxRoom(private val room: Room) {

fun timeline(eventId: String? = null): Observable<PagedList<EnrichedEvent>> {
return room.timeline(eventId).asObservable()
.subscribeOn(Schedulers.io())
}

}

View File

@ -2,7 +2,8 @@ package im.vector.matrix.android.internal.database.helper

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.internal.database.mapper.asEntity
import im.vector.matrix.android.internal.database.mapper.toEntity
import im.vector.matrix.android.internal.database.mapper.updateWith
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.EventEntityFields
@ -44,13 +45,14 @@ internal fun ChunkEntity.merge(chunkToMerge: ChunkEntity,
}
}

internal fun ChunkEntity.addAll(events: List<Event>,
internal fun ChunkEntity.addAll(roomId: String,
events: List<Event>,
direction: PaginationDirection,
stateIndexOffset: Int = 0,
isUnlinked: Boolean = false) {

events.forEach { event ->
add(event, direction, stateIndexOffset, isUnlinked)
add(roomId, event, direction, stateIndexOffset, isUnlinked)
}
}

@ -58,11 +60,13 @@ internal fun ChunkEntity.updateDisplayIndexes() {
events.forEachIndexed { index, eventEntity -> eventEntity.displayIndex = index }
}

internal fun ChunkEntity.add(event: Event,
internal fun ChunkEntity.add(roomId: String,
event: Event,
direction: PaginationDirection,
stateIndexOffset: Int = 0,
isUnlinked: Boolean = false) {
add(event.asEntity(), direction, stateIndexOffset, isUnlinked)

add(event.toEntity(roomId), direction, stateIndexOffset, isUnlinked)
}

internal fun ChunkEntity.add(eventEntity: EventEntity,
@ -76,7 +80,6 @@ internal fun ChunkEntity.add(eventEntity: EventEntity,
if (eventEntity.eventId.isEmpty() || events.fastContains(eventEntity.eventId)) {
return
}

var currentStateIndex = lastStateIndex(direction, defaultValue = stateIndexOffset)
if (direction == PaginationDirection.FORWARDS && EventType.isStateEvent(eventEntity.type)) {
currentStateIndex += 1
@ -86,16 +89,14 @@ internal fun ChunkEntity.add(eventEntity: EventEntity,
currentStateIndex -= 1
}
}

eventEntity.stateIndex = currentStateIndex
eventEntity.isUnlinked = isUnlinked
eventEntity.updateWith(currentStateIndex, isUnlinked)
val position = if (direction == PaginationDirection.FORWARDS) 0 else this.events.size
events.add(position, eventEntity)
}

internal fun ChunkEntity.lastStateIndex(direction: PaginationDirection, defaultValue: Int = 0): Int {
return when (direction) {
PaginationDirection.FORWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.DESCENDING).findFirst()?.stateIndex
PaginationDirection.BACKWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.ASCENDING).findFirst()?.stateIndex
} ?: defaultValue
PaginationDirection.FORWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.DESCENDING).findFirst()?.stateIndex
PaginationDirection.BACKWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.ASCENDING).findFirst()?.stateIndex
} ?: defaultValue
}

View File

@ -1,7 +1,8 @@
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.mapper.toEntity
import im.vector.matrix.android.internal.database.mapper.updateWith
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.RoomEntity

@ -28,9 +29,8 @@ internal fun RoomEntity.addStateEvents(stateEvents: List<Event>,
if (event.eventId == null) {
return@forEach
}
val eventEntity = event.asEntity()
eventEntity.stateIndex = stateIndex
eventEntity.isUnlinked = isUnlinked
val eventEntity = event.toEntity(roomId)
eventEntity.updateWith(stateIndex, isUnlinked)
untimelinedStateEvents.add(eventEntity)
}
}

View File

@ -8,9 +8,10 @@ import im.vector.matrix.android.internal.database.model.EventEntity
internal object EventMapper {


fun map(event: Event): EventEntity {
fun map(event: Event, roomId: String): EventEntity {
val eventEntity = EventEntity()
eventEntity.eventId = event.eventId ?: ""
eventEntity.roomId = event.roomId ?: roomId
eventEntity.content = ContentMapper.map(event.content)
val resolvedPrevContent = event.prevContent ?: event.unsignedData?.prevContent
eventEntity.prevContent = ContentMapper.map(resolvedPrevContent)
@ -32,19 +33,24 @@ internal object EventMapper {
originServerTs = eventEntity.originServerTs,
sender = eventEntity.sender,
stateKey = eventEntity.stateKey,
roomId = null,
roomId = eventEntity.roomId,
unsignedData = UnsignedData(eventEntity.age),
redacts = eventEntity.redacts
)
}

}

internal fun EventEntity.updateWith(stateIndex: Int, isUnlinked: Boolean) {
this.stateIndex = stateIndex
this.isUnlinked = isUnlinked
}

internal fun EventEntity.asDomain(): Event {
return EventMapper.map(this)
}

internal fun Event.asEntity(): EventEntity {
return EventMapper.map(this)
internal fun Event.toEntity(roomId: String): EventEntity {
return EventMapper.map(this, roomId)
}


View File

@ -8,6 +8,7 @@ import java.util.*

internal open class EventEntity(@PrimaryKey var localId: String = UUID.randomUUID().toString(),
var eventId: String = "",
var roomId: String = "",
var type: String = "",
var content: String? = null,
var prevContent: String? = null,
@ -27,9 +28,7 @@ internal open class EventEntity(@PrimaryKey var localId: String = UUID.randomUUI
BOTH
}

companion object {
const val DEFAULT_STATE_INDEX = Int.MIN_VALUE
}
companion object

@LinkingObjects("events")
val chunk: RealmResults<ChunkEntity>? = null

View File

@ -1,10 +1,8 @@
package im.vector.matrix.android.internal.database.query

import im.vector.matrix.android.internal.database.model.ChunkEntityFields
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.EventEntity.LinkFilterMode.*
import im.vector.matrix.android.internal.database.model.EventEntityFields
import im.vector.matrix.android.internal.database.model.RoomEntityFields
import io.realm.Realm
import io.realm.RealmList
import io.realm.RealmQuery
@ -22,11 +20,7 @@ internal fun EventEntity.Companion.where(realm: Realm,
linkFilterMode: EventEntity.LinkFilterMode = LINKED_ONLY): RealmQuery<EventEntity> {
val query = realm.where<EventEntity>()
if (roomId != null) {
query.beginGroup()
.equalTo("${EventEntityFields.CHUNK}.${ChunkEntityFields.ROOM}.${RoomEntityFields.ROOM_ID}", roomId)
.or()
.equalTo("${EventEntityFields.ROOM}.${RoomEntityFields.ROOM_ID}", roomId)
.endGroup()
query.equalTo(EventEntityFields.ROOM_ID, roomId)
}
if (type != null) {
query.equalTo(EventEntityFields.TYPE, type)
@ -69,7 +63,6 @@ internal fun RealmList<EventEntity>.find(eventId: String): EventEntity? {
return this.where().equalTo(EventEntityFields.EVENT_ID, eventId).findFirst()
}

internal fun RealmList<EventEntity>.
fastContains(eventId: String): Boolean {
internal fun RealmList<EventEntity>.fastContains(eventId: String): Boolean {
return this.find(eventId) != null
}

View File

@ -1,11 +1,6 @@
package im.vector.matrix.android.internal.session.room.send

import androidx.work.BackoffPolicy
import androidx.work.Constraints
import androidx.work.ExistingWorkPolicy
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.*
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.events.model.Event
@ -37,8 +32,8 @@ internal class DefaultSendService(private val roomId: String,

monarchy.tryTransactionAsync { realm ->
val chunkEntity = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
?: return@tryTransactionAsync
chunkEntity.add(event, PaginationDirection.FORWARDS)
?: return@tryTransactionAsync
chunkEntity.add(roomId, event, PaginationDirection.FORWARDS)
chunkEntity.updateDisplayIndexes()
}


View File

@ -2,12 +2,7 @@ package im.vector.matrix.android.internal.session.room.timeline

import arrow.core.Try
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.helper.addAll
import im.vector.matrix.android.internal.database.helper.addOrUpdate
import im.vector.matrix.android.internal.database.helper.addStateEvents
import im.vector.matrix.android.internal.database.helper.deleteOnCascade
import im.vector.matrix.android.internal.database.helper.isUnlinked
import im.vector.matrix.android.internal.database.helper.merge
import im.vector.matrix.android.internal.database.helper.*
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
@ -26,7 +21,7 @@ internal class TokenChunkEventPersistor(private val monarchy: Monarchy) {
return monarchy
.tryTransactionSync { realm ->
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
?: throw IllegalStateException("You shouldn't use this method without a room")
?: throw IllegalStateException("You shouldn't use this method without a room")

val nextToken: String?
val prevToken: String?
@ -46,13 +41,13 @@ internal class TokenChunkEventPersistor(private val monarchy: Monarchy) {

var currentChunk = if (direction == PaginationDirection.FORWARDS) {
prevChunk?.apply { this.nextToken = nextToken }
?: ChunkEntity.create(realm, prevToken, nextToken)
?: ChunkEntity.create(realm, prevToken, nextToken)
} else {
nextChunk?.apply { this.prevToken = prevToken }
?: ChunkEntity.create(realm, prevToken, nextToken)
?: ChunkEntity.create(realm, prevToken, nextToken)
}

currentChunk.addAll(receivedChunk.events, direction, isUnlinked = currentChunk.isUnlinked())
currentChunk.addAll(roomId, receivedChunk.events, direction, isUnlinked = currentChunk.isUnlinked())

// Then we merge chunks if needed
if (currentChunk != prevChunk && prevChunk != null) {

View File

@ -15,11 +15,7 @@ import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
import im.vector.matrix.android.internal.session.sync.model.InvitedRoomSync
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 im.vector.matrix.android.internal.session.sync.model.RoomsSyncResponse
import im.vector.matrix.android.internal.session.sync.model.*
import io.realm.Realm
import io.realm.kotlin.createObject

@ -45,9 +41,9 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,

private fun handleRoomSync(realm: Realm, handlingStrategy: HandlingStrategy) {
val rooms = when (handlingStrategy) {
is HandlingStrategy.JOINED -> handlingStrategy.data.map { handleJoinedRoom(realm, it.key, it.value) }
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(rooms)
}
@ -57,7 +53,7 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
roomSync: RoomSync): RoomEntity {

val roomEntity = RoomEntity.where(realm, roomId).findFirst()
?: realm.createObject(roomId)
?: realm.createObject(roomId)

if (roomEntity.membership == MyMembership.INVITED) {
roomEntity.chunks.deleteAllFromRealm()
@ -138,7 +134,7 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,

lastChunk?.isLast = false
chunkEntity.isLast = true
chunkEntity.addAll(eventList, PaginationDirection.FORWARDS, stateIndexOffset)
chunkEntity.addAll(roomId, eventList, PaginationDirection.FORWARDS, stateIndexOffset)
return chunkEntity
}

@ -147,7 +143,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()