| Index: sync/internal_api/sync_manager.cc
|
| diff --git a/sync/internal_api/sync_manager.cc b/sync/internal_api/sync_manager.cc
|
| index c8a293ea85f3ffc7e861d42891072d6535ca265d..e8ba9dd45dcadeb6335191a7f8cb8a61723361e8 100644
|
| --- a/sync/internal_api/sync_manager.cc
|
| +++ b/sync/internal_api/sync_manager.cc
|
| @@ -197,6 +197,11 @@ class SyncManager::SyncInternal
|
| // went wrong.
|
| bool SignIn(const SyncCredentials& credentials);
|
|
|
| + // Purge from the directory those types with non-empty progress markers
|
| + // but without initial synced ended set.
|
| + // Returns false if an error occurred, true otherwise.
|
| + bool PurgePartiallySyncedTypes();
|
| +
|
| // Update tokens that we're using in Sync. Email must stay the same.
|
| void UpdateCredentials(const SyncCredentials& credentials);
|
|
|
| @@ -357,6 +362,21 @@ class SyncManager::SyncInternal
|
| // Called only by our NetworkChangeNotifier.
|
| virtual void OnIPAddressChanged() OVERRIDE;
|
|
|
| + ModelTypeSet GetTypesWithEmptyProgressMarkerToken(ModelTypeSet types) {
|
| + DCHECK(initialized_);
|
| + syncer::ModelTypeSet result;
|
| + for (syncer::ModelTypeSet::Iterator i = types.First();
|
| + i.Good(); i.Inc()) {
|
| + sync_pb::DataTypeProgressMarker marker;
|
| + directory()->GetDownloadProgress(i.Get(), &marker);
|
| +
|
| + if (marker.token().empty())
|
| + result.Put(i.Get());
|
| +
|
| + }
|
| + return result;
|
| + }
|
| +
|
| syncer::ModelTypeSet InitialSyncEndedTypes() {
|
| DCHECK(initialized_);
|
| return directory()->initial_sync_ended_types();
|
| @@ -376,6 +396,8 @@ class SyncManager::SyncInternal
|
| const std::string& name, const JsArgList& args,
|
| const WeakHandle<JsReplyHandler>& reply_handler) OVERRIDE;
|
|
|
| + void SetSyncSchedulerForTest(scoped_ptr<SyncScheduler> scheduler);
|
| +
|
| private:
|
| struct NotificationInfo {
|
| int total_count;
|
| @@ -749,6 +771,15 @@ syncer::ModelTypeSet SyncManager::InitialSyncEndedTypes() {
|
| return data_->InitialSyncEndedTypes();
|
| }
|
|
|
| +syncer::ModelTypeSet SyncManager::GetTypesWithEmptyProgressMarkerToken(
|
| + syncer::ModelTypeSet types) {
|
| + return data_->GetTypesWithEmptyProgressMarkerToken(types);
|
| +}
|
| +
|
| +bool SyncManager::PurgePartiallySyncedTypes() {
|
| + return data_->PurgePartiallySyncedTypes();
|
| +}
|
| +
|
| void SyncManager::StartSyncingNormally(
|
| const syncer::ModelSafeRoutingInfo& routing_info) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| @@ -793,40 +824,39 @@ bool SyncManager::IsUsingExplicitPassphrase() {
|
| return data_ && data_->IsUsingExplicitPassphrase();
|
| }
|
|
|
| -void SyncManager::RequestCleanupDisabledTypes(
|
| - const syncer::ModelSafeRoutingInfo& routing_info) {
|
| +void SyncManager::ConfigureSyncer(
|
| + ConfigureReason reason,
|
| + const syncer::ModelTypeSet& types_to_config,
|
| + const syncer::ModelSafeRoutingInfo& new_routing_info,
|
| + const base::Closure& ready_task,
|
| + const base::Closure& retry_task) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (data_->scheduler()) {
|
| - data_->session_context()->set_routing_info(routing_info);
|
| - data_->scheduler()->CleanupDisabledTypes();
|
| - }
|
| -}
|
| + DCHECK(!ready_task.is_null());
|
| + DCHECK(!retry_task.is_null());
|
|
|
| -void SyncManager::RequestConfig(
|
| - const syncer::ModelSafeRoutingInfo& routing_info,
|
| - const ModelTypeSet& types, ConfigureReason reason) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (!data_->scheduler()) {
|
| - LOG(INFO)
|
| - << "SyncManager::RequestConfig: bailing out because scheduler is "
|
| - << "null";
|
| - return;
|
| - }
|
| - StartConfigurationMode(base::Closure());
|
| - data_->session_context()->set_routing_info(routing_info);
|
| - data_->scheduler()->ScheduleConfiguration(types, GetSourceFromReason(reason));
|
| -}
|
| + // TODO(zea): set this based on whether cryptographer has keystore
|
| + // encryption key or not (requires opening a transaction). crbug.com/129665.
|
| + ConfigurationParams::KeystoreKeyStatus keystore_key_status =
|
| + ConfigurationParams::KEYSTORE_KEY_UNNECESSARY;
|
| +
|
| + ConfigurationParams params(GetSourceFromReason(reason),
|
| + types_to_config,
|
| + new_routing_info,
|
| + keystore_key_status,
|
| + ready_task);
|
|
|
| -void SyncManager::StartConfigurationMode(const base::Closure& callback) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| if (!data_->scheduler()) {
|
| LOG(INFO)
|
| - << "SyncManager::StartConfigurationMode: could not start "
|
| - << "configuration mode because because scheduler is null";
|
| + << "SyncManager::ConfigureSyncer: could not configure because "
|
| + << "scheduler is null";
|
| + params.ready_task.Run();
|
| return;
|
| }
|
| - data_->scheduler()->Start(
|
| - syncer::SyncScheduler::CONFIGURATION_MODE, callback);
|
| +
|
| + data_->scheduler()->Start(syncer::SyncScheduler::CONFIGURATION_MODE);
|
| + if (!data_->scheduler()->ScheduleConfiguration(params))
|
| + retry_task.Run();
|
| +
|
| }
|
|
|
| bool SyncManager::SyncInternal::Init(
|
| @@ -923,16 +953,29 @@ bool SyncManager::SyncInternal::Init(
|
| scheduler_.reset(new SyncScheduler(name_, session_context(), new Syncer()));
|
| }
|
|
|
| - bool signed_in = SignIn(credentials);
|
| + bool success = SignIn(credentials);
|
|
|
| - if (signed_in) {
|
| + if (success) {
|
| if (scheduler()) {
|
| - scheduler()->Start(
|
| - syncer::SyncScheduler::CONFIGURATION_MODE, base::Closure());
|
| + scheduler()->Start(syncer::SyncScheduler::CONFIGURATION_MODE);
|
| }
|
|
|
| initialized_ = true;
|
|
|
| + // Unapplied datatypes (those that do not have initial sync ended set) get
|
| + // re-downloaded during any configuration. But, it's possible for a datatype
|
| + // to have a progress marker but not have initial sync ended yet, making
|
| + // it a candidate for migration. This is a problem, as the DataTypeManager
|
| + // does not support a migration while it's already in the middle of a
|
| + // configuration. As a result, any partially synced datatype can stall the
|
| + // DTM, waiting for the configuration to complete, which it never will due
|
| + // to the migration error. In addition, a partially synced nigori will
|
| + // trigger the migration logic before the backend is initialized, resulting
|
| + // in crashes. We therefore detect and purge any partially synced types as
|
| + // part of initialization.
|
| + if (!PurgePartiallySyncedTypes())
|
| + success = false;
|
| +
|
| // Cryptographer should only be accessed while holding a
|
| // transaction. Grabbing the user share for the transaction
|
| // checks the initialization state, so this must come after
|
| @@ -950,14 +993,14 @@ bool SyncManager::SyncInternal::Init(
|
| FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
|
| OnInitializationComplete(
|
| MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()),
|
| - signed_in));
|
| + success));
|
|
|
| - if (!signed_in && testing_mode_ == NON_TEST)
|
| + if (!success && testing_mode_ == NON_TEST)
|
| return false;
|
|
|
| sync_notifier_->AddObserver(this);
|
|
|
| - return signed_in;
|
| + return success;
|
| }
|
|
|
| void SyncManager::SyncInternal::UpdateCryptographerAndNigori(
|
| @@ -1102,9 +1145,13 @@ void SyncManager::SyncInternal::NotifyCryptographerState(
|
| void SyncManager::SyncInternal::StartSyncingNormally(
|
| const syncer::ModelSafeRoutingInfo& routing_info) {
|
| // Start the sync scheduler.
|
| - if (scheduler()) { // NULL during certain unittests.
|
| + if (scheduler()) { // NULL during certain unittests.
|
| + // TODO(sync): We always want the newest set of routes when we switch back
|
| + // to normal mode. Figure out how to enforce set_routing_info is always
|
| + // appropriately set and that it's only modified when switching to normal
|
| + // mode.
|
| session_context()->set_routing_info(routing_info);
|
| - scheduler()->Start(SyncScheduler::NORMAL_MODE, base::Closure());
|
| + scheduler()->Start(SyncScheduler::NORMAL_MODE);
|
| }
|
| }
|
|
|
| @@ -1158,6 +1205,20 @@ bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
|
| return true;
|
| }
|
|
|
| +bool SyncManager::SyncInternal::PurgePartiallySyncedTypes() {
|
| + syncer::ModelTypeSet partially_synced_types =
|
| + syncer::ModelTypeSet::All();
|
| + partially_synced_types.RemoveAll(InitialSyncEndedTypes());
|
| + partially_synced_types.RemoveAll(GetTypesWithEmptyProgressMarkerToken(
|
| + syncer::ModelTypeSet::All()));
|
| +
|
| + UMA_HISTOGRAM_COUNTS("Sync.PartiallySyncedTypes",
|
| + partially_synced_types.Size());
|
| + if (partially_synced_types.Empty())
|
| + return true;
|
| + return directory()->PurgeEntriesWithTypeIn(partially_synced_types);
|
| +}
|
| +
|
| void SyncManager::SyncInternal::UpdateCredentials(
|
| const SyncCredentials& credentials) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| @@ -2340,6 +2401,11 @@ void SyncManager::SyncInternal::RemoveObserver(
|
| observers_.RemoveObserver(observer);
|
| }
|
|
|
| +void SyncManager::SyncInternal::SetSyncSchedulerForTest(
|
| + scoped_ptr<SyncScheduler> sync_scheduler) {
|
| + scheduler_ = sync_scheduler.Pass();
|
| +}
|
| +
|
| SyncStatus SyncManager::GetDetailedStatus() const {
|
| return data_->GetStatus();
|
| }
|
| @@ -2370,6 +2436,10 @@ TimeDelta SyncManager::GetNudgeDelayTimeDelta(
|
| return data_->GetNudgeDelayTimeDelta(model_type);
|
| }
|
|
|
| +void SyncManager::SetSyncSchedulerForTest(scoped_ptr<SyncScheduler> scheduler) {
|
| + data_->SetSyncSchedulerForTest(scheduler.Pass());
|
| +}
|
| +
|
| syncer::ModelTypeSet SyncManager::GetEncryptedDataTypesForTest() const {
|
| ReadTransaction trans(FROM_HERE, GetUserShare());
|
| return GetEncryptedTypes(&trans);
|
| @@ -2459,20 +2529,4 @@ bool InitialSyncEndedForTypes(syncer::ModelTypeSet types,
|
| return true;
|
| }
|
|
|
| -syncer::ModelTypeSet GetTypesWithEmptyProgressMarkerToken(
|
| - syncer::ModelTypeSet types,
|
| - syncer::UserShare* share) {
|
| - syncer::ModelTypeSet result;
|
| - for (syncer::ModelTypeSet::Iterator i = types.First();
|
| - i.Good(); i.Inc()) {
|
| - sync_pb::DataTypeProgressMarker marker;
|
| - share->directory->GetDownloadProgress(i.Get(), &marker);
|
| -
|
| - if (marker.token().empty())
|
| - result.Put(i.Get());
|
| -
|
| - }
|
| - return result;
|
| -}
|
| -
|
| } // namespace syncer
|
|
|