[AndroidWebViewShell] Replace rebaseline script with a new version using test_runner.py
[chromium-blink-merge.git] / components / sync_driver / model_association_manager.cc
blob6924712fecabb73ca02a507856dfc786753c3fa7
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.
5 #include "components/sync_driver/model_association_manager.h"
7 #include <algorithm>
8 #include <functional>
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/trace_event/trace_event.h"
14 #include "sync/internal_api/public/base/model_type.h"
16 using syncer::ModelTypeSet;
18 namespace sync_driver {
20 namespace {
22 static const syncer::ModelType kStartOrder[] = {
23 syncer::NIGORI, // Listed for completeness.
24 syncer::DEVICE_INFO, // Listed for completeness.
25 syncer::EXPERIMENTS, // Listed for completeness.
26 syncer::PROXY_TABS, // Listed for completeness.
28 // Kick off the association of the non-UI types first so they can associate
29 // in parallel with the UI types.
30 syncer::PASSWORDS,
31 syncer::AUTOFILL,
32 syncer::AUTOFILL_PROFILE,
33 syncer::AUTOFILL_WALLET_DATA,
34 syncer::AUTOFILL_WALLET_METADATA,
35 syncer::EXTENSION_SETTINGS,
36 syncer::APP_SETTINGS,
37 syncer::TYPED_URLS,
38 syncer::HISTORY_DELETE_DIRECTIVES,
39 syncer::SYNCED_NOTIFICATIONS,
40 syncer::SYNCED_NOTIFICATION_APP_INFO,
42 // UI thread data types.
43 syncer::BOOKMARKS,
44 syncer::SUPERVISED_USERS, // Syncing supervised users on initial login
45 // might block creating a new supervised user,
46 // so we want to do it early.
47 syncer::PREFERENCES,
48 syncer::PRIORITY_PREFERENCES,
49 syncer::EXTENSIONS,
50 syncer::APPS,
51 syncer::APP_LIST,
52 syncer::THEMES,
53 syncer::SEARCH_ENGINES,
54 syncer::SESSIONS,
55 syncer::APP_NOTIFICATIONS,
56 syncer::DICTIONARY,
57 syncer::FAVICON_IMAGES,
58 syncer::FAVICON_TRACKING,
59 syncer::SUPERVISED_USER_SETTINGS,
60 syncer::SUPERVISED_USER_SHARED_SETTINGS,
61 syncer::SUPERVISED_USER_WHITELISTS,
62 syncer::ARTICLES,
63 syncer::WIFI_CREDENTIALS,
66 static_assert(arraysize(kStartOrder) ==
67 syncer::MODEL_TYPE_COUNT - syncer::FIRST_REAL_MODEL_TYPE,
68 "kStartOrder must have MODEL_TYPE_COUNT - "
69 "FIRST_REAL_MODEL_TYPE elements");
71 // The amount of time we wait for association to finish. If some types haven't
72 // finished association by the time, DataTypeManager is notified of the
73 // unfinished types.
74 const int64 kAssociationTimeOutInSeconds = 600;
76 syncer::DataTypeAssociationStats BuildAssociationStatsFromMergeResults(
77 const syncer::SyncMergeResult& local_merge_result,
78 const syncer::SyncMergeResult& syncer_merge_result,
79 const base::TimeDelta& association_wait_time,
80 const base::TimeDelta& association_time) {
81 DCHECK_EQ(local_merge_result.model_type(), syncer_merge_result.model_type());
82 syncer::DataTypeAssociationStats stats;
83 stats.had_error = local_merge_result.error().IsSet() ||
84 syncer_merge_result.error().IsSet();
85 stats.num_local_items_before_association =
86 local_merge_result.num_items_before_association();
87 stats.num_sync_items_before_association =
88 syncer_merge_result.num_items_before_association();
89 stats.num_local_items_after_association =
90 local_merge_result.num_items_after_association();
91 stats.num_sync_items_after_association =
92 syncer_merge_result.num_items_after_association();
93 stats.num_local_items_added =
94 local_merge_result.num_items_added();
95 stats.num_local_items_deleted =
96 local_merge_result.num_items_deleted();
97 stats.num_local_items_modified =
98 local_merge_result.num_items_modified();
99 stats.local_version_pre_association =
100 local_merge_result.pre_association_version();
101 stats.num_sync_items_added =
102 syncer_merge_result.num_items_added();
103 stats.num_sync_items_deleted =
104 syncer_merge_result.num_items_deleted();
105 stats.num_sync_items_modified =
106 syncer_merge_result.num_items_modified();
107 stats.sync_version_pre_association =
108 syncer_merge_result.pre_association_version();
109 stats.association_wait_time = association_wait_time;
110 stats.association_time = association_time;
111 return stats;
114 } // namespace
116 ModelAssociationManager::ModelAssociationManager(
117 const DataTypeController::TypeMap* controllers,
118 ModelAssociationManagerDelegate* processor)
119 : state_(IDLE),
120 controllers_(controllers),
121 delegate_(processor),
122 configure_status_(DataTypeManager::UNKNOWN),
123 weak_ptr_factory_(this) {
124 // Ensure all data type controllers are stopped.
125 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
126 it != controllers_->end(); ++it) {
127 DCHECK_EQ(DataTypeController::NOT_RUNNING, (*it).second->state());
131 ModelAssociationManager::~ModelAssociationManager() {
134 void ModelAssociationManager::Initialize(syncer::ModelTypeSet desired_types) {
135 // state_ can be INITIALIZED if types are reconfigured when
136 // data is being downloaded, so StartAssociationAsync() is never called for
137 // the first configuration.
138 DCHECK_NE(ASSOCIATING, state_);
140 // Only keep types that have controllers.
141 desired_types_.Clear();
142 for (syncer::ModelTypeSet::Iterator it = desired_types.First();
143 it.Good(); it.Inc()) {
144 if (controllers_->find(it.Get()) != controllers_->end())
145 desired_types_.Put(it.Get());
148 DVLOG(1) << "ModelAssociationManager: Initializing for "
149 << syncer::ModelTypeSetToString(desired_types_);
151 state_ = INITIALIZED;
153 StopDisabledTypes();
154 LoadEnabledTypes();
157 void ModelAssociationManager::StopDatatype(
158 const syncer::SyncError& error,
159 DataTypeController* dtc) {
160 loaded_types_.Remove(dtc->type());
161 associated_types_.Remove(dtc->type());
162 associating_types_.Remove(dtc->type());
164 if (error.IsSet() || dtc->state() != DataTypeController::NOT_RUNNING) {
165 // If an error was set, the delegate must be informed of the error.
166 delegate_->OnSingleDataTypeWillStop(dtc->type(), error);
167 dtc->Stop();
171 void ModelAssociationManager::StopDisabledTypes() {
172 DVLOG(1) << "ModelAssociationManager: Stopping disabled types.";
173 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
174 it != controllers_->end(); ++it) {
175 DataTypeController* dtc = (*it).second.get();
176 if (dtc->state() != DataTypeController::NOT_RUNNING &&
177 !desired_types_.Has(dtc->type())) {
178 DVLOG(1) << "ModelAssociationManager: stop " << dtc->name();
179 StopDatatype(syncer::SyncError(), dtc);
184 void ModelAssociationManager::LoadEnabledTypes() {
185 // Load in kStartOrder.
186 for (size_t i = 0; i < arraysize(kStartOrder); i++) {
187 syncer::ModelType type = kStartOrder[i];
188 if (!desired_types_.Has(type))
189 continue;
191 DCHECK(controllers_->find(type) != controllers_->end());
192 DataTypeController* dtc = controllers_->find(type)->second.get();
193 if (dtc->state() == DataTypeController::NOT_RUNNING) {
194 DCHECK(!loaded_types_.Has(dtc->type()));
195 DCHECK(!associated_types_.Has(dtc->type()));
196 dtc->LoadModels(base::Bind(&ModelAssociationManager::ModelLoadCallback,
197 weak_ptr_factory_.GetWeakPtr()));
202 void ModelAssociationManager::StartAssociationAsync(
203 const syncer::ModelTypeSet& types_to_associate) {
204 DCHECK_EQ(INITIALIZED, state_);
205 DVLOG(1) << "Starting association for "
206 << syncer::ModelTypeSetToString(types_to_associate);
207 state_ = ASSOCIATING;
209 association_start_time_ = base::TimeTicks::Now();
211 requested_types_ = types_to_associate;
213 associating_types_ = types_to_associate;
214 associating_types_.RetainAll(desired_types_);
215 associating_types_.RemoveAll(associated_types_);
217 // Assume success.
218 configure_status_ = DataTypeManager::OK;
220 // Done if no types to associate.
221 if (associating_types_.Empty()) {
222 ModelAssociationDone(INITIALIZED);
223 return;
226 timer_.Start(FROM_HERE,
227 base::TimeDelta::FromSeconds(kAssociationTimeOutInSeconds),
228 base::Bind(&ModelAssociationManager::ModelAssociationDone,
229 weak_ptr_factory_.GetWeakPtr(),
230 INITIALIZED));
232 // Start association of types that are loaded in specified order.
233 for (size_t i = 0; i < arraysize(kStartOrder); i++) {
234 syncer::ModelType type = kStartOrder[i];
235 if (!associating_types_.Has(type) || !loaded_types_.Has(type))
236 continue;
238 DataTypeController* dtc = controllers_->find(type)->second.get();
239 DCHECK(DataTypeController::MODEL_LOADED == dtc->state() ||
240 DataTypeController::ASSOCIATING == dtc->state());
241 if (dtc->state() == DataTypeController::MODEL_LOADED) {
242 TRACE_EVENT_ASYNC_BEGIN1("sync", "ModelAssociation",
243 dtc,
244 "DataType",
245 ModelTypeToString(type));
247 dtc->StartAssociating(
248 base::Bind(&ModelAssociationManager::TypeStartCallback,
249 weak_ptr_factory_.GetWeakPtr(),
250 type, base::TimeTicks::Now()));
255 void ModelAssociationManager::Stop() {
256 // Ignore callbacks from controllers.
257 weak_ptr_factory_.InvalidateWeakPtrs();
259 // Stop started data types.
260 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
261 it != controllers_->end(); ++it) {
262 DataTypeController* dtc = (*it).second.get();
263 if (dtc->state() != DataTypeController::NOT_RUNNING) {
264 StopDatatype(syncer::SyncError(), dtc);
265 DVLOG(1) << "ModelAssociationManager: Stopped " << dtc->name();
269 desired_types_.Clear();
270 loaded_types_.Clear();
271 associated_types_.Clear();
273 if (state_ == ASSOCIATING) {
274 if (configure_status_ == DataTypeManager::OK)
275 configure_status_ = DataTypeManager::ABORTED;
276 DVLOG(1) << "ModelAssociationManager: Calling OnModelAssociationDone";
277 ModelAssociationDone(IDLE);
278 } else {
279 DCHECK(associating_types_.Empty());
280 DCHECK(requested_types_.Empty());
281 state_ = IDLE;
285 void ModelAssociationManager::ModelLoadCallback(syncer::ModelType type,
286 syncer::SyncError error) {
287 DVLOG(1) << "ModelAssociationManager: ModelLoadCallback for "
288 << syncer::ModelTypeToString(type);
290 if (error.IsSet()) {
291 syncer::SyncMergeResult local_merge_result(type);
292 local_merge_result.set_error(error);
293 TypeStartCallback(type,
294 base::TimeTicks::Now(),
295 DataTypeController::ASSOCIATION_FAILED,
296 local_merge_result,
297 syncer::SyncMergeResult(type));
298 return;
301 // This happens when slow loading type is disabled by new configuration.
302 if (!desired_types_.Has(type))
303 return;
305 DCHECK(!loaded_types_.Has(type));
306 loaded_types_.Put(type);
307 if (associating_types_.Has(type)) {
308 DataTypeController* dtc = controllers_->find(type)->second.get();
309 dtc->StartAssociating(
310 base::Bind(&ModelAssociationManager::TypeStartCallback,
311 weak_ptr_factory_.GetWeakPtr(),
312 type, base::TimeTicks::Now()));
316 void ModelAssociationManager::TypeStartCallback(
317 syncer::ModelType type,
318 base::TimeTicks type_start_time,
319 DataTypeController::ConfigureResult start_result,
320 const syncer::SyncMergeResult& local_merge_result,
321 const syncer::SyncMergeResult& syncer_merge_result) {
322 if (desired_types_.Has(type) &&
323 !DataTypeController::IsSuccessfulResult(start_result)) {
324 DVLOG(1) << "ModelAssociationManager: Type encountered an error.";
325 desired_types_.Remove(type);
326 DataTypeController* dtc = controllers_->find(type)->second.get();
327 StopDatatype(local_merge_result.error(), dtc);
329 // Update configuration result.
330 if (start_result == DataTypeController::UNRECOVERABLE_ERROR)
331 configure_status_ = DataTypeManager::UNRECOVERABLE_ERROR;
334 // This happens when a slow associating type is disabled or if a type
335 // disables itself after initial configuration.
336 if (!desired_types_.Has(type)) {
337 // It's possible all types failed to associate, in which case association
338 // is complete.
339 if (state_ == ASSOCIATING && associating_types_.Empty())
340 ModelAssociationDone(INITIALIZED);
341 return;
344 DCHECK(!associated_types_.Has(type));
345 DCHECK(DataTypeController::IsSuccessfulResult(start_result));
346 associated_types_.Put(type);
348 if (state_ != ASSOCIATING)
349 return;
351 TRACE_EVENT_ASYNC_END1("sync", "ModelAssociation",
352 controllers_->find(type)->second.get(),
353 "DataType",
354 ModelTypeToString(type));
356 // Track the merge results if we succeeded or an association failure
357 // occurred.
358 if (syncer::ProtocolTypes().Has(type)) {
359 base::TimeDelta association_wait_time =
360 std::max(base::TimeDelta(), type_start_time - association_start_time_);
361 base::TimeDelta association_time =
362 base::TimeTicks::Now() - type_start_time;;
363 syncer::DataTypeAssociationStats stats =
364 BuildAssociationStatsFromMergeResults(local_merge_result,
365 syncer_merge_result,
366 association_wait_time,
367 association_time);
368 delegate_->OnSingleDataTypeAssociationDone(type, stats);
371 associating_types_.Remove(type);
373 if (associating_types_.Empty())
374 ModelAssociationDone(INITIALIZED);
377 void ModelAssociationManager::ModelAssociationDone(State new_state) {
378 DCHECK_NE(IDLE, state_);
380 if (state_ == INITIALIZED) {
381 // No associations are currently happening. Just reset the state.
382 state_ = new_state;
383 return;
386 DVLOG(1) << "Model association complete for "
387 << syncer::ModelTypeSetToString(requested_types_);
389 timer_.Stop();
391 // Treat any unfinished types as having errors.
392 desired_types_.RemoveAll(associating_types_);
393 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
394 it != controllers_->end(); ++it) {
395 DataTypeController* dtc = (*it).second.get();
396 if (associating_types_.Has(dtc->type()) &&
397 dtc->state() != DataTypeController::NOT_RUNNING) {
398 UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed",
399 ModelTypeToHistogramInt(dtc->type()),
400 syncer::MODEL_TYPE_COUNT);
401 StopDatatype(syncer::SyncError(FROM_HERE,
402 syncer::SyncError::DATATYPE_ERROR,
403 "Association timed out.",
404 dtc->type()),
405 dtc);
409 DataTypeManager::ConfigureResult result(configure_status_,
410 requested_types_);
412 // Need to reset state before invoking delegate in order to avoid re-entrancy
413 // issues (delegate may trigger a reconfiguration).
414 associating_types_.Clear();
415 requested_types_.Clear();
416 state_ = new_state;
418 delegate_->OnModelAssociationDone(result);
421 base::OneShotTimer<ModelAssociationManager>*
422 ModelAssociationManager::GetTimerForTesting() {
423 return &timer_;
426 } // namespace sync_driver