fix backup looping same keys

This commit is contained in:
Valere 2022-07-18 17:16:37 +02:00
parent 448b6e1c74
commit 309642845e
4 changed files with 11 additions and 33 deletions

View File

@ -24,7 +24,6 @@ import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.FixMethodOrder import org.junit.FixMethodOrder
import org.junit.Ignore
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -56,7 +55,6 @@ import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM) @FixMethodOrder(MethodSorters.JVM)
@LargeTest @LargeTest
@Ignore
class KeysBackupTest : InstrumentedTest { class KeysBackupTest : InstrumentedTest {
@get:Rule val rule = RetryTestRule(3) @get:Rule val rule = RetryTestRule(3)

View File

@ -21,13 +21,10 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.logger.LoggerTag
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import timber.log.Timber import timber.log.Timber
import java.util.Timer
import java.util.TimerTask
import javax.inject.Inject import javax.inject.Inject
internal data class InboundGroupSessionHolder( internal data class InboundGroupSessionHolder(
@ -57,18 +54,13 @@ internal class InboundGroupSessionStore @Inject constructor(
if (oldValue != null) { if (oldValue != null) {
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
Timber.tag(loggerTag.value).v("## Inbound: entryRemoved ${oldValue.wrapper.roomId}-${oldValue.wrapper.senderKey}") Timber.tag(loggerTag.value).v("## Inbound: entryRemoved ${oldValue.wrapper.roomId}-${oldValue.wrapper.senderKey}")
store.storeInboundGroupSessions(listOf(oldValue).map { it.wrapper }) // store.storeInboundGroupSessions(listOf(oldValue).map { it.wrapper })
oldValue.wrapper.session.releaseSession() oldValue.wrapper.session.releaseSession()
} }
} }
} }
} }
private val timer = Timer()
private var timerTask: TimerTask? = null
private val dirtySession = mutableListOf<InboundGroupSessionHolder>()
@Synchronized @Synchronized
fun clear() { fun clear() {
sessionCache.evictAll() sessionCache.evictAll()
@ -90,7 +82,6 @@ internal class InboundGroupSessionStore @Inject constructor(
@Synchronized @Synchronized
fun replaceGroupSession(old: InboundGroupSessionHolder, new: InboundGroupSessionHolder, sessionId: String, senderKey: String) { fun replaceGroupSession(old: InboundGroupSessionHolder, new: InboundGroupSessionHolder, sessionId: String, senderKey: String) {
Timber.tag(loggerTag.value).v("## Replacing outdated session ${old.wrapper.roomId}-${old.wrapper.senderKey}") Timber.tag(loggerTag.value).v("## Replacing outdated session ${old.wrapper.roomId}-${old.wrapper.senderKey}")
dirtySession.remove(old)
store.removeInboundGroupSession(sessionId, senderKey) store.removeInboundGroupSession(sessionId, senderKey)
sessionCache.remove(CacheKey(sessionId, senderKey)) sessionCache.remove(CacheKey(sessionId, senderKey))
@ -107,33 +98,14 @@ internal class InboundGroupSessionStore @Inject constructor(
private fun internalStoreGroupSession(holder: InboundGroupSessionHolder, sessionId: String, senderKey: String) { private fun internalStoreGroupSession(holder: InboundGroupSessionHolder, sessionId: String, senderKey: String) {
Timber.tag(loggerTag.value).v("## Inbound: getInboundGroupSession mark as dirty ${holder.wrapper.roomId}-${holder.wrapper.senderKey}") Timber.tag(loggerTag.value).v("## Inbound: getInboundGroupSession mark as dirty ${holder.wrapper.roomId}-${holder.wrapper.senderKey}")
// We want to batch this a bit for performances
dirtySession.add(holder)
if (sessionCache[CacheKey(sessionId, senderKey)] == null) { if (sessionCache[CacheKey(sessionId, senderKey)] == null) {
// first time seen, put it in memory cache while waiting for batch insert // first time seen, put it in memory cache while waiting for batch insert
// If it's already known, no need to update cache it's already there // If it's already known, no need to update cache it's already there
sessionCache.put(CacheKey(sessionId, senderKey), holder) sessionCache.put(CacheKey(sessionId, senderKey), holder)
} }
timerTask?.cancel()
timerTask = object : TimerTask() {
override fun run() {
batchSave()
}
}
timer.schedule(timerTask!!, 300)
}
@Synchronized
private fun batchSave() {
val toSave = mutableListOf<InboundGroupSessionHolder>().apply { addAll(dirtySession) }
dirtySession.clear()
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
Timber.tag(loggerTag.value).v("## Inbound: getInboundGroupSession batching save of ${toSave.size}") store.storeInboundGroupSessions(listOf(holder.wrapper))
tryOrNull {
store.storeInboundGroupSessions(toSave.map { it.wrapper })
}
} }
} }
} }

View File

@ -1349,6 +1349,8 @@ internal class DefaultKeysBackupService @Inject constructor(
// Mark keys as backed up // Mark keys as backed up
cryptoStore.markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers) cryptoStore.markBackupDoneForInboundGroupSessions(olmInboundGroupSessionWrappers)
// we can release the sessions now
olmInboundGroupSessionWrappers.onEach { it.session.releaseSession() }
if (olmInboundGroupSessionWrappers.size < KEY_BACKUP_SEND_KEYS_MAX_COUNT) { if (olmInboundGroupSessionWrappers.size < KEY_BACKUP_SEND_KEYS_MAX_COUNT) {
Timber.v("backupKeys: All keys have been backed up") Timber.v("backupKeys: All keys have been backed up")

View File

@ -763,11 +763,17 @@ internal class RealmCryptoStore @Inject constructor(
// } ?: false // } ?: false
val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionIdentifier, wrapper.sessionData.senderKey) val key = OlmInboundGroupSessionEntity.createPrimaryKey(sessionIdentifier, wrapper.sessionData.senderKey)
val existing = realm.where<OlmInboundGroupSessionEntity>()
.equalTo(OlmInboundGroupSessionEntityFields.PRIMARY_KEY, key)
.findFirst()
val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply { val realmOlmInboundGroupSession = OlmInboundGroupSessionEntity().apply {
primaryKey = key primaryKey = key
store(wrapper) store(wrapper)
backedUp = existing?.backedUp ?: false
} }
Timber.i("## CRYPTO | shouldShareHistory: ${wrapper.sessionData.sharedHistory} for $key")
Timber.v("## CRYPTO | shouldShareHistory: ${wrapper.sessionData.sharedHistory} for $key")
realm.insertOrUpdate(realmOlmInboundGroupSession) realm.insertOrUpdate(realmOlmInboundGroupSession)
} }
} }