Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: components/sync_driver/model_association_manager.cc

Issue 2203673002: [Sync] Move //components/sync_driver to //components/sync/driver. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@sd-a
Patch Set: Full change rebased on static lib. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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/model_association_manager.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <algorithm>
11 #include <functional>
12
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/metrics/histogram_macros.h"
17 #include "base/trace_event/trace_event.h"
18 #include "components/sync/api/sync_merge_result.h"
19 #include "components/sync/base/model_type.h"
20
21 using syncer::ModelTypeSet;
22
23 namespace sync_driver {
24
25 namespace {
26
27 static const syncer::ModelType kStartOrder[] = {
28 syncer::NIGORI, // Listed for completeness.
29 syncer::DEVICE_INFO, // Listed for completeness.
30 syncer::EXPERIMENTS, // Listed for completeness.
31 syncer::PROXY_TABS, // Listed for completeness.
32
33 // Kick off the association of the non-UI types first so they can associate
34 // in parallel with the UI types.
35 syncer::PASSWORDS,
36 syncer::AUTOFILL,
37 syncer::AUTOFILL_PROFILE,
38 syncer::AUTOFILL_WALLET_DATA,
39 syncer::AUTOFILL_WALLET_METADATA,
40 syncer::EXTENSION_SETTINGS,
41 syncer::APP_SETTINGS,
42 syncer::TYPED_URLS,
43 syncer::HISTORY_DELETE_DIRECTIVES,
44 syncer::SYNCED_NOTIFICATIONS,
45 syncer::SYNCED_NOTIFICATION_APP_INFO,
46
47 // UI thread data types.
48 syncer::BOOKMARKS,
49 syncer::SUPERVISED_USERS, // Syncing supervised users on initial login
50 // might block creating a new supervised user,
51 // so we want to do it early.
52 syncer::PREFERENCES,
53 syncer::PRIORITY_PREFERENCES,
54 syncer::EXTENSIONS,
55 syncer::APPS,
56 syncer::APP_LIST,
57 syncer::ARC_PACKAGE,
58 syncer::THEMES,
59 syncer::SEARCH_ENGINES,
60 syncer::SESSIONS,
61 syncer::APP_NOTIFICATIONS,
62 syncer::DICTIONARY,
63 syncer::FAVICON_IMAGES,
64 syncer::FAVICON_TRACKING,
65 syncer::SUPERVISED_USER_SETTINGS,
66 syncer::SUPERVISED_USER_SHARED_SETTINGS,
67 syncer::SUPERVISED_USER_WHITELISTS,
68 syncer::ARTICLES,
69 syncer::WIFI_CREDENTIALS,
70 };
71
72 static_assert(arraysize(kStartOrder) ==
73 syncer::MODEL_TYPE_COUNT - syncer::FIRST_REAL_MODEL_TYPE,
74 "kStartOrder must have MODEL_TYPE_COUNT - "
75 "FIRST_REAL_MODEL_TYPE elements");
76
77 // The amount of time we wait for association to finish. If some types haven't
78 // finished association by the time, DataTypeManager is notified of the
79 // unfinished types.
80 const int64_t kAssociationTimeOutInSeconds = 600;
81
82 syncer::DataTypeAssociationStats BuildAssociationStatsFromMergeResults(
83 const syncer::SyncMergeResult& local_merge_result,
84 const syncer::SyncMergeResult& syncer_merge_result,
85 const base::TimeDelta& association_wait_time,
86 const base::TimeDelta& association_time) {
87 DCHECK_EQ(local_merge_result.model_type(), syncer_merge_result.model_type());
88 syncer::DataTypeAssociationStats stats;
89 stats.had_error = local_merge_result.error().IsSet() ||
90 syncer_merge_result.error().IsSet();
91 stats.num_local_items_before_association =
92 local_merge_result.num_items_before_association();
93 stats.num_sync_items_before_association =
94 syncer_merge_result.num_items_before_association();
95 stats.num_local_items_after_association =
96 local_merge_result.num_items_after_association();
97 stats.num_sync_items_after_association =
98 syncer_merge_result.num_items_after_association();
99 stats.num_local_items_added =
100 local_merge_result.num_items_added();
101 stats.num_local_items_deleted =
102 local_merge_result.num_items_deleted();
103 stats.num_local_items_modified =
104 local_merge_result.num_items_modified();
105 stats.local_version_pre_association =
106 local_merge_result.pre_association_version();
107 stats.num_sync_items_added =
108 syncer_merge_result.num_items_added();
109 stats.num_sync_items_deleted =
110 syncer_merge_result.num_items_deleted();
111 stats.num_sync_items_modified =
112 syncer_merge_result.num_items_modified();
113 stats.sync_version_pre_association =
114 syncer_merge_result.pre_association_version();
115 stats.association_wait_time = association_wait_time;
116 stats.association_time = association_time;
117 return stats;
118 }
119
120 } // namespace
121
122 ModelAssociationManager::ModelAssociationManager(
123 const DataTypeController::TypeMap* controllers,
124 ModelAssociationManagerDelegate* processor)
125 : state_(IDLE),
126 controllers_(controllers),
127 delegate_(processor),
128 configure_status_(DataTypeManager::UNKNOWN),
129 notified_about_ready_for_configure_(false),
130 weak_ptr_factory_(this) {
131 // Ensure all data type controllers are stopped.
132 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
133 it != controllers_->end(); ++it) {
134 DCHECK_EQ(DataTypeController::NOT_RUNNING, (*it).second->state());
135 }
136 }
137
138 ModelAssociationManager::~ModelAssociationManager() {
139 }
140
141 void ModelAssociationManager::Initialize(syncer::ModelTypeSet desired_types) {
142 // state_ can be INITIALIZED if types are reconfigured when
143 // data is being downloaded, so StartAssociationAsync() is never called for
144 // the first configuration.
145 DCHECK_NE(ASSOCIATING, state_);
146
147 // Only keep types that have controllers.
148 desired_types_.Clear();
149 for (syncer::ModelTypeSet::Iterator it = desired_types.First();
150 it.Good(); it.Inc()) {
151 if (controllers_->find(it.Get()) != controllers_->end())
152 desired_types_.Put(it.Get());
153 }
154
155 DVLOG(1) << "ModelAssociationManager: Initializing for "
156 << syncer::ModelTypeSetToString(desired_types_);
157
158 state_ = INITIALIZED;
159 notified_about_ready_for_configure_ = false;
160
161 StopDisabledTypes();
162 LoadEnabledTypes();
163 }
164
165 void ModelAssociationManager::StopDatatype(
166 const syncer::SyncError& error,
167 DataTypeController* dtc) {
168 loaded_types_.Remove(dtc->type());
169 associated_types_.Remove(dtc->type());
170 associating_types_.Remove(dtc->type());
171
172 if (error.IsSet() || dtc->state() != DataTypeController::NOT_RUNNING) {
173 // If an error was set, the delegate must be informed of the error.
174 delegate_->OnSingleDataTypeWillStop(dtc->type(), error);
175 dtc->Stop();
176 }
177 }
178
179 void ModelAssociationManager::StopDisabledTypes() {
180 DVLOG(1) << "ModelAssociationManager: Stopping disabled types.";
181 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
182 it != controllers_->end(); ++it) {
183 DataTypeController* dtc = (*it).second.get();
184 if (dtc->state() != DataTypeController::NOT_RUNNING &&
185 !desired_types_.Has(dtc->type())) {
186 DVLOG(1) << "ModelAssociationManager: stop " << dtc->name();
187 StopDatatype(syncer::SyncError(), dtc);
188 }
189 }
190 }
191
192 void ModelAssociationManager::LoadEnabledTypes() {
193 // Load in kStartOrder.
194 for (size_t i = 0; i < arraysize(kStartOrder); i++) {
195 syncer::ModelType type = kStartOrder[i];
196 if (!desired_types_.Has(type))
197 continue;
198
199 DCHECK(controllers_->find(type) != controllers_->end());
200 DataTypeController* dtc = controllers_->find(type)->second.get();
201 if (dtc->state() == DataTypeController::NOT_RUNNING) {
202 DCHECK(!loaded_types_.Has(dtc->type()));
203 DCHECK(!associated_types_.Has(dtc->type()));
204 dtc->LoadModels(base::Bind(&ModelAssociationManager::ModelLoadCallback,
205 weak_ptr_factory_.GetWeakPtr()));
206 }
207 }
208 NotifyDelegateIfReadyForConfigure();
209 }
210
211 void ModelAssociationManager::StartAssociationAsync(
212 const syncer::ModelTypeSet& types_to_associate) {
213 DCHECK_EQ(INITIALIZED, state_);
214 DVLOG(1) << "Starting association for "
215 << syncer::ModelTypeSetToString(types_to_associate);
216 state_ = ASSOCIATING;
217
218 association_start_time_ = base::TimeTicks::Now();
219
220 requested_types_ = types_to_associate;
221
222 associating_types_ = types_to_associate;
223 associating_types_.RetainAll(desired_types_);
224 associating_types_.RemoveAll(associated_types_);
225
226 // Assume success.
227 configure_status_ = DataTypeManager::OK;
228
229 // Done if no types to associate.
230 if (associating_types_.Empty()) {
231 ModelAssociationDone(INITIALIZED);
232 return;
233 }
234
235 timer_.Start(FROM_HERE,
236 base::TimeDelta::FromSeconds(kAssociationTimeOutInSeconds),
237 base::Bind(&ModelAssociationManager::ModelAssociationDone,
238 weak_ptr_factory_.GetWeakPtr(),
239 INITIALIZED));
240
241 // Start association of types that are loaded in specified order.
242 for (size_t i = 0; i < arraysize(kStartOrder); i++) {
243 syncer::ModelType type = kStartOrder[i];
244 if (!associating_types_.Has(type) || !loaded_types_.Has(type))
245 continue;
246
247 DataTypeController* dtc = controllers_->find(type)->second.get();
248 DCHECK(DataTypeController::MODEL_LOADED == dtc->state() ||
249 DataTypeController::ASSOCIATING == dtc->state());
250 if (dtc->state() == DataTypeController::MODEL_LOADED) {
251 TRACE_EVENT_ASYNC_BEGIN1("sync", "ModelAssociation",
252 dtc,
253 "DataType",
254 ModelTypeToString(type));
255
256 dtc->StartAssociating(
257 base::Bind(&ModelAssociationManager::TypeStartCallback,
258 weak_ptr_factory_.GetWeakPtr(),
259 type, base::TimeTicks::Now()));
260 }
261 }
262 }
263
264 void ModelAssociationManager::Stop() {
265 // Ignore callbacks from controllers.
266 weak_ptr_factory_.InvalidateWeakPtrs();
267
268 // Stop started data types.
269 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
270 it != controllers_->end(); ++it) {
271 DataTypeController* dtc = (*it).second.get();
272 if (dtc->state() != DataTypeController::NOT_RUNNING) {
273 StopDatatype(syncer::SyncError(), dtc);
274 DVLOG(1) << "ModelAssociationManager: Stopped " << dtc->name();
275 }
276 }
277
278 desired_types_.Clear();
279 loaded_types_.Clear();
280 associated_types_.Clear();
281
282 if (state_ == ASSOCIATING) {
283 if (configure_status_ == DataTypeManager::OK)
284 configure_status_ = DataTypeManager::ABORTED;
285 DVLOG(1) << "ModelAssociationManager: Calling OnModelAssociationDone";
286 ModelAssociationDone(IDLE);
287 } else {
288 DCHECK(associating_types_.Empty());
289 DCHECK(requested_types_.Empty());
290 state_ = IDLE;
291 }
292 }
293
294 void ModelAssociationManager::ModelLoadCallback(syncer::ModelType type,
295 syncer::SyncError error) {
296 DVLOG(1) << "ModelAssociationManager: ModelLoadCallback for "
297 << syncer::ModelTypeToString(type);
298
299 if (error.IsSet()) {
300 syncer::SyncMergeResult local_merge_result(type);
301 local_merge_result.set_error(error);
302 TypeStartCallback(type,
303 base::TimeTicks::Now(),
304 DataTypeController::ASSOCIATION_FAILED,
305 local_merge_result,
306 syncer::SyncMergeResult(type));
307 return;
308 }
309
310 // This happens when slow loading type is disabled by new configuration.
311 if (!desired_types_.Has(type))
312 return;
313
314 DCHECK(!loaded_types_.Has(type));
315 loaded_types_.Put(type);
316 NotifyDelegateIfReadyForConfigure();
317 if (associating_types_.Has(type)) {
318 DataTypeController* dtc = controllers_->find(type)->second.get();
319 // If initial sync was done for this datatype then
320 // NotifyDelegateIfReadyForConfigure possibly already triggered model
321 // association and StartAssociating was already called for this type. To
322 // ensure StartAssociating is called only once only make a call if state is
323 // MODEL_LOADED.
324 // TODO(pavely): Add test for this scenario in DataTypeManagerImpl
325 // unittests.
326 if (dtc->state() == DataTypeController::MODEL_LOADED) {
327 dtc->StartAssociating(base::Bind(
328 &ModelAssociationManager::TypeStartCallback,
329 weak_ptr_factory_.GetWeakPtr(), type, base::TimeTicks::Now()));
330 }
331 }
332 }
333
334 void ModelAssociationManager::TypeStartCallback(
335 syncer::ModelType type,
336 base::TimeTicks type_start_time,
337 DataTypeController::ConfigureResult start_result,
338 const syncer::SyncMergeResult& local_merge_result,
339 const syncer::SyncMergeResult& syncer_merge_result) {
340 if (desired_types_.Has(type) &&
341 !DataTypeController::IsSuccessfulResult(start_result)) {
342 DVLOG(1) << "ModelAssociationManager: Type encountered an error.";
343 desired_types_.Remove(type);
344 DataTypeController* dtc = controllers_->find(type)->second.get();
345 StopDatatype(local_merge_result.error(), dtc);
346 NotifyDelegateIfReadyForConfigure();
347
348 // Update configuration result.
349 if (start_result == DataTypeController::UNRECOVERABLE_ERROR)
350 configure_status_ = DataTypeManager::UNRECOVERABLE_ERROR;
351 }
352
353 // This happens when a slow associating type is disabled or if a type
354 // disables itself after initial configuration.
355 if (!desired_types_.Has(type)) {
356 // It's possible all types failed to associate, in which case association
357 // is complete.
358 if (state_ == ASSOCIATING && associating_types_.Empty())
359 ModelAssociationDone(INITIALIZED);
360 return;
361 }
362
363 DCHECK(!associated_types_.Has(type));
364 DCHECK(DataTypeController::IsSuccessfulResult(start_result));
365 associated_types_.Put(type);
366
367 if (state_ != ASSOCIATING)
368 return;
369
370 TRACE_EVENT_ASYNC_END1("sync", "ModelAssociation",
371 controllers_->find(type)->second.get(),
372 "DataType",
373 ModelTypeToString(type));
374
375 // Track the merge results if we succeeded or an association failure
376 // occurred.
377 if (syncer::ProtocolTypes().Has(type)) {
378 base::TimeDelta association_wait_time =
379 std::max(base::TimeDelta(), type_start_time - association_start_time_);
380 base::TimeDelta association_time =
381 base::TimeTicks::Now() - type_start_time;
382 syncer::DataTypeAssociationStats stats =
383 BuildAssociationStatsFromMergeResults(local_merge_result,
384 syncer_merge_result,
385 association_wait_time,
386 association_time);
387 delegate_->OnSingleDataTypeAssociationDone(type, stats);
388 }
389
390 associating_types_.Remove(type);
391
392 if (associating_types_.Empty())
393 ModelAssociationDone(INITIALIZED);
394 }
395
396 void ModelAssociationManager::ModelAssociationDone(State new_state) {
397 DCHECK_NE(IDLE, state_);
398
399 if (state_ == INITIALIZED) {
400 // No associations are currently happening. Just reset the state.
401 state_ = new_state;
402 return;
403 }
404
405 DVLOG(1) << "Model association complete for "
406 << syncer::ModelTypeSetToString(requested_types_);
407
408 timer_.Stop();
409
410 // Treat any unfinished types as having errors.
411 desired_types_.RemoveAll(associating_types_);
412 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
413 it != controllers_->end(); ++it) {
414 DataTypeController* dtc = (*it).second.get();
415 if (associating_types_.Has(dtc->type()) &&
416 dtc->state() != DataTypeController::NOT_RUNNING) {
417 UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed",
418 ModelTypeToHistogramInt(dtc->type()),
419 syncer::MODEL_TYPE_COUNT);
420 StopDatatype(syncer::SyncError(FROM_HERE,
421 syncer::SyncError::DATATYPE_ERROR,
422 "Association timed out.",
423 dtc->type()),
424 dtc);
425 }
426 }
427
428 DataTypeManager::ConfigureResult result(configure_status_,
429 requested_types_);
430
431 // Need to reset state before invoking delegate in order to avoid re-entrancy
432 // issues (delegate may trigger a reconfiguration).
433 associating_types_.Clear();
434 requested_types_.Clear();
435 state_ = new_state;
436
437 delegate_->OnModelAssociationDone(result);
438 }
439
440 base::OneShotTimer* ModelAssociationManager::GetTimerForTesting() {
441 return &timer_;
442 }
443
444 void ModelAssociationManager::NotifyDelegateIfReadyForConfigure() {
445 if (notified_about_ready_for_configure_)
446 return;
447 for (const auto& type_dtc_pair : *controllers_) {
448 syncer::ModelType type = type_dtc_pair.first;
449 if (!desired_types_.Has(type))
450 continue;
451 DataTypeController* dtc = type_dtc_pair.second.get();
452 if (dtc->ShouldLoadModelBeforeConfigure() && !loaded_types_.Has(type)) {
453 // At least one type is not ready.
454 return;
455 }
456 }
457
458 notified_about_ready_for_configure_ = true;
459 delegate_->OnAllDataTypesReadyForConfigure();
460 }
461
462 } // namespace sync_driver
OLDNEW
« no previous file with comments | « components/sync_driver/model_association_manager.h ('k') | components/sync_driver/model_association_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698