From cb2285de62bab825baefaecfab833ccf3f5ada88 Mon Sep 17 00:00:00 2001 From: Karthikeyan S Date: Fri, 20 Dec 2024 16:46:59 +0530 Subject: [PATCH] fix: clear cache when clearing DB in MatrixSdkDatabase --- lib/src/database/indexeddb_box.dart | 67 +++++++++++------------ lib/src/database/matrix_sdk_database.dart | 27 ++++++++- lib/src/database/sqflite_box.dart | 42 +++++++------- 3 files changed, 81 insertions(+), 55 deletions(-) diff --git a/lib/src/database/indexeddb_box.dart b/lib/src/database/indexeddb_box.dart index 268006a1..080b1ad5 100644 --- a/lib/src/database/indexeddb_box.dart +++ b/lib/src/database/indexeddb_box.dart @@ -100,27 +100,25 @@ class BoxCollection with ZoneTransactionMixin { class Box { final String name; final BoxCollection boxCollection; - final Map _cache = {}; + final Map _quickAccessCache = {}; - /// _cachedKeys is only used to make sure that if you fetch all keys from a + /// _quickAccessCachedKeys is only used to make sure that if you fetch all keys from a /// box, you do not need to have an expensive read operation twice. There is /// no other usage for this at the moment. So the cache is never partial. /// Once the keys are cached, they need to be updated when changed in put and /// delete* so that the cache does not become outdated. - Set? _cachedKeys; - - bool get _keysCached => _cachedKeys != null; + Set? _quickAccessCachedKeys; Box(this.name, this.boxCollection); Future> getAllKeys([Transaction? txn]) async { - if (_keysCached) return _cachedKeys!.toList(); + if (_quickAccessCachedKeys != null) return _quickAccessCachedKeys!.toList(); txn ??= boxCollection._db.transaction(name, 'readonly'); final store = txn.objectStore(name); final request = store.getAllKeys(null); await request.onSuccess.first; final keys = request.result.cast(); - _cachedKeys = keys.toSet(); + _quickAccessCachedKeys = keys.toSet(); return keys; } @@ -136,16 +134,16 @@ class Box { } Future get(String key, [Transaction? txn]) async { - if (_cache.containsKey(key)) return _cache[key]; + if (_quickAccessCache.containsKey(key)) return _quickAccessCache[key]; txn ??= boxCollection._db.transaction(name, 'readonly'); final store = txn.objectStore(name); - _cache[key] = await store.getObject(key).then(_fromValue); - return _cache[key]; + _quickAccessCache[key] = await store.getObject(key).then(_fromValue); + return _quickAccessCache[key]; } Future> getAll(List keys, [Transaction? txn]) async { - if (keys.every((key) => _cache.containsKey(key))) { - return keys.map((key) => _cache[key]).toList(); + if (keys.every((key) => _quickAccessCache.containsKey(key))) { + return keys.map((key) => _quickAccessCache[key]).toList(); } txn ??= boxCollection._db.transaction(name, 'readonly'); final store = txn.objectStore(name); @@ -153,7 +151,7 @@ class Box { keys.map((key) => store.getObject(key).then(_fromValue)), ); for (var i = 0; i < keys.length; i++) { - _cache[keys[i]] = list[i]; + _quickAccessCache[keys[i]] = list[i]; } return list; } @@ -161,24 +159,24 @@ class Box { Future put(String key, V val, [Transaction? txn]) async { if (boxCollection._txnCache != null) { boxCollection._txnCache!.add((txn) => put(key, val, txn)); - _cache[key] = val; - _cachedKeys?.add(key); + _quickAccessCache[key] = val; + _quickAccessCachedKeys?.add(key); return; } txn ??= boxCollection._db.transaction(name, 'readwrite'); final store = txn.objectStore(name); await store.put(val as Object, key); - _cache[key] = val; - _cachedKeys?.add(key); + _quickAccessCache[key] = val; + _quickAccessCachedKeys?.add(key); return; } Future delete(String key, [Transaction? txn]) async { if (boxCollection._txnCache != null) { boxCollection._txnCache!.add((txn) => delete(key, txn)); - _cache[key] = null; - _cachedKeys?.remove(key); + _quickAccessCache[key] = null; + _quickAccessCachedKeys?.remove(key); return; } @@ -188,8 +186,8 @@ class Box { // Set to null instead remove() so that inside of transactions null is // returned. - _cache[key] = null; - _cachedKeys?.remove(key); + _quickAccessCache[key] = null; + _quickAccessCachedKeys?.remove(key); return; } @@ -197,9 +195,9 @@ class Box { if (boxCollection._txnCache != null) { boxCollection._txnCache!.add((txn) => deleteAll(keys, txn)); for (final key in keys) { - _cache[key] = null; + _quickAccessCache[key] = null; } - _cachedKeys?.removeAll(keys); + _quickAccessCachedKeys?.removeAll(keys); return; } @@ -207,26 +205,27 @@ class Box { final store = txn.objectStore(name); for (final key in keys) { await store.delete(key); - _cache[key] = null; - _cachedKeys?.remove(key); + _quickAccessCache[key] = null; + _quickAccessCachedKeys?.remove(key); } return; } + void clearQuickAccessCache() { + _quickAccessCache.clear(); + _quickAccessCachedKeys = null; + } + Future clear([Transaction? txn]) async { if (boxCollection._txnCache != null) { boxCollection._txnCache!.add((txn) => clear(txn)); - _cache.clear(); - _cachedKeys = null; - return; + } else { + txn ??= boxCollection._db.transaction(name, 'readwrite'); + final store = txn.objectStore(name); + await store.clear(); } - txn ??= boxCollection._db.transaction(name, 'readwrite'); - final store = txn.objectStore(name); - await store.clear(); - _cache.clear(); - _cachedKeys = null; - return; + clearQuickAccessCache(); } V? _fromValue(Object? value) { diff --git a/lib/src/database/matrix_sdk_database.dart b/lib/src/database/matrix_sdk_database.dart index 247141b1..8c7ca444 100644 --- a/lib/src/database/matrix_sdk_database.dart +++ b/lib/src/database/matrix_sdk_database.dart @@ -338,7 +338,32 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage { } @override - Future clear() => _collection.clear(); + Future clear() async { + _clientBox.clearQuickAccessCache(); + _accountDataBox.clearQuickAccessCache(); + _roomsBox.clearQuickAccessCache(); + _preloadRoomStateBox.clearQuickAccessCache(); + _nonPreloadRoomStateBox.clearQuickAccessCache(); + _roomMembersBox.clearQuickAccessCache(); + _toDeviceQueueBox.clearQuickAccessCache(); + _roomAccountDataBox.clearQuickAccessCache(); + _inboundGroupSessionsBox.clearQuickAccessCache(); + _inboundGroupSessionsUploadQueueBox.clearQuickAccessCache(); + _outboundGroupSessionsBox.clearQuickAccessCache(); + _olmSessionsBox.clearQuickAccessCache(); + _userDeviceKeysBox.clearQuickAccessCache(); + _userDeviceKeysOutdatedBox.clearQuickAccessCache(); + _userCrossSigningKeysBox.clearQuickAccessCache(); + _ssssCacheBox.clearQuickAccessCache(); + _presencesBox.clearQuickAccessCache(); + _timelineFragmentsBox.clearQuickAccessCache(); + _eventsBox.clearQuickAccessCache(); + _seenDeviceIdsBox.clearQuickAccessCache(); + _seenDeviceKeysBox.clearQuickAccessCache(); + _userProfilesBox.clearQuickAccessCache(); + + await _collection.clear(); + } @override Future clearCache() => transaction(() async { diff --git a/lib/src/database/sqflite_box.dart b/lib/src/database/sqflite_box.dart index 4ab23115..99372ebd 100644 --- a/lib/src/database/sqflite_box.dart +++ b/lib/src/database/sqflite_box.dart @@ -81,15 +81,14 @@ class BoxCollection with ZoneTransactionMixin { class Box { final String name; final BoxCollection boxCollection; - final Map _cache = {}; + final Map _quickAccessCache = {}; - /// _cachedKeys is only used to make sure that if you fetch all keys from a + /// _quickAccessCachedKeys is only used to make sure that if you fetch all keys from a /// box, you do not need to have an expensive read operation twice. There is /// no other usage for this at the moment. So the cache is never partial. /// Once the keys are cached, they need to be updated when changed in put and /// delete* so that the cache does not become outdated. - Set? _cachedKeys; - bool get _keysCached => _cachedKeys != null; + Set? _quickAccessCachedKeys; static const Set allowedValueTypes = { List, @@ -148,14 +147,14 @@ class Box { } Future> getAllKeys([Transaction? txn]) async { - if (_keysCached) return _cachedKeys!.toList(); + if (_quickAccessCachedKeys != null) return _quickAccessCachedKeys!.toList(); final executor = txn ?? boxCollection._db; final result = await executor.query(name, columns: ['k']); final keys = result.map((row) => row['k'] as String).toList(); - _cachedKeys = keys.toSet(); + _quickAccessCachedKeys = keys.toSet(); return keys; } @@ -174,7 +173,7 @@ class Box { } Future get(String key, [Transaction? txn]) async { - if (_cache.containsKey(key)) return _cache[key]; + if (_quickAccessCache.containsKey(key)) return _quickAccessCache[key]; final executor = txn ?? boxCollection._db; @@ -186,13 +185,13 @@ class Box { ); final value = result.isEmpty ? null : _fromString(result.single['v']); - _cache[key] = value; + _quickAccessCache[key] = value; return value; } Future> getAll(List keys, [Transaction? txn]) async { - if (!keys.any((key) => !_cache.containsKey(key))) { - return keys.map((key) => _cache[key]).toList(); + if (!keys.any((key) => !_quickAccessCache.containsKey(key))) { + return keys.map((key) => _quickAccessCache[key]).toList(); } // The SQL operation might fail with more than 1000 keys. We define some @@ -224,7 +223,7 @@ class Box { // `resultMap.values`. list.addAll(keys.map((key) => resultMap[key])); - _cache.addAll(resultMap); + _quickAccessCache.addAll(resultMap); return list; } @@ -250,8 +249,8 @@ class Box { ); } - _cache[key] = val; - _cachedKeys?.add(key); + _quickAccessCache[key] = val; + _quickAccessCachedKeys?.add(key); return; } @@ -266,8 +265,8 @@ class Box { // Set to null instead remove() so that inside of transactions null is // returned. - _cache[key] = null; - _cachedKeys?.remove(key); + _quickAccessCache[key] = null; + _quickAccessCachedKeys?.remove(key); return; } @@ -290,12 +289,17 @@ class Box { } for (final key in keys) { - _cache[key] = null; - _cachedKeys?.removeAll(keys); + _quickAccessCache[key] = null; + _quickAccessCachedKeys?.removeAll(keys); } return; } + void clearQuickAccessCache() { + _quickAccessCache.clear(); + _quickAccessCachedKeys = null; + } + Future clear([Batch? txn]) async { txn ??= boxCollection._activeBatch; @@ -305,8 +309,6 @@ class Box { txn.delete(name); } - _cache.clear(); - _cachedKeys = null; - return; + clearQuickAccessCache(); } }