@@ -422,17 +422,15 @@ void SyncSession::update_error_and_mark_file_for_deletion(SyncError& error, Shou
422422 }
423423}
424424
425- void SyncSession::download_fresh_realm (sync::ProtocolErrorInfo::Action server_requests_action )
425+ void SyncSession::download_fresh_realm (const sync::SessionErrorInfo& error_info )
426426{
427427 // first check that recovery will not be prevented
428- if (server_requests_action == sync::ProtocolErrorInfo::Action::ClientResetNoRecovery) {
428+ if (error_info. server_requests_action == sync::ProtocolErrorInfo::Action::ClientResetNoRecovery) {
429429 auto mode = config (&SyncConfig::client_resync_mode);
430430 if (mode == ClientResyncMode::Recover) {
431431 handle_fresh_realm_downloaded (
432- nullptr ,
433- {ErrorCodes::RuntimeError,
434- " A client reset is required but the server does not permit recovery for this client" },
435- server_requests_action);
432+ nullptr , {ErrorCodes::RuntimeError,
433+ " A client reset is required but the server does not permit recovery for this client" });
436434 return ;
437435 }
438436 }
@@ -469,14 +467,15 @@ void SyncSession::download_fresh_realm(sync::ProtocolErrorInfo::Action server_re
469467 catch (...) {
470468 // Failed to open the fresh path after attempting to delete it, so we
471469 // just can't do automatic recovery.
472- handle_fresh_realm_downloaded (nullptr , exception_to_status (), server_requests_action );
470+ handle_fresh_realm_downloaded (nullptr , exception_to_status ());
473471 return ;
474472 }
475473
476474 util::CheckedLockGuard state_lock (m_state_mutex);
477475 if (m_state != State::Active) {
478476 return ;
479477 }
478+
480479 RealmConfig fresh_config;
481480 {
482481 util::CheckedLockGuard config_lock (m_config_mutex);
@@ -511,7 +510,7 @@ void SyncSession::download_fresh_realm(sync::ProtocolErrorInfo::Action server_re
511510 using SubscriptionState = sync::SubscriptionSet::State;
512511 fresh_sub.get_state_change_notification (SubscriptionState::Complete)
513512 .then ([=](SubscriptionState) -> util::Future<sync::SubscriptionSet> {
514- if (server_requests_action != sync::ProtocolErrorInfo::Action::MigrateToFLX) {
513+ if (error_info. server_requests_action != sync::ProtocolErrorInfo::Action::MigrateToFLX) {
515514 return fresh_sub;
516515 }
517516 if (!self->m_migration_store ->is_migration_in_progress ()) {
@@ -527,7 +526,7 @@ void SyncSession::download_fresh_realm(sync::ProtocolErrorInfo::Action server_re
527526 fresh_sync_session->m_migration_store ->create_subscriptions (*fresh_sub_store, *query_string);
528527 return fresh_sub_store->get_latest ()
529528 .get_state_change_notification (SubscriptionState::Complete)
530- .then ([= ](SubscriptionState) {
529+ .then ([fresh_sub_store ](SubscriptionState) {
531530 return fresh_sub_store->get_latest ();
532531 });
533532 })
@@ -536,29 +535,32 @@ void SyncSession::download_fresh_realm(sync::ProtocolErrorInfo::Action server_re
536535 // it immediately
537536 fresh_sync_session->force_close ();
538537 if (subs.is_ok ()) {
539- self->handle_fresh_realm_downloaded (db, Status::OK (), server_requests_action,
540- std::move (subs.get_value ()));
538+ self->handle_fresh_realm_downloaded (db, std::move (error_info), std::move (subs.get_value ()));
541539 }
542540 else {
543- self->handle_fresh_realm_downloaded (nullptr , subs.get_status (), server_requests_action );
541+ self->handle_fresh_realm_downloaded (nullptr , std::move ( subs.get_status ()) );
544542 }
545543 });
546544 }
547545 else { // pbs
548- fresh_sync_session->wait_for_download_completion ([=, weak_self = weak_from_this ()](Status s ) {
546+ fresh_sync_session->wait_for_download_completion ([=, weak_self = weak_from_this ()](Status status ) {
549547 // Keep the sync session alive while it's downloading, but then close
550548 // it immediately
551549 fresh_sync_session->force_close ();
552550 if (auto strong_self = weak_self.lock ()) {
553- strong_self->handle_fresh_realm_downloaded (db, s, server_requests_action);
551+ if (status.is_ok ()) {
552+ strong_self->handle_fresh_realm_downloaded (db, std::move (error_info));
553+ }
554+ else {
555+ strong_self->handle_fresh_realm_downloaded (nullptr , std::move (status));
556+ }
554557 }
555558 });
556559 }
557560 fresh_sync_session->revive_if_needed ();
558561}
559562
560- void SyncSession::handle_fresh_realm_downloaded (DBRef db, Status status,
561- sync::ProtocolErrorInfo::Action server_requests_action,
563+ void SyncSession::handle_fresh_realm_downloaded (DBRef db, StatusWith<sync::SessionErrorInfo> error_info,
562564 std::optional<sync::SubscriptionSet> new_subs)
563565{
564566 util::CheckedUniqueLock lock (m_state_mutex);
@@ -569,15 +571,15 @@ void SyncSession::handle_fresh_realm_downloaded(DBRef db, Status status,
569571 // - unable to write the fresh copy to the file system
570572 // - during download of the fresh copy, the fresh copy itself is reset
571573 // - in FLX mode there was a problem fulfilling the previously active subscription
572- if (!status .is_ok ()) {
573- if (status == ErrorCodes::OperationAborted) {
574+ if (!error_info .is_ok ()) {
575+ if (error_info. get_status () == ErrorCodes::OperationAborted) {
574576 return ;
575577 }
576578 lock.unlock ();
577579
578580 sync::SessionErrorInfo synthetic (
579581 Status{ErrorCodes::AutoClientResetFailed,
580- util::format (" A fatal error occurred during client reset: '%1'" , status. reason ())},
582+ util::format (" A fatal error occurred during client reset: '%1'" , error_info. get_status ())},
581583 sync::IsFatal{true });
582584 handle_error (synthetic);
583585 return ;
@@ -593,9 +595,12 @@ void SyncSession::handle_fresh_realm_downloaded(DBRef db, Status status,
593595 // that moving to the inactive state doesn't clear them - they will be
594596 // re-registered when the session becomes active again.
595597 {
596- m_server_requests_action = server_requests_action;
597598 m_client_reset_fresh_copy = db;
598599 CompletionCallbacks callbacks;
600+ // 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 ());
603+
599604 std::swap (m_completion_callbacks, callbacks);
600605 // always swap back, even if advance_state throws
601606 auto guard = util::make_scope_exit ([&]() noexcept {
@@ -607,11 +612,13 @@ void SyncSession::handle_fresh_realm_downloaded(DBRef db, Status status,
607612 });
608613 // Do not cancel the notifications on subscriptions.
609614 bool cancel_subscription_notifications = false ;
615+ bool is_migration =
616+ m_client_reset_error->server_requests_action == sync::ProtocolErrorInfo::Action::MigrateToFLX ||
617+ m_client_reset_error->server_requests_action == sync::ProtocolErrorInfo::Action::RevertToPBS;
610618 become_inactive (std::move (lock), Status::OK (), cancel_subscription_notifications); // unlocks the lock
611619
612620 // Once the session is inactive, update sync config and subscription store after migration.
613- if (server_requests_action == sync::ProtocolErrorInfo::Action::MigrateToFLX ||
614- server_requests_action == sync::ProtocolErrorInfo::Action::RevertToPBS) {
621+ if (is_migration) {
615622 apply_sync_config_after_migration_or_rollback ();
616623 auto flx_sync_requested = config (&SyncConfig::flx_sync_requested);
617624 update_subscription_store (flx_sync_requested, std::move (new_subs));
@@ -695,7 +702,7 @@ void SyncSession::handle_error(sync::SessionErrorInfo error)
695702 case ClientResyncMode::RecoverOrDiscard:
696703 [[fallthrough]];
697704 case ClientResyncMode::Recover:
698- download_fresh_realm (error. server_requests_action );
705+ download_fresh_realm (error);
699706 return ; // do not propagate the error to the user at this point
700707 }
701708 break ;
@@ -707,7 +714,7 @@ void SyncSession::handle_error(sync::SessionErrorInfo error)
707714 m_migration_store->migrate_to_flx (*error.migration_query_string ,
708715 m_original_sync_config->partition_value );
709716 save_sync_config_after_migration_or_rollback ();
710- download_fresh_realm (error. server_requests_action );
717+ download_fresh_realm (error);
711718 return ;
712719 case sync::ProtocolErrorInfo::Action::RevertToPBS:
713720 // If the client was updated to use FLX natively, but the server was rolled back to PBS,
@@ -721,7 +728,7 @@ void SyncSession::handle_error(sync::SessionErrorInfo error)
721728 // Original config was PBS, rollback the migration
722729 m_migration_store->rollback_to_pbs ();
723730 save_sync_config_after_migration_or_rollback ();
724- download_fresh_realm (error. server_requests_action );
731+ download_fresh_realm (error);
725732 return ;
726733 case sync::ProtocolErrorInfo::Action::RefreshUser:
727734 if (auto u = user ()) {
@@ -824,17 +831,15 @@ void SyncSession::handle_progress_update(uint64_t downloaded, uint64_t downloada
824831 upload_estimate, query_version);
825832}
826833
827- static sync::Session::Config::ClientReset make_client_reset_config ( const RealmConfig& base_config,
828- const std::shared_ptr<SyncConfig>& sync_config,
829- DBRef&& fresh_copy, bool recovery_is_allowed ,
830- bool schema_migration_detected)
834+
835+ static sync::Session::Config::ClientReset
836+ make_client_reset_config ( const RealmConfig& base_config, const std::shared_ptr<SyncConfig>& sync_config ,
837+ DBRef&& fresh_copy, sync::SessionErrorInfo&& error_info, bool schema_migration_detected)
831838{
832839 REALM_ASSERT (sync_config->client_resync_mode != ClientResyncMode::Manual);
833840
834- sync::Session::Config::ClientReset config;
835- config.mode = sync_config->client_resync_mode ;
836- config.fresh_copy = std::move (fresh_copy);
837- config.recovery_is_allowed = recovery_is_allowed;
841+ sync::Session::Config::ClientReset config{sync_config->client_resync_mode , std::move (fresh_copy),
842+ std::move (error_info.status ), error_info.server_requests_action };
838843
839844 // The conditions here are asymmetric because if we have *either* a before
840845 // or after callback we need to make sure to initialize the local schema
@@ -940,17 +945,15 @@ void SyncSession::create_sync_session()
940945 }
941946 session_config.custom_http_headers = sync_config.custom_http_headers ;
942947
943- if (m_server_requests_action != sync::ProtocolErrorInfo::Action::NoAction) {
944- // Migrations are allowed to recover local data.
945- const bool allowed_to_recover = m_server_requests_action == sync::ProtocolErrorInfo::Action::ClientReset ||
946- m_server_requests_action == sync::ProtocolErrorInfo::Action::MigrateToFLX ||
947- m_server_requests_action == sync::ProtocolErrorInfo::Action::RevertToPBS;
948- // Use the original sync config, not the updated one from the migration store
949- session_config.client_reset_config =
950- make_client_reset_config (m_config, m_original_sync_config, std::move (m_client_reset_fresh_copy),
951- allowed_to_recover, m_previous_schema_version.has_value ());
952- session_config.schema_version = m_previous_schema_version.value_or (m_config.schema_version );
953- m_server_requests_action = sync::ProtocolErrorInfo::Action::NoAction;
948+ if (m_client_reset_error) {
949+ auto client_reset_error = std::exchange (m_client_reset_error, std::nullopt );
950+ if (client_reset_error->server_requests_action != sync::ProtocolErrorInfo::Action::NoAction) {
951+ // Use the original sync config, not the updated one from the migration store
952+ session_config.client_reset_config =
953+ make_client_reset_config (m_config, m_original_sync_config, std::move (m_client_reset_fresh_copy),
954+ std::move (*client_reset_error), m_previous_schema_version.has_value ());
955+ session_config.schema_version = m_previous_schema_version.value_or (m_config.schema_version );
956+ }
954957 }
955958
956959 session_config.progress_handler = [weak_self](uint_fast64_t downloaded, uint_fast64_t downloadable,
0 commit comments