Skip to content

Commit e246b7d

Browse files
author
Michael Wilkerson-Barker
authored
RCORE-2150 Include originating client reset error message when reporting auto client reset failures (#7761)
* Added originating client reset error to reason strings of AutoClientResetFailed errors * Updated changelog
1 parent 352b981 commit e246b7d

File tree

6 files changed

+40
-25
lines changed

6 files changed

+40
-25
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
### Enhancements
44
* <New feature description> (PR [#????](https://github.com/realm/realm-core/pull/????))
5-
* None.
5+
* Include the originating client reset error in AutoClientResetFailure errors. ([#7761](https://github.com/realm/realm-core/pull/7761))
66

77
### Fixed
88
* <How do the end-user experience this issue? what was the impact?> ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?)

src/realm/object-store/sync/sync_session.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -429,8 +429,10 @@ void SyncSession::download_fresh_realm(const sync::SessionErrorInfo& error_info)
429429
auto mode = config(&SyncConfig::client_resync_mode);
430430
if (mode == ClientResyncMode::Recover) {
431431
handle_fresh_realm_downloaded(
432-
nullptr, {ErrorCodes::RuntimeError,
433-
"A client reset is required but the server does not permit recovery for this client"});
432+
nullptr,
433+
{ErrorCodes::RuntimeError,
434+
"A client reset is required but the server does not permit recovery for this client"},
435+
error_info);
434436
return;
435437
}
436438
}
@@ -467,7 +469,7 @@ void SyncSession::download_fresh_realm(const sync::SessionErrorInfo& error_info)
467469
catch (...) {
468470
// Failed to open the fresh path after attempting to delete it, so we
469471
// just can't do automatic recovery.
470-
handle_fresh_realm_downloaded(nullptr, exception_to_status());
472+
handle_fresh_realm_downloaded(nullptr, exception_to_status(), error_info);
471473
return;
472474
}
473475

@@ -535,10 +537,10 @@ void SyncSession::download_fresh_realm(const sync::SessionErrorInfo& error_info)
535537
// it immediately
536538
fresh_sync_session->force_close();
537539
if (subs.is_ok()) {
538-
self->handle_fresh_realm_downloaded(db, std::move(error_info), std::move(subs.get_value()));
540+
self->handle_fresh_realm_downloaded(db, Status::OK(), error_info, std::move(subs.get_value()));
539541
}
540542
else {
541-
self->handle_fresh_realm_downloaded(nullptr, std::move(subs.get_status()));
543+
self->handle_fresh_realm_downloaded(nullptr, std::move(subs.get_status()), error_info);
542544
}
543545
});
544546
}
@@ -549,18 +551,18 @@ void SyncSession::download_fresh_realm(const sync::SessionErrorInfo& error_info)
549551
fresh_sync_session->force_close();
550552
if (auto strong_self = weak_self.lock()) {
551553
if (status.is_ok()) {
552-
strong_self->handle_fresh_realm_downloaded(db, std::move(error_info));
554+
strong_self->handle_fresh_realm_downloaded(db, Status::OK(), error_info);
553555
}
554556
else {
555-
strong_self->handle_fresh_realm_downloaded(nullptr, std::move(status));
557+
strong_self->handle_fresh_realm_downloaded(nullptr, std::move(status), error_info);
556558
}
557559
}
558560
});
559561
}
560562
fresh_sync_session->revive_if_needed();
561563
}
562564

563-
void SyncSession::handle_fresh_realm_downloaded(DBRef db, StatusWith<sync::SessionErrorInfo> error_info,
565+
void SyncSession::handle_fresh_realm_downloaded(DBRef db, Status result, const sync::SessionErrorInfo& cr_error_info,
564566
std::optional<sync::SubscriptionSet> new_subs)
565567
{
566568
util::CheckedUniqueLock lock(m_state_mutex);
@@ -571,15 +573,16 @@ void SyncSession::handle_fresh_realm_downloaded(DBRef db, StatusWith<sync::Sessi
571573
// - unable to write the fresh copy to the file system
572574
// - during download of the fresh copy, the fresh copy itself is reset
573575
// - in FLX mode there was a problem fulfilling the previously active subscription
574-
if (!error_info.is_ok()) {
575-
if (error_info.get_status() == ErrorCodes::OperationAborted) {
576+
if (!result.is_ok()) {
577+
if (result == ErrorCodes::OperationAborted) {
576578
return;
577579
}
578580
lock.unlock();
579581

580582
sync::SessionErrorInfo synthetic(
581583
Status{ErrorCodes::AutoClientResetFailed,
582-
util::format("A fatal error occurred during client reset: '%1'", error_info.get_status())},
584+
util::format("A fatal error occurred during '%1' client reset for %2: '%3'",
585+
cr_error_info.server_requests_action, cr_error_info.status, result)},
583586
sync::IsFatal{true});
584587
handle_error(synthetic);
585588
return;
@@ -598,8 +601,7 @@ void SyncSession::handle_fresh_realm_downloaded(DBRef db, StatusWith<sync::Sessi
598601
m_client_reset_fresh_copy = db;
599602
CompletionCallbacks callbacks;
600603
// Save the client reset error for when the original sync session is revived
601-
REALM_ASSERT(error_info.is_ok()); // required if we get here
602-
m_client_reset_error = std::move(error_info.get_value());
604+
m_client_reset_error = cr_error_info;
603605

604606
std::swap(m_completion_callbacks, callbacks);
605607
// always swap back, even if advance_state throws

src/realm/object-store/sync/sync_session.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ class SyncSession : public std::enable_shared_from_this<SyncSession> {
408408

409409
void download_fresh_realm(const sync::SessionErrorInfo& error_info)
410410
REQUIRES(!m_config_mutex, !m_state_mutex, !m_connection_state_mutex);
411-
void handle_fresh_realm_downloaded(DBRef db, StatusWith<sync::SessionErrorInfo> error_info,
411+
void handle_fresh_realm_downloaded(DBRef db, Status result, const sync::SessionErrorInfo& cr_error_info,
412412
std::optional<sync::SubscriptionSet> new_subs = std::nullopt)
413413
REQUIRES(!m_state_mutex, !m_config_mutex, !m_connection_state_mutex);
414414
void handle_error(sync::SessionErrorInfo) REQUIRES(!m_state_mutex, !m_config_mutex, !m_connection_state_mutex);

src/realm/sync/noinst/client_impl_base.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2345,11 +2345,21 @@ Status Session::receive_ident_message(SaltedFileIdent client_file_ident)
23452345
// if a client reset happens, it will take care of setting the file ident
23462346
// and if not, we do it here
23472347
bool did_client_reset = false;
2348+
2349+
// Save some of the client reset info for reporting to the client if an error occurs.
2350+
Status cr_status(Status::OK()); // Start with no client reset
2351+
ProtocolErrorInfo::Action cr_action = ProtocolErrorInfo::Action::NoAction;
2352+
if (auto& cr_config = get_client_reset_config()) {
2353+
cr_status = cr_config->error;
2354+
cr_action = cr_config->action;
2355+
}
2356+
23482357
try {
23492358
did_client_reset = client_reset_if_needed();
23502359
}
23512360
catch (const std::exception& e) {
2352-
auto err_msg = util::format("A fatal error occurred during client reset: '%1'", e.what());
2361+
auto err_msg = util::format("A fatal error occurred during '%1' client reset for %2: '%3'", cr_action,
2362+
cr_status, e.what());
23532363
logger.error(err_msg.c_str());
23542364
SessionErrorInfo err_info(Status{ErrorCodes::AutoClientResetFailed, err_msg}, IsFatal{true});
23552365
suspend(err_info);

test/object-store/sync/flx_sync.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,8 @@ TEST_CASE("flx: client reset", "[sync][flx][client reset][baas]") {
908908
REQUIRE(before_reset_count == 1);
909909
REQUIRE(after_reset_count == 0);
910910
REQUIRE(sync_error.status == ErrorCodes::AutoClientResetFailed);
911+
REQUIRE(sync_error.status.reason().find(
912+
"SyncClientResetRequired: Bad client file identifier (IDENT)") != std::string::npos);
911913
REQUIRE(sync_error.is_client_reset_requested());
912914
local_realm->refresh();
913915
auto table = local_realm->read_group().get_table("class_TopLevel");
@@ -1133,6 +1135,8 @@ TEST_CASE("flx: client reset", "[sync][flx][client reset][baas]") {
11331135
auto sync_error = wait_for_future(std::move(err_future)).get();
11341136
INFO(sync_error.status);
11351137
CHECK(sync_error.status == ErrorCodes::AutoClientResetFailed);
1138+
REQUIRE(sync_error.status.reason().find(
1139+
"SyncClientResetRequired: Bad client file identifier (IDENT)") != std::string::npos);
11361140
})
11371141
->run();
11381142
}
@@ -1420,8 +1424,7 @@ TEST_CASE("flx: client reset", "[sync][flx][client reset][baas]") {
14201424
REQUIRE(!ref);
14211425
REQUIRE(error);
14221426
REQUIRE_THROWS_CONTAINING(std::rethrow_exception(error),
1423-
"A fatal error occurred during client reset: 'Client reset cannot recover when "
1424-
"classes have been removed: {AddedClass}'");
1427+
"'Client reset cannot recover when classes have been removed: {AddedClass}'");
14251428
});
14261429
error_future.get();
14271430
CHECK(before_reset_count == 1);
@@ -1441,8 +1444,7 @@ TEST_CASE("flx: client reset", "[sync][flx][client reset][baas]") {
14411444
REQUIRE(error);
14421445
REQUIRE_THROWS_CONTAINING(
14431446
std::rethrow_exception(error),
1444-
"A fatal error occurred during client reset: 'The following changes cannot be "
1445-
"made in additive-only schema mode:\n"
1447+
"'The following changes cannot be made in additive-only schema mode:\n"
14461448
"- Property 'TopLevel._id' has been changed from 'object id' to 'uuid'.\nIf your app is running in "
14471449
"development mode, you can delete the realm and restart the app to update your schema.'");
14481450
});

test/test_client_reset.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -730,12 +730,12 @@ TEST(ClientReset_DoNotRecoverSchema)
730730
// schema change is not allowed and so fails with a client reset error.
731731
{
732732
Session::Config session_config;
733+
std::string error_msg = "Some bad client file identifier (IDENT)";
733734
{
734-
Session::Config::ClientReset cr_config{
735-
ClientResyncMode::DiscardLocal,
736-
sg_fresh1,
737-
{ErrorCodes::SyncClientResetRequired, "Bad client file identifier (IDENT)"},
738-
sync::ProtocolErrorInfo::Action::ClientReset};
735+
Session::Config::ClientReset cr_config{ClientResyncMode::DiscardLocal,
736+
sg_fresh1,
737+
{ErrorCodes::SyncClientResetRequired, error_msg},
738+
sync::ProtocolErrorInfo::Action::ClientReset};
739739
session_config.client_reset_config = std::move(cr_config);
740740
}
741741

@@ -746,6 +746,7 @@ TEST(ClientReset_DoNotRecoverSchema)
746746
return;
747747
REALM_ASSERT(error_info);
748748
CHECK_EQUAL(error_info->status, ErrorCodes::AutoClientResetFailed);
749+
CHECK(error_info->status.reason().find(error_msg) != std::string::npos);
749750
bowl.add_stone();
750751
};
751752
Session session = fixture.make_session(path_1, server_path_2, std::move(session_config));

0 commit comments

Comments
 (0)