Skip to content

Commit

Permalink
fix: allow isolate to exit when database is closed (#239)
Browse files Browse the repository at this point in the history
Fixes #231
  • Loading branch information
blaugold committed Nov 16, 2021
1 parent 9023258 commit 8c481d8
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 7 deletions.
37 changes: 33 additions & 4 deletions packages/cbl/lib/src/query/proxy_query.dart
Expand Up @@ -11,6 +11,7 @@ import '../service/cbl_service_api.dart';
import '../service/proxy_object.dart';
import '../support/encoding.dart';
import '../support/listener_token.dart';
import '../support/resource.dart';
import '../support/streams.dart';
import '../support/utils.dart';
import 'data_source.dart';
Expand All @@ -37,6 +38,7 @@ class ProxyQuery extends QueryBase with ProxyObjectMixin implements AsyncQuery {
late final _lock = Lock();
late final _listenerTokens = ListenerTokenRegistry(this);
late List<String> _columnNames;
_ProxyQueryEarlyFinalizer? _earlyFinalizer;

@override
ProxyDatabase? get database => super.database as ProxyDatabase?;
Expand Down Expand Up @@ -128,7 +130,18 @@ class ProxyQuery extends QueryBase with ProxyObjectMixin implements AsyncQuery {

_columnNames = state.columnNames;

bindToTargetObject(channel, state.id);
// We need this so we don't capture `this` in the closure of proxyFinalizer.
late final _ProxyQueryEarlyFinalizer earlyFinalizer;

bindToTargetObject(
channel,
state.id,
// ignore: unnecessary_lambdas
proxyFinalizer: () => earlyFinalizer.deactivate(),
);

_earlyFinalizer =
earlyFinalizer = _ProxyQueryEarlyFinalizer(database!, finalizeEarly);
}

Future<void> _applyParameters(Parameters? parameters) {
Expand All @@ -147,9 +160,25 @@ class ProxyQuery extends QueryBase with ProxyObjectMixin implements AsyncQuery {
}

@override
Future<void> performClose() async {
if (isBoundToTarget) {
return finalizeEarly();
FutureOr<void> performClose() => _earlyFinalizer?.close();
}

class _ProxyQueryEarlyFinalizer with ClosableResourceMixin {
_ProxyQueryEarlyFinalizer(ProxyDatabase database, this._finalizerEarly) {
// We need to attach to the database and not to the query. Otherwise,
// the query could never be garbage collected.
attachTo(database);
}

final Future<void> Function() _finalizerEarly;

@override
FutureOr<void> performClose() => _finalizerEarly();

/// Deactivates this finalizer if it has not been closed yet.
void deactivate() {
if (!isClosed) {
needsToBeClosedByParent = false;
}
}
}
Expand Down
14 changes: 11 additions & 3 deletions packages/cbl/lib/src/service/proxy_object.dart
Expand Up @@ -58,10 +58,18 @@ mixin ProxyObjectMixin {
);
}

Future<void> finalizeEarly() {
Future<void> Function() get finalizeEarly {
assert(isBoundToTarget);
dartFinalizerRegistry.unregisterFinalizer(_finalizerToken);
return channel!.call(ReleaseObject(objectId!));

// Don't capture `this` in the closure of the returned function.
final finalizerToken = _finalizerToken;
final objectId = this.objectId!;
final channel = this.channel!;

return () {
dartFinalizerRegistry.unregisterFinalizer(finalizerToken);
return channel.call(ReleaseObject(objectId));
};
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/cbl/lib/src/support/resource.dart
Expand Up @@ -56,6 +56,7 @@ mixin ClosableResourceMixin implements ClosableResource {
/// not leak resources.
///
/// Even if this property is `false`, the parent might still closed it.
@protected
bool get needsToBeClosedByParent => _needsToBeClosedByParent;
bool _needsToBeClosedByParent = true;

Expand Down

0 comments on commit 8c481d8

Please sign in to comment.