@@ -821,10 +821,10 @@ void SyncSession::cancel_pending_waits(util::CheckedUniqueLock lock, Status erro
821821
822822void SyncSession::handle_progress_update (uint64_t downloaded, uint64_t downloadable, uint64_t uploaded,
823823 uint64_t uploadable, uint64_t snapshot_version, double download_estimate,
824- double upload_estimate)
824+ double upload_estimate, int64_t query_version )
825825{
826826 m_progress_notifier.update (downloaded, downloadable, uploaded, uploadable, snapshot_version, download_estimate,
827- upload_estimate);
827+ upload_estimate, query_version );
828828}
829829
830830static sync::Session::Config::ClientReset make_client_reset_config (const RealmConfig& base_config,
@@ -962,10 +962,10 @@ void SyncSession::create_sync_session()
962962 m_session->set_progress_handler ([weak_self](uint_fast64_t downloaded, uint_fast64_t downloadable,
963963 uint_fast64_t uploaded, uint_fast64_t uploadable,
964964 uint_fast64_t snapshot_version, double download_estimate,
965- double upload_estimate) {
965+ double upload_estimate, int64_t query_version ) {
966966 if (auto self = weak_self.lock ()) {
967967 self->handle_progress_update (downloaded, downloadable, uploaded, uploadable, snapshot_version,
968- download_estimate, upload_estimate);
968+ download_estimate, upload_estimate, query_version );
969969 }
970970 });
971971
@@ -1267,7 +1267,11 @@ void SyncSession::wait_for_download_completion(util::UniqueFunction<void(Status)
12671267uint64_t SyncSession::register_progress_notifier (std::function<ProgressNotifierCallback>&& notifier,
12681268 ProgressDirection direction, bool is_streaming)
12691269{
1270- return m_progress_notifier.register_callback (std::move (notifier), direction, is_streaming);
1270+ int64_t pending_query_version = 0 ;
1271+ if (auto sub_store = get_flx_subscription_store ()) {
1272+ pending_query_version = sub_store->get_version_info ().latest ;
1273+ }
1274+ return m_progress_notifier.register_callback (std::move (notifier), direction, is_streaming, pending_query_version);
12711275}
12721276
12731277void SyncSession::unregister_progress_notifier (uint64_t token)
@@ -1519,22 +1523,23 @@ void SyncSession::did_drop_external_reference()
15191523}
15201524
15211525uint64_t SyncProgressNotifier::register_callback (std::function<ProgressNotifierCallback> notifier,
1522- NotifierType direction, bool is_streaming)
1526+ NotifierType direction, bool is_streaming,
1527+ int64_t pending_query_version)
15231528{
15241529 util::UniqueFunction<void ()> invocation;
15251530 uint64_t token_value = 0 ;
15261531 {
15271532 std::lock_guard<std::mutex> lock (m_mutex);
15281533 token_value = m_progress_notifier_token++;
15291534 NotifierPackage package{std::move (notifier), m_local_transaction_version, is_streaming,
1530- direction == NotifierType::download};
1535+ direction == NotifierType::download, pending_query_version };
15311536 if (!m_current_progress) {
15321537 // Simply register the package, since we have no data yet.
15331538 m_packages.emplace (token_value, std::move (package));
15341539 return token_value;
15351540 }
15361541 bool skip_registration = false ;
1537- invocation = package.create_invocation (*m_current_progress, skip_registration, true );
1542+ invocation = package.create_invocation (*m_current_progress, skip_registration);
15381543 if (skip_registration) {
15391544 token_value = 0 ;
15401545 }
@@ -1553,13 +1558,14 @@ void SyncProgressNotifier::unregister_callback(uint64_t token)
15531558}
15541559
15551560void SyncProgressNotifier::update (uint64_t downloaded, uint64_t downloadable, uint64_t uploaded, uint64_t uploadable,
1556- uint64_t snapshot_version, double download_estimate, double upload_estimate)
1561+ uint64_t snapshot_version, double download_estimate, double upload_estimate,
1562+ int64_t query_version)
15571563{
15581564 std::vector<util::UniqueFunction<void ()>> invocations;
15591565 {
15601566 std::lock_guard<std::mutex> lock (m_mutex);
1561- m_current_progress = Progress{uploadable, downloadable, uploaded, downloaded,
1562- upload_estimate, download_estimate, snapshot_version};
1567+ m_current_progress = Progress{uploadable, downloadable, uploaded, downloaded,
1568+ upload_estimate, download_estimate, snapshot_version, query_version };
15631569
15641570 for (auto it = m_packages.begin (); it != m_packages.end ();) {
15651571 bool should_delete = false ;
@@ -1579,49 +1585,50 @@ void SyncProgressNotifier::set_local_version(uint64_t snapshot_version)
15791585}
15801586
15811587util::UniqueFunction<void ()>
1582- SyncProgressNotifier::NotifierPackage::create_invocation (Progress const & current_progress, bool & is_expired,
1583- bool initial_registration)
1588+ SyncProgressNotifier::NotifierPackage::create_invocation (Progress const & current_progress, bool & is_expired)
15841589{
1585- uint64_t transferred = is_download ? current_progress.downloaded : current_progress.uploaded ;
1590+ uint64_t transfered = is_download ? current_progress.downloaded : current_progress.uploaded ;
15861591 uint64_t transferable = is_download ? current_progress.downloadable : current_progress.uploadable ;
1587- double progress_estimate = is_download ? current_progress.download_estimate : current_progress.upload_estimate ;
1588-
1589- // If the sync client has not yet processed all of the local
1590- // transactions then the uploadable data is incorrect and we should
1591- // not invoke the callback
1592- if (!is_download && snapshot_version > current_progress.snapshot_version )
1593- return [] {};
1594-
1595- // for download only invoke the callback on registration if is in active data transfer,
1596- // otherwise delay notifying until an update with the new transfer signaled
1597- if (is_download && !started_notifying && progress_estimate >= 1 ) {
1598- if (initial_registration) {
1599- initial_transferred = transferred;
1600- return [] {};
1601- }
1602- else if (initial_transferred == transferred)
1592+ double estimate = is_download ? current_progress.download_estimate : current_progress.upload_estimate ;
1593+
1594+ if (!is_streaming) {
1595+ // If the sync client has not yet processed all of the local
1596+ // transactions then the uploadable data is incorrect and we should
1597+ // not invoke the callback
1598+ if (!is_download && snapshot_version > current_progress.snapshot_version )
16031599 return [] {};
1604- }
16051600
1606- started_notifying = true ;
1601+ // If this is a non-streaming download progress update and this notifier was
1602+ // created for a later query version (e.g. we're currently downloading
1603+ // subscription set version zero, but subscription set version 1 existed
1604+ // when the notifier was registered), then we want to skip this callback.
1605+ if (is_download && current_progress.query_version < pending_query_version) {
1606+ return [] {};
1607+ }
16071608
1608- // only capture and adjust transferable bytes for upload non-streaming to provide
1609- // the progress of upload for the callback registered right after the commit
1610- if (!is_streaming && !is_download) {
1609+ // The initial download size we get from the server is the uncompacted
1610+ // size, and so the download may complete before we actually receive
1611+ // that much data. When that happens, transferrable will drop and we
1612+ // need to use the new value instead of the captured one.
16111613 if (!captured_transferable || *captured_transferable > transferable)
16121614 captured_transferable = transferable;
16131615 transferable = *captured_transferable;
1614- }
16151616
1616- // A notifier is expired for upload if at least as many bytes have been transferred
1617- // as were originally considered transferable based on local committed version
1618- // on callback registration, or when simply 1.0 progress is reached for download
1619- // since the amount of bytes is not precisely known until the end
1620- if (!is_streaming)
1621- is_expired = is_download ? progress_estimate >= 1 : transferred >= transferable;
1617+ // Since we can adjust the transferrable downwards the estimate for uploads
1618+ // won't be correct since the sync client's view of the estimate is based on
1619+ // the total number of uploadable bytes available rather than the number of
1620+ // bytes this NotifierPackage was waiting to upload.
1621+ if (!is_download) {
1622+ estimate = transferable > 0 ? std::min (transfered / double (transferable), 1.0 ) : 0.0 ;
1623+ }
1624+ }
16221625
1626+ // A notifier is expired if at least as many bytes have been transferred
1627+ // as were originally considered transferrable.
1628+ is_expired =
1629+ !is_streaming && (transfered >= transferable && (!is_download || !pending_query_version || estimate >= 1.0 ));
16231630 return [=, notifier = notifier] {
1624- notifier (transferred , transferable, progress_estimate );
1631+ notifier (transfered , transferable, estimate );
16251632 };
16261633}
16271634
0 commit comments