Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finalizers keep-alive #243

Merged
merged 1 commit into from
May 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions objectbox/lib/src/native/bindings/bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,13 @@ late final native_query_close =
_lib!.lookup<NativeFunction<_native_close>>('obx_query_close');
late final native_query_prop_close =
_lib!.lookup<NativeFunction<_native_close>>('obx_query_prop_close');

/// Keeps `this` alive until this call, preventing finalizers to run.
/// Necessary for objects with a finalizer attached because the optimizer may
/// mark the object as unused (-> GCed -> finalized) even before it's method
/// finished executing.
/// See https://github.com/dart-lang/sdk/issues/35770#issuecomment-840398463
@pragma('vm:never-inline')
Object reachabilityFence(Object obj) {
return obj;
}
15 changes: 11 additions & 4 deletions objectbox/lib/src/native/query/property.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ class PropertyQuery<T> {
bool _distinct = false;
bool _caseSensitive = false;

PropertyQuery._(Pointer<OBX_query> cQuery, ModelProperty property)
: _type = property.type,
_cProp = checkObxPtr(
C.query_prop(cQuery, property.id.id), 'property query') {
PropertyQuery._(this._cProp, this._type) {
checkObxPtr(_cProp, 'property query');
_cFinalizer = C.dartc_attach_finalizer(
this, native_query_prop_close, _cProp.cast(), 64);
if (_cFinalizer == nullptr) {
Expand All @@ -38,6 +36,7 @@ class PropertyQuery<T> {
final ptr = malloc<Uint64>();
try {
checkObx(C.query_prop_count(_cProp, ptr));
reachabilityFence(this);
return ptr.value;
} finally {
malloc.free(ptr);
Expand All @@ -53,6 +52,7 @@ class PropertyQuery<T> {
try {
cItems = checkObxPtr(
findFn(_cProp, cDefault ?? nullptr), 'Property query failed');
reachabilityFence(this);
return listReadFn(cItems);
} finally {
if (cDefault != null) malloc.free(cDefault);
Expand All @@ -64,6 +64,7 @@ class PropertyQuery<T> {
final ptr = malloc<Double>();
try {
checkObx(C.query_prop_avg(_cProp, ptr, nullptr));
reachabilityFence(this);
return ptr.value;
} finally {
malloc.free(ptr);
Expand All @@ -79,6 +80,7 @@ extension IntegerPropertyQuery on PropertyQuery<int> {
final ptr = malloc<Int64>();
try {
checkObx(fn(_cProp, ptr, nullptr));
reachabilityFence(this);
return ptr.value;
} finally {
malloc.free(ptr);
Expand All @@ -101,6 +103,7 @@ extension IntegerPropertyQuery on PropertyQuery<int> {
set distinct(bool d) {
_distinct = d;
checkObx(C.query_prop_distinct(_cProp, d));
reachabilityFence(this);
}

/// Minimum value of the property over all objects matching the query.
Expand Down Expand Up @@ -175,6 +178,7 @@ extension DoublePropertyQuery on PropertyQuery<double> {
final ptr = malloc<Double>();
try {
checkObx(fn(_cProp, ptr, nullptr));
reachabilityFence(this);
return ptr.value;
} finally {
malloc.free(ptr);
Expand All @@ -197,6 +201,7 @@ extension DoublePropertyQuery on PropertyQuery<double> {
set distinct(bool d) {
_distinct = d;
checkObx(C.query_prop_distinct(_cProp, d));
reachabilityFence(this);
}

/// Minimum value of the property over all objects matching the query.
Expand Down Expand Up @@ -248,6 +253,7 @@ extension StringPropertyQuery on PropertyQuery<String> {
set caseSensitive(bool caseSensitive) {
_caseSensitive = caseSensitive;
checkObx(C.query_prop_distinct_case(_cProp, _distinct, _caseSensitive));
reachabilityFence(this);
}

/// Get status of the case-sensitive configuration.
Expand All @@ -263,6 +269,7 @@ extension StringPropertyQuery on PropertyQuery<String> {
set distinct(bool d) {
_distinct = d;
checkObx(C.query_prop_distinct_case(_cProp, d, _caseSensitive));
reachabilityFence(this);
}

/// Returns the count of non-null values.
Expand Down
35 changes: 29 additions & 6 deletions objectbox/lib/src/native/query/query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ class _ByteVectorCondition<EntityT>
func) =>
withNativeBytes(
_value,
(Pointer<Uint8> ptr, int size) =>
(Pointer<Uint8> ptr, int size) =>
func(builder._cBuilder, _property._model.id.id, ptr, size));

@override
Expand Down Expand Up @@ -652,7 +652,11 @@ class Query<T> {
/// the whole result, e.g. for "result paging".
///
/// Set offset=0 to reset to the default - starting from the first element.
set offset(int offset) => checkObx(C.query_offset(_ptr, offset));
set offset(int offset) {
final result = checkObx(C.query_offset(_ptr, offset));
reachabilityFence(this);
return result;
}

/// Configure a [limit] for this query.
///
Expand All @@ -661,13 +665,18 @@ class Query<T> {
/// the whole result, e.g. for "result paging".
///
/// Set limit=0 to reset to the default behavior - no limit applied.
set limit(int limit) => checkObx(C.query_limit(_ptr, limit));
set limit(int limit) {
final result = checkObx(C.query_limit(_ptr, limit));
reachabilityFence(this);
return result;
}

/// Returns the number of matching Objects.
int count() {
final ptr = malloc<Uint64>();
try {
checkObx(C.query_count(_ptr, ptr));
reachabilityFence(this);
return ptr.value;
} finally {
malloc.free(ptr);
Expand Down Expand Up @@ -710,12 +719,14 @@ class Query<T> {
_store.runInTransaction(TxMode.read, () {
checkObx(C.query_visit(_ptr, visitor, nullptr));
});
reachabilityFence(this);
return result;
}

/// Finds Objects matching the query and returns their IDs.
List<int> findIds() {
final idArrayPtr = checkObxPtr(C.query_find_ids(_ptr), 'find ids');
reachabilityFence(this);
try {
final idArray = idArrayPtr.ref;
return idArray.count == 0
Expand All @@ -732,6 +743,7 @@ class Query<T> {
final collector = objectCollector(result, _store, _entity);
_store.runInTransaction(
TxMode.read, () => checkObx(C.query_visit(_ptr, collector, nullptr)));
reachabilityFence(this);
return result;
}

Expand All @@ -754,6 +766,7 @@ class Query<T> {
closed = true;
C.dartc_stream_close(cStream);
port.close();
reachabilityFence(this);
};

try {
Expand Down Expand Up @@ -838,10 +851,18 @@ class Query<T> {
// }

/// For internal testing purposes.
String describe() => dartStringFromC(C.query_describe(_ptr));
String describe() {
final result = dartStringFromC(C.query_describe(_ptr));
reachabilityFence(this);
return result;
}

/// For internal testing purposes.
String describeParameters() => dartStringFromC(C.query_describe_params(_ptr));
String describeParameters() {
final result = dartStringFromC(C.query_describe_params(_ptr));
reachabilityFence(this);
return result;
}

/// Use the same query conditions but only return a single property (field).
///
Expand All @@ -852,7 +873,9 @@ class Query<T> {
/// var results = query.property(tInteger).find();
/// ```
PropertyQuery<DartType> property<DartType>(QueryProperty<T, DartType> prop) {
final result = PropertyQuery<DartType>._(_ptr, prop._model);
final result = PropertyQuery<DartType>._(
C.query_prop(_ptr, prop._model.id.id), prop._model.type);
reachabilityFence(this);
if (prop._model.type == OBXPropertyType.String) {
result._caseSensitive = InternalStoreAccess.queryCS(_store);
}
Expand Down