refactor: Remove database transaction workaround

The workaround was from the
time when we have used
sqflite or when Hive had
bugs. But now HiveCollections
already supports transactions
in Dart zones and concurrent
write operations shouldn't
be a problem anymore.
This commit is contained in:
Christian Pauly 2022-12-13 10:12:42 +01:00
parent 9d9b1e38ec
commit 7a5b013c92
4 changed files with 4 additions and 68 deletions

View File

@ -308,7 +308,7 @@ abstract class DatabaseApi {
Future<dynamic> close();
Future<T> transaction<T>(Future<T> Function() action);
Future<void> transaction(Future<void> Function() action);
Future<String> exportDump();

View File

@ -1310,61 +1310,9 @@ class HiveCollectionsDatabase extends DatabaseApi {
return;
}
Completer<void>? _transactionLock;
final _transactionZones = <Zone>{};
@override
Future<T> transaction<T>(Future<T> Function() action) async {
// we want transactions to lock, however NOT if transactoins are run inside of each other.
// to be able to do this, we use dart zones (https://dart.dev/articles/archive/zones).
// _transactionZones holds a set of all zones which are currently running a transaction.
// _transactionLock holds the lock.
// first we try to determine if we are inside of a transaction currently
var isInTransaction = false;
Zone? zone = Zone.current;
// for that we keep on iterating to the parent zone until there is either no zone anymore
// or we have found a zone inside of _transactionZones.
while (zone != null) {
if (_transactionZones.contains(zone)) {
isInTransaction = true;
break;
}
zone = zone.parent;
}
// if we are inside a transaction....just run the action
if (isInTransaction) {
return await action();
}
// if we are *not* in a transaction, time to wait for the lock!
while (_transactionLock != null) {
await _transactionLock!.future;
}
// claim the lock
final lock = Completer<void>();
_transactionLock = lock;
try {
// run the action inside of a new zone
return await runZoned(() async {
try {
// don't forget to add the new zone to _transactionZones!
_transactionZones.add(Zone.current);
late final T result;
await _collection.transaction(() async {
result = await action();
});
return result;
} finally {
// aaaand remove the zone from _transactionZones again
_transactionZones.remove(Zone.current);
}
});
} finally {
// aaaand finally release the lock
_transactionLock = null;
lock.complete();
}
}
Future<void> transaction(Future<void> Function() action) =>
_collection.transaction(action);
@override
Future<void> updateClient(

View File

@ -1255,7 +1255,7 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
final _transactionZones = <Zone>{};
@override
Future<T> transaction<T>(Future<T> Function() action) async {
Future<void> transaction(Future<void> Function() action) async {
// we want transactions to lock, however NOT if transactoins are run inside of each other.
// to be able to do this, we use dart zones (https://dart.dev/articles/archive/zones).
// _transactionZones holds a set of all zones which are currently running a transaction.

View File

@ -64,18 +64,6 @@ void testDatabase(
});
expect(counter++, 3);
});
// we can't use Zone.root.run inside of tests so we abuse timers instead
Timer(Duration(milliseconds: 50), () async {
await database.transaction(() async {
expect(counter++, 6);
});
});
await database.transaction(() async {
expect(counter++, 4);
await Future.delayed(Duration(milliseconds: 100));
expect(counter++, 5);
});
});
test('insertIntoToDeviceQueue', () async {
toDeviceQueueIndex = await database.insertIntoToDeviceQueue(