-
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
Make explicitly pausing the sync session a separate state #6183
Changes from 6 commits
4c6134d
f1197b8
92cd654
9331c90
1375581
697176d
ddeafce
cb649d0
4c3d409
5c22d9f
208c301
0b9684d
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 |
---|---|---|
|
@@ -132,6 +132,19 @@ void SyncSession::become_inactive(util::CheckedUniqueLock lock, std::error_code | |
REALM_ASSERT(m_state != State::Inactive); | ||
m_state = State::Inactive; | ||
|
||
do_become_inactive(std::move(lock), ec); | ||
} | ||
|
||
void SyncSession::become_paused(util::CheckedUniqueLock lock) | ||
{ | ||
REALM_ASSERT(m_state != State::Paused); | ||
m_state = State::Paused; | ||
|
||
do_become_inactive(std::move(lock), {}); | ||
} | ||
|
||
void SyncSession::do_become_inactive(util::CheckedUniqueLock lock, std::error_code ec) | ||
{ | ||
// Manually set the disconnected state. Sync would also do this, but | ||
// since the underlying SyncSession object already have been destroyed, | ||
// we are not able to get the callback. | ||
|
@@ -653,7 +666,7 @@ void SyncSession::handle_error(SyncError error) | |
|
||
// Dont't bother invoking m_config.error_handler if the sync is inactive. | ||
// It does not make sense to call the handler when the session is closed. | ||
if (m_state == State::Inactive) { | ||
if (m_state == State::Inactive || m_state == State::Paused) { | ||
return; | ||
} | ||
|
||
|
@@ -882,6 +895,7 @@ void SyncSession::nonsync_transact_notify(sync::version_type version) | |
break; | ||
case State::Dying: | ||
case State::Inactive: | ||
case State::Paused: | ||
break; | ||
} | ||
} | ||
|
@@ -892,25 +906,12 @@ void SyncSession::revive_if_needed() | |
switch (m_state) { | ||
case State::Active: | ||
case State::WaitingForAccessToken: | ||
case State::Paused: | ||
return; | ||
case State::Dying: | ||
case State::Inactive: { | ||
// Revive. | ||
auto u = user(); | ||
if (!u || !u->access_token_refresh_required()) { | ||
become_active(); | ||
return; | ||
} | ||
|
||
become_waiting_for_access_token(); | ||
// Release the lock for SDKs with a single threaded | ||
// networking implementation such as our test suite | ||
// so that the update can trigger a state change from | ||
// the completion handler. | ||
lock.unlock(); | ||
initiate_access_token_refresh(); | ||
case State::Inactive: | ||
do_revive(std::move(lock)); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
|
@@ -924,11 +925,12 @@ void SyncSession::handle_reconnect() | |
case State::Dying: | ||
case State::Inactive: | ||
case State::WaitingForAccessToken: | ||
case State::Paused: | ||
break; | ||
} | ||
} | ||
|
||
void SyncSession::log_out() | ||
void SyncSession::force_close() | ||
{ | ||
util::CheckedUniqueLock lock(m_state_mutex); | ||
switch (m_state) { | ||
|
@@ -938,10 +940,59 @@ void SyncSession::log_out() | |
become_inactive(std::move(lock)); | ||
break; | ||
case State::Inactive: | ||
case State::Paused: | ||
break; | ||
} | ||
} | ||
|
||
void SyncSession::pause() | ||
{ | ||
util::CheckedUniqueLock lock(m_state_mutex); | ||
switch (m_state) { | ||
case State::Active: | ||
case State::Dying: | ||
case State::WaitingForAccessToken: | ||
become_paused(std::move(lock)); | ||
break; | ||
case State::Inactive: | ||
case State::Paused: | ||
break; | ||
} | ||
} | ||
|
||
void SyncSession::resume() | ||
{ | ||
util::CheckedUniqueLock lock(m_state_mutex); | ||
switch (m_state) { | ||
case State::Active: | ||
case State::WaitingForAccessToken: | ||
return; | ||
case State::Paused: | ||
case State::Dying: | ||
case State::Inactive: | ||
do_revive(std::move(lock)); | ||
break; | ||
} | ||
} | ||
|
||
void SyncSession::do_revive(util::CheckedUniqueLock&& lock) | ||
{ | ||
auto u = user(); | ||
if (!u || !u->access_token_refresh_required()) { | ||
become_active(); | ||
m_state_mutex.unlock(lock); | ||
return; | ||
} | ||
|
||
become_waiting_for_access_token(); | ||
// Release the lock for SDKs with a single threaded | ||
// networking implementation such as our test suite | ||
// so that the update can trigger a state change from | ||
// the completion handler. | ||
m_state_mutex.unlock(lock); | ||
initiate_access_token_refresh(); | ||
} | ||
|
||
void SyncSession::close() | ||
{ | ||
util::CheckedUniqueLock lock(m_state_mutex); | ||
|
@@ -970,6 +1021,9 @@ void SyncSession::close(util::CheckedUniqueLock lock) | |
case State::Dying: | ||
m_state_mutex.unlock(lock); | ||
break; | ||
case State::Paused: | ||
m_state_mutex.unlock(lock); | ||
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. Would you mind adding a comment here that mentions paused is supposed to be sticky and that state should not be changed to inactive. |
||
break; | ||
case State::Inactive: { | ||
if (m_sync_manager) { | ||
m_sync_manager->unregister_session(m_db->get_path()); | ||
|
@@ -994,7 +1048,7 @@ void SyncSession::shutdown_and_wait() | |
// Realm file to be closed. This works so long as this SyncSession object remains in the | ||
// `inactive` state after the invocation of shutdown_and_wait(). | ||
util::CheckedUniqueLock lock(m_state_mutex); | ||
if (m_state != State::Inactive) { | ||
if (m_state != State::Inactive && m_state != State::Paused) { | ||
become_inactive(std::move(lock)); | ||
} | ||
} | ||
|
@@ -1111,18 +1165,20 @@ void SyncSession::update_configuration(SyncConfig new_config) | |
{ | ||
while (true) { | ||
util::CheckedUniqueLock state_lock(m_state_mutex); | ||
if (m_state != State::Inactive) { | ||
if (m_state != State::Inactive && m_state != State::Paused) { | ||
// Changing the state releases the lock, which means that by the | ||
// time we reacquire the lock the state may have changed again | ||
// (either due to one of the callbacks being invoked or another | ||
// thread coincidentally doing something). We just attempt to keep | ||
// switching it to inactive until it stays there. | ||
become_inactive(std::move(state_lock)); | ||
if (m_state != State::Paused) { | ||
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. This check can never be false. 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. 💯 |
||
become_inactive(std::move(state_lock)); | ||
} | ||
continue; | ||
} | ||
|
||
util::CheckedUniqueLock config_lock(m_config_mutex); | ||
REALM_ASSERT(m_state == State::Inactive); | ||
REALM_ASSERT(m_state == State::Inactive || m_state == State::Paused); | ||
REALM_ASSERT(!m_session); | ||
REALM_ASSERT(m_config.sync_config->user == new_config.user); | ||
m_config.sync_config = std::make_shared<SyncConfig>(std::move(new_config)); | ||
|
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.
Is it correct to stay in Inactive here? This'd mean that pause() -> revive_if_needed() does sometimes result in an active session.
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, it's not correct. become_paused() needs to check if the old state was inactive and early return in this case.