1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/sync_driver/backend_migrator.h"
7 #include "base/location.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "base/tracked_objects.h"
12 #include "components/sync_driver/sync_service.h"
13 #include "sync/internal_api/public/configure_reason.h"
14 #include "sync/internal_api/public/read_transaction.h"
15 #include "sync/protocol/sync.pb.h"
16 #include "sync/syncable/directory.h" // TODO(tim): Bug 131130.
18 using syncer::ModelTypeSet
;
20 namespace browser_sync
{
22 using syncer::ModelTypeToString
;
24 MigrationObserver::~MigrationObserver() {}
26 BackendMigrator::BackendMigrator(const std::string
& name
,
27 syncer::UserShare
* user_share
,
28 sync_driver::SyncService
* service
,
29 sync_driver::DataTypeManager
* manager
,
30 const base::Closure
&migration_done_callback
)
31 : name_(name
), user_share_(user_share
), service_(service
),
32 manager_(manager
), state_(IDLE
),
33 migration_done_callback_(migration_done_callback
),
34 weak_ptr_factory_(this) {
37 BackendMigrator::~BackendMigrator() {
40 // Helper macros to log with the syncer thread name; useful when there
41 // are multiple syncer threads involved.
43 #define SLOG(severity) LOG(severity) << name_ << ": "
45 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
47 void BackendMigrator::MigrateTypes(syncer::ModelTypeSet types
) {
48 const ModelTypeSet old_to_migrate
= to_migrate_
;
49 to_migrate_
.PutAll(types
);
50 SDVLOG(1) << "MigrateTypes called with " << ModelTypeSetToString(types
)
51 << ", old_to_migrate = " << ModelTypeSetToString(old_to_migrate
)
52 << ", to_migrate_ = " << ModelTypeSetToString(to_migrate_
);
53 if (old_to_migrate
.Equals(to_migrate_
)) {
54 SDVLOG(1) << "MigrateTypes called with no new types; ignoring";
59 ChangeState(WAITING_TO_START
);
61 if (state_
== WAITING_TO_START
) {
63 SDVLOG(1) << "Manager not configured; waiting";
67 DCHECK_GT(state_
, WAITING_TO_START
);
68 // If we're already migrating, interrupt the current migration.
72 void BackendMigrator::AddMigrationObserver(MigrationObserver
* observer
) {
73 migration_observers_
.AddObserver(observer
);
76 bool BackendMigrator::HasMigrationObserver(
77 const MigrationObserver
* observer
) const {
78 return migration_observers_
.HasObserver(observer
);
81 void BackendMigrator::RemoveMigrationObserver(MigrationObserver
* observer
) {
82 migration_observers_
.RemoveObserver(observer
);
85 void BackendMigrator::ChangeState(State new_state
) {
87 FOR_EACH_OBSERVER(MigrationObserver
, migration_observers_
,
88 OnMigrationStateChange());
91 bool BackendMigrator::TryStart() {
92 DCHECK_EQ(state_
, WAITING_TO_START
);
93 if (manager_
->state() == sync_driver::DataTypeManager::CONFIGURED
) {
100 void BackendMigrator::RestartMigration() {
101 // We'll now disable any running types that need to be migrated.
102 ChangeState(DISABLING_TYPES
);
103 SDVLOG(1) << "BackendMigrator disabling types "
104 << ModelTypeSetToString(to_migrate_
);
106 manager_
->PurgeForMigration(to_migrate_
, syncer::CONFIGURE_REASON_MIGRATION
);
109 void BackendMigrator::OnConfigureDone(
110 const sync_driver::DataTypeManager::ConfigureResult
& result
) {
114 // |manager_|'s methods aren't re-entrant, and we're notified from
115 // them, so post a task to avoid problems.
116 SDVLOG(1) << "Posting OnConfigureDoneImpl";
117 base::ThreadTaskRunnerHandle::Get()->PostTask(
118 FROM_HERE
, base::Bind(&BackendMigrator::OnConfigureDoneImpl
,
119 weak_ptr_factory_
.GetWeakPtr(), result
));
124 syncer::ModelTypeSet
GetUnsyncedDataTypes(syncer::UserShare
* user_share
) {
125 syncer::ReadTransaction
trans(FROM_HERE
, user_share
);
126 syncer::ModelTypeSet unsynced_data_types
;
127 for (int i
= syncer::FIRST_REAL_MODEL_TYPE
;
128 i
< syncer::MODEL_TYPE_COUNT
; ++i
) {
129 syncer::ModelType type
= syncer::ModelTypeFromInt(i
);
130 sync_pb::DataTypeProgressMarker progress_marker
;
131 trans
.GetDirectory()->GetDownloadProgress(type
, &progress_marker
);
132 if (progress_marker
.token().empty()) {
133 unsynced_data_types
.Put(type
);
136 return unsynced_data_types
;
141 void BackendMigrator::OnConfigureDoneImpl(
142 const sync_driver::DataTypeManager::ConfigureResult
& result
) {
143 SDVLOG(1) << "OnConfigureDone with requested types "
144 << ModelTypeSetToString(result
.requested_types
)
145 << ", status " << result
.status
146 << ", and to_migrate_ = " << ModelTypeSetToString(to_migrate_
);
147 if (state_
== WAITING_TO_START
) {
149 SDVLOG(1) << "Manager still not configured; still waiting";
153 DCHECK_GT(state_
, WAITING_TO_START
);
155 const ModelTypeSet intersection
=
156 Intersection(result
.requested_types
, to_migrate_
);
157 // This intersection check is to determine if our disable request
158 // was interrupted by a user changing preferred types.
159 if (state_
== DISABLING_TYPES
&& !intersection
.Empty()) {
160 SDVLOG(1) << "Disable request interrupted by user changing types";
165 if (result
.status
!= sync_driver::DataTypeManager::OK
) {
166 // If this fails, and we're disabling types, a type may or may not be
167 // disabled until the user restarts the browser. If this wasn't an abort,
168 // any failure will be reported as an unrecoverable error to the UI. If it
169 // was an abort, then typically things are shutting down anyway. There isn't
170 // much we can do in any case besides wait until a restart to try again.
171 // The server will send down MIGRATION_DONE again for types needing
172 // migration as the type will still be enabled on restart.
173 SLOG(WARNING
) << "Unable to migrate, configuration failed!";
179 if (state_
== DISABLING_TYPES
) {
180 const syncer::ModelTypeSet unsynced_types
=
181 GetUnsyncedDataTypes(user_share_
);
182 if (!unsynced_types
.HasAll(to_migrate_
)) {
183 SLOG(WARNING
) << "Set of unsynced types: "
184 << syncer::ModelTypeSetToString(unsynced_types
)
185 << " does not contain types to migrate: "
186 << syncer::ModelTypeSetToString(to_migrate_
)
187 << "; not re-enabling yet";
191 ChangeState(REENABLING_TYPES
);
192 // Don't use |to_migrate_| for the re-enabling because the user
193 // may have chosen to disable types during the migration.
194 const ModelTypeSet full_set
= service_
->GetPreferredDataTypes();
195 SDVLOG(1) << "BackendMigrator re-enabling types: "
196 << syncer::ModelTypeSetToString(full_set
);
197 manager_
->Configure(full_set
, syncer::CONFIGURE_REASON_MIGRATION
);
198 } else if (state_
== REENABLING_TYPES
) {
202 SDVLOG(1) << "BackendMigrator: Migration complete for: "
203 << syncer::ModelTypeSetToString(to_migrate_
);
206 if (!migration_done_callback_
.is_null())
207 migration_done_callback_
.Run();
211 BackendMigrator::State
BackendMigrator::state() const {
215 syncer::ModelTypeSet
BackendMigrator::GetPendingMigrationTypesForTest() const {
223 }; // namespace browser_sync