Chromium Code Reviews| Index: chrome/browser/sync/glue/sync_backend_host.cc |
| diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc |
| index d86bdaed7ca1d96b01b496c1643640f4461e1fed..722b394f7a41a1b2a86a05f1b3dbbf0d81ae768f 100644 |
| --- a/chrome/browser/sync/glue/sync_backend_host.cc |
| +++ b/chrome/browser/sync/glue/sync_backend_host.cc |
| @@ -91,7 +91,8 @@ class SyncBackendHost::Core |
| const syncer::sessions::SyncSessionSnapshot& snapshot) OVERRIDE; |
| virtual void OnInitializationComplete( |
| const syncer::WeakHandle<syncer::JsBackend>& js_backend, |
| - bool success) OVERRIDE; |
| + bool success, |
| + syncer::ModelTypeSet restored_types) OVERRIDE; |
| virtual void OnConnectionStatusChange( |
| syncer::ConnectionStatus status) OVERRIDE; |
| virtual void OnPassphraseRequired( |
| @@ -367,7 +368,6 @@ void SyncBackendHost::Initialize( |
| SyncFrontend* frontend, |
| const syncer::WeakHandle<syncer::JsEventHandler>& event_handler, |
| const GURL& sync_service_url, |
| - syncer::ModelTypeSet initial_types, |
| const SyncCredentials& credentials, |
| bool delete_sync_data_folder, |
| syncer::SyncManagerFactory* sync_manager_factory, |
| @@ -384,14 +384,7 @@ void SyncBackendHost::Initialize( |
| frontend_ = frontend; |
| DCHECK(frontend); |
| - syncer::ModelTypeSet initial_types_with_nigori(initial_types); |
| - CHECK(sync_prefs_.get()); |
| - if (sync_prefs_->HasSyncSetupCompleted()) { |
| - initial_types_with_nigori.Put(syncer::NIGORI); |
| - } |
| - |
| - registrar_.reset(new SyncBackendRegistrar(initial_types_with_nigori, |
| - name_, |
| + registrar_.reset(new SyncBackendRegistrar(name_, |
| profile_, |
| sync_thread_.message_loop())); |
| syncer::ModelSafeRoutingInfo routing_info; |
| @@ -599,6 +592,14 @@ void SyncBackendHost::ConfigureDataTypes( |
| NigoriState nigori_state, |
| const base::Callback<void(syncer::ModelTypeSet)>& ready_task, |
| const base::Callback<void()>& retry_callback) { |
| + // Only one configure is allowed at a time. This is guaranteed by our |
| + // callers. The SyncBackendHost requests one configure as the backend is |
| + // initializing and waits for it to complete. After initialization, all |
| + // configurations will pass through the DataTypeManager, which is careful to |
| + // never send a new configure request until the current request succeeds. |
| + |
| + DCHECK_GT(initialization_state_, NOT_INITIALIZED); |
| + |
| syncer::ModelTypeSet types_to_add_with_nigori = types_to_add; |
| syncer::ModelTypeSet types_to_remove_with_nigori = types_to_remove; |
| if (nigori_state == WITH_NIGORI) { |
| @@ -608,53 +609,50 @@ void SyncBackendHost::ConfigureDataTypes( |
| types_to_add_with_nigori.Remove(syncer::NIGORI); |
| types_to_remove_with_nigori.Put(syncer::NIGORI); |
| } |
| - // Only one configure is allowed at a time (DataTypeManager handles user |
| - // changes that happen while the syncer is reconfiguring, and will only |
| - // trigger another call to ConfigureDataTypes once the current reconfiguration |
| - // completes). |
| - DCHECK_GT(initialization_state_, NOT_INITIALIZED); |
| - // The new set of enabled types is types_to_add_with_nigori + the |
| - // previously enabled types (on restart, the preferred types are already |
| - // enabled) - types_to_remove_with_nigori. After reconfiguring the registrar, |
| - // the new routing info will reflect the set of enabled types. |
| + // The SyncBackendRegistrar's routing info will be updated by adding the |
| + // types_to_add_with_nigori to the list then removing |
| + // types_to_remove_with_nigori. Any types which are not in either of those |
| + // sets will remain untouched. |
| + // |
| + // Types which were not in the list previously are not cached locally, so we |
| + // must ask the syncer to download them. Any newly supported datatypes will |
| + // not have been in that routing info list, so they will be among the types |
| + // downloaded if they are enabled. |
| + // |
| + // The SyncBackendRegistrar's state was initially derrived from the types |
| + // marked initial_sync_ended when the sync database was loaded. Afterwards it |
| + // is modified only by this function. We expect it to remain in sync with the |
| + // backend because configuration requests are never aborted; they are retried |
| + // until they succeed or the browser is closed. |
| + |
| + syncer::ModelTypeSet types_to_download = registrar_->ConfigureDataTypes( |
| + types_to_add_with_nigori, types_to_remove_with_nigori); |
| + if (!types_to_download.Empty()) |
| + types_to_download.Put(syncer::NIGORI); |
| + |
| + // TODO(137550): It's dangerous to configure types that have progress markers. |
|
Nicolas Zea
2012/07/23 19:12:16
nit: the more common format is TODO(sync/username)
|
| + // Types with progress markers can trigger a MIGRATION_DONE response. We are |
| + // not prepared to handle a migration during a configure, so we must ensure |
| + // that all our types_to_download actually contain no data before we sync |
| + // them. |
| + // |
| + // The most common way to end up in this situation used to be types which had |
| + // !initial_sync_ended, but did have some progress markers. We avoid problems |
| + // with those types by purging the data of any such partially synced types |
| + // soon after we load the directory. |
| + |
| syncer::ModelSafeRoutingInfo routing_info; |
| - registrar_->ConfigureDataTypes(types_to_add_with_nigori, |
| - types_to_remove_with_nigori); |
| registrar_->GetModelSafeRoutingInfo(&routing_info); |
| - const syncer::ModelTypeSet enabled_types = |
| - GetRoutingInfoTypes(routing_info); |
| - |
| - // Figure out which types need to actually be downloaded. We pass those on |
| - // to the syncer while it's in configuration mode so that they can be |
| - // downloaded before we perform association. Once we switch to normal mode |
| - // downloads will get applied normally and hit the datatype's change |
| - // processor. |
| - // A datatype is in need of downloading if any of the following are true: |
| - // 1. it's enabled and initial_sync_ended is false (initial_sync_ended is |
| - // set after applying updates, and hence is a more conservative measure |
| - // than having a non-empty progress marker, which is set during |
| - // StoreTimestamps). |
| - // 2. the type is NIGORI, and any other datatype is being downloaded (nigori |
| - // is always included if we download a datatype). |
| - // TODO(sync): consider moving this logic onto the sync thread (perhaps |
| - // as part of SyncManager::ConfigureSyncer). |
| - syncer::ModelTypeSet initial_sync_ended_types = |
| - core_->sync_manager()->InitialSyncEndedTypes(); |
| - initial_sync_ended_types.RetainAll(enabled_types); |
| - syncer::ModelTypeSet types_to_config = |
| - Difference(enabled_types, initial_sync_ended_types); |
| - if (!types_to_config.Empty() && enabled_types.Has(syncer::NIGORI)) |
| - types_to_config.Put(syncer::NIGORI); |
| SDVLOG(1) << "Types " |
| - << syncer::ModelTypeSetToString(types_to_config) |
| + << syncer::ModelTypeSetToString(types_to_download) |
| << " added; calling DoConfigureSyncer"; |
| // TODO(zea): figure out how to bypass this call if no types are being |
| // configured and GetKey is not needed. For now we rely on determining the |
| // need for GetKey as part of the SyncManager::ConfigureSyncer logic. |
| RequestConfigureSyncer(reason, |
| - types_to_config, |
| + types_to_download, |
| routing_info, |
| ready_task, |
| retry_callback); |
| @@ -681,6 +679,11 @@ syncer::UserShare* SyncBackendHost::GetUserShare() const { |
| return core_->sync_manager()->GetUserShare(); |
| } |
| +// Bypasses the initialized() check. |
| +syncer::UserShare* SyncBackendHost::GetUserShareForTest() const { |
| + return core_->sync_manager()->GetUserShare(); |
| +} |
| + |
| SyncBackendHost::Status SyncBackendHost::GetDetailedStatus() { |
| DCHECK(initialized()); |
| return core_->sync_manager()->GetDetailedStatus(); |
| @@ -771,6 +774,13 @@ void SyncBackendHost::FinishConfigureDataTypesOnFrontendLoop( |
| ready_task.Run(failed_configuration_types); |
| } |
| +void SyncBackendHost::HandleSyncManagerInitializationOnFrontendLoop( |
| + const syncer::WeakHandle<syncer::JsBackend>& js_backend, bool success, |
| + syncer::ModelTypeSet restored_types) { |
| + registrar_->SetInitialTypes(restored_types); |
| + HandleInitializationCompletedOnFrontendLoop(js_backend, success); |
| +} |
| + |
| SyncBackendHost::DoInitializeOptions::DoInitializeOptions( |
| MessageLoop* sync_loop, |
| SyncBackendRegistrar* registrar, |
| @@ -842,12 +852,13 @@ void SyncBackendHost::Core::OnSyncCycleCompleted( |
| void SyncBackendHost::Core::OnInitializationComplete( |
| const syncer::WeakHandle<syncer::JsBackend>& js_backend, |
| - bool success) { |
| + bool success, |
| + const syncer::ModelTypeSet restored_types) { |
| DCHECK_EQ(MessageLoop::current(), sync_loop_); |
| host_.Call( |
| FROM_HERE, |
| - &SyncBackendHost::HandleInitializationCompletedOnFrontendLoop, |
| - js_backend, success); |
| + &SyncBackendHost::HandleSyncManagerInitializationOnFrontendLoop, |
| + js_backend, success, restored_types); |
| if (success) { |
| // Initialization is complete, so we can schedule recurring SaveChanges. |
| @@ -978,7 +989,6 @@ void SyncBackendHost::Core::DoInitialize(const DoInitializeOptions& options) { |
| options.service_url.SchemeIsSecure(), |
| BrowserThread::GetBlockingPool(), |
| options.make_http_bridge_factory_fn.Run().Pass(), |
| - options.routing_info, |
| options.workers, |
| options.extensions_activity_monitor, |
| options.registrar /* as SyncManager::ChangeDelegate */, |
| @@ -1176,17 +1186,14 @@ void SyncBackendHost::HandleInitializationCompletedOnFrontendLoop( |
| return; |
| } |
| - // If setup has completed, start off in DOWNLOADING_NIGORI so that |
| - // we start off by refreshing nigori. |
| - CHECK(sync_prefs_.get()); |
| - if (sync_prefs_->HasSyncSetupCompleted() && |
| - initialization_state_ < DOWNLOADING_NIGORI) { |
| - initialization_state_ = DOWNLOADING_NIGORI; |
| - } |
| - |
| // Run initialization state machine. |
| switch (initialization_state_) { |
| case NOT_INITIALIZED: |
| + // It is essential that only the Nigori node is actually downloaded here. |
| + // The receipt of a MIGRATION_DONE response in this download attempt would |
| + // be very bad. The server is smart enough to ignore migration |
| + // requirements only if the source (configure reason) is properly set and |
| + // NIGORI is the only enabled type. |
|
Nicolas Zea
2012/07/23 19:12:16
Note: as discussed offline, the server does not pr
|
| initialization_state_ = DOWNLOADING_NIGORI; |
| ConfigureDataTypes( |
| syncer::CONFIGURE_REASON_NEW_CLIENT, |