-
Notifications
You must be signed in to change notification settings - Fork 172
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
RCORE-2185 Sync client should steal file ident of fresh realm when performing client reset #7850
Changes from 24 commits
520faad
b1b1dd9
5e1e1e9
73ad369
f5e1044
1d3ca5b
4b02363
9c38925
3a2af9a
aae37b7
6842197
2ddca98
86ca88a
005fea6
705a114
59a7b51
5072e32
1e51055
427d8fe
c82d03b
bacdd57
49ec153
f5569c1
043a470
f7d915c
49a5016
aa50680
d88f2e4
85abf4b
6a426a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1687,12 +1687,11 @@ void Session::activate() | |
|
||
if (REALM_LIKELY(!get_client().is_dry_run())) { | ||
bool file_exists = util::File::exists(get_realm_path()); | ||
m_performing_client_reset = get_client_reset_config().has_value(); | ||
m_has_client_reset_config = get_client_reset_config().has_value(); | ||
|
||
logger.info("client_reset_config = %1, Realm exists = %2 ", m_performing_client_reset, file_exists); | ||
if (!m_performing_client_reset) { | ||
get_history().get_status(m_last_version_available, m_client_file_ident, m_progress); // Throws | ||
} | ||
logger.info("client_reset_config = %1, Realm exists = %2, uploads allowed = %3", m_has_client_reset_config, | ||
file_exists, are_uploads_allowed() ? "yes" : "no"); | ||
get_history().get_status(m_last_version_available, m_client_file_ident, m_progress); // Throws | ||
} | ||
logger.debug("client_file_ident = %1, client_file_ident_salt = %2", m_client_file_ident.ident, | ||
m_client_file_ident.salt); // Throws | ||
|
@@ -1701,7 +1700,7 @@ void Session::activate() | |
REALM_ASSERT_3(m_last_version_available, >=, m_progress.upload.client_version); | ||
init_progress_handler(); | ||
|
||
logger.debug("last_version_available = %1", m_last_version_available); // Throws | ||
logger.debug("last_version_available = %1", m_last_version_available); // Throws | ||
logger.debug("progress_download_server_version = %1", m_progress.download.server_version); // Throws | ||
logger.debug("progress_download_client_version = %1", | ||
m_progress.download.last_integrated_client_version); // Throws | ||
|
@@ -1871,13 +1870,17 @@ void Session::send_message() | |
return false; | ||
} | ||
|
||
// Send QUERY messages when the upload progress client version reaches the snapshot version | ||
// of a pending subscription, or if this is a fresh realm download session, since UPLOAD | ||
// messages are not allowed and the upload progress will not be updated. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the local upload progress is actually updated, but no upload messages are sent |
||
return m_upload_progress.client_version >= m_pending_flx_sub_set->snapshot_version; | ||
}; | ||
|
||
if (check_pending_flx_version()) { | ||
return send_query_change_message(); // throws | ||
} | ||
|
||
// Don't allow UPLOAD messages for client reset fresh realm download sessions | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not really doing anything in that sense to justify the comment |
||
if (m_allow_upload && (m_last_version_available > m_upload_progress.client_version)) { | ||
return send_upload_message(); // Throws | ||
} | ||
|
@@ -1889,10 +1892,10 @@ void Session::send_bind_message() | |
REALM_ASSERT_EX(m_state == Active, m_state); | ||
|
||
session_ident_type session_ident = m_ident; | ||
bool need_client_file_ident = !have_client_file_ident(); | ||
// Request an ident if we don't already have one and there isn't a pending client reset diff | ||
bool need_client_file_ident = !have_client_file_ident() && !m_has_client_reset_config; | ||
const bool is_subserver = false; | ||
|
||
|
||
ClientProtocol& protocol = m_conn.get_client_protocol(); | ||
int protocol_version = m_conn.get_negotiated_protocol_version(); | ||
OutputBuffer& out = m_conn.get_output_buffer(); | ||
|
@@ -1931,8 +1934,9 @@ void Session::send_bind_message() | |
m_bind_message_sent = true; | ||
call_debug_hook(SyncClientHookEvent::BindMessageSent); | ||
|
||
// Ready to send the IDENT message if the file identifier pair is already | ||
// available. | ||
// If there is a pending client reset diff, process that when the BIND message has | ||
// been sent successfully and wait before sending the IDENT message. Otherwise, | ||
// ready to send the IDENT message if the file identifier pair is already available. | ||
if (!need_client_file_ident) | ||
enlist_to_send(); // Throws | ||
} | ||
|
@@ -1945,7 +1949,6 @@ void Session::send_ident_message() | |
REALM_ASSERT(!m_unbind_message_sent); | ||
REALM_ASSERT(have_client_file_ident()); | ||
|
||
|
||
ClientProtocol& protocol = m_conn.get_client_protocol(); | ||
OutputBuffer& out = m_conn.get_output_buffer(); | ||
session_ident_type session_ident = m_ident; | ||
|
@@ -2050,6 +2053,14 @@ void Session::send_upload_message() | |
version_type progress_client_version = m_upload_progress.client_version; | ||
version_type progress_server_version = m_upload_progress.last_integrated_server_version; | ||
|
||
if (!are_uploads_allowed()) { | ||
logger.debug("UPLOAD not allowed: upload progress(progress_client_version=%1, progress_server_version=%2, " | ||
"locked_server_version=%3, num_changesets=%4)", | ||
progress_client_version, progress_server_version, locked_server_version, | ||
uploadable_changesets.size()); // Throws | ||
return; | ||
} | ||
|
||
logger.debug("Sending: UPLOAD(progress_client_version=%1, progress_server_version=%2, " | ||
"locked_server_version=%3, num_changesets=%4)", | ||
progress_client_version, progress_server_version, locked_server_version, | ||
|
@@ -2135,6 +2146,8 @@ void Session::send_upload_message() | |
locked_server_version); // Throws | ||
m_conn.initiate_write_message(out, this); // Throws | ||
|
||
call_debug_hook(SyncClientHookEvent::UploadMessageSent); | ||
|
||
// Other messages may be waiting to be sent | ||
enlist_to_send(); // Throws | ||
} | ||
|
@@ -2236,7 +2249,7 @@ bool Session::client_reset_if_needed() | |
{ | ||
// Regardless of what happens, once we return from this function we will | ||
// no longer be in the middle of a client reset | ||
m_performing_client_reset = false; | ||
m_has_client_reset_config = false; | ||
|
||
// Even if we end up not actually performing a client reset, consume the | ||
// config to ensure that the resources it holds are released | ||
|
@@ -2245,29 +2258,51 @@ bool Session::client_reset_if_needed() | |
return false; | ||
} | ||
|
||
// Save a copy of the status and action in case an error/exception occurs | ||
Status cr_status = client_reset_config->error; | ||
ProtocolErrorInfo::Action cr_action = client_reset_config->action; | ||
|
||
auto on_flx_version_complete = [this](int64_t version) { | ||
this->on_flx_sync_version_complete(version); | ||
}; | ||
bool did_reset = | ||
client_reset::perform_client_reset(logger, *get_db(), std::move(*client_reset_config), m_client_file_ident, | ||
get_flx_subscription_store(), on_flx_version_complete); | ||
try { | ||
// The file ident from the fresh realm will be copied over to the local realm | ||
bool did_reset = client_reset::perform_client_reset(logger, *get_db(), std::move(*client_reset_config), | ||
get_flx_subscription_store(), on_flx_version_complete); | ||
|
||
call_debug_hook(SyncClientHookEvent::ClientResetMergeComplete); | ||
if (!did_reset) { | ||
call_debug_hook(SyncClientHookEvent::ClientResetMergeComplete); | ||
if (!did_reset) { | ||
return false; | ||
} | ||
} | ||
catch (const std::exception& e) { | ||
auto err_msg = util::format("A fatal error occurred during '%1' client reset diff for %2: '%3'", cr_action, | ||
cr_status, e.what()); | ||
logger.error(err_msg.c_str()); | ||
SessionErrorInfo err_info(Status{ErrorCodes::AutoClientResetFailed, err_msg}, IsFatal{true}); | ||
suspend(err_info); | ||
return false; | ||
} | ||
|
||
// The fresh Realm has been used to reset the state | ||
logger.debug("Client reset is completed, path=%1", get_realm_path()); // Throws | ||
logger.debug("Client reset is completed, path = %1", get_realm_path()); // Throws | ||
|
||
// Update the version, file ident and progress info after the client reset diff is done | ||
get_history().get_status(m_last_version_available, m_client_file_ident, m_progress); // Throws | ||
// Print the version/progress information before performing the asserts | ||
logger.debug("client_file_ident = %1, client_file_ident_salt = %2", m_client_file_ident.ident, | ||
m_client_file_ident.salt); // Throws | ||
logger.debug("last_version_available = %1", m_last_version_available); // Throws | ||
logger.debug("upload_progress_client_version = %1, upload_progress_server_version = %2", | ||
m_progress.upload.client_version, | ||
m_progress.upload.last_integrated_server_version); // Throws | ||
logger.debug("download_progress_client_version = %1, download_progress_server_version = %2", | ||
m_progress.download.last_integrated_client_version, | ||
m_progress.download.server_version); // Throws | ||
|
||
SaltedFileIdent client_file_ident; | ||
get_history().get_status(m_last_version_available, client_file_ident, m_progress); // Throws | ||
REALM_ASSERT_3(m_client_file_ident.ident, ==, client_file_ident.ident); | ||
REALM_ASSERT_3(m_client_file_ident.salt, ==, client_file_ident.salt); | ||
REALM_ASSERT_EX(m_progress.download.last_integrated_client_version == 0, | ||
m_progress.download.last_integrated_client_version); | ||
REALM_ASSERT_EX(m_progress.upload.client_version == 0, m_progress.upload.client_version); | ||
logger.trace("last_version_available = %1", m_last_version_available); // Throws | ||
|
||
m_upload_progress = m_progress.upload; | ||
m_download_progress = m_progress.download; | ||
|
@@ -2321,35 +2356,10 @@ Status Session::receive_ident_message(SaltedFileIdent client_file_ident) | |
return Status::OK(); // Success | ||
} | ||
|
||
// if a client reset happens, it will take care of setting the file ident | ||
// and if not, we do it here | ||
bool did_client_reset = false; | ||
|
||
// Save some of the client reset info for reporting to the client if an error occurs. | ||
Status cr_status(Status::OK()); // Start with no client reset | ||
ProtocolErrorInfo::Action cr_action = ProtocolErrorInfo::Action::NoAction; | ||
if (auto& cr_config = get_client_reset_config()) { | ||
cr_status = cr_config->error; | ||
cr_action = cr_config->action; | ||
} | ||
|
||
try { | ||
did_client_reset = client_reset_if_needed(); | ||
} | ||
catch (const std::exception& e) { | ||
auto err_msg = util::format("A fatal error occurred during '%1' client reset for %2: '%3'", cr_action, | ||
cr_status, e.what()); | ||
logger.error(err_msg.c_str()); | ||
SessionErrorInfo err_info(Status{ErrorCodes::AutoClientResetFailed, err_msg}, IsFatal{true}); | ||
suspend(err_info); | ||
return Status::OK(); | ||
} | ||
if (!did_client_reset) { | ||
get_history().set_client_file_ident(client_file_ident, | ||
m_fix_up_object_ids); // Throws | ||
m_progress.download.last_integrated_client_version = 0; | ||
m_progress.upload.client_version = 0; | ||
} | ||
get_history().set_client_file_ident(client_file_ident, | ||
m_fix_up_object_ids); // Throws | ||
m_progress.download.last_integrated_client_version = 0; | ||
m_progress.upload.client_version = 0; | ||
|
||
// Ready to send the IDENT message | ||
ensure_enlisted_to_send(); // Throws | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -847,6 +847,10 @@ class ClientImpl::Session { | |
/// Returns the schema version the synchronization session connects with to the server. | ||
uint64_t get_schema_version() noexcept; | ||
|
||
// Returns false if this session is not allowed to send UPLOAD messages to the server to | ||
// update the cursor info, such as during a client reset fresh realm download | ||
bool are_uploads_allowed() noexcept; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a bit odd to have this method while there is also There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I renamed the function to |
||
|
||
/// \brief Initiate the integration of downloaded changesets. | ||
/// | ||
/// This function must provide for the passed changesets (if any) to | ||
|
@@ -981,7 +985,7 @@ class ClientImpl::Session { | |
SaltedFileIdent m_client_file_ident = {0, 0}; | ||
|
||
// True while this session is in the process of performing a client reset. | ||
bool m_performing_client_reset = false; | ||
bool m_has_client_reset_config = false; | ||
|
||
// The latest sync progress reported by the server via a DOWNLOAD | ||
// message. See struct SyncProgress for a description. The values stored in | ||
|
@@ -1427,6 +1431,14 @@ inline void ClientImpl::Session::message_sent() | |
// No message will be sent after the UNBIND message | ||
REALM_ASSERT(!m_unbind_message_send_complete); | ||
|
||
// If the client reset config structure is populated, then try to perform | ||
// the client reset diff once the BIND message has been sent successfully | ||
if (m_bind_message_sent && m_has_client_reset_config) { | ||
client_reset_if_needed(); // resets m_has_client_reset_config | ||
// Ready to send the IDENT message | ||
ensure_enlisted_to_send(); // Throws | ||
} | ||
|
||
if (m_unbind_message_sent) { | ||
REALM_ASSERT(!m_enlisted_to_send); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to assign a default value since you must do it in the constructor