Skip to content

Commit

Permalink
[RKOTLIN-1079] Add support for transfer progress estimate (#1575)
Browse files Browse the repository at this point in the history
  • Loading branch information
clementetb authored May 24, 2024
1 parent 3255d12 commit e8949fe
Show file tree
Hide file tree
Showing 10 changed files with 416 additions and 123 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ This release will bump the Realm file format 24. Opening a file with an older fo
* Some authentication related operations will no longer throw specialized `InvalidCredentialsException` and `CredentialsCannotBeLinkedException` but the more general `AuthException` and `ServiceException`. (Issue [#1763](https://github.com/realm/realm-kotlin/issues/1763)/[RKOTLIN-1091](https://jira.mongodb.org/browse/RKOTLIN-1091))
* [Sync] Removed deprecated methods `User.identity` and `User.provider`, user identities can be accessed with the already existing `User.identities`. (Issue [#1751](https://github.com/realm/realm-kotlin/issues/1751) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1083))
* [Sync] `App.allUsers` does no longer return a map, but only a list of users known locally. (Issue [#1751](https://github.com/realm/realm-kotlin/issues/1751) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1083))
* [Sync ]Removed deprecated `DiscardUnsyncedChangesStrategy.onError`. (Issue [#1755](https://github.com/realm/realm-kotlin/issues/1755) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1085))
* [Sync] Removed deprecated `DiscardUnsyncedChangesStrategy.onError`. (Issue [#1755](https://github.com/realm/realm-kotlin/issues/1755) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1085))
* [Sync] Sync progress notifications now reports an estimate ranged from `0.0` to `1.0` with `Progress.estimate` instead of `transferredBytes` and `totalBytes`. (Issue [#1744](https://github.com/realm/realm-kotlin/issues/1744) [RKOTLIN-1079](https://jira.mongodb.org/browse/RKOTLIN-1079)).

### Enhancements
* Support for RealmLists and RealmDictionaries in `RealmAny`. (Issue [#1434](https://github.com/realm/realm-kotlin/issues/1434))
* Optimized `RealmList.indexOf()` and `RealmList.contains()` using Core implementation of operations instead of iterating elements and comparing them in Kotlin. (Issue [#1625](https://github.com/realm/realm-kotlin/pull/1666) [RKOTLIN-995](https://jira.mongodb.org/browse/RKOTLIN-995)).
* Add support for filtering logs by category. (Issue [#1691](https://github.com/realm/realm-kotlin/issues/1691) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1038))
* [Sync] Add Mongo Client API to access Atlas App Service collections. It can be accessed through `User.mongoClient`. (Issue [#972](https://github.com/realm/realm-kotlin/issues/972)/[RKOTLIN-612](https://jira.mongodb.org/browse/RKOTLIN-612))
* [Sync] Sync progress notifications is now also supported for flexible sync configurations. (Issue [#1744](https://github.com/realm/realm-kotlin/issues/1744) [RKOTLIN-1079](https://jira.mongodb.org/browse/RKOTLIN-1079)).

### Fixed
* Inserting the same typed link to the same key in a dictionary more than once would incorrectly create multiple backlinks to the object. This did not appear to cause any crashes later, but would have affecting explicit backlink count queries (eg: `...@links.@count`) and possibly notifications (Core Issue [realm/realm-core#7676](https://github.com/realm/realm-core/issues/7676) since v1.16.0).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fun interface AsyncOpenCallback {
}

fun interface ProgressCallback {
fun onChange(transferredBytes: Long, totalBytes: Long)
fun onChange(progressEstimate: Double)
}

fun interface ConnectionStateChangeCallback {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ fun String.toRString(memScope: MemScope) = cValue<realm_string_t> {
set(memScope, this@toRString)
}

@OptIn(ExperimentalForeignApi::class)
@Suppress("LargeClass", "FunctionNaming")
actual object RealmInterop {

Expand Down Expand Up @@ -2813,10 +2814,9 @@ actual object RealmInterop {
return CPointerWrapper(
realm_wrapper.realm_sync_session_register_progress_notifier(
syncSession.cptr(),
staticCFunction<COpaquePointer?, ULong, ULong, Double, Unit> { userData, transferred_bytes, total_bytes, _ ->
staticCFunction<COpaquePointer?, ULong, ULong, Double, Unit> { userData, _, _, progress_estimate ->
safeUserData<ProgressCallback>(userData).run {
// TODO Progress ignored until https://github.com/realm/realm-kotlin/pull/1575
onChange(transferred_bytes.toLong(), total_bytes.toLong())
onChange(progress_estimate)
}
},
direction.nativeValue,
Expand Down
7 changes: 3 additions & 4 deletions packages/jni-swig-stub/src/main/jni/realm_api_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1244,14 +1244,13 @@ sync_after_client_reset_handler(realm_sync_config_t* config, jobject after_handl
}

void
realm_sync_session_progress_notifier_callback(void *userdata, uint64_t transferred_bytes, uint64_t total_bytes, double progress) {
realm_sync_session_progress_notifier_callback(void *userdata, uint64_t, uint64_t, double progress_estimate) {
auto env = get_env(true);

// TODO Progress ignored until https://github.com/realm/realm-kotlin/pull/1575
static JavaMethod java_callback_method(env, JavaClassGlobalDef::progress_callback(), "onChange", "(JJ)V");
static JavaMethod java_callback_method(env, JavaClassGlobalDef::progress_callback(), "onChange", "(D)V");

jni_check_exception(env);
env->CallVoidMethod(static_cast<jobject>(userdata), java_callback_method, jlong(transferred_bytes), jlong(total_bytes));
env->CallVoidMethod(static_cast<jobject>(userdata), java_callback_method, jdouble(progress_estimate));
jni_check_exception(env);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/jni-swig-stub/src/main/jni/realm_api_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void
sync_after_client_reset_handler(realm_sync_config_t* config, jobject after_handler);

void
realm_sync_session_progress_notifier_callback(void *userdata, uint64_t transferred_bytes, uint64_t total_bytes, double progress);
realm_sync_session_progress_notifier_callback(void *userdata, uint64_t, uint64_t, double progress_estimate);

void
realm_sync_session_connection_state_change_callback(void *userdata, realm_sync_connection_state_e old_state, realm_sync_connection_state_e new_state);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package io.realm.kotlin.mongodb.internal

import io.realm.kotlin.internal.InternalConfiguration
import io.realm.kotlin.internal.NotificationToken
import io.realm.kotlin.internal.RealmImpl
import io.realm.kotlin.internal.interop.CoreError
Expand Down Expand Up @@ -109,9 +108,6 @@ internal open class SyncSessionImpl(
direction: Direction,
progressMode: ProgressMode,
): Flow<Progress> {
if ((configuration as InternalConfiguration).isFlexibleSyncConfiguration) {
throw UnsupportedOperationException("Progress listeners are not supported for Flexible Sync.")
}
return realm.scopedFlow {
callbackFlow {
val token: AtomicRef<Cancellable> =
Expand All @@ -124,8 +120,8 @@ internal open class SyncSessionImpl(
Direction.UPLOAD -> ProgressDirection.RLM_SYNC_PROGRESS_DIRECTION_UPLOAD
},
progressMode == ProgressMode.INDEFINITELY
) { transferredBytes: Long, totalBytes: Long ->
val progress = Progress(transferredBytes.toULong(), totalBytes.toULong())
) { progressEstimate: Double ->
val progress = Progress(progressEstimate)
trySendWithBufferOverflowCheck(progress)
if (progressMode == ProgressMode.CURRENT_CHANGES && progress.isTransferComplete) {
close()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,9 @@ package io.realm.kotlin.mongodb.sync
*/
public data class Progress(
/**
* Total number of bytes that has been transferred by the [SyncSession].
* Transfer progress estimation ranged from 0.0 to 1.0.
*/
val transferredBytes: ULong,
/**
* Total number of transferable bytes (bytes that have been transferred + pending bytes not
* yet transferred).
*/
val transferableBytes: ULong
val estimate: Double,
) {
/**
* Property indicating if all pending bytes have been transferred.
Expand All @@ -40,5 +35,5 @@ public data class Progress(
* flow can continue to emit events with `isTransferComplete = false` for subsequent events
* after returning a progress indicator with `isTransferComplete = true`.
*/
public val isTransferComplete: Boolean = transferredBytes >= transferableBytes
public val isTransferComplete: Boolean = estimate >= 1.0
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,6 @@ public interface SyncSession {
*
* The flow has an internal buffer of [Channel.BUFFERED] but if the consumer fails to consume the
* elements in a timely manner the flow will be completed with an [IllegalStateException].
*
* @throws UnsupportedOperationException if invoked on a realm with Flexible Sync enabled.
*/
public fun progressAsFlow(
direction: Direction,
Expand Down
Loading

0 comments on commit e8949fe

Please sign in to comment.