Skip to content

Commit b7076a1

Browse files
authored
Merge pull request #7879 from vector-im/feature/bma/still_investigating
Reduce number of crypto database transactions when handling the sync response
2 parents 41bcdd7 + dbf3b76 commit b7076a1

File tree

18 files changed

+380
-183
lines changed

18 files changed

+380
-183
lines changed

changelog.d/7879.bugfix

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Reduce number of crypto database transactions when handling the sync response

library/ui-strings/src/main/res/values/strings.xml

+3
Original file line numberDiff line numberDiff line change
@@ -3506,4 +3506,7 @@
35063506
<string name="message_reply_to_sender_sent_video">sent a video.</string>
35073507
<string name="message_reply_to_sender_sent_sticker">sent a sticker.</string>
35083508
<string name="message_reply_to_sender_created_poll">created a poll.</string>
3509+
3510+
<string name="settings_access_token">Access Token</string>
3511+
<string name="settings_access_token_summary">Your access token gives full access to your account. Do not share it with anyone.</string>
35093512
</resources>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2023 The Matrix.org Foundation C.I.C.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.matrix.android.sdk.api.session.crypto.crosssigning
18+
19+
/**
20+
* Container for the three cross signing keys: master, self signing and user signing.
21+
*/
22+
data class UserIdentity(
23+
val masterKey: CryptoCrossSigningKey?,
24+
val selfSigningKey: CryptoCrossSigningKey?,
25+
val userSigningKey: CryptoCrossSigningKey?,
26+
)

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt

+23-9
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ import org.matrix.android.sdk.internal.crypto.model.SessionInfo
8989
import org.matrix.android.sdk.internal.crypto.model.toRest
9090
import org.matrix.android.sdk.internal.crypto.repository.WarnOnUnknownDeviceRepository
9191
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
92+
import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
9293
import org.matrix.android.sdk.internal.crypto.tasks.DeleteDeviceTask
9394
import org.matrix.android.sdk.internal.crypto.tasks.GetDeviceInfoTask
9495
import org.matrix.android.sdk.internal.crypto.tasks.GetDevicesTask
@@ -192,21 +193,21 @@ internal class DefaultCryptoService @Inject constructor(
192193
private val isStarting = AtomicBoolean(false)
193194
private val isStarted = AtomicBoolean(false)
194195

195-
fun onStateEvent(roomId: String, event: Event) {
196+
fun onStateEvent(roomId: String, event: Event, cryptoStoreAggregator: CryptoStoreAggregator?) {
196197
when (event.type) {
197198
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
198199
EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
199-
EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
200+
EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event, cryptoStoreAggregator)
200201
}
201202
}
202203

203-
fun onLiveEvent(roomId: String, event: Event, isInitialSync: Boolean) {
204+
fun onLiveEvent(roomId: String, event: Event, isInitialSync: Boolean, cryptoStoreAggregator: CryptoStoreAggregator?) {
204205
// handle state events
205206
if (event.isStateEvent()) {
206207
when (event.type) {
207208
EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
208209
EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
209-
EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
210+
EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event, cryptoStoreAggregator)
210211
}
211212
}
212213

@@ -430,8 +431,10 @@ internal class DefaultCryptoService @Inject constructor(
430431
* A sync response has been received.
431432
*
432433
* @param syncResponse the syncResponse
434+
* @param cryptoStoreAggregator data aggregated during the sync response treatment to store
433435
*/
434-
fun onSyncCompleted(syncResponse: SyncResponse) {
436+
fun onSyncCompleted(syncResponse: SyncResponse, cryptoStoreAggregator: CryptoStoreAggregator) {
437+
cryptoStore.storeData(cryptoStoreAggregator)
435438
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
436439
runCatching {
437440
if (syncResponse.deviceLists != null) {
@@ -998,15 +1001,26 @@ internal class DefaultCryptoService @Inject constructor(
9981001
}
9991002
}
10001003

1001-
private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event) {
1004+
private fun onRoomHistoryVisibilityEvent(roomId: String, event: Event, cryptoStoreAggregator: CryptoStoreAggregator?) {
10021005
if (!event.isStateEvent()) return
10031006
val eventContent = event.content.toModel<RoomHistoryVisibilityContent>()
10041007
val historyVisibility = eventContent?.historyVisibility
10051008
if (historyVisibility == null) {
1006-
cryptoStore.setShouldShareHistory(roomId, false)
1009+
if (cryptoStoreAggregator != null) {
1010+
cryptoStoreAggregator.setShouldShareHistoryData[roomId] = false
1011+
} else {
1012+
// Store immediately
1013+
cryptoStore.setShouldShareHistory(roomId, false)
1014+
}
10071015
} else {
1008-
cryptoStore.setShouldEncryptForInvitedMembers(roomId, historyVisibility != RoomHistoryVisibility.JOINED)
1009-
cryptoStore.setShouldShareHistory(roomId, historyVisibility.shouldShareHistory())
1016+
if (cryptoStoreAggregator != null) {
1017+
cryptoStoreAggregator.setShouldEncryptForInvitedMembersData[roomId] = historyVisibility != RoomHistoryVisibility.JOINED
1018+
cryptoStoreAggregator.setShouldShareHistoryData[roomId] = historyVisibility.shouldShareHistory()
1019+
} else {
1020+
// Store immediately
1021+
cryptoStore.setShouldEncryptForInvitedMembers(roomId, historyVisibility != RoomHistoryVisibility.JOINED)
1022+
cryptoStore.setShouldShareHistory(roomId, historyVisibility.shouldShareHistory())
1023+
}
10101024
}
10111025
}
10121026

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt

+11-6
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ import org.matrix.android.sdk.api.auth.data.Credentials
2525
import org.matrix.android.sdk.api.extensions.measureMetric
2626
import org.matrix.android.sdk.api.metrics.DownloadDeviceKeysMetricsPlugin
2727
import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel
28+
import org.matrix.android.sdk.api.session.crypto.crosssigning.UserIdentity
2829
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
2930
import org.matrix.android.sdk.api.session.crypto.model.MXUsersDevicesMap
3031
import org.matrix.android.sdk.internal.crypto.model.CryptoInfoMapper
3132
import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryResponse
3233
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
34+
import org.matrix.android.sdk.internal.crypto.store.UserDataToStore
3335
import org.matrix.android.sdk.internal.crypto.tasks.DownloadKeysForUsersTask
3436
import org.matrix.android.sdk.internal.session.SessionScope
3537
import org.matrix.android.sdk.internal.session.sync.SyncTokenStore
@@ -371,6 +373,8 @@ internal class DeviceListManager @Inject constructor(
371373
Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users")
372374
}
373375

376+
val userDataToStore = UserDataToStore()
377+
374378
for (userId in filteredUsers) {
375379
// al devices =
376380
val models = response.deviceKeys?.get(userId)?.mapValues { entry -> CryptoInfoMapper.map(entry.value) }
@@ -404,7 +408,7 @@ internal class DeviceListManager @Inject constructor(
404408
}
405409
// Update the store
406410
// Note that devices which aren't in the response will be removed from the stores
407-
cryptoStore.storeUserDevices(userId, workingCopy)
411+
userDataToStore.userDevices[userId] = workingCopy
408412
}
409413

410414
val masterKey = response.masterKeys?.get(userId)?.toCryptoModel().also {
@@ -416,14 +420,15 @@ internal class DeviceListManager @Inject constructor(
416420
val userSigningKey = response.userSigningKeys?.get(userId)?.toCryptoModel()?.also {
417421
Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : USK ${it.unpaddedBase64PublicKey}")
418422
}
419-
cryptoStore.storeUserCrossSigningKeys(
420-
userId,
421-
masterKey,
422-
selfSigningKey,
423-
userSigningKey
423+
userDataToStore.userIdentities[userId] = UserIdentity(
424+
masterKey = masterKey,
425+
selfSigningKey = selfSigningKey,
426+
userSigningKey = userSigningKey
424427
)
425428
}
426429

430+
cryptoStore.storeData(userDataToStore)
431+
427432
// Update devices trust for these users
428433
// dispatchDeviceChange(downloadUsers)
429434

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt

+24-5
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ import org.matrix.android.sdk.api.session.crypto.GlobalCryptoConfig
2222
import org.matrix.android.sdk.api.session.crypto.NewSessionListener
2323
import org.matrix.android.sdk.api.session.crypto.OutgoingKeyRequest
2424
import org.matrix.android.sdk.api.session.crypto.OutgoingRoomKeyRequestState
25-
import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
2625
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
2726
import org.matrix.android.sdk.api.session.crypto.crosssigning.PrivateKeysInfo
27+
import org.matrix.android.sdk.api.session.crypto.crosssigning.UserIdentity
2828
import org.matrix.android.sdk.api.session.crypto.keysbackup.SavedKeyBackupKeyInfo
2929
import org.matrix.android.sdk.api.session.crypto.model.AuditTrail
3030
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
@@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.util.Optional
3939
import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper
4040
import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper
4141
import org.matrix.android.sdk.internal.crypto.model.OutboundGroupSessionWrapper
42+
import org.matrix.android.sdk.internal.crypto.store.db.CryptoStoreAggregator
4243
import org.matrix.android.sdk.internal.crypto.store.db.model.KeysBackupDataEntity
4344
import org.matrix.olm.OlmAccount
4445
import org.matrix.olm.OlmOutboundGroupSession
@@ -230,11 +231,12 @@ internal interface IMXCryptoStore {
230231
*/
231232
fun storeUserDevices(userId: String, devices: Map<String, CryptoDeviceInfo>?)
232233

233-
fun storeUserCrossSigningKeys(
234+
/**
235+
* Store the cross signing keys for the user userId.
236+
*/
237+
fun storeUserIdentity(
234238
userId: String,
235-
masterKey: CryptoCrossSigningKey?,
236-
selfSigningKey: CryptoCrossSigningKey?,
237-
userSigningKey: CryptoCrossSigningKey?
239+
userIdentity: UserIdentity
238240
)
239241

240242
/**
@@ -290,6 +292,13 @@ internal interface IMXCryptoStore {
290292

291293
fun shouldEncryptForInvitedMembers(roomId: String): Boolean
292294

295+
/**
296+
* Sets a boolean flag that will determine whether or not this device should encrypt Events for
297+
* invited members.
298+
*
299+
* @param roomId the room id
300+
* @param shouldEncryptForInvitedMembers The boolean flag
301+
*/
293302
fun setShouldEncryptForInvitedMembers(roomId: String, shouldEncryptForInvitedMembers: Boolean)
294303

295304
fun shouldShareHistory(roomId: String): Boolean
@@ -580,4 +589,14 @@ internal interface IMXCryptoStore {
580589
fun areDeviceKeysUploaded(): Boolean
581590
fun tidyUpDataBase()
582591
fun getOutgoingRoomKeyRequests(inStates: Set<OutgoingRoomKeyRequestState>): List<OutgoingKeyRequest>
592+
593+
/**
594+
* Store a bunch of data collected during a sync response treatment. @See [CryptoStoreAggregator].
595+
*/
596+
fun storeData(cryptoStoreAggregator: CryptoStoreAggregator)
597+
598+
/**
599+
* Store a bunch of data related to the users. @See [UserDataToStore].
600+
*/
601+
fun storeData(userDataToStore: UserDataToStore)
583602
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright (c) 2023 The Matrix.org Foundation C.I.C.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.matrix.android.sdk.internal.crypto.store
18+
19+
import org.matrix.android.sdk.api.session.crypto.crosssigning.UserIdentity
20+
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
21+
22+
internal data class UserDataToStore(
23+
/**
24+
* Map of userId -> (Map of deviceId -> [CryptoDeviceInfo]).
25+
*/
26+
val userDevices: MutableMap<String, Map<String, CryptoDeviceInfo>> = mutableMapOf(),
27+
/**
28+
* Map of userId -> [UserIdentity].
29+
*/
30+
val userIdentities: MutableMap<String, UserIdentity> = mutableMapOf(),
31+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (c) 2023 The Matrix.org Foundation C.I.C.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.matrix.android.sdk.internal.crypto.store.db
18+
19+
data class CryptoStoreAggregator(
20+
val setShouldShareHistoryData: MutableMap<String, Boolean> = mutableMapOf(),
21+
val setShouldEncryptForInvitedMembersData: MutableMap<String, Boolean> = mutableMapOf(),
22+
) {
23+
fun isEmpty(): Boolean {
24+
return setShouldShareHistoryData.isEmpty() &&
25+
setShouldEncryptForInvitedMembersData.isEmpty()
26+
}
27+
}

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt

+8-4
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ import android.util.Base64
2020
import io.realm.Realm
2121
import io.realm.RealmConfiguration
2222
import io.realm.RealmObject
23+
import timber.log.Timber
2324
import java.io.ByteArrayOutputStream
2425
import java.io.ObjectOutputStream
2526
import java.util.zip.GZIPInputStream
2627
import java.util.zip.GZIPOutputStream
28+
import kotlin.system.measureTimeMillis
2729

2830
/**
2931
* Get realm, invoke the action, close realm, and return the result of the action.
@@ -55,10 +57,12 @@ internal fun <T : RealmObject> doRealmQueryAndCopyList(realmConfiguration: Realm
5557
/**
5658
* Get realm instance, invoke the action in a transaction and close realm.
5759
*/
58-
internal fun doRealmTransaction(realmConfiguration: RealmConfiguration, action: (Realm) -> Unit) {
59-
Realm.getInstance(realmConfiguration).use { realm ->
60-
realm.executeTransaction { action.invoke(it) }
61-
}
60+
internal fun doRealmTransaction(tag: String, realmConfiguration: RealmConfiguration, action: (Realm) -> Unit) {
61+
measureTimeMillis {
62+
Realm.getInstance(realmConfiguration).use { realm ->
63+
realm.executeTransaction { action.invoke(it) }
64+
}
65+
}.also { Timber.w("doRealmTransaction for $tag took $it millis") }
6266
}
6367

6468
internal fun doRealmTransactionAsync(realmConfiguration: RealmConfiguration, action: (Realm) -> Unit) {

0 commit comments

Comments
 (0)