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> {
|
class Box<V> {
|
||||||
final String name;
|
final String name;
|
||||||
final BoxCollection boxCollection;
|
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
|
/// 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.
|
/// 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
|
/// Once the keys are cached, they need to be updated when changed in put and
|
||||||
/// delete* so that the cache does not become outdated.
|
/// delete* so that the cache does not become outdated.
|
||||||
Set<String>? _cachedKeys;
|
Set<String>? _quickAccessCachedKeys;
|
||||||
|
|
||||||
bool get _keysCached => _cachedKeys != null;
|
|
||||||
|
|
||||||
Box(this.name, this.boxCollection);
|
Box(this.name, this.boxCollection);
|
||||||
|
|
||||||
Future<List<String>> getAllKeys([Transaction? txn]) async {
|
Future<List<String>> getAllKeys([Transaction? txn]) async {
|
||||||
if (_keysCached) return _cachedKeys!.toList();
|
if (_quickAccessCachedKeys != null) return _quickAccessCachedKeys!.toList();
|
||||||
txn ??= boxCollection._db.transaction(name, 'readonly');
|
txn ??= boxCollection._db.transaction(name, 'readonly');
|
||||||
final store = txn.objectStore(name);
|
final store = txn.objectStore(name);
|
||||||
final request = store.getAllKeys(null);
|
final request = store.getAllKeys(null);
|
||||||
await request.onSuccess.first;
|
await request.onSuccess.first;
|
||||||
final keys = request.result.cast<String>();
|
final keys = request.result.cast<String>();
|
||||||
_cachedKeys = keys.toSet();
|
_quickAccessCachedKeys = keys.toSet();
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,16 +134,16 @@ class Box<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<V?> get(String key, [Transaction? txn]) async {
|
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');
|
txn ??= boxCollection._db.transaction(name, 'readonly');
|
||||||
final store = txn.objectStore(name);
|
final store = txn.objectStore(name);
|
||||||
_cache[key] = await store.getObject(key).then(_fromValue);
|
_quickAccessCache[key] = await store.getObject(key).then(_fromValue);
|
||||||
return _cache[key];
|
return _quickAccessCache[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<V?>> getAll(List<String> keys, [Transaction? txn]) async {
|
Future<List<V?>> getAll(List<String> keys, [Transaction? txn]) async {
|
||||||
if (keys.every((key) => _cache.containsKey(key))) {
|
if (keys.every((key) => _quickAccessCache.containsKey(key))) {
|
||||||
return keys.map((key) => _cache[key]).toList();
|
return keys.map((key) => _quickAccessCache[key]).toList();
|
||||||
}
|
}
|
||||||
txn ??= boxCollection._db.transaction(name, 'readonly');
|
txn ??= boxCollection._db.transaction(name, 'readonly');
|
||||||
final store = txn.objectStore(name);
|
final store = txn.objectStore(name);
|
||||||
|
|
@ -153,7 +151,7 @@ class Box<V> {
|
||||||
keys.map((key) => store.getObject(key).then(_fromValue)),
|
keys.map((key) => store.getObject(key).then(_fromValue)),
|
||||||
);
|
);
|
||||||
for (var i = 0; i < keys.length; i++) {
|
for (var i = 0; i < keys.length; i++) {
|
||||||
_cache[keys[i]] = list[i];
|
_quickAccessCache[keys[i]] = list[i];
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
@ -161,24 +159,24 @@ class Box<V> {
|
||||||
Future<void> put(String key, V val, [Transaction? txn]) async {
|
Future<void> put(String key, V val, [Transaction? txn]) async {
|
||||||
if (boxCollection._txnCache != null) {
|
if (boxCollection._txnCache != null) {
|
||||||
boxCollection._txnCache!.add((txn) => put(key, val, txn));
|
boxCollection._txnCache!.add((txn) => put(key, val, txn));
|
||||||
_cache[key] = val;
|
_quickAccessCache[key] = val;
|
||||||
_cachedKeys?.add(key);
|
_quickAccessCachedKeys?.add(key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
txn ??= boxCollection._db.transaction(name, 'readwrite');
|
txn ??= boxCollection._db.transaction(name, 'readwrite');
|
||||||
final store = txn.objectStore(name);
|
final store = txn.objectStore(name);
|
||||||
await store.put(val as Object, key);
|
await store.put(val as Object, key);
|
||||||
_cache[key] = val;
|
_quickAccessCache[key] = val;
|
||||||
_cachedKeys?.add(key);
|
_quickAccessCachedKeys?.add(key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> delete(String key, [Transaction? txn]) async {
|
Future<void> delete(String key, [Transaction? txn]) async {
|
||||||
if (boxCollection._txnCache != null) {
|
if (boxCollection._txnCache != null) {
|
||||||
boxCollection._txnCache!.add((txn) => delete(key, txn));
|
boxCollection._txnCache!.add((txn) => delete(key, txn));
|
||||||
_cache[key] = null;
|
_quickAccessCache[key] = null;
|
||||||
_cachedKeys?.remove(key);
|
_quickAccessCachedKeys?.remove(key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,8 +186,8 @@ class Box<V> {
|
||||||
|
|
||||||
// Set to null instead remove() so that inside of transactions null is
|
// Set to null instead remove() so that inside of transactions null is
|
||||||
// returned.
|
// returned.
|
||||||
_cache[key] = null;
|
_quickAccessCache[key] = null;
|
||||||
_cachedKeys?.remove(key);
|
_quickAccessCachedKeys?.remove(key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,9 +195,9 @@ class Box<V> {
|
||||||
if (boxCollection._txnCache != null) {
|
if (boxCollection._txnCache != null) {
|
||||||
boxCollection._txnCache!.add((txn) => deleteAll(keys, txn));
|
boxCollection._txnCache!.add((txn) => deleteAll(keys, txn));
|
||||||
for (final key in keys) {
|
for (final key in keys) {
|
||||||
_cache[key] = null;
|
_quickAccessCache[key] = null;
|
||||||
}
|
}
|
||||||
_cachedKeys?.removeAll(keys);
|
_quickAccessCachedKeys?.removeAll(keys);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,26 +205,27 @@ class Box<V> {
|
||||||
final store = txn.objectStore(name);
|
final store = txn.objectStore(name);
|
||||||
for (final key in keys) {
|
for (final key in keys) {
|
||||||
await store.delete(key);
|
await store.delete(key);
|
||||||
_cache[key] = null;
|
_quickAccessCache[key] = null;
|
||||||
_cachedKeys?.remove(key);
|
_quickAccessCachedKeys?.remove(key);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearQuickAccessCache() {
|
||||||
|
_quickAccessCache.clear();
|
||||||
|
_quickAccessCachedKeys = null;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> clear([Transaction? txn]) async {
|
Future<void> clear([Transaction? txn]) async {
|
||||||
if (boxCollection._txnCache != null) {
|
if (boxCollection._txnCache != null) {
|
||||||
boxCollection._txnCache!.add((txn) => clear(txn));
|
boxCollection._txnCache!.add((txn) => clear(txn));
|
||||||
_cache.clear();
|
} else {
|
||||||
_cachedKeys = null;
|
txn ??= boxCollection._db.transaction(name, 'readwrite');
|
||||||
return;
|
final store = txn.objectStore(name);
|
||||||
|
await store.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
txn ??= boxCollection._db.transaction(name, 'readwrite');
|
clearQuickAccessCache();
|
||||||
final store = txn.objectStore(name);
|
|
||||||
await store.clear();
|
|
||||||
_cache.clear();
|
|
||||||
_cachedKeys = null;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
V? _fromValue(Object? value) {
|
V? _fromValue(Object? value) {
|
||||||
|
|
|
||||||
|
|
@ -338,7 +338,32 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@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
|
@override
|
||||||
Future<void> clearCache() => transaction(() async {
|
Future<void> clearCache() => transaction(() async {
|
||||||
|
|
|
||||||
|
|
@ -81,15 +81,14 @@ class BoxCollection with ZoneTransactionMixin {
|
||||||
class Box<V> {
|
class Box<V> {
|
||||||
final String name;
|
final String name;
|
||||||
final BoxCollection boxCollection;
|
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
|
/// 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.
|
/// 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
|
/// Once the keys are cached, they need to be updated when changed in put and
|
||||||
/// delete* so that the cache does not become outdated.
|
/// delete* so that the cache does not become outdated.
|
||||||
Set<String>? _cachedKeys;
|
Set<String>? _quickAccessCachedKeys;
|
||||||
bool get _keysCached => _cachedKeys != null;
|
|
||||||
|
|
||||||
static const Set<Type> allowedValueTypes = {
|
static const Set<Type> allowedValueTypes = {
|
||||||
List<dynamic>,
|
List<dynamic>,
|
||||||
|
|
@ -148,14 +147,14 @@ class Box<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<String>> getAllKeys([Transaction? txn]) async {
|
Future<List<String>> getAllKeys([Transaction? txn]) async {
|
||||||
if (_keysCached) return _cachedKeys!.toList();
|
if (_quickAccessCachedKeys != null) return _quickAccessCachedKeys!.toList();
|
||||||
|
|
||||||
final executor = txn ?? boxCollection._db;
|
final executor = txn ?? boxCollection._db;
|
||||||
|
|
||||||
final result = await executor.query(name, columns: ['k']);
|
final result = await executor.query(name, columns: ['k']);
|
||||||
final keys = result.map((row) => row['k'] as String).toList();
|
final keys = result.map((row) => row['k'] as String).toList();
|
||||||
|
|
||||||
_cachedKeys = keys.toSet();
|
_quickAccessCachedKeys = keys.toSet();
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -174,7 +173,7 @@ class Box<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<V?> get(String key, [Transaction? txn]) async {
|
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;
|
final executor = txn ?? boxCollection._db;
|
||||||
|
|
||||||
|
|
@ -186,13 +185,13 @@ class Box<V> {
|
||||||
);
|
);
|
||||||
|
|
||||||
final value = result.isEmpty ? null : _fromString(result.single['v']);
|
final value = result.isEmpty ? null : _fromString(result.single['v']);
|
||||||
_cache[key] = value;
|
_quickAccessCache[key] = value;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<V?>> getAll(List<String> keys, [Transaction? txn]) async {
|
Future<List<V?>> getAll(List<String> keys, [Transaction? txn]) async {
|
||||||
if (!keys.any((key) => !_cache.containsKey(key))) {
|
if (!keys.any((key) => !_quickAccessCache.containsKey(key))) {
|
||||||
return keys.map((key) => _cache[key]).toList();
|
return keys.map((key) => _quickAccessCache[key]).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The SQL operation might fail with more than 1000 keys. We define some
|
// The SQL operation might fail with more than 1000 keys. We define some
|
||||||
|
|
@ -224,7 +223,7 @@ class Box<V> {
|
||||||
// `resultMap.values`.
|
// `resultMap.values`.
|
||||||
list.addAll(keys.map((key) => resultMap[key]));
|
list.addAll(keys.map((key) => resultMap[key]));
|
||||||
|
|
||||||
_cache.addAll(resultMap);
|
_quickAccessCache.addAll(resultMap);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
@ -250,8 +249,8 @@ class Box<V> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_cache[key] = val;
|
_quickAccessCache[key] = val;
|
||||||
_cachedKeys?.add(key);
|
_quickAccessCachedKeys?.add(key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -266,8 +265,8 @@ class Box<V> {
|
||||||
|
|
||||||
// Set to null instead remove() so that inside of transactions null is
|
// Set to null instead remove() so that inside of transactions null is
|
||||||
// returned.
|
// returned.
|
||||||
_cache[key] = null;
|
_quickAccessCache[key] = null;
|
||||||
_cachedKeys?.remove(key);
|
_quickAccessCachedKeys?.remove(key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,12 +289,17 @@ class Box<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final key in keys) {
|
for (final key in keys) {
|
||||||
_cache[key] = null;
|
_quickAccessCache[key] = null;
|
||||||
_cachedKeys?.removeAll(keys);
|
_quickAccessCachedKeys?.removeAll(keys);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearQuickAccessCache() {
|
||||||
|
_quickAccessCache.clear();
|
||||||
|
_quickAccessCachedKeys = null;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> clear([Batch? txn]) async {
|
Future<void> clear([Batch? txn]) async {
|
||||||
txn ??= boxCollection._activeBatch;
|
txn ??= boxCollection._activeBatch;
|
||||||
|
|
||||||
|
|
@ -305,8 +309,6 @@ class Box<V> {
|
||||||
txn.delete(name);
|
txn.delete(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
_cache.clear();
|
clearQuickAccessCache();
|
||||||
_cachedKeys = null;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue