Make |track_| in MediaStreamTrack const. and a couple of other cosmetic changes.
[chromium-blink-merge.git] / components / sync_driver / model_association_manager.cc
blob2fa90ab739ae4dc415397f842f0666d00cc297da
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/debug/trace_event.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/histogram.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::EXTENSION_SETTINGS,
34 syncer::APP_SETTINGS,
35 syncer::TYPED_URLS,
36 syncer::HISTORY_DELETE_DIRECTIVES,
37 syncer::SYNCED_NOTIFICATIONS,
38 syncer::SYNCED_NOTIFICATION_APP_INFO,
40 // UI thread data types.
41 syncer::BOOKMARKS,
42 syncer::ENHANCED_BOOKMARKS,
43 syncer::SUPERVISED_USERS, // Syncing supervised users on initial login
44 // might block creating a new supervised user,
45 // so we want to do it early.
46 syncer::PREFERENCES,
47 syncer::PRIORITY_PREFERENCES,
48 syncer::EXTENSIONS,
49 syncer::APPS,
50 syncer::APP_LIST,
51 syncer::THEMES,
52 syncer::SEARCH_ENGINES,
53 syncer::SESSIONS,
54 syncer::APP_NOTIFICATIONS,
55 syncer::DICTIONARY,
56 syncer::FAVICON_IMAGES,
57 syncer::FAVICON_TRACKING,
58 syncer::SUPERVISED_USER_SETTINGS,
59 syncer::SUPERVISED_USER_SHARED_SETTINGS,
60 syncer::ARTICLES,
63 COMPILE_ASSERT(arraysize(kStartOrder) ==
64 syncer::MODEL_TYPE_COUNT - syncer::FIRST_REAL_MODEL_TYPE,
65 kStartOrder_IncorrectSize);
67 // The amount of time we wait for association to finish. If some types haven't
68 // finished association by the time, DataTypeManager is notified of the
69 // unfinished types.
70 const int64 kAssociationTimeOutInSeconds = 600;
72 syncer::DataTypeAssociationStats BuildAssociationStatsFromMergeResults(
73 const syncer::SyncMergeResult& local_merge_result,
74 const syncer::SyncMergeResult& syncer_merge_result,
75 const base::TimeDelta& association_wait_time,
76 const base::TimeDelta& association_time) {
77 DCHECK_EQ(local_merge_result.model_type(), syncer_merge_result.model_type());
78 syncer::DataTypeAssociationStats stats;
79 stats.had_error = local_merge_result.error().IsSet() ||
80 syncer_merge_result.error().IsSet();
81 stats.num_local_items_before_association =
82 local_merge_result.num_items_before_association();
83 stats.num_sync_items_before_association =
84 syncer_merge_result.num_items_before_association();
85 stats.num_local_items_after_association =
86 local_merge_result.num_items_after_association();
87 stats.num_sync_items_after_association =
88 syncer_merge_result.num_items_after_association();
89 stats.num_local_items_added =
90 local_merge_result.num_items_added();
91 stats.num_local_items_deleted =
92 local_merge_result.num_items_deleted();
93 stats.num_local_items_modified =
94 local_merge_result.num_items_modified();
95 stats.local_version_pre_association =
96 local_merge_result.pre_association_version();
97 stats.num_sync_items_added =
98 syncer_merge_result.num_items_added();
99 stats.num_sync_items_deleted =
100 syncer_merge_result.num_items_deleted();
101 stats.num_sync_items_modified =
102 syncer_merge_result.num_items_modified();
103 stats.sync_version_pre_association =
104 syncer_merge_result.pre_association_version();
105 stats.association_wait_time = association_wait_time;
106 stats.association_time = association_time;
107 return stats;
110 } // namespace
112 ModelAssociationManager::ModelAssociationManager(
113 const DataTypeController::TypeMap* controllers,
114 ModelAssociationManagerDelegate* processor)
115 : state_(IDLE),
116 controllers_(controllers),
117 delegate_(processor),
118 configure_status_(DataTypeManager::UNKNOWN),
119 weak_ptr_factory_(this) {
120 // Ensure all data type controllers are stopped.
121 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
122 it != controllers_->end(); ++it) {
123 DCHECK_EQ(DataTypeController::NOT_RUNNING, (*it).second->state());
127 ModelAssociationManager::~ModelAssociationManager() {
130 void ModelAssociationManager::Initialize(syncer::ModelTypeSet desired_types) {
131 // state_ can be INITIALIZED_TO_CONFIGURE if types are reconfigured when
132 // data is being downloaded, so StartAssociationAsync() is never called for
133 // the first configuration.
134 DCHECK_NE(CONFIGURING, state_);
136 // Only keep types that have controllers.
137 desired_types_.Clear();
138 for (syncer::ModelTypeSet::Iterator it = desired_types.First();
139 it.Good(); it.Inc()) {
140 if (controllers_->find(it.Get()) != controllers_->end())
141 desired_types_.Put(it.Get());
144 DVLOG(1) << "ModelAssociationManager: Initializing for "
145 << syncer::ModelTypeSetToString(desired_types_);
147 state_ = INITIALIZED_TO_CONFIGURE;
149 StopDisabledTypes();
150 LoadEnabledTypes();
153 void ModelAssociationManager::StopDatatype(
154 const syncer::SyncError& error,
155 DataTypeController* dtc) {
156 loaded_types_.Remove(dtc->type());
157 associated_types_.Remove(dtc->type());
158 associating_types_.Remove(dtc->type());
160 if (error.IsSet() || dtc->state() != DataTypeController::NOT_RUNNING) {
161 // If an error was set, the delegate must be informed of the error.
162 delegate_->OnSingleDataTypeWillStop(dtc->type(), error);
163 dtc->Stop();
167 void ModelAssociationManager::StopDisabledTypes() {
168 DVLOG(1) << "ModelAssociationManager: Stopping disabled types.";
169 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
170 it != controllers_->end(); ++it) {
171 DataTypeController* dtc = (*it).second.get();
172 if (dtc->state() != DataTypeController::NOT_RUNNING &&
173 !desired_types_.Has(dtc->type())) {
174 DVLOG(1) << "ModelTypeToString: stop " << dtc->name();
175 StopDatatype(syncer::SyncError(), dtc);
180 void ModelAssociationManager::LoadEnabledTypes() {
181 // Load in kStartOrder.
182 for (size_t i = 0; i < arraysize(kStartOrder); i++) {
183 syncer::ModelType type = kStartOrder[i];
184 if (!desired_types_.Has(type))
185 continue;
187 DCHECK(controllers_->find(type) != controllers_->end());
188 DataTypeController* dtc = controllers_->find(type)->second.get();
189 if (dtc->state() == DataTypeController::NOT_RUNNING) {
190 DCHECK(!loaded_types_.Has(dtc->type()));
191 DCHECK(!associated_types_.Has(dtc->type()));
192 dtc->LoadModels(base::Bind(&ModelAssociationManager::ModelLoadCallback,
193 weak_ptr_factory_.GetWeakPtr()));
198 void ModelAssociationManager::StartAssociationAsync(
199 const syncer::ModelTypeSet& types_to_associate) {
200 DCHECK_NE(CONFIGURING, state_);
201 state_ = CONFIGURING;
203 association_start_time_ = base::TimeTicks::Now();
205 requested_types_ = types_to_associate;
207 associating_types_ = types_to_associate;
208 associating_types_.RetainAll(desired_types_);
209 associating_types_.RemoveAll(associated_types_);
211 // Assume success.
212 configure_status_ = DataTypeManager::OK;
214 // Done if no types to associate.
215 if (associating_types_.Empty()) {
216 ModelAssociationDone();
217 return;
220 timer_.Start(FROM_HERE,
221 base::TimeDelta::FromSeconds(kAssociationTimeOutInSeconds),
222 this,
223 &ModelAssociationManager::ModelAssociationDone);
225 // Start association of types that are loaded in specified order.
226 for (size_t i = 0; i < arraysize(kStartOrder); i++) {
227 syncer::ModelType type = kStartOrder[i];
228 if (!associating_types_.Has(type) || !loaded_types_.Has(type))
229 continue;
231 DataTypeController* dtc = controllers_->find(type)->second.get();
232 DCHECK(DataTypeController::MODEL_LOADED == dtc->state() ||
233 DataTypeController::ASSOCIATING == dtc->state());
234 if (dtc->state() == DataTypeController::MODEL_LOADED) {
235 TRACE_EVENT_ASYNC_BEGIN1("sync", "ModelAssociation",
236 dtc,
237 "DataType",
238 ModelTypeToString(type));
240 dtc->StartAssociating(
241 base::Bind(&ModelAssociationManager::TypeStartCallback,
242 weak_ptr_factory_.GetWeakPtr(),
243 type, base::TimeTicks::Now()));
248 void ModelAssociationManager::ResetForNextAssociation() {
249 DVLOG(1) << "ModelAssociationManager: Reseting for next configuration";
250 // |loaded_types_| and |associated_types_| are not cleared. So
251 // reconfiguration won't restart types that are already started.
252 requested_types_.Clear();
253 associating_types_.Clear();
256 void ModelAssociationManager::Stop() {
257 // Ignore callbacks from controllers.
258 weak_ptr_factory_.InvalidateWeakPtrs();
260 desired_types_.Clear();
261 loaded_types_.Clear();
262 associated_types_.Clear();
263 associating_types_.Clear();
265 // Stop started data types.
266 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
267 it != controllers_->end(); ++it) {
268 DataTypeController* dtc = (*it).second.get();
269 if (dtc->state() != DataTypeController::NOT_RUNNING) {
270 StopDatatype(syncer::SyncError(), dtc);
271 DVLOG(1) << "ModelAssociationManager: Stopped " << dtc->name();
275 if (state_ == CONFIGURING) {
276 if (configure_status_ == DataTypeManager::OK)
277 configure_status_ = DataTypeManager::ABORTED;
278 DVLOG(1) << "ModelAssociationManager: Calling OnModelAssociationDone";
279 ModelAssociationDone();
282 ResetForNextAssociation();
284 state_ = IDLE;
287 void ModelAssociationManager::ModelLoadCallback(syncer::ModelType type,
288 syncer::SyncError error) {
289 DVLOG(1) << "ModelAssociationManager: ModelLoadCallback for "
290 << syncer::ModelTypeToString(type);
292 if (error.IsSet()) {
293 syncer::SyncMergeResult local_merge_result(type);
294 local_merge_result.set_error(error);
295 TypeStartCallback(type,
296 base::TimeTicks::Now(),
297 DataTypeController::ASSOCIATION_FAILED,
298 local_merge_result,
299 syncer::SyncMergeResult(type));
300 return;
303 // This happens when slow loading type is disabled by new configuration.
304 if (!desired_types_.Has(type))
305 return;
307 DCHECK(!loaded_types_.Has(type));
308 loaded_types_.Put(type);
309 if (associating_types_.Has(type)) {
310 DataTypeController* dtc = controllers_->find(type)->second.get();
311 dtc->StartAssociating(
312 base::Bind(&ModelAssociationManager::TypeStartCallback,
313 weak_ptr_factory_.GetWeakPtr(),
314 type, base::TimeTicks::Now()));
318 void ModelAssociationManager::TypeStartCallback(
319 syncer::ModelType type,
320 base::TimeTicks type_start_time,
321 DataTypeController::ConfigureResult start_result,
322 const syncer::SyncMergeResult& local_merge_result,
323 const syncer::SyncMergeResult& syncer_merge_result) {
324 if (desired_types_.Has(type) &&
325 !DataTypeController::IsSuccessfulResult(start_result)) {
326 DVLOG(1) << "ModelAssociationManager: Type encountered an error.";
327 desired_types_.Remove(type);
328 DataTypeController* dtc = controllers_->find(type)->second.get();
329 StopDatatype(local_merge_result.error(), dtc);
331 // Update configuration result.
332 if (start_result == DataTypeController::UNRECOVERABLE_ERROR)
333 configure_status_ = DataTypeManager::UNRECOVERABLE_ERROR;
336 // This happens when a slow associating type is disabled or if a type
337 // disables itself after initial configuration.
338 if (!desired_types_.Has(type)) {
339 // It's possible all types failed to associate, in which case association
340 // is complete.
341 if (state_ == CONFIGURING && associating_types_.Empty())
342 ModelAssociationDone();
343 return;
346 DCHECK(!associated_types_.Has(type));
347 DCHECK(DataTypeController::IsSuccessfulResult(start_result));
348 associated_types_.Put(type);
350 if (state_ != CONFIGURING)
351 return;
353 TRACE_EVENT_ASYNC_END1("sync", "ModelAssociation",
354 controllers_->find(type)->second.get(),
355 "DataType",
356 ModelTypeToString(type));
358 // Track the merge results if we succeeded or an association failure
359 // occurred.
360 if (syncer::ProtocolTypes().Has(type)) {
361 base::TimeDelta association_wait_time =
362 std::max(base::TimeDelta(), type_start_time - association_start_time_);
363 base::TimeDelta association_time =
364 base::TimeTicks::Now() - type_start_time;;
365 syncer::DataTypeAssociationStats stats =
366 BuildAssociationStatsFromMergeResults(local_merge_result,
367 syncer_merge_result,
368 association_wait_time,
369 association_time);
370 delegate_->OnSingleDataTypeAssociationDone(type, stats);
373 associating_types_.Remove(type);
375 if (associating_types_.Empty())
376 ModelAssociationDone();
379 void ModelAssociationManager::ModelAssociationDone() {
380 CHECK_EQ(CONFIGURING, state_);
382 timer_.Stop();
384 // Treat any unfinished types as having errors.
385 desired_types_.RemoveAll(associating_types_);
386 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
387 it != controllers_->end(); ++it) {
388 DataTypeController* dtc = (*it).second.get();
389 if (associating_types_.Has(dtc->type()) &&
390 dtc->state() != DataTypeController::NOT_RUNNING) {
391 UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed",
392 ModelTypeToHistogramInt(dtc->type()),
393 syncer::MODEL_TYPE_COUNT);
394 StopDatatype(syncer::SyncError(FROM_HERE,
395 syncer::SyncError::DATATYPE_ERROR,
396 "Association timed out.",
397 dtc->type()),
398 dtc);
402 DataTypeManager::ConfigureResult result(configure_status_,
403 requested_types_);
405 // Reset state before notifying |delegate_| because that might
406 // trigger a new round of configuration.
407 ResetForNextAssociation();
408 state_ = IDLE;
410 delegate_->OnModelAssociationDone(result);
413 base::OneShotTimer<ModelAssociationManager>*
414 ModelAssociationManager::GetTimerForTesting() {
415 return &timer_;
418 } // namespace sync_driver