Merge pull request #3018 from vector-im/feature/bma/improve_perf

Fix issue with Realm in UpdateTrustWorker
This commit is contained in:
Benoit Marty 2021-03-18 10:27:54 +01:00 committed by GitHub
commit ef6e57066b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 66 additions and 63 deletions

View file

@ -8,6 +8,7 @@ Improvements 🙌:
-
Bugfix 🐛:
- Fix regression in UpdateTrustWorker (introduced in 1.1.2)
- Timeline : Fix ripple effect on text item and fix background color of separators.
Translations 🗣:

View file

@ -39,7 +39,7 @@ internal class GossipingWorkManager @Inject constructor(
.setConstraints(WorkManagerProvider.workConstraints)
.startChain(startChain)
.setInputData(data)
.setBackoffCriteria(BackoffPolicy.LINEAR, 10_000L, TimeUnit.MILLISECONDS)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
.build()
}

View file

@ -43,6 +43,7 @@ import org.matrix.android.sdk.internal.task.TaskThread
import org.matrix.android.sdk.internal.task.configureWith
import org.matrix.android.sdk.internal.util.JsonCanonicalizer
import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers
import org.matrix.android.sdk.internal.util.logLimit
import org.matrix.android.sdk.internal.worker.WorkerParamsFactory
import org.matrix.olm.OlmPkSigning
import org.matrix.olm.OlmUtility
@ -750,7 +751,7 @@ internal class DefaultCrossSigningService @Inject constructor(
}
override fun onUsersDeviceUpdate(userIds: List<String>) {
Timber.d("## CrossSigning - onUsersDeviceUpdate for ${userIds.size} users: $userIds")
Timber.d("## CrossSigning - onUsersDeviceUpdate for users: ${userIds.logLimit()}")
val workerParams = UpdateTrustWorker.Params(
sessionId = sessionId,
filename = updateTrustWorkerDataRepository.createParam(userIds)
@ -759,7 +760,7 @@ internal class DefaultCrossSigningService @Inject constructor(
val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<UpdateTrustWorker>()
.setInputData(workerData)
.setBackoffCriteria(BackoffPolicy.LINEAR, 2_000L, TimeUnit.MILLISECONDS)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
.build()
workManagerProvider.workManager

View file

@ -97,22 +97,17 @@ internal class UpdateTrustWorker(context: Context,
// Unfortunately we don't have much info on what did exactly changed (is it the cross signing keys of that user,
// or a new device?) So we check all again :/
Timber.d("## CrossSigning - Updating trust for users: ${userList.logLimit()}")
Realm.getInstance(cryptoRealmConfiguration).use { cryptoRealm ->
Realm.getInstance(sessionRealmConfiguration).use {
updateTrust(userList, cryptoRealm)
}
}
updateTrust(userList)
}
cleanup(params)
return Result.success()
}
private suspend fun updateTrust(userListParam: List<String>,
cRealm: Realm) {
private suspend fun updateTrust(userListParam: List<String>) {
var userList = userListParam
var myCrossSigningInfo: MXCrossSigningInfo? = null
// First we check that the users MSK are trusted by mine
// After that we check the trust chain for each devices of each users
awaitTransaction(cryptoRealmConfiguration) { cryptoRealm ->
@ -203,38 +198,43 @@ internal class UpdateTrustWorker(context: Context,
// So Cross Signing keys trust is updated, device trust is updated
// We can now update room shields? in the session DB?
updateTrustStep2(userList, myCrossSigningInfo)
}
private suspend fun updateTrustStep2(userList: List<String>, myCrossSigningInfo: MXCrossSigningInfo?) {
Timber.d("## CrossSigning - Updating shields for impacted rooms...")
awaitTransaction(sessionRealmConfiguration) { sessionRealm ->
sessionRealm.where(RoomMemberSummaryEntity::class.java)
.`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray())
.distinct(RoomMemberSummaryEntityFields.ROOM_ID)
.findAll()
.map { it.roomId }
.also { Timber.d("## CrossSigning - ... impacted rooms ${it.logLimit()}") }
.forEach { roomId ->
RoomSummaryEntity.where(sessionRealm, roomId)
.equalTo(RoomSummaryEntityFields.IS_ENCRYPTED, true)
.findFirst()
?.let { roomSummary ->
Timber.d("## CrossSigning - Check shield state for room $roomId")
val allActiveRoomMembers = RoomMemberHelper(sessionRealm, roomId).getActiveRoomMemberIds()
try {
val updatedTrust = computeRoomShield(
myCrossSigningInfo,
cRealm,
allActiveRoomMembers,
roomSummary
)
if (roomSummary.roomEncryptionTrustLevel != updatedTrust) {
Timber.d("## CrossSigning - Shield change detected for $roomId -> $updatedTrust")
roomSummary.roomEncryptionTrustLevel = updatedTrust
Realm.getInstance(cryptoRealmConfiguration).use { cryptoRealm ->
sessionRealm.where(RoomMemberSummaryEntity::class.java)
.`in`(RoomMemberSummaryEntityFields.USER_ID, userList.toTypedArray())
.distinct(RoomMemberSummaryEntityFields.ROOM_ID)
.findAll()
.map { it.roomId }
.also { Timber.d("## CrossSigning - ... impacted rooms ${it.logLimit()}") }
.forEach { roomId ->
RoomSummaryEntity.where(sessionRealm, roomId)
.equalTo(RoomSummaryEntityFields.IS_ENCRYPTED, true)
.findFirst()
?.let { roomSummary ->
Timber.d("## CrossSigning - Check shield state for room $roomId")
val allActiveRoomMembers = RoomMemberHelper(sessionRealm, roomId).getActiveRoomMemberIds()
try {
val updatedTrust = computeRoomShield(
myCrossSigningInfo,
cryptoRealm,
allActiveRoomMembers,
roomSummary
)
if (roomSummary.roomEncryptionTrustLevel != updatedTrust) {
Timber.d("## CrossSigning - Shield change detected for $roomId -> $updatedTrust")
roomSummary.roomEncryptionTrustLevel = updatedTrust
}
} catch (failure: Throwable) {
Timber.e(failure)
}
} catch (failure: Throwable) {
Timber.e(failure)
}
}
}
}
}
}
}

View file

@ -45,7 +45,7 @@ internal class CrossSigningKeysMapper @Inject constructor(moshi: Moshi) {
return CryptoCrossSigningKey(
userId = userId ?: "",
keys = mapOf("ed25519:$pubKey" to pubKey),
usages = keyInfo.usages.map { it },
usages = keyInfo.usages.toList(),
signatures = deserializeSignatures(keyInfo.signatures),
trustLevel = keyInfo.trustLevelEntity?.let {
DeviceTrustLevel(

View file

@ -183,7 +183,7 @@ internal class VerificationTransportRoomMessage(
val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<SendVerificationMessageWorker>()
.setConstraints(WorkManagerProvider.workConstraints)
.setInputData(workerParams)
.setBackoffCriteria(BackoffPolicy.LINEAR, 2_000L, TimeUnit.MILLISECONDS)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
.build()
workManagerProvider.workManager
@ -280,7 +280,7 @@ internal class VerificationTransportRoomMessage(
val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<SendVerificationMessageWorker>()
.setConstraints(WorkManagerProvider.workConstraints)
.setInputData(workerParams)
.setBackoffCriteria(BackoffPolicy.LINEAR, 2_000L, TimeUnit.MILLISECONDS)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
.build()
return workManagerProvider.workManager
.beginUniqueWork(uniqueQueueName(), ExistingWorkPolicy.APPEND_OR_REPLACE, workRequest)

View file

@ -23,6 +23,7 @@ import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkRequest
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@ -69,6 +70,7 @@ internal class WorkManagerProvider @Inject constructor(
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
const val BACKOFF_DELAY = 10_000L
// Use min value, smaller value will be ignored
const val BACKOFF_DELAY_MILLIS = WorkRequest.MIN_BACKOFF_MILLIS
}
}

View file

@ -96,7 +96,7 @@ internal class DefaultPushersService @Inject constructor(
val request = workManagerProvider.matrixOneTimeWorkRequestBuilder<AddHttpPusherWorker>()
.setConstraints(WorkManagerProvider.workConstraints)
.setInputData(WorkerParamsFactory.toData(params))
.setBackoffCriteria(BackoffPolicy.LINEAR, 10_000L, TimeUnit.MILLISECONDS)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
.build()
workManagerProvider.workManager.enqueue(request)
return request.id

View file

@ -318,7 +318,7 @@ internal class DefaultSendService @AssistedInject constructor(
.setConstraints(WorkManagerProvider.workConstraints)
.startChain(true)
.setInputData(uploadWorkData)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY, TimeUnit.MILLISECONDS)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
.build()
}
@ -332,7 +332,7 @@ internal class DefaultSendService @AssistedInject constructor(
// .setConstraints(WorkManagerProvider.workConstraints)
.startChain(false)
.setInputData(workData)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY, TimeUnit.MILLISECONDS)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
.build()
}
}

View file

@ -50,7 +50,7 @@ internal class TimelineSendEventWorkCommon @Inject constructor(
.setConstraints(WorkManagerProvider.workConstraints)
.startChain(startChain)
.setInputData(data)
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
.build()
}
@ -60,6 +60,5 @@ internal class TimelineSendEventWorkCommon @Inject constructor(
companion object {
private const val SEND_WORK = "SEND_WORK"
private const val BACKOFF_DELAY = 10_000L
}
}

View file

@ -65,7 +65,7 @@ internal class FileInitialSyncStatusRepository(directory: File) : InitialSyncSta
val state = cache?.step ?: InitialSyncStatus.STEP_INIT
return if (state >= InitialSyncStatus.STEP_DOWNLOADED
&& System.currentTimeMillis() > (cache?.downloadedDate ?: 0) + INIT_SYNC_FILE_LIFETIME) {
Timber.v("INIT_SYNC downloaded file is outdated, download it again")
Timber.d("INIT_SYNC downloaded file is outdated, download it again")
// The downloaded file is outdated
setStep(InitialSyncStatus.STEP_INIT)
InitialSyncStatus.STEP_INIT

View file

@ -147,13 +147,13 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
if (numberOfChunks > 1) {
reportSubtask(reporter, InitSyncStep.ImportingAccountJoinedRooms, numberOfChunks, 0.6f) {
val chunkSize = listSize / numberOfChunks
Timber.v("INIT_SYNC $listSize rooms to insert, split into $numberOfChunks sublists of $chunkSize items")
Timber.d("INIT_SYNC $listSize rooms to insert, split into $numberOfChunks sublists of $chunkSize items")
// I cannot find a better way to chunk a map, so chunk the keys and then create new maps
handlingStrategy.data.keys
.chunked(chunkSize)
.forEachIndexed { index, roomIds ->
val roomEntities = roomIds
.also { Timber.v("INIT_SYNC insert ${roomIds.size} rooms") }
.also { Timber.d("INIT_SYNC insert ${roomIds.size} rooms") }
.map {
handleJoinedRoom(
realm = realm,

View file

@ -101,7 +101,7 @@ internal class DefaultSyncTask @Inject constructor(
val readTimeOut = (params.timeout + TIMEOUT_MARGIN).coerceAtLeast(TimeOutInterceptor.DEFAULT_LONG_TIMEOUT)
if (isInitialSync) {
Timber.v("INIT_SYNC with filter: ${requestParams["filter"]}")
Timber.d("INIT_SYNC with filter: ${requestParams["filter"]}")
val initSyncStrategy = initialSyncStrategy
logDuration("INIT_SYNC strategy: $initSyncStrategy") {
if (initSyncStrategy is InitialSyncStrategy.Optimized) {
@ -145,7 +145,7 @@ internal class DefaultSyncTask @Inject constructor(
val workingFile = File(workingDir, "initSync.json")
val status = initialSyncStatusRepository.getStep()
if (workingFile.exists() && status >= InitialSyncStatus.STEP_DOWNLOADED) {
Timber.v("INIT_SYNC file is already here")
Timber.d("INIT_SYNC file is already here")
reportSubtask(initialSyncProgressService, InitSyncStep.Downloading, 1, 0.3f) {
// Empty task
}
@ -204,7 +204,7 @@ internal class DefaultSyncTask @Inject constructor(
// Log some stats
val nbOfJoinedRooms = syncResponse.rooms?.join?.size ?: 0
val nbOfJoinedRoomsInFile = syncResponse.rooms?.join?.values?.count { it.ephemeral is LazyRoomSyncEphemeral.Stored }
Timber.v("INIT_SYNC $nbOfJoinedRooms rooms, $nbOfJoinedRoomsInFile ephemeral stored into files")
Timber.d("INIT_SYNC $nbOfJoinedRooms rooms, $nbOfJoinedRoomsInFile ephemeral stored into files")
logDuration("INIT_SYNC Database insertion") {
syncResponseHandler.handleResponse(syncResponse, null, initialSyncProgressService)

View file

@ -106,7 +106,7 @@ internal class SyncWorker(context: Context,
val data = WorkerParamsFactory.toData(Params(sessionId, serverTimeout, 0L, false))
val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(WorkManagerProvider.workConstraints)
.setBackoffCriteria(BackoffPolicy.LINEAR, 1_000, TimeUnit.MILLISECONDS)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
.setInputData(data)
.build()
workManagerProvider.workManager
@ -118,7 +118,7 @@ internal class SyncWorker(context: Context,
val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(WorkManagerProvider.workConstraints)
.setInputData(data)
.setBackoffCriteria(BackoffPolicy.LINEAR, 1_000, TimeUnit.MILLISECONDS)
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY_MILLIS, TimeUnit.MILLISECONDS)
.setInitialDelay(delayInSeconds, TimeUnit.SECONDS)
.build()

View file

@ -57,12 +57,12 @@ internal class SplitLazyRoomSyncEphemeralJsonAdapter(
}
val limit = syncStrategy.minSizeToStoreInFile
return if (json.length > limit) {
Timber.v("INIT_SYNC $path content length: ${json.length} copy to a file")
Timber.d("INIT_SYNC $path content length: ${json.length} copy to a file")
// Copy the source to a file
roomSyncEphemeralTemporaryStore.write(roomId, json)
LazyRoomSyncEphemeral.Stored
} else {
Timber.v("INIT_SYNC $path content length: ${json.length} parse it now")
Timber.d("INIT_SYNC $path content length: ${json.length} parse it now")
val roomSync = delegate.fromJson(json) ?: return null
LazyRoomSyncEphemeral.Parsed(roomSync)
}

View file

@ -33,9 +33,9 @@ internal class InitialSyncResponseParser @Inject constructor(
fun parse(syncStrategy: InitialSyncStrategy.Optimized, workingFile: File): SyncResponse {
val syncResponseLength = workingFile.length().toInt()
Timber.v("INIT_SYNC Sync file size is $syncResponseLength bytes")
Timber.d("INIT_SYNC Sync file size is $syncResponseLength bytes")
val shouldSplit = syncResponseLength >= syncStrategy.minSizeToSplit
Timber.v("INIT_SYNC should split in several files: $shouldSplit")
Timber.d("INIT_SYNC should split in several files: $shouldSplit")
return getMoshi(syncStrategy, shouldSplit)
.adapter(SyncResponse::class.java)
.fromJson(workingFile.source().buffer())!!

View file

@ -33,13 +33,13 @@ internal fun <T> Collection<T>.logLimit(maxQuantity: Int = 5): String {
internal suspend fun <T> logDuration(message: String,
block: suspend () -> T): T {
Timber.v("$message -- BEGIN")
Timber.d("$message -- BEGIN")
val start = System.currentTimeMillis()
val result = logRamUsage(message) {
block()
}
val duration = System.currentTimeMillis() - start
Timber.v("$message -- END duration: $duration ms")
Timber.d("$message -- END duration: $duration ms")
return result
}
@ -50,12 +50,12 @@ internal suspend fun <T> logRamUsage(message: String, block: suspend () -> T): T
runtime.gc()
val freeMemoryInMb = runtime.freeMemory() / 1048576L
val usedMemInMBStart = runtime.totalMemory() / 1048576L - freeMemoryInMb
Timber.v("$message -- BEGIN (free memory: $freeMemoryInMb MB)")
Timber.d("$message -- BEGIN (free memory: $freeMemoryInMb MB)")
val result = block()
runtime.gc()
val usedMemInMBEnd = (runtime.totalMemory() - runtime.freeMemory()) / 1048576L
val usedMemInMBDiff = usedMemInMBEnd - usedMemInMBStart
Timber.v("$message -- END RAM usage: $usedMemInMBDiff MB")
Timber.d("$message -- END RAM usage: $usedMemInMBDiff MB")
result
} else {
block()