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

Fix client reset callbacks not populating Realm instances sometimes #5654

Merged
merged 2 commits into from
Jul 15, 2022

Conversation

ironage
Copy link
Contributor

@ironage ironage commented Jul 8, 2022

As reported by @LaPeste, the client reset callbacks would be called with null Realm instances if the call to RealmCoordinator ::get_existing_coordinator() returned a nullptr. This can happen if the sync session is running a client reset operation while all references to the Realm have been released. To fix this, we need to get or create a coordinator and the way to do that is to pass in the RealmConfig. This is not something that the sync session had, so I added it in place of the SyncConfig that was already there. It is a bit of a heavy handed solution, but a better way wasn't obvious to me.

☑️ ToDos

  • 📝 Changelog update
  • 🚦 Tests (or not relevant)
  • C-API, if public C++ API changed.

@ironage ironage requested a review from tgoyne July 8, 2022 01:35
@ironage ironage self-assigned this Jul 8, 2022
@cla-bot cla-bot bot added the cla: yes label Jul 8, 2022
@tgoyne
Copy link
Member

tgoyne commented Jul 8, 2022

I have recently been thinking that the RealmConfig/SyncConfig split doesn't make sense any more, and hasn't for a long time.

When we first designed it, there were two very big differences from today. The first was that sync was closed-source (including the SDK part at the time) and minimizing merge conflicts between the public and private branches was important. Splitting the sync stuff off as much as possible helped with that.

The second and probably bigger one was that we were still thinking of ObjectStore as a set of modular components that SDKs would use when they found them useful, and skip if they didn't. This meant that SyncSession should be totally decoupled from Realm so that you could use one without the other (and in practice Java did use SyncSession without Realm for a while). There's a pile of design quirks remaining from this, but SyncConfig and RealmConfig being different types is the most obvious and probably easiest to fix of them. (realm.config().sync_config->user->session_for_on_disk_path(realm.config().path) is another example of a now-silly result of this design which is mostly gone).

I haven't looked at the actual changes here yet, but I guess the point is that I don't hate the idea of passing RealmConfig to SyncSession.

@@ -311,16 +314,17 @@ class SyncSession : public std::enable_shared_from_this<SyncSession> {

friend class realm::SyncManager;
// Called by SyncManager {
static std::shared_ptr<SyncSession> create(_impl::SyncClient& client, std::shared_ptr<DB> db, SyncConfig config,
static std::shared_ptr<SyncSession> create(_impl::SyncClient& client, std::shared_ptr<DB> db, RealmConfig config,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything in the chain SyncSession::get_session() to SyncSession::SyncSession() should probably be passing const RealmConfig&. RealmConfig is sufficiently large and complicated that even moving it is not really trivial.

config.mode = session_config.sync_config->client_resync_mode;
config.notify_after_client_reset = [config = copy_config](std::string local_path, VersionID previous_version,
bool did_recover) {
if (config.sync_config->notify_after_client_reset) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this condition be pulled out of the lambda?

@@ -235,7 +235,7 @@ SyncSession::handle_refresh(const std::shared_ptr<SyncSession>& session)
};
}

SyncSession::SyncSession(SyncClient& client, std::shared_ptr<DB> db, SyncConfig config, SyncManager* sync_manager)
SyncSession::SyncSession(SyncClient& client, std::shared_ptr<DB> db, RealmConfig config, SyncManager* sync_manager)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to set scheduler and audit_config to nullptr on m_config. Trying to use the explicitly set scheduler will break since we're not obtaining the Realm instance while inside that scheduler. Audit stuff might not break but we don't really want to be initializing that while performing a client reset regardless.

@ironage ironage force-pushed the js/notify-resets branch from 6698e46 to 0d2655e Compare July 15, 2022 20:09
@ironage ironage merged commit 90fbde9 into master Jul 15, 2022
@ironage ironage deleted the js/notify-resets branch July 15, 2022 23:38
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 22, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

notify_after_client_reset callback is executed even if an existing RealmCoordinator is not available
2 participants