Merge pull request #2765 from vector-im/feature/bma/big_e2e_rooms

[DANGEROUS PR] Properly delete all objects from Realm, avoid orphaned
This commit is contained in:
Benoit Marty 2021-02-08 15:44:43 +01:00 committed by GitHub
commit eecb789603
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 136 additions and 77 deletions

View File

@ -56,6 +56,7 @@ Bugfix 🐛:
- Widgets: Support $matrix_widget_id parameter (#2748) - Widgets: Support $matrix_widget_id parameter (#2748)
- Data for Worker overload (#2721) - Data for Worker overload (#2721)
- Fix multiple tasks - Fix multiple tasks
- Object deletion in database is not complete (#2759)
SDK API changes ⚠️: SDK API changes ⚠️:
- Increase targetSdkVersion to 30 (#2600) - Increase targetSdkVersion to 30 (#2600)

View File

@ -21,11 +21,11 @@ import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo
import org.matrix.android.sdk.internal.util.JsonCanonicalizer import org.matrix.android.sdk.internal.util.JsonCanonicalizer
import timber.log.Timber import timber.log.Timber
fun CryptoDeviceInfo.canonicalSignable(): String { internal fun CryptoDeviceInfo.canonicalSignable(): String {
return JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableJSONDictionary()) return JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableJSONDictionary())
} }
fun CryptoCrossSigningKey.canonicalSignable(): String { internal fun CryptoCrossSigningKey.canonicalSignable(): String {
return JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableJSONDictionary()) return JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableJSONDictionary())
} }
@ -40,7 +40,7 @@ fun String.fromBase64(): ByteArray {
/** /**
* Decode the base 64. Return null in case of bad format. Should be used when parsing received data from external source * Decode the base 64. Return null in case of bad format. Should be used when parsing received data from external source
*/ */
fun String.fromBase64Safe(): ByteArray? { internal fun String.fromBase64Safe(): ByteArray? {
return try { return try {
Base64.decode(this, Base64.DEFAULT) Base64.decode(this, Base64.DEFAULT)
} catch (throwable: Throwable) { } catch (throwable: Throwable) {

View File

@ -63,7 +63,7 @@ data class CryptoCrossSigningKey(
) )
} }
data class Builder( internal data class Builder(
val userId: String, val userId: String,
val usage: KeyUsage, val usage: KeyUsage,
private var base64Pkey: String? = null, private var base64Pkey: String? = null,
@ -97,7 +97,7 @@ data class CryptoCrossSigningKey(
} }
} }
enum class KeyUsage(val value: String) { internal enum class KeyUsage(val value: String) {
MASTER("master"), MASTER("master"),
SELF_SIGNING("self_signing"), SELF_SIGNING("self_signing"),
USER_SIGNING("user_signing") USER_SIGNING("user_signing")

View File

@ -83,6 +83,7 @@ import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntity import org.matrix.android.sdk.internal.crypto.store.db.model.WithHeldSessionEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.createPrimaryKey import org.matrix.android.sdk.internal.crypto.store.db.model.createPrimaryKey
import org.matrix.android.sdk.internal.crypto.store.db.model.deleteOnCascade
import org.matrix.android.sdk.internal.crypto.store.db.query.create import org.matrix.android.sdk.internal.crypto.store.db.query.create
import org.matrix.android.sdk.internal.crypto.store.db.query.delete import org.matrix.android.sdk.internal.crypto.store.db.query.delete
import org.matrix.android.sdk.internal.crypto.store.db.query.get import org.matrix.android.sdk.internal.crypto.store.db.query.get
@ -94,6 +95,7 @@ import org.matrix.android.sdk.internal.di.CryptoDatabase
import org.matrix.android.sdk.internal.di.DeviceId import org.matrix.android.sdk.internal.di.DeviceId
import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.extensions.clearWith
import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.SessionScope
import org.matrix.olm.OlmAccount import org.matrix.olm.OlmAccount
import org.matrix.olm.OlmException import org.matrix.olm.OlmException
@ -293,7 +295,7 @@ internal class RealmCryptoStore @Inject constructor(
realm.insertOrUpdate(entity) realm.insertOrUpdate(entity)
} }
// Ensure all other devices are deleted // Ensure all other devices are deleted
u.devices.deleteAllFromRealm() u.devices.clearWith { it.deleteOnCascade() }
u.devices.addAll(new) u.devices.addAll(new)
} }
} }
@ -309,7 +311,7 @@ internal class RealmCryptoStore @Inject constructor(
.let { userEntity -> .let { userEntity ->
if (masterKey == null || selfSigningKey == null) { if (masterKey == null || selfSigningKey == null) {
// The user has disabled cross signing? // The user has disabled cross signing?
userEntity.crossSigningInfoEntity?.deleteFromRealm() userEntity.crossSigningInfoEntity?.deleteOnCascade()
userEntity.crossSigningInfoEntity = null userEntity.crossSigningInfoEntity = null
} else { } else {
var shouldResetMyDevicesLocalTrust = false var shouldResetMyDevicesLocalTrust = false
@ -1633,7 +1635,7 @@ internal class RealmCryptoStore @Inject constructor(
} else { } else {
// Just override existing, caller should check and untrust id needed // Just override existing, caller should check and untrust id needed
val existing = CrossSigningInfoEntity.getOrCreate(realm, userId) val existing = CrossSigningInfoEntity.getOrCreate(realm, userId)
existing.crossSigningKeys.deleteAllFromRealm() existing.crossSigningKeys.clearWith { it.deleteOnCascade() }
existing.crossSigningKeys.addAll( existing.crossSigningKeys.addAll(
info.crossSigningKeys.map { info.crossSigningKeys.map {
crossSigningKeysMapper.map(it) crossSigningKeysMapper.map(it)

View File

@ -16,10 +16,11 @@
package org.matrix.android.sdk.internal.crypto.store.db.model package org.matrix.android.sdk.internal.crypto.store.db.model
import org.matrix.android.sdk.internal.crypto.model.KeyUsage
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import org.matrix.android.sdk.internal.crypto.model.KeyUsage
import org.matrix.android.sdk.internal.extensions.clearWith
internal open class CrossSigningInfoEntity( internal open class CrossSigningInfoEntity(
@PrimaryKey @PrimaryKey
@ -56,3 +57,8 @@ internal open class CrossSigningInfoEntity(
info?.let { crossSigningKeys.add(it) } info?.let { crossSigningKeys.add(it) }
} }
} }
internal fun CrossSigningInfoEntity.deleteOnCascade() {
crossSigningKeys.clearWith { it.deleteOnCascade() }
deleteFromRealm()
}

View File

@ -47,3 +47,8 @@ internal open class DeviceInfoEntity(
companion object companion object
} }
internal fun DeviceInfoEntity.deleteOnCascade() {
trustLevelEntity?.deleteFromRealm()
deleteFromRealm()
}

View File

@ -30,3 +30,8 @@ internal open class KeyInfoEntity(
var signatures: String? = null, var signatures: String? = null,
var trustLevelEntity: TrustLevelEntity? = null var trustLevelEntity: TrustLevelEntity? = null
) : RealmObject() ) : RealmObject()
internal fun KeyInfoEntity.deleteOnCascade() {
trustLevelEntity?.deleteFromRealm()
deleteFromRealm()
}

View File

@ -19,13 +19,20 @@ package org.matrix.android.sdk.internal.crypto.store.db.model
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import org.matrix.android.sdk.internal.extensions.clearWith
internal open class UserEntity( internal open class UserEntity(
@PrimaryKey var userId: String? = null, @PrimaryKey var userId: String? = null,
var devices: RealmList<DeviceInfoEntity> = RealmList(), var devices: RealmList<DeviceInfoEntity> = RealmList(),
var crossSigningInfoEntity: CrossSigningInfoEntity? = null, var crossSigningInfoEntity: CrossSigningInfoEntity? = null,
var deviceTrackingStatus: Int = 0) var deviceTrackingStatus: Int = 0
: RealmObject() { ) : RealmObject() {
companion object companion object
} }
internal fun UserEntity.deleteOnCascade() {
devices.clearWith { it.deleteOnCascade() }
crossSigningInfoEntity?.deleteOnCascade()
deleteFromRealm()
}

View File

@ -16,11 +16,12 @@
package org.matrix.android.sdk.internal.crypto.store.db.query package org.matrix.android.sdk.internal.crypto.store.db.query
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
import io.realm.Realm import io.realm.Realm
import io.realm.kotlin.createObject import io.realm.kotlin.createObject
import io.realm.kotlin.where import io.realm.kotlin.where
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntity
import org.matrix.android.sdk.internal.crypto.store.db.model.UserEntityFields
import org.matrix.android.sdk.internal.crypto.store.db.model.deleteOnCascade
/** /**
* Get or create a user * Get or create a user
@ -39,5 +40,5 @@ internal fun UserEntity.Companion.delete(realm: Realm, userId: String) {
realm.where<UserEntity>() realm.where<UserEntity>()
.equalTo(UserEntityFields.USER_ID, userId) .equalTo(UserEntityFields.USER_ID, userId)
.findFirst() .findFirst()
?.deleteFromRealm() ?.deleteOnCascade()
} }

View File

@ -21,7 +21,7 @@ import org.matrix.olm.OlmPkEncryption
import org.matrix.olm.OlmPkSigning import org.matrix.olm.OlmPkSigning
import org.matrix.olm.OlmUtility import org.matrix.olm.OlmUtility
fun <T> withOlmEncryption(block: (OlmPkEncryption) -> T): T { internal fun <T> withOlmEncryption(block: (OlmPkEncryption) -> T): T {
val olmPkEncryption = OlmPkEncryption() val olmPkEncryption = OlmPkEncryption()
try { try {
return block(olmPkEncryption) return block(olmPkEncryption)
@ -30,7 +30,7 @@ fun <T> withOlmEncryption(block: (OlmPkEncryption) -> T): T {
} }
} }
fun <T> withOlmDecryption(block: (OlmPkDecryption) -> T): T { internal fun <T> withOlmDecryption(block: (OlmPkDecryption) -> T): T {
val olmPkDecryption = OlmPkDecryption() val olmPkDecryption = OlmPkDecryption()
try { try {
return block(olmPkDecryption) return block(olmPkDecryption)
@ -39,7 +39,7 @@ fun <T> withOlmDecryption(block: (OlmPkDecryption) -> T): T {
} }
} }
fun <T> withOlmSigning(block: (OlmPkSigning) -> T): T { internal fun <T> withOlmSigning(block: (OlmPkSigning) -> T): T {
val olmPkSigning = OlmPkSigning() val olmPkSigning = OlmPkSigning()
try { try {
return block(olmPkSigning) return block(olmPkSigning)
@ -48,7 +48,7 @@ fun <T> withOlmSigning(block: (OlmPkSigning) -> T): T {
} }
} }
fun <T> withOlmUtility(block: (OlmUtility) -> T): T { internal fun <T> withOlmUtility(block: (OlmUtility) -> T): T {
val olmUtility = OlmUtility() val olmUtility = OlmUtility()
try { try {
return block(olmUtility) return block(olmUtility)

View File

@ -16,6 +16,10 @@
package org.matrix.android.sdk.internal.database package org.matrix.android.sdk.internal.database
import io.realm.Realm
import io.realm.RealmConfiguration
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.matrix.android.sdk.internal.database.helper.nextDisplayIndex import org.matrix.android.sdk.internal.database.helper.nextDisplayIndex
import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.ChunkEntityFields import org.matrix.android.sdk.internal.database.model.ChunkEntityFields
@ -23,14 +27,11 @@ import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.RoomEntity import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.database.model.deleteOnCascade
import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.session.SessionLifecycleObserver import org.matrix.android.sdk.internal.session.SessionLifecycleObserver
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.TaskExecutor
import io.realm.Realm
import io.realm.RealmConfiguration
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -56,7 +57,7 @@ internal class DatabaseCleaner @Inject constructor(@SessionDatabase private val
} }
} }
private suspend fun cleanUp(realm: Realm, threshold: Long) { private fun cleanUp(realm: Realm, threshold: Long) {
val numberOfEvents = realm.where(EventEntity::class.java).findAll().size val numberOfEvents = realm.where(EventEntity::class.java).findAll().size
val numberOfTimelineEvents = realm.where(TimelineEventEntity::class.java).findAll().size val numberOfTimelineEvents = realm.where(TimelineEventEntity::class.java).findAll().size
Timber.v("Number of events in db: $numberOfEvents | Number of timeline events in db: $numberOfTimelineEvents") Timber.v("Number of events in db: $numberOfEvents | Number of timeline events in db: $numberOfTimelineEvents")
@ -76,20 +77,7 @@ internal class DatabaseCleaner @Inject constructor(@SessionDatabase private val
chunk.numberOfTimelineEvents = chunk.numberOfTimelineEvents - eventsToRemove.size chunk.numberOfTimelineEvents = chunk.numberOfTimelineEvents - eventsToRemove.size
eventsToRemove.forEach { eventsToRemove.forEach {
val canDeleteRoot = it.root?.stateKey == null val canDeleteRoot = it.root?.stateKey == null
if (canDeleteRoot) { it.deleteOnCascade(canDeleteRoot)
it.root?.deleteFromRealm()
}
it.readReceipts?.readReceipts?.deleteAllFromRealm()
it.readReceipts?.deleteFromRealm()
it.annotations?.apply {
editSummary?.deleteFromRealm()
pollResponseSummary?.deleteFromRealm()
referencesSummaryEntity?.deleteFromRealm()
reactionsSummary.deleteAllFromRealm()
}
it.annotations?.deleteFromRealm()
it.readReceipts?.deleteFromRealm()
it.deleteFromRealm()
} }
// We reset the prevToken so we will need to fetch again. // We reset the prevToken so we will need to fetch again.
chunk.prevToken = null chunk.prevToken = null

View File

@ -38,12 +38,6 @@ import io.realm.Sort
import io.realm.kotlin.createObject import io.realm.kotlin.createObject
import timber.log.Timber import timber.log.Timber
internal fun ChunkEntity.deleteOnCascade() {
assertIsManaged()
this.timelineEvents.deleteAllFromRealm()
this.deleteFromRealm()
}
internal fun ChunkEntity.merge(roomId: String, chunkToMerge: ChunkEntity, direction: PaginationDirection) { internal fun ChunkEntity.merge(roomId: String, chunkToMerge: ChunkEntity, direction: PaginationDirection) {
assertIsManaged() assertIsManaged()
val localRealm = this.realm val localRealm = this.realm

View File

@ -19,12 +19,7 @@ package org.matrix.android.sdk.internal.database.helper
import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.RoomEntity import org.matrix.android.sdk.internal.database.model.RoomEntity
internal fun RoomEntity.deleteOnCascade(chunkEntity: ChunkEntity) { internal fun RoomEntity.addIfNecessary(chunkEntity: ChunkEntity) {
chunks.remove(chunkEntity)
chunkEntity.deleteOnCascade()
}
internal fun RoomEntity.addOrUpdate(chunkEntity: ChunkEntity) {
if (!chunks.contains(chunkEntity)) { if (!chunks.contains(chunkEntity)) {
chunks.add(chunkEntity) chunks.add(chunkEntity)
} }

View File

@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.database.helper
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.extensions.assertIsManaged
import io.realm.Realm import io.realm.Realm
internal fun TimelineEventEntity.Companion.nextId(realm: Realm): Long { internal fun TimelineEventEntity.Companion.nextId(realm: Realm): Long {
@ -29,11 +28,3 @@ internal fun TimelineEventEntity.Companion.nextId(realm: Realm): Long {
currentIdNum.toLong() + 1 currentIdNum.toLong() + 1
} }
} }
internal fun TimelineEventEntity.deleteOnCascade() {
assertIsManaged()
root?.deleteFromRealm()
annotations?.deleteFromRealm()
readReceipts?.deleteFromRealm()
deleteFromRealm()
}

View File

@ -21,6 +21,8 @@ import io.realm.RealmObject
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.annotations.Index import io.realm.annotations.Index
import io.realm.annotations.LinkingObjects import io.realm.annotations.LinkingObjects
import org.matrix.android.sdk.internal.extensions.assertIsManaged
import org.matrix.android.sdk.internal.extensions.clearWith
internal open class ChunkEntity(@Index var prevToken: String? = null, internal open class ChunkEntity(@Index var prevToken: String? = null,
// Because of gaps we can have several chunks with nextToken == null // Because of gaps we can have several chunks with nextToken == null
@ -43,3 +45,12 @@ internal open class ChunkEntity(@Index var prevToken: String? = null,
companion object companion object
} }
internal fun ChunkEntity.deleteOnCascade(deleteStateEvents: Boolean, canDeleteRoot: Boolean) {
assertIsManaged()
if (deleteStateEvents) {
stateEvents.deleteAllFromRealm()
}
timelineEvents.clearWith { it.deleteOnCascade(canDeleteRoot) }
deleteFromRealm()
}

View File

@ -31,3 +31,11 @@ internal open class EventAnnotationsSummaryEntity(
companion object companion object
} }
internal fun EventAnnotationsSummaryEntity.deleteOnCascade() {
reactionsSummary.deleteAllFromRealm()
editSummary?.deleteFromRealm()
referencesSummaryEntity?.deleteFromRealm()
pollResponseSummary?.deleteFromRealm()
deleteFromRealm()
}

View File

@ -40,3 +40,8 @@ internal open class PushRuleEntity(
companion object companion object
} }
internal fun PushRuleEntity.deleteOnCascade() {
conditions?.deleteAllFromRealm()
deleteFromRealm()
}

View File

@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.database.model
import org.matrix.android.sdk.api.pushrules.RuleKind import org.matrix.android.sdk.api.pushrules.RuleKind
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import org.matrix.android.sdk.internal.extensions.clearWith
internal open class PushRulesEntity( internal open class PushRulesEntity(
var scope: String = "", var scope: String = "",
@ -35,3 +36,8 @@ internal open class PushRulesEntity(
companion object companion object
} }
internal fun PushRulesEntity.deleteOnCascade() {
pushRules.clearWith { it.deleteOnCascade() }
deleteFromRealm()
}

View File

@ -15,8 +15,8 @@
*/ */
package org.matrix.android.sdk.internal.database.model package org.matrix.android.sdk.internal.database.model
import org.matrix.android.sdk.api.session.pushers.PusherState
import io.realm.RealmObject import io.realm.RealmObject
import org.matrix.android.sdk.api.session.pushers.PusherState
// TODO // TODO
// at java.lang.Thread.run(Thread.java:764) // at java.lang.Thread.run(Thread.java:764)
@ -54,3 +54,8 @@ internal open class PusherEntity(
companion object companion object
} }
internal fun PusherEntity.deleteOnCascade() {
data?.deleteFromRealm()
deleteFromRealm()
}

View File

@ -34,3 +34,8 @@ internal open class ReadReceiptsSummaryEntity(
companion object companion object
} }
internal fun ReadReceiptsSummaryEntity.deleteOnCascade() {
readReceipts.deleteAllFromRealm()
deleteFromRealm()
}

View File

@ -20,6 +20,7 @@ import io.realm.RealmObject
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.annotations.Index import io.realm.annotations.Index
import io.realm.annotations.LinkingObjects import io.realm.annotations.LinkingObjects
import org.matrix.android.sdk.internal.extensions.assertIsManaged
internal open class TimelineEventEntity(var localId: Long = 0, internal open class TimelineEventEntity(var localId: Long = 0,
@Index var eventId: String = "", @Index var eventId: String = "",
@ -39,3 +40,13 @@ internal open class TimelineEventEntity(var localId: Long = 0,
companion object companion object
} }
internal fun TimelineEventEntity.deleteOnCascade(canDeleteRoot: Boolean) {
assertIsManaged()
if (canDeleteRoot) {
root?.deleteFromRealm()
}
annotations?.deleteOnCascade()
readReceipts?.deleteOnCascade()
deleteFromRealm()
}

View File

@ -16,8 +16,18 @@
package org.matrix.android.sdk.internal.extensions package org.matrix.android.sdk.internal.extensions
import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
internal fun RealmObject.assertIsManaged() { internal fun RealmObject.assertIsManaged() {
check(isManaged) { "${javaClass.simpleName} entity should be managed to use this function" } check(isManaged) { "${javaClass.simpleName} entity should be managed to use this function" }
} }
/**
* Clear a RealmList by deleting all its items calling the provided lambda
*/
internal fun <T> RealmList<T>.clearWith(delete: (T) -> Unit) {
while (!isEmpty()) {
first()?.let { delete.invoke(it) }
}
}

View File

@ -19,6 +19,7 @@ import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.session.pushers.PusherState import org.matrix.android.sdk.api.session.pushers.PusherState
import org.matrix.android.sdk.internal.database.mapper.toEntity import org.matrix.android.sdk.internal.database.mapper.toEntity
import org.matrix.android.sdk.internal.database.model.PusherEntity import org.matrix.android.sdk.internal.database.model.PusherEntity
import org.matrix.android.sdk.internal.database.model.deleteOnCascade
import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.network.executeRequest
@ -41,7 +42,8 @@ internal class DefaultGetPushersTask @Inject constructor(
monarchy.awaitTransaction { realm -> monarchy.awaitTransaction { realm ->
// clear existings? // clear existings?
realm.where(PusherEntity::class.java) realm.where(PusherEntity::class.java)
.findAll().deleteAllFromRealm() .findAll()
.forEach { it.deleteOnCascade() }
response.pushers?.forEach { jsonPusher -> response.pushers?.forEach { jsonPusher ->
jsonPusher.toEntity().also { jsonPusher.toEntity().also {
it.state = PusherState.REGISTERED it.state = PusherState.REGISTERED

View File

@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.pushrules.RuleSetKey
import org.matrix.android.sdk.api.pushrules.rest.GetPushRulesResponse import org.matrix.android.sdk.api.pushrules.rest.GetPushRulesResponse
import org.matrix.android.sdk.internal.database.mapper.PushRulesMapper import org.matrix.android.sdk.internal.database.mapper.PushRulesMapper
import org.matrix.android.sdk.internal.database.model.PushRulesEntity import org.matrix.android.sdk.internal.database.model.PushRulesEntity
import org.matrix.android.sdk.internal.database.model.deleteOnCascade
import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.task.Task import org.matrix.android.sdk.internal.task.Task
import org.matrix.android.sdk.internal.util.awaitTransaction import org.matrix.android.sdk.internal.util.awaitTransaction
@ -40,7 +41,7 @@ internal class DefaultSavePushRulesTask @Inject constructor(@SessionDatabase pri
// clear current push rules // clear current push rules
realm.where(PushRulesEntity::class.java) realm.where(PushRulesEntity::class.java)
.findAll() .findAll()
.deleteAllFromRealm() .forEach { it.deleteOnCascade() }
// Save only global rules for the moment // Save only global rules for the moment
val globalRules = params.pushRules.global val globalRules = params.pushRules.global

View File

@ -22,16 +22,16 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.internal.database.helper.addOrUpdate import org.matrix.android.sdk.internal.database.helper.addIfNecessary
import org.matrix.android.sdk.internal.database.helper.addStateEvent import org.matrix.android.sdk.internal.database.helper.addStateEvent
import org.matrix.android.sdk.internal.database.helper.addTimelineEvent import org.matrix.android.sdk.internal.database.helper.addTimelineEvent
import org.matrix.android.sdk.internal.database.helper.deleteOnCascade
import org.matrix.android.sdk.internal.database.helper.merge import org.matrix.android.sdk.internal.database.helper.merge
import org.matrix.android.sdk.internal.database.mapper.toEntity import org.matrix.android.sdk.internal.database.mapper.toEntity
import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.EventInsertType import org.matrix.android.sdk.internal.database.model.EventInsertType
import org.matrix.android.sdk.internal.database.model.RoomEntity import org.matrix.android.sdk.internal.database.model.RoomEntity
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.deleteOnCascade
import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
import org.matrix.android.sdk.internal.database.query.create import org.matrix.android.sdk.internal.database.query.create
import org.matrix.android.sdk.internal.database.query.find import org.matrix.android.sdk.internal.database.query.find
@ -172,7 +172,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri
val currentLastForwardChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId) val currentLastForwardChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId)
if (currentChunk != currentLastForwardChunk) { if (currentChunk != currentLastForwardChunk) {
currentChunk.isLastForward = true currentChunk.isLastForward = true
currentLastForwardChunk?.deleteOnCascade() currentLastForwardChunk?.deleteOnCascade(deleteStateEvents = false, canDeleteRoot = false)
RoomSummaryEntity.where(realm, roomId).findFirst()?.apply { RoomSummaryEntity.where(realm, roomId).findFirst()?.apply {
latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId)
} }
@ -235,7 +235,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri
} }
} }
chunksToDelete.forEach { chunksToDelete.forEach {
it.deleteOnCascade() it.deleteOnCascade(deleteStateEvents = false, canDeleteRoot = false)
} }
val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId) val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId)
val shouldUpdateSummary = roomSummaryEntity.latestPreviewableEvent == null val shouldUpdateSummary = roomSummaryEntity.latestPreviewableEvent == null
@ -244,7 +244,7 @@ internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase pri
roomSummaryEntity.latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) roomSummaryEntity.latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId)
} }
if (currentChunk.isValid) { if (currentChunk.isValid) {
RoomEntity.where(realm, roomId).findFirst()?.addOrUpdate(currentChunk) RoomEntity.where(realm, roomId).findFirst()?.addIfNecessary(currentChunk)
} }
} }
} }

View File

@ -30,9 +30,8 @@ import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.internal.crypto.DefaultCryptoService import org.matrix.android.sdk.internal.crypto.DefaultCryptoService
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult
import org.matrix.android.sdk.internal.database.helper.addOrUpdate import org.matrix.android.sdk.internal.database.helper.addIfNecessary
import org.matrix.android.sdk.internal.database.helper.addTimelineEvent import org.matrix.android.sdk.internal.database.helper.addTimelineEvent
import org.matrix.android.sdk.internal.database.helper.deleteOnCascade
import org.matrix.android.sdk.internal.database.mapper.asDomain import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.mapper.toEntity import org.matrix.android.sdk.internal.database.mapper.toEntity
import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.ChunkEntity
@ -40,6 +39,7 @@ import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.EventInsertType import org.matrix.android.sdk.internal.database.model.EventInsertType
import org.matrix.android.sdk.internal.database.model.RoomEntity import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
import org.matrix.android.sdk.internal.database.model.deleteOnCascade
import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
import org.matrix.android.sdk.internal.database.query.find import org.matrix.android.sdk.internal.database.query.find
import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom import org.matrix.android.sdk.internal.database.query.findLastForwardChunkOfRoom
@ -48,6 +48,7 @@ import org.matrix.android.sdk.internal.database.query.getOrNull
import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.extensions.clearWith
import org.matrix.android.sdk.internal.session.DefaultInitialSyncProgressService import org.matrix.android.sdk.internal.session.DefaultInitialSyncProgressService
import org.matrix.android.sdk.internal.session.mapWithProgress import org.matrix.android.sdk.internal.session.mapWithProgress
import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembershipStateDataSource import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembershipStateDataSource
@ -175,7 +176,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
syncLocalTimestampMillis, syncLocalTimestampMillis,
isInitialSync isInitialSync
) )
roomEntity.addOrUpdate(chunkEntity) roomEntity.addIfNecessary(chunkEntity)
} }
val hasRoomMember = roomSync.state?.events?.firstOrNull { val hasRoomMember = roomSync.state?.events?.firstOrNull {
it.type == EventType.STATE_ROOM_MEMBER it.type == EventType.STATE_ROOM_MEMBER
@ -263,7 +264,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
val leftMember = RoomMemberSummaryEntity.where(realm, roomId, userId).findFirst() val leftMember = RoomMemberSummaryEntity.where(realm, roomId, userId).findFirst()
val membership = leftMember?.membership ?: Membership.LEAVE val membership = leftMember?.membership ?: Membership.LEAVE
roomEntity.membership = membership roomEntity.membership = membership
roomEntity.chunks.deleteAllFromRealm() roomEntity.chunks.clearWith { it.deleteOnCascade(deleteStateEvents = true, canDeleteRoot = true) }
roomTypingUsersHandler.handle(realm, roomId, null) roomTypingUsersHandler.handle(realm, roomId, null)
roomChangeMembershipStateDataSource.setMembershipFromSync(roomId, Membership.LEAVE) roomChangeMembershipStateDataSource.setMembershipFromSync(roomId, Membership.LEAVE)
roomSummaryUpdater.update(realm, roomId, membership, roomSync.summary, roomSync.unreadNotifications) roomSummaryUpdater.update(realm, roomId, membership, roomSync.summary, roomSync.unreadNotifications)
@ -340,7 +341,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
} }
} }
// Finally delete the local echo // Finally delete the local echo
sendingEventEntity.deleteOnCascade() sendingEventEntity.deleteOnCascade(true)
} else { } else {
Timber.v("Can't find corresponding local echo for tx:$it") Timber.v("Can't find corresponding local echo for tx:$it")
} }

View File

@ -16,8 +16,10 @@
package org.matrix.android.sdk.internal.session.sync package org.matrix.android.sdk.internal.session.sync
import com.squareup.moshi.Moshi
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
import io.realm.RealmList
import io.realm.kotlin.where
import org.matrix.android.sdk.api.pushrules.RuleScope import org.matrix.android.sdk.api.pushrules.RuleScope
import org.matrix.android.sdk.api.pushrules.RuleSetKey import org.matrix.android.sdk.api.pushrules.RuleSetKey
import org.matrix.android.sdk.api.pushrules.rest.GetPushRulesResponse import org.matrix.android.sdk.api.pushrules.rest.GetPushRulesResponse
@ -37,6 +39,7 @@ 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.model.UserAccountDataEntity import org.matrix.android.sdk.internal.database.model.UserAccountDataEntity
import org.matrix.android.sdk.internal.database.model.UserAccountDataEntityFields import org.matrix.android.sdk.internal.database.model.UserAccountDataEntityFields
import org.matrix.android.sdk.internal.database.model.deleteOnCascade
import org.matrix.android.sdk.internal.database.query.getDirectRooms import org.matrix.android.sdk.internal.database.query.getDirectRooms
import org.matrix.android.sdk.internal.database.query.getOrCreate import org.matrix.android.sdk.internal.database.query.getOrCreate
import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.database.query.where
@ -50,9 +53,6 @@ import org.matrix.android.sdk.internal.session.sync.model.accountdata.IgnoredUse
import org.matrix.android.sdk.internal.session.sync.model.accountdata.UserAccountDataSync import org.matrix.android.sdk.internal.session.sync.model.accountdata.UserAccountDataSync
import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask
import io.realm.Realm
import io.realm.RealmList
import io.realm.kotlin.where
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -60,7 +60,6 @@ internal class UserAccountDataSyncHandler @Inject constructor(
@SessionDatabase private val monarchy: Monarchy, @SessionDatabase private val monarchy: Monarchy,
@UserId private val userId: String, @UserId private val userId: String,
private val directChatsHelper: DirectChatsHelper, private val directChatsHelper: DirectChatsHelper,
private val moshi: Moshi,
private val updateUserAccountDataTask: UpdateUserAccountDataTask) { private val updateUserAccountDataTask: UpdateUserAccountDataTask) {
fun handle(realm: Realm, accountData: UserAccountDataSync?) { fun handle(realm: Realm, accountData: UserAccountDataSync?) {
@ -113,7 +112,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(
val pushRules = event.content.toModel<GetPushRulesResponse>() ?: return val pushRules = event.content.toModel<GetPushRulesResponse>() ?: return
realm.where(PushRulesEntity::class.java) realm.where(PushRulesEntity::class.java)
.findAll() .findAll()
.deleteAllFromRealm() .forEach { it.deleteOnCascade() }
// Save only global rules for the moment // Save only global rules for the moment
val globalRules = pushRules.global val globalRules = pushRules.global