OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "components/sync_driver/backend_migrator.h" | |
6 | |
7 #include "base/location.h" | |
8 #include "base/single_thread_task_runner.h" | |
9 #include "base/strings/string_number_conversions.h" | |
10 #include "base/threading/thread_task_runner_handle.h" | |
11 #include "base/tracked_objects.h" | |
12 #include "components/sync/core/configure_reason.h" | |
13 #include "components/sync/core/read_transaction.h" | |
14 #include "components/sync/protocol/sync.pb.h" | |
15 #include "components/sync/syncable/directory.h" // TODO(tim): Bug 131130. | |
16 #include "components/sync_driver/sync_service.h" | |
17 | |
18 using syncer::ModelTypeSet; | |
19 | |
20 namespace browser_sync { | |
21 | |
22 using syncer::ModelTypeToString; | |
23 | |
24 MigrationObserver::~MigrationObserver() {} | |
25 | |
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) { | |
35 } | |
36 | |
37 BackendMigrator::~BackendMigrator() { | |
38 } | |
39 | |
40 // Helper macros to log with the syncer thread name; useful when there | |
41 // are multiple syncer threads involved. | |
42 | |
43 #define SLOG(severity) LOG(severity) << name_ << ": " | |
44 | |
45 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": " | |
46 | |
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 == to_migrate_) { | |
54 SDVLOG(1) << "MigrateTypes called with no new types; ignoring"; | |
55 return; | |
56 } | |
57 | |
58 if (state_ == IDLE) | |
59 ChangeState(WAITING_TO_START); | |
60 | |
61 if (state_ == WAITING_TO_START) { | |
62 if (!TryStart()) | |
63 SDVLOG(1) << "Manager not configured; waiting"; | |
64 return; | |
65 } | |
66 | |
67 DCHECK_GT(state_, WAITING_TO_START); | |
68 // If we're already migrating, interrupt the current migration. | |
69 RestartMigration(); | |
70 } | |
71 | |
72 void BackendMigrator::AddMigrationObserver(MigrationObserver* observer) { | |
73 migration_observers_.AddObserver(observer); | |
74 } | |
75 | |
76 bool BackendMigrator::HasMigrationObserver( | |
77 const MigrationObserver* observer) const { | |
78 return migration_observers_.HasObserver(observer); | |
79 } | |
80 | |
81 void BackendMigrator::RemoveMigrationObserver(MigrationObserver* observer) { | |
82 migration_observers_.RemoveObserver(observer); | |
83 } | |
84 | |
85 void BackendMigrator::ChangeState(State new_state) { | |
86 state_ = new_state; | |
87 FOR_EACH_OBSERVER(MigrationObserver, migration_observers_, | |
88 OnMigrationStateChange()); | |
89 } | |
90 | |
91 bool BackendMigrator::TryStart() { | |
92 DCHECK_EQ(state_, WAITING_TO_START); | |
93 if (manager_->state() == sync_driver::DataTypeManager::CONFIGURED) { | |
94 RestartMigration(); | |
95 return true; | |
96 } | |
97 return false; | |
98 } | |
99 | |
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_); | |
105 | |
106 manager_->PurgeForMigration(to_migrate_, syncer::CONFIGURE_REASON_MIGRATION); | |
107 } | |
108 | |
109 void BackendMigrator::OnConfigureDone( | |
110 const sync_driver::DataTypeManager::ConfigureResult& result) { | |
111 if (state_ == IDLE) | |
112 return; | |
113 | |
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)); | |
120 } | |
121 | |
122 namespace { | |
123 | |
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); | |
134 } | |
135 } | |
136 return unsynced_data_types; | |
137 } | |
138 | |
139 } // namespace | |
140 | |
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) { | |
148 if (!TryStart()) | |
149 SDVLOG(1) << "Manager still not configured; still waiting"; | |
150 return; | |
151 } | |
152 | |
153 DCHECK_GT(state_, WAITING_TO_START); | |
154 | |
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"; | |
161 RestartMigration(); | |
162 return; | |
163 } | |
164 | |
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!"; | |
174 ChangeState(IDLE); | |
175 to_migrate_.Clear(); | |
176 return; | |
177 } | |
178 | |
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"; | |
188 return; | |
189 } | |
190 | |
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) { | |
199 // We're done! | |
200 ChangeState(IDLE); | |
201 | |
202 SDVLOG(1) << "BackendMigrator: Migration complete for: " | |
203 << syncer::ModelTypeSetToString(to_migrate_); | |
204 to_migrate_.Clear(); | |
205 | |
206 if (!migration_done_callback_.is_null()) | |
207 migration_done_callback_.Run(); | |
208 } | |
209 } | |
210 | |
211 BackendMigrator::State BackendMigrator::state() const { | |
212 return state_; | |
213 } | |
214 | |
215 syncer::ModelTypeSet BackendMigrator::GetPendingMigrationTypesForTest() const { | |
216 return to_migrate_; | |
217 } | |
218 | |
219 #undef SDVLOG | |
220 | |
221 #undef SLOG | |
222 | |
223 }; // namespace browser_sync | |
OLD | NEW |