diff --git a/CHANGELOG.md b/CHANGELOG.md index bf67df175..6987f8b1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ **This project is in Release Candidate stage.** ### Breaking Changes -* None +* File format version bumped. +* The layout of the lock-file has changed, the lock file format version is bumped and all participants in a multiprocess scenario needs to be up to date so they expect the same format. This requires an update of Studio. (Core upgrade) ### Enhancements * Support setting `maxNumberOfActiveVersions` when creating a `Configuration`. ([#1036](https://github.com/realm/realm-dart/pull/1036)) @@ -11,12 +12,20 @@ ### Fixed * Support mapping into `SyncSessionErrorCode` for "Compensating write" with error code 231. ([#1022](https://github.com/realm/realm-dart/pull/1022)) +* Errors from core will be raised correctly for `beginWriteAsync` and `commitAsync`. ([#1042](https://github.com/realm/realm-dart/pull/1042)) +* The realm file will be shrunk if the larger file size is no longer needed. (Core upgrade) +* Most of the file growth caused by version pinning is eliminated. (Core upgrade) +* Fetching a user's profile while the user logs out would result in an assertion failure. (Core upgrade) +* Removed the ".tmp_compaction_space" file being left over after compacting a Realm on Windows. (Core upgrade). +* Restore fallback to full barrier when F_BARRIERSYNC is not available on Apple platforms. (Core upgrade, since v0.8.0+rc) +* Fixed wrong assertion on query error that could result in a crash. (Core upgrade) ### Compatibility -* Realm Studio: 12.0.0 or later. +* Realm Studio: 13.0.0 or later. +* Fileformat: Generates files with format v23. Reads and automatically upgrades from fileformat v5. ### Internal -* Using Core 12.12.0. +* Using Core 13.1.0. ## 0.8.0+rc (2022-11-14) @@ -35,7 +44,7 @@ * Realm Studio: 12.0.0 or later. ### Internal -* Using Core 12.12.0. ([#1025](https://github.com/realm/realm-dart/pull/1025)) +* Using Core 12.12.0. ## 0.7.0+rc (2022-11-04) @@ -88,7 +97,7 @@ * Realm Studio: 12.0.0 or later. ### Internal -* Using Core 12.11.0. ([#988](https://github.com/realm/realm-dart/pull/988)) +* Using Core 12.11.0. ## 0.6.0+beta (2022-10-21) diff --git a/lib/src/native/realm_bindings.dart b/lib/src/native/realm_bindings.dart index 3a3f5632a..5bdfd79f5 100644 --- a/lib/src/native/realm_bindings.dart +++ b/lib/src/native/realm_bindings.dart @@ -1672,12 +1672,13 @@ class RealmLibrary { realm_free_userdata_func_t)>(); /// start a new write transaction asynchronously for the realm passed as argument. - int realm_async_begin_write( + bool realm_async_begin_write( ffi.Pointer realm, realm_async_begin_write_func_t arg1, ffi.Pointer userdata, realm_free_userdata_func_t userdata_free, bool notify_only, + ffi.Pointer transaction_id, ) { return _realm_async_begin_write( realm, @@ -1685,20 +1686,27 @@ class RealmLibrary { userdata, userdata_free, notify_only, + transaction_id, ); } late final _realm_async_begin_writePtr = _lookup< ffi.NativeFunction< - ffi.UnsignedInt Function( + ffi.Bool Function( ffi.Pointer, realm_async_begin_write_func_t, ffi.Pointer, realm_free_userdata_func_t, - ffi.Bool)>>('realm_async_begin_write'); + ffi.Bool, + ffi.Pointer)>>('realm_async_begin_write'); late final _realm_async_begin_write = _realm_async_begin_writePtr.asFunction< - int Function(ffi.Pointer, realm_async_begin_write_func_t, - ffi.Pointer, realm_free_userdata_func_t, bool)>(); + bool Function( + ffi.Pointer, + realm_async_begin_write_func_t, + ffi.Pointer, + realm_free_userdata_func_t, + bool, + ffi.Pointer)>(); /// Cancel the transaction referenced by the token passed as argument and set the optional boolean flag in order to /// inform the caller if the transaction was cancelled. @@ -1722,12 +1730,13 @@ class RealmLibrary { bool Function(ffi.Pointer, int, ffi.Pointer)>(); /// commit a transaction asynchronously for the realm passed as argument. - int realm_async_commit( + bool realm_async_commit( ffi.Pointer realm, realm_async_commit_func_t arg1, ffi.Pointer userdata, realm_free_userdata_func_t userdata_free, bool allow_grouping, + ffi.Pointer transaction_id, ) { return _realm_async_commit( realm, @@ -1735,20 +1744,27 @@ class RealmLibrary { userdata, userdata_free, allow_grouping, + transaction_id, ); } late final _realm_async_commitPtr = _lookup< ffi.NativeFunction< - ffi.UnsignedInt Function( + ffi.Bool Function( ffi.Pointer, realm_async_commit_func_t, ffi.Pointer, realm_free_userdata_func_t, - ffi.Bool)>>('realm_async_commit'); + ffi.Bool, + ffi.Pointer)>>('realm_async_commit'); late final _realm_async_commit = _realm_async_commitPtr.asFunction< - int Function(ffi.Pointer, realm_async_commit_func_t, - ffi.Pointer, realm_free_userdata_func_t, bool)>(); + bool Function( + ffi.Pointer, + realm_async_commit_func_t, + ffi.Pointer, + realm_free_userdata_func_t, + bool, + ffi.Pointer)>(); void realm_async_open_task_cancel( ffi.Pointer arg0, @@ -1765,7 +1781,8 @@ class RealmLibrary { late final _realm_async_open_task_cancel = _realm_async_open_task_cancelPtr .asFunction)>(); - int realm_async_open_task_register_download_progress_notifier( + ffi.Pointer + realm_async_open_task_register_download_progress_notifier( ffi.Pointer arg0, realm_sync_progress_func_t arg1, ffi.Pointer userdata, @@ -1782,7 +1799,7 @@ class RealmLibrary { late final _realm_async_open_task_register_download_progress_notifierPtr = _lookup< ffi.NativeFunction< - ffi.Uint64 Function( + ffi.Pointer Function( ffi.Pointer, realm_sync_progress_func_t, ffi.Pointer, @@ -1790,7 +1807,7 @@ class RealmLibrary { 'realm_async_open_task_register_download_progress_notifier'); late final _realm_async_open_task_register_download_progress_notifier = _realm_async_open_task_register_download_progress_notifierPtr.asFunction< - int Function( + ffi.Pointer Function( ffi.Pointer, realm_sync_progress_func_t, ffi.Pointer, @@ -1825,27 +1842,6 @@ class RealmLibrary { ffi.Pointer, realm_free_userdata_func_t)>(); - void realm_async_open_task_unregister_download_progress_notifier( - ffi.Pointer arg0, - int token, - ) { - return _realm_async_open_task_unregister_download_progress_notifier( - arg0, - token, - ); - } - - late final _realm_async_open_task_unregister_download_progress_notifierPtr = - _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer, ffi.Uint64)>>( - 'realm_async_open_task_unregister_download_progress_notifier'); - late final _realm_async_open_task_unregister_download_progress_notifier = - _realm_async_open_task_unregister_download_progress_notifierPtr - .asFunction< - void Function(ffi.Pointer, int)>(); - ffi.Pointer realm_attach_finalizer( Object handle, ffi.Pointer realmPtr, @@ -7675,6 +7671,28 @@ class RealmLibrary { bool Function( ffi.Pointer, ffi.Pointer, int)>(); + /// Register a callback handler for bindings interested in registering callbacks before/after the ObjectStore thread + /// runs. + /// @param thread_observer a ptr to an implementation class that can receive these notifications. If nullptr is passed + /// instead, this will have the effect of unregistering the callback. + void realm_set_binding_callback_thread_observer( + ffi.Pointer thread_observer, + ) { + return _realm_set_binding_callback_thread_observer( + thread_observer, + ); + } + + late final _realm_set_binding_callback_thread_observerPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer)>>( + 'realm_set_binding_callback_thread_observer'); + late final _realm_set_binding_callback_thread_observer = + _realm_set_binding_callback_thread_observerPtr.asFunction< + void Function( + ffi.Pointer)>(); + /// Clear a set of values. /// /// @return True if no exception occurred. @@ -9040,8 +9058,9 @@ class RealmLibrary { /// Register a callback that will be invoked every time the session's connection state changes. /// - /// @return A token value that can be used to unregiser the callback. - int realm_sync_session_register_connection_state_change_callback( + /// @return a notification token object. Dispose it to stop receiving notifications. + ffi.Pointer + realm_sync_session_register_connection_state_change_callback( ffi.Pointer arg0, realm_sync_connection_state_changed_func_t arg1, ffi.Pointer userdata, @@ -9058,20 +9077,19 @@ class RealmLibrary { late final _realm_sync_session_register_connection_state_change_callbackPtr = _lookup< ffi.NativeFunction< - ffi.Uint64 Function( + ffi.Pointer Function( ffi.Pointer, realm_sync_connection_state_changed_func_t, ffi.Pointer, realm_free_userdata_func_t)>>( 'realm_sync_session_register_connection_state_change_callback'); late final _realm_sync_session_register_connection_state_change_callback = - _realm_sync_session_register_connection_state_change_callbackPtr - .asFunction< - int Function( - ffi.Pointer, - realm_sync_connection_state_changed_func_t, - ffi.Pointer, - realm_free_userdata_func_t)>(); + _realm_sync_session_register_connection_state_change_callbackPtr.asFunction< + ffi.Pointer Function( + ffi.Pointer, + realm_sync_connection_state_changed_func_t, + ffi.Pointer, + realm_free_userdata_func_t)>(); /// Register a callback that will be invoked every time the session reports progress. /// @@ -9080,8 +9098,9 @@ class RealmLibrary { /// Otherwise, the number of downloaded or uploaded bytes will always be reported /// relative to the number of downloadable or uploadable bytes at the point in time /// when the notifier was registered. - /// @return A token value that can be used to unregiser the notifier. - int realm_sync_session_register_progress_notifier( + /// @return a notification token object. Dispose it to stop receiving notifications. + ffi.Pointer + realm_sync_session_register_progress_notifier( ffi.Pointer arg0, realm_sync_progress_func_t arg1, int arg2, @@ -9101,7 +9120,7 @@ class RealmLibrary { late final _realm_sync_session_register_progress_notifierPtr = _lookup< ffi.NativeFunction< - ffi.Uint64 Function( + ffi.Pointer Function( ffi.Pointer, realm_sync_progress_func_t, ffi.Int32, @@ -9111,7 +9130,7 @@ class RealmLibrary { 'realm_sync_session_register_progress_notifier'); late final _realm_sync_session_register_progress_notifier = _realm_sync_session_register_progress_notifierPtr.asFunction< - int Function( + ffi.Pointer Function( ffi.Pointer, realm_sync_progress_func_t, int, @@ -9137,50 +9156,6 @@ class RealmLibrary { late final _realm_sync_session_resume = _realm_sync_session_resumePtr .asFunction)>(); - /// Unregister a callback that will be invoked every time the session's connection state changes. - /// @param session ptr to a valid sync session - /// @param token the token returned by `realm_sync_session_register_connection_state_change_callback` - void realm_sync_session_unregister_connection_state_change_callback( - ffi.Pointer session, - int token, - ) { - return _realm_sync_session_unregister_connection_state_change_callback( - session, - token, - ); - } - - late final _realm_sync_session_unregister_connection_state_change_callbackPtr = - _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer, ffi.Uint64)>>( - 'realm_sync_session_unregister_connection_state_change_callback'); - late final _realm_sync_session_unregister_connection_state_change_callback = - _realm_sync_session_unregister_connection_state_change_callbackPtr - .asFunction, int)>(); - - /// Unregister a callback that will be invoked every time the session reports progress. - /// @param session ptr to a valid sync session - /// @param token the token returned by `realm_sync_session_register_progress_notifier` - void realm_sync_session_unregister_progress_notifier( - ffi.Pointer session, - int token, - ) { - return _realm_sync_session_unregister_progress_notifier( - session, - token, - ); - } - - late final _realm_sync_session_unregister_progress_notifierPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function(ffi.Pointer, - ffi.Uint64)>>('realm_sync_session_unregister_progress_notifier'); - late final _realm_sync_session_unregister_progress_notifier = - _realm_sync_session_unregister_progress_notifierPtr - .asFunction, int)>(); - /// Register a callback that will be invoked when all pending downloads have completed. void realm_sync_session_wait_for_download_completion( ffi.Pointer arg0, @@ -10358,6 +10333,11 @@ typedef realm_async_open_task_completion_func_t = ffi.Pointer< ffi.Pointer, ffi.Pointer, ffi.Pointer)>>; + +class realm_async_open_task_progress_notification_token extends ffi.Opaque {} + +typedef realm_async_open_task_progress_notification_token_t + = realm_async_open_task_progress_notification_token; typedef realm_async_open_task_t = realm_async_open_task; abstract class realm_auth_provider { @@ -10382,6 +10362,8 @@ class realm_binary extends ffi.Struct { typedef realm_binary_t = realm_binary; +class realm_callback_interface_thread_observer extends ffi.Opaque {} + class realm_callback_token extends ffi.Opaque {} typedef realm_callback_token_t = realm_callback_token; @@ -10639,6 +10621,8 @@ class realm_index_range extends ffi.Struct { } typedef realm_index_range_t = realm_index_range; +typedef realm_interface_callback_thread_observer_t + = realm_callback_interface_thread_observer; class realm_key_path extends ffi.Struct { @ffi.Size() @@ -11153,6 +11137,12 @@ typedef realm_sync_progress_func_t = ffi.Pointer< class realm_sync_session extends ffi.Opaque {} +class realm_sync_session_connection_state_notification_token + extends ffi.Opaque {} + +typedef realm_sync_session_connection_state_notification_token_t + = realm_sync_session_connection_state_notification_token; + abstract class realm_sync_session_resync_mode { static const int RLM_SYNC_SESSION_RESYNC_MODE_MANUAL = 0; static const int RLM_SYNC_SESSION_RESYNC_MODE_DISCARD_LOCAL = 1; diff --git a/lib/src/native/realm_core.dart b/lib/src/native/realm_core.dart index f3232381a..e142050ee 100644 --- a/lib/src/native/realm_core.dart +++ b/lib/src/native/realm_core.dart @@ -687,8 +687,18 @@ class _RealmCore { Future beginWriteAsync(Realm realm, CancellationToken? ct) { final completer = WriteCompleter(realm, ct); if (!completer.isCancelled) { - completer.id = _realmLib.realm_async_begin_write(realm.handle._pointer, Pointer.fromFunction(_completeAsyncBeginWrite), completer.toPersistentHandle(), - _realmLib.addresses.realm_dart_delete_persistent_handle, true); + using((arena) { + final transaction_id = arena(); + _realmLib.invokeGetBool(() => _realmLib.realm_async_begin_write( + realm.handle._pointer, + Pointer.fromFunction(_completeAsyncBeginWrite), + completer.toPersistentHandle(), + _realmLib.addresses.realm_dart_delete_persistent_handle, + true, + transaction_id, + )); + completer.id = transaction_id.value; + }); } return completer.future; @@ -697,8 +707,18 @@ class _RealmCore { Future commitWriteAsync(Realm realm, CancellationToken? ct) { final completer = WriteCompleter(realm, ct); if (!completer.isCancelled) { - completer.id = _realmLib.realm_async_commit(realm.handle._pointer, Pointer.fromFunction(_completeAsyncCommit), completer.toPersistentHandle(), - _realmLib.addresses.realm_dart_delete_persistent_handle, false); + using((arena) { + final transaction_id = arena(); + _realmLib.invokeGetBool(() => _realmLib.realm_async_commit( + realm.handle._pointer, + Pointer.fromFunction(_completeAsyncCommit), + completer.toPersistentHandle(), + _realmLib.addresses.realm_dart_delete_persistent_handle, + false, + transaction_id, + )); + completer.id = transaction_id.value; + }); } return completer.future; @@ -1941,16 +1961,19 @@ class _RealmCore { _realmLib.realm_sync_session_resume(session.handle._pointer); } - int sessionRegisterProgressNotifier(Session session, ProgressDirection direction, ProgressMode mode, SessionProgressNotificationsController controller) { + RealmSyncSessionConnectionStateNotificationTokenHandle sessionRegisterProgressNotifier( + Session session, ProgressDirection direction, ProgressMode mode, SessionProgressNotificationsController controller) { final isStreaming = mode == ProgressMode.reportIndefinitely; final callback = Pointer.fromFunction(_progressCallback); final userdata = _realmLib.realm_dart_userdata_async_new(controller, callback.cast(), scheduler.handle._pointer); - return _realmLib.realm_sync_session_register_progress_notifier(session.handle._pointer, _realmLib.addresses.realm_dart_sync_progress_callback, - direction.index, isStreaming, userdata.cast(), _realmLib.addresses.realm_dart_userdata_async_free); - } - - void sessionUnregisterProgressNotifier(Session session, int token) { - _realmLib.realm_sync_session_unregister_progress_notifier(session.handle._pointer, token); + final notification_token = _realmLib.realm_sync_session_register_progress_notifier( + session.handle._pointer, + _realmLib.addresses.realm_dart_sync_progress_callback, + direction.index, + isStreaming, + userdata.cast(), + _realmLib.addresses.realm_dart_userdata_async_free); + return RealmSyncSessionConnectionStateNotificationTokenHandle._(notification_token); } static void _progressCallback(Object userdata, int transferred, int transferable) { @@ -1959,15 +1982,16 @@ class _RealmCore { controller.onProgress(transferred, transferable); } - int sessionRegisterConnectionStateNotifier(Session session, SessionConnectionStateController controller) { + RealmSyncSessionConnectionStateNotificationTokenHandle sessionRegisterConnectionStateNotifier(Session session, SessionConnectionStateController controller) { final callback = Pointer.fromFunction(_onConnectionStateChange); final userdata = _realmLib.realm_dart_userdata_async_new(controller, callback.cast(), scheduler.handle._pointer); - return _realmLib.realm_sync_session_register_connection_state_change_callback(session.handle._pointer, - _realmLib.addresses.realm_dart_sync_connection_state_changed_callback, userdata.cast(), _realmLib.addresses.realm_dart_userdata_async_free); - } - - void sessionUnregisterConnectionStateNotifier(Session session, int token) { - _realmLib.realm_sync_session_unregister_connection_state_change_callback(session.handle._pointer, token); + final notification_token = _realmLib.realm_sync_session_register_connection_state_change_callback( + session.handle._pointer, + _realmLib.addresses.realm_dart_sync_connection_state_changed_callback, + userdata.cast(), + _realmLib.addresses.realm_dart_userdata_async_free, + ); + return RealmSyncSessionConnectionStateNotificationTokenHandle._(notification_token); } static void _onConnectionStateChange(Object userdata, int oldState, int newState) { @@ -2477,6 +2501,10 @@ class RealmNotificationTokenHandle extends RootedHandleBase pointer, RealmHandle root) : super(root, pointer, 32); } +class RealmSyncSessionConnectionStateNotificationTokenHandle extends HandleBase { + RealmSyncSessionConnectionStateNotificationTokenHandle._(Pointer pointer) : super(pointer, 32); +} + class RealmCollectionChangesHandle extends HandleBase { RealmCollectionChangesHandle._(Pointer pointer) : super(pointer, 256); } diff --git a/lib/src/session.dart b/lib/src/session.dart index cf0e735d8..728aa9793 100644 --- a/lib/src/session.dart +++ b/lib/src/session.dart @@ -176,7 +176,7 @@ class SessionProgressNotificationsController { final ProgressDirection _direction; final ProgressMode _mode; - int? _token; + RealmSyncSessionConnectionStateNotificationTokenHandle? _token; late final StreamController _streamController; SessionProgressNotificationsController(this._session, this._direction, this._mode); @@ -198,16 +198,11 @@ class SessionProgressNotificationsController { if (_token != null) { throw RealmStateError("Session progress subscription already started"); } - _token = realmCore.sessionRegisterProgressNotifier(_session, _direction, _mode, this); } void _stop() { - if (_token == null || _session._handle.released) { - return; - } - - realmCore.sessionUnregisterProgressNotifier(_session, _token!); + _token?.release(); _token = null; } } @@ -216,7 +211,7 @@ class SessionProgressNotificationsController { class SessionConnectionStateController { final Session _session; late final StreamController _streamController; - int? _token; + RealmSyncSessionConnectionStateNotificationTokenHandle? _token; SessionConnectionStateController(this._session); @@ -233,16 +228,11 @@ class SessionConnectionStateController { if (_token != null) { throw RealmStateError("Session connection state subscription already started"); } - _token = realmCore.sessionRegisterConnectionStateNotifier(_session, this); } void _stop() { - if (_token == null) { - return; - } - - realmCore.sessionUnregisterConnectionStateNotifier(_session, _token!); + _token?.release(); _token = null; } } diff --git a/src/realm-core b/src/realm-core index 97ba3412b..b0e035e3f 160000 --- a/src/realm-core +++ b/src/realm-core @@ -1 +1 @@ -Subproject commit 97ba3412bda8dabf2eaa2221f19e214296631999 +Subproject commit b0e035e3fbf382a611229fbd89c79eb1fa1efc90