Skip to content
This repository has been archived by the owner on Nov 8, 2021. It is now read-only.

Implement precise, unbatched notification of sync completion events #1054

Closed
wants to merge 1 commit into from

Conversation

RedBeard0531
Copy link
Contributor

@RedBeard0531 RedBeard0531 commented Jul 9, 2020

This avoids a race condition where an earlier upload completion event will
notify a later waiter whose changes haven't been uploaded yet.

Closes #1056.

This avoids a race condition where an earlier upload completion event will
notify a later waiter whose changes haven't been uploaded yet.
@RedBeard0531 RedBeard0531 requested a review from tgoyne July 9, 2020 16:57
auto waiter = is_download ? &sync::Session::async_wait_for_download_completion
: &sync::Session::async_wait_for_upload_completion;
(m_session.get()->*waiter)([resync_counter, weak_self, is_download](std::error_code ec) {
(m_session.get()->*waiter)([is_download,
resync_counter = m_client_resync_counter,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the resync_counter logic is now redundant since if there was a resync, it won't find the entry for this id in the map. If you agree, I will remove that logic.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, this looks like a more general solution to the problem the resync counter was addressing.

m_upload_completion_callbacks.push_back(std::move(callback));
m_completion_request_counter++; // read in wait_for_completion()
m_state->wait_for_completion(*this, _impl::SyncProgressNotifier::NotifierType::upload);
m_upload_completion_callbacks.emplace_hint(m_upload_completion_callbacks.end(),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you think it is worth moving this into add_completion_callback? I can't really see any reason for the current distribution of work between the functions, but I didn't want to make too much unnecessary change in a bugfix commit.

Copy link
Member

Choose a reason for hiding this comment

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

Do we still need separate upload/download completion callback maps with this change? If not then merging them and pushing this into add_completion_callback() makes sense, but without merging them it'd be another awkward conditional there?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, I don't think so. Merging them cleans up the code nicely.

Copy link
Member

@tgoyne tgoyne left a comment

Choose a reason for hiding this comment

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

This doesn't handle completion handlers added while the state is Inactive correctly. In sync_session_states::Active::enter_state() it calls add_completion_callback() once per direction if there's any pending completion handlers, which no longer does the required thing.

I'm not sure if any of that code still actually makes sense. Pre-v10 it was primarily there to support adding completion handlers while waiting for the refresh token, and it might just be dead code now or only required for very strange things (adding a completion handler after calling logout and then expecting it to be called after logging in?).

auto waiter = is_download ? &sync::Session::async_wait_for_download_completion
: &sync::Session::async_wait_for_upload_completion;
(m_session.get()->*waiter)([resync_counter, weak_self, is_download](std::error_code ec) {
(m_session.get()->*waiter)([is_download,
resync_counter = m_client_resync_counter,
Copy link
Member

Choose a reason for hiding this comment

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

Yes, this looks like a more general solution to the problem the resync counter was addressing.

m_upload_completion_callbacks.push_back(std::move(callback));
m_completion_request_counter++; // read in wait_for_completion()
m_state->wait_for_completion(*this, _impl::SyncProgressNotifier::NotifierType::upload);
m_upload_completion_callbacks.emplace_hint(m_upload_completion_callbacks.end(),
Copy link
Member

Choose a reason for hiding this comment

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

Do we still need separate upload/download completion callback maps with this change? If not then merging them and pushing this into add_completion_callback() makes sense, but without merging them it'd be another awkward conditional there?

@jbreams
Copy link
Contributor

jbreams commented Oct 8, 2020

@tgoyne, do you know what the status of this is? This PR doesn't currently compile - at least not on my machine. I looked at making the fixes/improvements in the comments between you and Mathias, but they cause a bunch of test failures. Before I dig into this anymore, do you know if this is still something we want to do?

@tgoyne
Copy link
Member

tgoyne commented Oct 8, 2020

It is a bug that needs to be fixed still, and this is most of the way to a correct fix. I think the only thing left to do is to figure out if we still need to support adding completion handlers while the session is inactive, and then either removing that code (if we don't) or finding a way to make that work correctly.

@jbreams
Copy link
Contributor

jbreams commented Oct 9, 2020

Closing this in favor of #1118.

@jbreams jbreams closed this Oct 9, 2020
@jbreams jbreams deleted the ms/sync_notification_race branch October 9, 2020 19:50
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants