Merge pull request #1961 from famedly/karthi/cache-clear-matrix-sdk-db
fix: clear cache when clearing DB in MatrixSdkDatabase
This commit is contained in:
commit
f2e2ee8daf
|
|
@ -100,27 +100,25 @@ class BoxCollection with ZoneTransactionMixin {
|
|||
class Box<V> {
|
||||
final String name;
|
||||
final BoxCollection boxCollection;
|
||||
final Map<String, V?> _cache = {};
|
||||
final Map<String, V?> _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<String>? _cachedKeys;
|
||||
|
||||
bool get _keysCached => _cachedKeys != null;
|
||||
Set<String>? _quickAccessCachedKeys;
|
||||
|
||||
Box(this.name, this.boxCollection);
|
||||
|
||||
Future<List<String>> 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<String>();
|
||||
_cachedKeys = keys.toSet();
|
||||
_quickAccessCachedKeys = keys.toSet();
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
|
@ -136,16 +134,16 @@ class Box<V> {
|
|||
}
|
||||
|
||||
Future<V?> 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<List<V?>> getAll(List<String> 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<V> {
|
|||
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<V> {
|
|||
Future<void> 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<void> 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<V> {
|
|||
|
||||
// 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<V> {
|
|||
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<V> {
|
|||
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<void> 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) {
|
||||
|
|
|
|||
|
|
@ -338,7 +338,32 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> clear() => _collection.clear();
|
||||
Future<void> 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<void> clearCache() => transaction(() async {
|
||||
|
|
|
|||
|
|
@ -81,15 +81,14 @@ class BoxCollection with ZoneTransactionMixin {
|
|||
class Box<V> {
|
||||
final String name;
|
||||
final BoxCollection boxCollection;
|
||||
final Map<String, V?> _cache = {};
|
||||
final Map<String, V?> _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<String>? _cachedKeys;
|
||||
bool get _keysCached => _cachedKeys != null;
|
||||
Set<String>? _quickAccessCachedKeys;
|
||||
|
||||
static const Set<Type> allowedValueTypes = {
|
||||
List<dynamic>,
|
||||
|
|
@ -148,14 +147,14 @@ class Box<V> {
|
|||
}
|
||||
|
||||
Future<List<String>> 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<V> {
|
|||
}
|
||||
|
||||
Future<V?> 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<V> {
|
|||
);
|
||||
|
||||
final value = result.isEmpty ? null : _fromString(result.single['v']);
|
||||
_cache[key] = value;
|
||||
_quickAccessCache[key] = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
Future<List<V?>> getAll(List<String> 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<V> {
|
|||
// `resultMap.values`.
|
||||
list.addAll(keys.map((key) => resultMap[key]));
|
||||
|
||||
_cache.addAll(resultMap);
|
||||
_quickAccessCache.addAll(resultMap);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
|
@ -250,8 +249,8 @@ class Box<V> {
|
|||
);
|
||||
}
|
||||
|
||||
_cache[key] = val;
|
||||
_cachedKeys?.add(key);
|
||||
_quickAccessCache[key] = val;
|
||||
_quickAccessCachedKeys?.add(key);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -266,8 +265,8 @@ class Box<V> {
|
|||
|
||||
// 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<V> {
|
|||
}
|
||||
|
||||
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<void> clear([Batch? txn]) async {
|
||||
txn ??= boxCollection._activeBatch;
|
||||
|
||||
|
|
@ -305,8 +309,6 @@ class Box<V> {
|
|||
txn.delete(name);
|
||||
}
|
||||
|
||||
_cache.clear();
|
||||
_cachedKeys = null;
|
||||
return;
|
||||
clearQuickAccessCache();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue