Skip to content

Commit

Permalink
Workaround issue when initiating sync on a copied realm file
Browse files Browse the repository at this point in the history
The problem is that the server does not know that the client has already
integrated some server versions, and therefore it sends down 0 as
progress/upload/last_integrated_server_version. On the client this number
may be bigger and in this case that number will not be overwritten with 0.
There may still be issues on the server, however.
  • Loading branch information
jedelbo committed Aug 27, 2021
1 parent 8bc8541 commit 1ca0865
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 4 deletions.
12 changes: 8 additions & 4 deletions src/realm/sync/noinst/client_history_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -953,8 +953,10 @@ void ClientHistoryImpl::update_sync_progress(const SyncProgress& progress,
version_type(root.get_as_ref_or_tagged(s_progress_download_client_version_iip).get_as_int()));
REALM_ASSERT(progress.upload.client_version >=
version_type(root.get_as_ref_or_tagged(s_progress_upload_client_version_iip).get_as_int()));
REALM_ASSERT(progress.upload.last_integrated_server_version >=
version_type(root.get_as_ref_or_tagged(s_progress_upload_server_version_iip).get_as_int()));
if (progress.upload.last_integrated_server_version > 0) {
REALM_ASSERT(progress.upload.last_integrated_server_version >=
version_type(root.get_as_ref_or_tagged(s_progress_upload_server_version_iip).get_as_int()));
}

auto uploaded_bytes = std::uint_fast64_t(root.get_as_ref_or_tagged(s_progress_uploaded_bytes_iip).get_as_int());
auto previous_upload_client_version =
Expand All @@ -971,8 +973,10 @@ void ClientHistoryImpl::update_sync_progress(const SyncProgress& progress,
RefOrTagged::make_tagged(progress.latest_server_version.salt)); // Throws
root.set(s_progress_upload_client_version_iip,
RefOrTagged::make_tagged(progress.upload.client_version)); // Throws
root.set(s_progress_upload_server_version_iip,
RefOrTagged::make_tagged(progress.upload.last_integrated_server_version)); // Throws
if (progress.upload.last_integrated_server_version > 0) {
root.set(s_progress_upload_server_version_iip,
RefOrTagged::make_tagged(progress.upload.last_integrated_server_version)); // Throws
}
if (downloadable_bytes) {
root.set(s_progress_downloadable_bytes_iip,
RefOrTagged::make_tagged(*downloadable_bytes)); // Throws
Expand Down
121 changes: 121 additions & 0 deletions test/object-store/sync/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <realm/object-store/sync/mongo_database.hpp>
#include <realm/object-store/sync/mongo_collection.hpp>
#include <realm/object-store/sync/sync_session.hpp>
#include <realm/object-store/thread_safe_reference.hpp>

#include "util/baas_admin_api.hpp"
#include "util/event_loop.hpp"
Expand Down Expand Up @@ -1988,6 +1989,126 @@ TEST_CASE("app: set new embedded object", "[sync][app]") {
}
}

TEST_CASE("app: make distributable client file", "[sync][app]") {
std::unique_ptr<GenericNetworkTransport> (*factory)() = [] {
return std::unique_ptr<GenericNetworkTransport>(new IntTestTransport);
};
std::string base_url = get_base_url();
REQUIRE(!base_url.empty());
auto app_session = get_runtime_app_session(base_url);

auto app_id = app_session.client_app_id;
auto config = App::Config{app_id,
factory,
base_url,
util::none,
Optional<std::string>("A Local App Version"),
util::none,
"Object Store Platform Tests",
"Object Store Platform Version Blah",
"An sdk version"};

auto base_path = util::make_temp_dir();
util::try_remove_dir_recursive(base_path);
util::try_make_dir(base_path);
util::try_make_dir(base_path + "/orig");
util::try_make_dir(base_path + "/copy");

// Create realm file without client file id
{
TestSyncManager sync_manager(TestSyncManager::Config(config), {});
auto app = sync_manager.app();
app->log_in_with_credentials(AppCredentials::anonymous(),
[&](std::shared_ptr<SyncUser> user, Optional<app::AppError> error) {
REQUIRE(!error);
REQUIRE(user);
});

ThreadSafeReference realm_ref;

realm::Realm::Config realm_config;
realm_config.sync_config = std::make_shared<realm::SyncConfig>(app->current_user(), bson::Bson("foo"));
realm_config.sync_config->client_resync_mode = ClientResyncMode::Manual;
realm_config.sync_config->error_handler = [](std::shared_ptr<SyncSession>, SyncError error) {
std::cerr << error.message << std::endl;
};
realm_config.schema_version = 1;
realm_config.path = base_path + "/orig/default.realm";

std::mutex mutex;
auto task = realm::Realm::get_synchronized_realm(realm_config);
task->start([&](ThreadSafeReference ref, std::exception_ptr error) {
std::lock_guard<std::mutex> lock(mutex);
REQUIRE(!error);
realm_ref = std::move(ref);
});
util::EventLoop::main().run_until([&] {
std::lock_guard<std::mutex> lock(mutex);
return bool(realm_ref);
});
SharedRealm realm = Realm::get_shared_realm(std::move(realm_ref));

// Write some data
realm->begin_transaction();
CppContext c;
Object::create(c, realm, "Person",
util::Any(realm::AnyDict{{"_id", util::Any(ObjectId::gen())},
{"age", INT64_C(64)},
{"firstName", std::string("Paul")},
{"lastName", std::string("McCartney")}}));
realm->commit_transaction();
wait_for_upload(*realm);
wait_for_download(*realm);

realm->write_copy(base_path + "/copy/default.realm", BinaryData());

// Write some additional data
realm->begin_transaction();
Object::create(c, realm, "Dog",
util::Any(realm::AnyDict{{"_id", util::Any(ObjectId::gen())},
{"breed", std::string("stabyhoun")},
{"name", std::string("albert")},
{"realm_id", std::string("foo")}}));
realm->commit_transaction();
wait_for_upload(*realm);
}
// Starting a new session based on the copy
{
TestSyncManager sync_manager(TestSyncManager::Config(config), {});
auto app = sync_manager.app();
app->log_in_with_credentials(AppCredentials::anonymous(),
[&](std::shared_ptr<SyncUser> user, Optional<app::AppError> error) {
REQUIRE(!error);
REQUIRE(user);
});

ThreadSafeReference realm_ref;

realm::Realm::Config realm_config;
realm_config.sync_config = std::make_shared<realm::SyncConfig>(app->current_user(), bson::Bson("foo"));
realm_config.sync_config->client_resync_mode = ClientResyncMode::Manual;
realm_config.sync_config->error_handler = [](std::shared_ptr<SyncSession>, SyncError error) {
std::cerr << error.message << std::endl;
};
realm_config.schema_version = 1;
realm_config.path = base_path + "/copy/default.realm";

SharedRealm realm = realm::Realm::get_shared_realm(realm_config);
wait_for_download(*realm);

// Check that we can continue committing to this realm
realm->begin_transaction();
CppContext c;
Object::create(c, realm, "Dog",
util::Any(realm::AnyDict{{"_id", util::Any(ObjectId::gen())},
{"breed", std::string("bulldog")},
{"name", std::string("fido")},
{"realm_id", std::string("foo")}}));
realm->commit_transaction();
wait_for_upload(*realm);
}
}

TEST_CASE("app: sync integration", "[sync][app]") {
std::unique_ptr<GenericNetworkTransport> (*factory)() = [] {
return std::unique_ptr<GenericNetworkTransport>(new IntTestTransport);
Expand Down

0 comments on commit 1ca0865

Please sign in to comment.