Skip to content

Commit

Permalink
Add error propagation on JVM
Browse files Browse the repository at this point in the history
  • Loading branch information
clementetb committed Nov 22, 2023
1 parent a88bb46 commit 15a01b9
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,23 @@ data class SyncError constructor(
val isFatal: Boolean,
val isUnrecognizedByClient: Boolean,
val isClientResetRequested: Boolean,
val compensatingWrites: Array<CoreCompensatingWriteInfo>
val compensatingWrites: Array<CoreCompensatingWriteInfo>,
val userError: Throwable?,
) {
// Constructs an SyncError out from a simple code. There are some situations (SyncSessionTransferCompletionCallback)
// where we receive an error code rather than a full SyncErrorCode, wrapping the code
// simplifies the error handling logic.
constructor(
error: CoreError
error: CoreError,
) : this(
errorCode = error,
originalFilePath = null,
recoveryFilePath = null,
isFatal = false,
isUnrecognizedByClient = false,
isClientResetRequested = false,
compensatingWrites = emptyArray()
compensatingWrites = emptyArray(),
userError = null,
)

// Constructor used by JNI so we avoid creating too many objects on the JNI side.
Expand All @@ -56,14 +58,16 @@ data class SyncError constructor(
isFatal: Boolean,
isUnrecognizedByClient: Boolean,
isClientResetRequested: Boolean,
compensatingWrites: Array<CoreCompensatingWriteInfo>
compensatingWrites: Array<CoreCompensatingWriteInfo>,
userError: Throwable?,
) : this(
CoreError(categoryFlags, value, message),
originalFilePath,
recoveryFilePath,
isFatal,
isUnrecognizedByClient,
isClientResetRequested,
compensatingWrites
compensatingWrites,
userError,
)
}
2 changes: 1 addition & 1 deletion packages/external/core
Submodule core updated 56 files
+2 −1 .github/pull_request_template.md
+4 −0 .gitignore
+26 −1 CHANGELOG.md
+1 −1 Package.swift
+1 −0 bindgen/spec.yml
+1 −1 dependencies.list
+295 −0 doc/development/how-to-use-remote-baas-host.md
+181 −22 evergreen/config.yml
+237 −0 evergreen/configure_baas_proxy.sh
+299 −217 evergreen/install_baas.sh
+4 −0 evergreen/proxy-network-faults.toxics
+5 −0 evergreen/proxy-nonideal-transfer.toxics
+160 −30 evergreen/setup_baas_host.sh
+149 −55 evergreen/setup_baas_host_local.sh
+263 −0 evergreen/setup_baas_proxy.sh
+21 −11 evergreen/wait_for_baas.sh
+1 −0 src/realm.h
+11 −11 src/realm/collection.hpp
+12 −0 src/realm/exceptions.cpp
+9 −0 src/realm/exceptions.hpp
+3 −2 src/realm/object-store/c_api/sync.cpp
+3 −13 src/realm/object-store/c_api/types.hpp
+4 −4 src/realm/object-store/sync/sync_session.cpp
+137 −129 src/realm/set.cpp
+0 −22 src/realm/set.hpp
+9 −7 src/realm/sync/client.cpp
+4 −1 src/realm/sync/client_base.hpp
+3 −0 src/realm/sync/config.hpp
+104 −116 src/realm/sync/noinst/client_impl_base.cpp
+29 −48 src/realm/sync/noinst/client_impl_base.hpp
+3 −7 src/realm/sync/noinst/client_reset.cpp
+1 −1 src/realm/sync/noinst/client_reset.hpp
+41 −83 src/realm/sync/noinst/client_reset_operation.cpp
+12 −50 src/realm/sync/noinst/client_reset_operation.hpp
+47 −53 src/realm/sync/subscriptions.cpp
+26 −23 src/realm/sync/subscriptions.hpp
+5 −0 src/realm/table.cpp
+2 −0 src/realm/table.hpp
+16 −0 test/object-store/CMakeLists.txt
+1 −1 test/object-store/audit.cpp
+129 −5 test/object-store/c_api/c_api.cpp
+12 −0 test/object-store/main.cpp
+22 −28 test/object-store/sync/app.cpp
+16 −18 test/object-store/sync/client_reset.cpp
+18 −29 test/object-store/sync/flx_migration.cpp
+5 −8 test/object-store/sync/flx_sync.cpp
+87 −63 test/object-store/util/sync/baas_admin_api.cpp
+21 −12 test/object-store/util/sync/baas_admin_api.hpp
+1 −1 test/object-store/util/sync/flx_sync_harness.hpp
+58 −16 test/object-store/util/sync/sync_test_utils.cpp
+10 −5 test/object-store/util/sync/sync_test_utils.hpp
+4 −3 test/object-store/util/test_file.cpp
+3 −0 test/object-store/util/test_file.hpp
+387 −6 test/test_client_reset.cpp
+144 −34 test/test_set.cpp
+9 −0 test/util/test_path.hpp
38 changes: 10 additions & 28 deletions packages/jni-swig-stub/src/main/jni/realm_api_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,6 @@ inline std::string get_exception_message(JNIEnv *env) {
return env->GetStringUTFChars(message, NULL);
}

inline void system_out_println(JNIEnv *env, std::string message) {
jclass system_class = env->FindClass("java/lang/System");
jfieldID field_id = env->GetStaticFieldID(system_class, "out", "Ljava/io/PrintStream;");
jobject system_out = env->GetStaticObjectField(system_class, field_id);
jclass print_stream_class = env->FindClass("java/io/PrintStream");
jmethodID method_id = env->GetMethodID(print_stream_class, "println", "(Ljava/lang/String;)V");
env->CallVoidMethod(system_out, method_id, to_jstring(env, message));
}

void
realm_changed_callback(void* userdata) {
auto env = get_env(true);
Expand Down Expand Up @@ -716,7 +707,7 @@ jobject convert_to_jvm_sync_error(JNIEnv* jenv, const realm_sync_error_t& error)
static JavaMethod sync_error_constructor(jenv,
JavaClassGlobalDef::sync_error(),
"<init>",
"(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZ[Lio/realm/kotlin/internal/interop/sync/CoreCompensatingWriteInfo;)V");
"(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZ[Lio/realm/kotlin/internal/interop/sync/CoreCompensatingWriteInfo;Ljava/lang/Throwable;)V");

jint category = static_cast<jint>(error.status.categories);
jint value = static_cast<jint>(error.status.error);
Expand Down Expand Up @@ -788,7 +779,7 @@ jobject convert_to_jvm_sync_error(JNIEnv* jenv, const realm_sync_error_t& error)
}
}

return jenv->NewObject(
jobject result = jenv->NewObject(
JavaClassGlobalDef::sync_error(),
sync_error_constructor,
category,
Expand All @@ -799,8 +790,13 @@ jobject convert_to_jvm_sync_error(JNIEnv* jenv, const realm_sync_error_t& error)
is_fatal,
is_unrecognized_by_client,
is_client_reset_requested,
j_compensating_write_info_array
j_compensating_write_info_array,
static_cast<jobject>(error.usercode_error)
);

jni_check_exception(jenv);
jenv->DeleteGlobalRef(static_cast<jobject>(error.usercode_error));
return result;
}

void sync_set_error_handler(realm_sync_config_t* sync_config, jobject error_handler) {
Expand Down Expand Up @@ -887,14 +883,7 @@ before_client_reset(void* userdata, realm_t* before_realm) {
"(Lio/realm/kotlin/internal/interop/NativePointer;)V");
auto before_pointer = wrap_pointer(env, reinterpret_cast<jlong>(before_realm), false);
env->CallVoidMethod(static_cast<jobject>(userdata), java_before_callback_function, before_pointer);
if (env->ExceptionCheck()) {
std::string exception_message = get_exception_message(env);
std::string message_template = "An error has occurred in the 'onBefore' callback: ";
system_out_println(env, message_template.append(exception_message));
return false;
}

return true;
return jni_check_exception(env);
}

bool
Expand All @@ -913,14 +902,7 @@ after_client_reset(void* userdata, realm_t* before_realm,
auto after_pointer = wrap_pointer(env, reinterpret_cast<jlong>(after_realm_ptr), false);
env->CallVoidMethod(static_cast<jobject>(userdata), java_after_callback_function, before_pointer, after_pointer, did_recover);
realm_close(after_realm_ptr);
if (env->ExceptionCheck()) {
std::string exception_message = get_exception_message(env);
std::string message_template = "An error has occurred in the 'onAfter' callback: ";
system_out_println(env, message_template.append(exception_message));
return false;
}

return true;
return jni_check_exception(env);
}

void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ import io.realm.kotlin.mongodb.internal.createMessageFromSyncError
*/
public class ClientResetRequiredException constructor(
private val appPointer: RealmAppPointer,
error: SyncError
) : Throwable(message = createMessageFromSyncError(error.errorCode)) {
error: SyncError,
) : Throwable(
message = createMessageFromSyncError(error.errorCode),
cause = error.userError,
) {

/**
* Path to the original (local) copy of the realm when the Client Reset event was triggered.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertIs
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import kotlin.test.fail
Expand Down Expand Up @@ -740,6 +741,11 @@ class SyncClientResetIntegrationTests {
"[Sync][AutoClientResetFailed(1028)] A fatal error occurred during client reset: 'User-provided callback failed'.",
exception.message
)
assertIs<java.lang.IllegalStateException>(exception.cause)
assertEquals(
"User exception",
exception.cause?.message
)
channel.trySend(ClientResetEvents.ON_MANUAL_RESET_FALLBACK)
}

Expand All @@ -752,6 +758,11 @@ class SyncClientResetIntegrationTests {
"[Sync][AutoClientResetFailed(1028)] A fatal error occurred during client reset: 'User-provided callback failed'.",
exception.message
)
assertIs<java.lang.IllegalStateException>(exception.cause)
assertEquals(
"User exception",
exception.cause?.message
)
channel.trySend(ClientResetEvents.ON_MANUAL_RESET_FALLBACK)
}
}).build()
Expand Down

0 comments on commit 15a01b9

Please sign in to comment.