-
Notifications
You must be signed in to change notification settings - Fork 165
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 handling of users with multiple identities #6837
Conversation
c6e0a8c
to
d5e5cd1
Compare
This unfortunately grew to be pretty large in the process of making tsan happy, but hopefully the commits make enough sense individually that it's not too awful to review. There's no particular hurry here; this is just some incidental bug fixes extracted out of my multiprocess sync work. |
d5e5cd1
to
82cb437
Compare
e0a3e6d
to
d95d48c
Compare
d95d48c
to
ded15f1
Compare
SyncTestFile config(app, partition, schema); | ||
auto r = Realm::get_shared_realm(config); | ||
REQUIRE_FALSE(user->is_logged_in()); | ||
REQUIRE(user->state() == SyncUser::State::LoggedOut); |
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.
should this test wait for the access token response before checking the user state?
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.
oh never mind, we use a synchronous transport
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.
This is a much needed clean up of a neglected area of the code. 👍
Adding some defensive checks (or assertions) in log_out_user
would be bonus, but not blocking.
ROS users were identified by the pair (identity, auth_url), and in the v10 port this was translated to (user_id, provider_type), but that isn't actually how Atlas users work. An App is the equivalent of the old auth_url, and within an App user_id uniquely identifies a user. Users don't actually have a "provider type" at all: users have one or more identities, each of which has a provider type, and the same SyncUser should be used regardless of which identity was used to log in. This had surprisingly mild consequences, but was visibly broken in a few ways. Logging into the same user using two different identities resulted in two SyncUsers with the same user id. Opening the same partition (or any flx Realm) with both users resulted in both using whichever SyncUser happened to open it first, and the second would not create a SyncSession. This meant that most of the potential bad things (such as creating two session for one file) didn't actually happen, but the second user's list of sessions would be "incorrect", and removing one of the users would remove the incorrect set of local files. Linking identities to anonymous users resulted in the user still being treated as anonymous. The primary negative effect of this was that linking an identity, logging out, then logging back in would result in the user being removed entirely in between, forcing the re-download of all Realms (and the loss of any un-uploaded data). This bumps the schema version of the metadata Realm primarily for the sake of recovery on metadata Realms in invalid states: the migration block handles the case of multiple users with the same user id and unifies them. Since this needs a migration anyway, it fixes some incidental problems with the metadata Realm's schema which weren't fixable without a migration: the marked_for_deletion column was redundant with the Removed state, identity objects were leaked due to not being embedded, and the local_uuid field is no longer used for anything other than opening files written by early v10 versions, so there's no need to populate it for new users.
12d2f62
to
dd7e4fa
Compare
…ealm Initializing sync users read from the metadata Realm used the same code path as initializing newly logged in users, resulting in it performing three no-op write transactions per user to write the data which was just read back to the Realm.
It had incorrect semantics (users from different Apps which happened to have the same id would compare equal), and simply isn't neccesary as there should only ever be a single SyncUser instance per user and so pointer equality suffices.
SyncUser previously allowed setting the state to LoggedIn without setting its tokens, and conversely allowed setting tokens while not logged in. This was error-prone and happened to result in a lock-order inversion due to that both the state and the tokens had to be checked in places where we only wanted to care about one of them.
dd7e4fa
to
64bf842
Compare
ROS users were identified by the pair (identity, auth_url), and in the v10 port this was translated to (user_id, provider_type), but that isn't actually how Atlas users work. An App is the equivalent of the old auth_url, and within an App user_id uniquely identifies a user. Users don't actually have a "provider type" at all: users have one or more identities, each of which has a provider type, and the same SyncUser should be used regardless of which identity was used to log in.
This had surprisingly mild consequences, but was visibly broken in a few ways. Logging into the same user using two different identities resulted in two SyncUsers with the same user id. Opening the same partition (or any flx Realm) with both users resulted in both using whichever SyncUser happened to open it first, and the second would not create a SyncSession. This meant that most of the potential bad things (such as creating two session for one file) didn't actually happen, but the second user's list of sessions would be "incorrect", and removing one of the users would remove the incorrect set of local files.
Linking identities to anonymous users resulted in the user still being treated as anonymous. The primary negative effect of this was that linking an identity, logging out, then logging back in would result in the user being removed entirely in between, forcing the re-download of all Realms (and the loss of any un-uploaded data).
This bumps the schema version of the metadata Realm primarily for the sake of recovery on metadata Realms in invalid states: the migration block handles the case of multiple users with the same user id and unifies them. Since this needs a migration anyway, it fixes some incidental problems with the metadata Realm's schema which weren't fixable without a migration: the marked_for_deletion column was redundant with the Removed state, identity objects were leaked due to not being embedded, and the local_uuid field is no longer used for anything other than opening files written by early v10 versions, so there's no need to populate it for new users.
Initializing a sync manager opened the metadata Realm, read the persisted users, and then wrote the persisted users back to the Realm using three separate write transactions per user. It now just reads the data and doesn't write anything.
SyncUser's internal API permitted doing some invalid state transitions such as marking a user as logged in despite it not having any tokens. The two specific things which definitely could break was logging out a user while the profile was being updated and logging out a user while the access token was being refreshed, but there may have been more things. There also just was some dead code trying to support state transitions which could never happen.