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

Unify remaining std::error_codes into Status/ErrorCodes in sync client #6869

Merged
merged 37 commits into from
Aug 11, 2023
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0c081b4
big shabang
jbreams Jul 12, 2023
66eee63
remove more std::error_codes
jbreams Jul 12, 2023
91a29b8
add websocket_error.hpp header
jbreams Jul 12, 2023
04a83d2
remove C API realm_sync_error_code and remaining public uses of std::…
jbreams Jul 13, 2023
ee757e6
more test failures
jbreams Jul 13, 2023
8371bac
remove unused code
jbreams Jul 13, 2023
10e5041
make IntegrationException unambiguous
jbreams Jul 13, 2023
043fe3f
even less unambiguous
jbreams Jul 13, 2023
5abc4cc
Merge remote-tracking branch 'origin/master' into jbr/collapse_sync_e…
jbreams Jul 13, 2023
4c2a8b8
Merge remote-tracking branch 'origin/master' into jbr/collapse_sync_e…
jbreams Jul 15, 2023
daa8fb9
Merge remote-tracking branch 'origin/master' into jbr/collapse_sync_e…
jbreams Jul 15, 2023
f7a6b5f
remove extrainfo part of status
jbreams Jul 19, 2023
5167a8d
Merge remote-tracking branch 'origin/master' into jbr/collapse_sync_e…
jbreams Jul 20, 2023
104ca6d
Replace ClientError error_code with ErrorCodes/Status
jbreams Jul 30, 2023
4fe8d93
fixes from PR
jbreams Aug 2, 2023
c53c6c8
changelog
jbreams Aug 3, 2023
753f2ec
Handle websocket errors entirely within sync client
jbreams Aug 3, 2023
00ff52e
Merge branch 'feature/sync_error_unification' into jbr/websocket_error
jbreams Aug 3, 2023
2367f93
add missing header
jbreams Aug 3, 2023
8cb0c68
undo weird formatting changes
jbreams Aug 3, 2023
f1e5fce
clang format again
jbreams Aug 3, 2023
e6e8fa9
whoops
jbreams Aug 4, 2023
7d4ead0
fix a bunch of IsFatal mixups
jbreams Aug 4, 2023
8ecbed3
handle redirects
jbreams Aug 4, 2023
982c9d5
formatting fixups
jbreams Aug 4, 2023
caa3721
fix emscripten build
jbreams Aug 4, 2023
5833adf
Refresh user on unauthorized error
jbreams Aug 5, 2023
a175488
nits
jbreams Aug 7, 2023
f74beec
Merge branch 'jbr/websocket_error' into jbr/protocol_errors
jbreams Aug 7, 2023
06cdd8f
Merge branch 'feature/sync_error_unification' into jbr/sync_error_las…
jbreams Aug 8, 2023
952277c
fixes
jbreams Aug 8, 2023
a96a3f2
handle auth errors correctly
jbreams Aug 9, 2023
49df1d3
fixups
jbreams Aug 9, 2023
ec5d292
fixes from PR
jbreams Aug 10, 2023
f2d5c8f
update error message
jbreams Aug 10, 2023
d164b3f
remove duplicate
jbreams Aug 10, 2023
3e36355
changelog
jbreams Aug 11, 2023
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
46 changes: 7 additions & 39 deletions src/realm.h
Original file line number Diff line number Diff line change
Expand Up @@ -3334,26 +3334,6 @@ typedef enum realm_sync_progress_direction {
RLM_SYNC_PROGRESS_DIRECTION_DOWNLOAD,
} realm_sync_progress_direction_e;

/**
* Possible error categories realm_sync_error_code_t can fall in.
*/
typedef enum realm_sync_error_category {
RLM_SYNC_ERROR_CATEGORY_CLIENT,
RLM_SYNC_ERROR_CATEGORY_CONNECTION,
RLM_SYNC_ERROR_CATEGORY_SESSION,
RLM_SYNC_ERROR_CATEGORY_WEBSOCKET,

/**
* System error - POSIX errno, Win32 HRESULT, etc.
*/
RLM_SYNC_ERROR_CATEGORY_SYSTEM,

/**
* Unknown source of error.
*/
RLM_SYNC_ERROR_CATEGORY_UNKNOWN,
} realm_sync_error_category_e;

typedef enum realm_sync_error_action {
RLM_SYNC_ERROR_ACTION_NO_ACTION,
RLM_SYNC_ERROR_ACTION_PROTOCOL_VIOLATION,
Expand All @@ -3370,17 +3350,6 @@ typedef enum realm_sync_error_action {
typedef struct realm_sync_session realm_sync_session_t;
typedef struct realm_async_open_task realm_async_open_task_t;

// This type should never be returned from a function.
// It's only meant as an asynchronous callback argument.
// Pointers to this struct and its pointer members are only valid inside the scope
// of the callback they were passed to.
typedef struct realm_sync_error_code {
realm_sync_error_category_e category;
int value;
const char* message;
const char* category_name;
} realm_sync_error_code_t;

typedef struct realm_sync_error_user_info {
const char* key;
const char* value;
Expand All @@ -3397,8 +3366,7 @@ typedef struct realm_sync_error_compensating_write_info {
// Pointers to this struct and its pointer members are only valid inside the scope
// of the callback they were passed to.
typedef struct realm_sync_error {
realm_sync_error_code_t error_code;
const char* detailed_message;
realm_error_t status;
const char* c_original_file_path_key;
const char* c_recovery_file_path_key;
bool is_fatal;
Expand All @@ -3422,7 +3390,7 @@ typedef struct realm_sync_error {
*
* @param error Null, if the operation completed successfully.
*/
typedef void (*realm_sync_wait_for_completion_func_t)(realm_userdata_t userdata, realm_sync_error_code_t* error);
typedef void (*realm_sync_wait_for_completion_func_t)(realm_userdata_t userdata, realm_error_t* error);
typedef void (*realm_sync_connection_state_changed_func_t)(realm_userdata_t userdata,
realm_sync_connection_state_e old_state,
realm_sync_connection_state_e new_state);
Expand Down Expand Up @@ -3864,13 +3832,13 @@ RLM_API void realm_sync_session_wait_for_upload_completion(realm_sync_session_t*
/**
* Wrapper for SyncSession::OnlyForTesting::handle_error. This routine should be used only for testing.
* @param session ptr to a valid sync session
* @param error_code error code to simulate
* @param category category of the error to simulate
* @param error_message string representing the error
* @param error_code realm_errno_e representing the error to simulate
* @param error_str error message to be included with Status
* @param is_fatal boolean to signal if the error is fatal or not
*/
RLM_API void realm_sync_session_handle_error_for_testing(const realm_sync_session_t* session, int error_code,
int category, const char* error_message, bool is_fatal);
RLM_API void realm_sync_session_handle_error_for_testing(const realm_sync_session_t* session,
realm_errno_e error_code, const char* error_str,
bool is_fatal);

/**
* In case of exception thrown in user code callbacks, this api will allow the sdk to store the user code exception
Expand Down
8 changes: 0 additions & 8 deletions src/realm/error_codes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,6 @@ ErrorCategory ErrorCodes::error_categories(Error code)
.set(ErrorCategory::app_error)
.set(ErrorCategory::service_error);

case WebSocketResolveFailedError:
case WebSocketConnectionClosedClientError:
case WebSocketConnectionClosedServerError:
return ErrorCategory().set(ErrorCategory::runtime_error).set(ErrorCategory::websocket_error);

case UnknownError:
break;
}
Expand Down Expand Up @@ -400,9 +395,6 @@ static const MapElem string_to_error_code[] = {
{"ValueAlreadyExists", ErrorCodes::ValueAlreadyExists},
{"ValueDuplicateName", ErrorCodes::ValueDuplicateName},
{"ValueNotFound", ErrorCodes::ValueNotFound},
{"WebSocketConnectionClosedClientError", ErrorCodes::WebSocketConnectionClosedClientError},
{"WebSocketConnectionClosedServerError", ErrorCodes::WebSocketConnectionClosedServerError},
{"WebSocketResolveFailedError", ErrorCodes::WebSocketResolveFailedError},
{"WrongSyncType", ErrorCodes::WrongSyncType},
{"WrongThread", ErrorCodes::WrongThread},
{"WrongTransactionState", ErrorCodes::WrongTransactionState},
Expand Down
4 changes: 0 additions & 4 deletions src/realm/error_codes.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,6 @@ typedef enum realm_errno {
RLM_ERR_INVALID_SERVER_RESPONSE = 4354,
RLM_ERR_APP_SERVER_ERROR = 4355,

RLM_ERR_WEBSOCKET_RESOLVE_FAILED_ERROR = 4400,
RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_CLIENT_ERROR = 4401,
RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_SERVER_ERROR = 4402,

RLM_ERR_CALLBACK = 1000000, /**< A user-provided callback failed. */
RLM_ERR_UNKNOWN = 2000000 /* Should not be used in code */
} realm_errno_e;
Expand Down
4 changes: 0 additions & 4 deletions src/realm/error_codes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,10 +246,6 @@ class ErrorCodes {
InvalidServerResponse = RLM_ERR_INVALID_SERVER_RESPONSE,
AppServerError = RLM_ERR_APP_SERVER_ERROR,

WebSocketResolveFailedError = RLM_ERR_WEBSOCKET_RESOLVE_FAILED_ERROR,
WebSocketConnectionClosedClientError = RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_CLIENT_ERROR,
WebSocketConnectionClosedServerError = RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_SERVER_ERROR,

CallbackFailed = RLM_ERR_CALLBACK,
UnknownError = RLM_ERR_UNKNOWN,
};
Expand Down
13 changes: 2 additions & 11 deletions src/realm/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,20 +367,11 @@ struct SystemError : RuntimeError {

~SystemError() noexcept override;

std::error_code get_system_error() const
{
return to_status().get_std_error_code();
}

const std::error_category& get_category() const
{
return get_system_error().category();
}

private:
static Status make_status(std::error_code err, std::string_view msg, bool msg_is_prefix)
{
return Status(err, msg_is_prefix ? util::format("%1: %2 (%3)", msg, err.message(), err.value()) : msg);
return Status(ErrorCodes::SystemError,
msg_is_prefix ? util::format("%1: %2 (%3)", msg, err.message(), err.value()) : msg);
}
};

Expand Down
30 changes: 8 additions & 22 deletions src/realm/impl/simulated_failure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <cstdint>
#include <system_error>

#include <realm/exceptions.hpp>
#include <realm/util/features.h>

#ifdef REALM_DEBUG
Expand All @@ -31,7 +32,7 @@
namespace realm {
namespace _impl {

class SimulatedFailure : public std::system_error {
class SimulatedFailure : public RuntimeError {
public:
enum FailureType {
generic,
Expand Down Expand Up @@ -64,11 +65,6 @@ class SimulatedFailure : public std::system_error {
/// not defined, this function always return false.
static bool check_trigger(FailureType) noexcept;

/// The specified error code is set to `make_error_code(failure_type)` if
/// check_trigger() returns true. Otherwise it is set to
/// `std::error_code()`. Returns a copy of the updated error code.
static std::error_code trigger(FailureType failure_type, std::error_code&) noexcept;

/// Throws SimulatedFailure if check_trigger() returns true. The exception
/// will be constructed with an error code equal to
/// `make_error_code(failure_type)`.
Expand All @@ -90,7 +86,7 @@ class SimulatedFailure : public std::system_error {
/// when turning this off.
static void set_thread_local(bool);

SimulatedFailure(std::error_code);
SimulatedFailure(FailureType);

private:
#ifdef REALM_ENABLE_SIMULATED_FAILURE
Expand Down Expand Up @@ -132,7 +128,8 @@ std::error_code make_error_code(SimulatedFailure::FailureType) noexcept;

namespace std {

template<> struct is_error_code_enum<realm::_impl::SimulatedFailure::FailureType> {
template <>
struct is_error_code_enum<realm::_impl::SimulatedFailure::FailureType> {
static const bool value = true;
};

Expand Down Expand Up @@ -184,21 +181,10 @@ inline bool SimulatedFailure::check_trigger(FailureType failure_type) noexcept
#endif
}

inline std::error_code SimulatedFailure::trigger(FailureType failure_type, std::error_code& ec) noexcept
{
if (check_trigger(failure_type)) {
ec = make_error_code(failure_type);
}
else {
ec = std::error_code();
}
return ec;
}

inline void SimulatedFailure::trigger(FailureType failure_type)
{
if (check_trigger(failure_type))
throw SimulatedFailure(make_error_code(failure_type));
throw SimulatedFailure(failure_type);
}

inline constexpr bool SimulatedFailure::is_enabled()
Expand All @@ -219,8 +205,8 @@ inline void SimulatedFailure::set_thread_local(bool tl)
#endif
}

inline SimulatedFailure::SimulatedFailure(std::error_code ec)
: std::system_error(ec)
inline SimulatedFailure::SimulatedFailure(FailureType)
: RuntimeError(Status{ErrorCodes::RuntimeError, "SimulatedFailure"})
{
}

Expand Down
4 changes: 2 additions & 2 deletions src/realm/object-store/audit.mm
Original file line number Diff line number Diff line change
Expand Up @@ -783,8 +783,8 @@ bool write_event(Timestamp timestamp, StringData activity, StringData event_type
std::string path = session->path();
session->close();
m_open_paths.erase(path);
if (status.get_std_error_code()) {
m_logger->error("Events: Upload on '%1' failed with error '%2'.", path, status.reason());
if (!status.is_ok()) {
m_logger->error("Events: Upload on '%1' failed with error '%2'.", path, status);
if (m_error_handler) {
m_error_handler(SyncError(std::move(status), false));
}
Expand Down
10 changes: 8 additions & 2 deletions src/realm/object-store/c_api/conversion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,8 +485,14 @@ static inline realm_version_id_t to_capi(const VersionID& v)
return version_id;
}

realm_sync_error_code_t to_capi(const Status& status, std::string& message);
void sync_error_to_error_code(const realm_sync_error_code_t& sync_error_code, std::error_code* error_code_out);
static inline realm_error_t to_capi(const Status& s)
{
realm_error_t err;
err.error = static_cast<realm_errno_e>(s.code());
err.categories = static_cast<realm_error_category_e>(ErrorCodes::error_categories(s.code()).value());
err.message = s.reason().c_str();
return err;
}

} // namespace realm::c_api

Expand Down
85 changes: 11 additions & 74 deletions src/realm/object-store/c_api/sync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,64 +122,6 @@ static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Un

} // namespace

realm_sync_error_code_t to_capi(const Status& status, std::string& message)
{
auto ret = realm_sync_error_code_t();

auto error_code = status.get_std_error_code();
const std::error_category& category = error_code.category();
if (status != ErrorCodes::SystemError) {
// TODO this will all go away when the unify error handling project is done, but for now just treat the
// ErrorCodes enum as client errors.
ret.category = RLM_SYNC_ERROR_CATEGORY_CLIENT;
}
else if (category == realm::sync::protocol_error_category()) {
if (realm::sync::is_session_level_error(realm::sync::ProtocolError(error_code.value()))) {
ret.category = RLM_SYNC_ERROR_CATEGORY_SESSION;
}
else {
ret.category = RLM_SYNC_ERROR_CATEGORY_CONNECTION;
}
}
else if (category == std::system_category() || category == realm::util::error::basic_system_error_category()) {
ret.category = RLM_SYNC_ERROR_CATEGORY_SYSTEM;
}
else {
ret.category = RLM_SYNC_ERROR_CATEGORY_UNKNOWN;
}

if (status == ErrorCodes::SystemError) {
ret.value = error_code.value();
message = error_code.message();
}
else {
ret.value = status.code();
message = status.reason();
}
ret.message = message.c_str();
ret.category_name = category.name();

return ret;
}

void sync_error_to_error_code(const realm_sync_error_code_t& sync_error_code, std::error_code* error_code_out)
{
if (error_code_out) {
const realm_sync_error_category_e category = sync_error_code.category;
if (category == RLM_SYNC_ERROR_CATEGORY_CLIENT) {
error_code_out->assign(sync_error_code.value, std::generic_category());
}
else if (category == RLM_SYNC_ERROR_CATEGORY_SESSION || category == RLM_SYNC_ERROR_CATEGORY_CONNECTION) {
error_code_out->assign(sync_error_code.value, realm::sync::protocol_error_category());
}
else if (category == RLM_SYNC_ERROR_CATEGORY_SYSTEM) {
error_code_out->assign(sync_error_code.value, std::system_category());
}
else if (category == RLM_SYNC_ERROR_CATEGORY_UNKNOWN) {
error_code_out->assign(sync_error_code.value, realm::util::error::basic_system_error_category());
}
}
}

static Query add_ordering_to_realm_query(Query realm_query, const DescriptorOrdering& ordering)
{
Expand Down Expand Up @@ -315,8 +257,7 @@ RLM_API void realm_sync_config_set_error_handler(realm_sync_config_t* config, re
auto c_error = realm_sync_error_t();

std::string error_code_message;
c_error.error_code = to_capi(error.status, error_code_message);
c_error.detailed_message = error.status.reason().c_str();
c_error.status = to_capi(error.status);
c_error.is_fatal = error.is_fatal;
c_error.is_unrecognized_by_client = error.is_unrecognized_by_client;
c_error.is_client_reset_requested = error.is_client_reset_requested();
Expand Down Expand Up @@ -856,9 +797,8 @@ RLM_API void realm_sync_session_wait_for_download_completion(realm_sync_session_
{
util::UniqueFunction<void(Status)> cb =
[done, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](Status s) {
if (s.get_std_error_code()) {
std::string error_code_message;
realm_sync_error_code_t error = to_capi(s, error_code_message);
if (!s.is_ok()) {
realm_error_t error = to_capi(s);
done(userdata.get(), &error);
}
else {
Expand All @@ -875,9 +815,8 @@ RLM_API void realm_sync_session_wait_for_upload_completion(realm_sync_session_t*
{
util::UniqueFunction<void(Status)> cb =
[done, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](Status s) {
if (s.get_std_error_code()) {
std::string error_code_message;
realm_sync_error_code_t error = to_capi(s, error_code_message);
if (!s.is_ok()) {
realm_error_t error = to_capi(s);
done(userdata.get(), &error);
}
else {
Expand All @@ -887,16 +826,14 @@ RLM_API void realm_sync_session_wait_for_upload_completion(realm_sync_session_t*
(*session)->wait_for_upload_completion(std::move(cb));
}

RLM_API void realm_sync_session_handle_error_for_testing(const realm_sync_session_t* session, int error_code,
int error_category, const char* error_message, bool is_fatal)
RLM_API void realm_sync_session_handle_error_for_testing(const realm_sync_session_t* session,
realm_errno_e error_code, const char* error_str,
bool is_fatal)
{
REALM_ASSERT(session);
realm_sync_error_code_t sync_error{static_cast<realm_sync_error_category_e>(error_category), error_code,
error_message};
std::error_code err;
sync_error_to_error_code(sync_error, &err);
SyncSession::OnlyForTesting::handle_error(*session->get(),
sync::SessionErrorInfo{Status{err, error_message}, IsFatal{is_fatal}});
SyncSession::OnlyForTesting::handle_error(
*session->get(),
sync::SessionErrorInfo{Status{static_cast<ErrorCodes::Error>(error_code), error_str}, !is_fatal});
}

} // namespace realm::c_api
Loading
Loading