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

Side by Side Diff: chrome/browser/sync/glue/model_association_manager.cc

Issue 133503011: Move files from //chrome/browser/sync to sync_driver component. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 10 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 | Annotate | Revision Log
OLDNEW
(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 "chrome/browser/sync/glue/model_association_manager.h"
6
7 #include <algorithm>
8 #include <functional>
9
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 "content/public/browser/browser_thread.h"
15 #include "sync/internal_api/public/base/model_type.h"
16
17 using content::BrowserThread;
18 using syncer::ModelTypeSet;
19
20 namespace browser_sync {
21
22 namespace {
23
24 static const syncer::ModelType kStartOrder[] = {
25 syncer::NIGORI, // Listed for completeness.
26 syncer::DEVICE_INFO, // Listed for completeness.
27 syncer::EXPERIMENTS, // Listed for completeness.
28 syncer::PROXY_TABS, // Listed for completeness.
29
30 // Kick off the association of the non-UI types first so they can associate
31 // in parallel with the UI types.
32 syncer::PASSWORDS,
33 syncer::AUTOFILL,
34 syncer::AUTOFILL_PROFILE,
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,
41
42 // UI thread data types.
43 syncer::BOOKMARKS,
44 syncer::MANAGED_USERS, // Syncing managed users on initial login might
45 // block creating a new managed user, so we
46 // 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::MANAGED_USER_SETTINGS,
60 syncer::MANAGED_USER_SHARED_SETTINGS,
61 syncer::ARTICLES,
62 };
63
64 COMPILE_ASSERT(arraysize(kStartOrder) ==
65 syncer::MODEL_TYPE_COUNT - syncer::FIRST_REAL_MODEL_TYPE,
66 kStartOrder_IncorrectSize);
67
68 // The amount of time we wait for association to finish. If some types haven't
69 // finished association by the time, configuration result will be
70 // PARTIAL_SUCCESS and DataTypeManager is notified of the unfinished types.
71 const int64 kAssociationTimeOutInSeconds = 600;
72
73 syncer::DataTypeAssociationStats BuildAssociationStatsFromMergeResults(
74 const syncer::SyncMergeResult& local_merge_result,
75 const syncer::SyncMergeResult& syncer_merge_result,
76 const base::TimeDelta& association_wait_time,
77 const base::TimeDelta& association_time) {
78 DCHECK_EQ(local_merge_result.model_type(), syncer_merge_result.model_type());
79 syncer::DataTypeAssociationStats stats;
80 stats.had_error = local_merge_result.error().IsSet() ||
81 syncer_merge_result.error().IsSet();
82 stats.num_local_items_before_association =
83 local_merge_result.num_items_before_association();
84 stats.num_sync_items_before_association =
85 syncer_merge_result.num_items_before_association();
86 stats.num_local_items_after_association =
87 local_merge_result.num_items_after_association();
88 stats.num_sync_items_after_association =
89 syncer_merge_result.num_items_after_association();
90 stats.num_local_items_added =
91 local_merge_result.num_items_added();
92 stats.num_local_items_deleted =
93 local_merge_result.num_items_deleted();
94 stats.num_local_items_modified =
95 local_merge_result.num_items_modified();
96 stats.local_version_pre_association =
97 local_merge_result.pre_association_version();
98 stats.num_sync_items_added =
99 syncer_merge_result.num_items_added();
100 stats.num_sync_items_deleted =
101 syncer_merge_result.num_items_deleted();
102 stats.num_sync_items_modified =
103 syncer_merge_result.num_items_modified();
104 stats.sync_version_pre_association =
105 syncer_merge_result.pre_association_version();
106 stats.association_wait_time = association_wait_time;
107 stats.association_time = association_time;
108 return stats;
109 }
110
111 } // namespace
112
113 ModelAssociationManager::ModelAssociationManager(
114 const DataTypeController::TypeMap* controllers,
115 ModelAssociationResultProcessor* processor)
116 : state_(IDLE),
117 controllers_(controllers),
118 result_processor_(processor),
119 weak_ptr_factory_(this),
120 configure_status_(DataTypeManager::UNKNOWN) {
121 // Ensure all data type controllers are stopped.
122 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
123 it != controllers_->end(); ++it) {
124 DCHECK_EQ(DataTypeController::NOT_RUNNING, (*it).second->state());
125 }
126 }
127
128 ModelAssociationManager::~ModelAssociationManager() {
129 }
130
131 void ModelAssociationManager::Initialize(syncer::ModelTypeSet desired_types) {
132 // state_ can be INITIALIZED_TO_CONFIGURE if types are reconfigured when
133 // data is being downloaded, so StartAssociationAsync() is never called for
134 // the first configuration.
135 DCHECK_NE(CONFIGURING, state_);
136
137 // Only keep types that have controllers.
138 desired_types_.Clear();
139 slow_types_.Clear();
140 for (syncer::ModelTypeSet::Iterator it = desired_types.First();
141 it.Good(); it.Inc()) {
142 if (controllers_->find(it.Get()) != controllers_->end())
143 desired_types_.Put(it.Get());
144 }
145
146 DVLOG(1) << "ModelAssociationManager: Initializing for "
147 << syncer::ModelTypeSetToString(desired_types_);
148
149 state_ = INITIALIZED_TO_CONFIGURE;
150
151 StopDisabledTypes();
152 LoadEnabledTypes();
153 }
154
155 void ModelAssociationManager::StopDisabledTypes() {
156 DVLOG(1) << "ModelAssociationManager: Stopping disabled types.";
157 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
158 it != controllers_->end(); ++it) {
159 DataTypeController* dtc = (*it).second.get();
160 if (dtc->state() != DataTypeController::NOT_RUNNING &&
161 (!desired_types_.Has(dtc->type()) ||
162 failed_data_types_info_.count(dtc->type()) > 0)) {
163 DVLOG(1) << "ModelTypeToString: stop " << dtc->name();
164 dtc->Stop();
165
166 loaded_types_.Remove(dtc->type());
167 associated_types_.Remove(dtc->type());
168 }
169 }
170 }
171
172 void ModelAssociationManager::LoadEnabledTypes() {
173 // Load in kStartOrder.
174 for (size_t i = 0; i < arraysize(kStartOrder); i++) {
175 syncer::ModelType type = kStartOrder[i];
176 if (!desired_types_.Has(type))
177 continue;
178
179 DCHECK(controllers_->find(type) != controllers_->end());
180 DataTypeController* dtc = controllers_->find(type)->second.get();
181 if (dtc->state() == DataTypeController::NOT_RUNNING) {
182 DCHECK(!loaded_types_.Has(dtc->type()));
183 DCHECK(!associated_types_.Has(dtc->type()));
184 dtc->LoadModels(base::Bind(&ModelAssociationManager::ModelLoadCallback,
185 weak_ptr_factory_.GetWeakPtr()));
186 }
187 }
188 }
189
190 void ModelAssociationManager::StartAssociationAsync(
191 const syncer::ModelTypeSet& types_to_associate) {
192 DCHECK_NE(CONFIGURING, state_);
193 state_ = CONFIGURING;
194
195 association_start_time_ = base::TimeTicks::Now();
196
197 requested_types_ = types_to_associate;
198
199 associating_types_ = types_to_associate;
200 associating_types_.RetainAll(desired_types_);
201 associating_types_.RemoveAll(associated_types_);
202
203 // Assume success.
204 configure_status_ = DataTypeManager::OK;
205
206 // Remove types that already failed.
207 for (std::map<syncer::ModelType, syncer::SyncError>::const_iterator it =
208 failed_data_types_info_.begin();
209 it != failed_data_types_info_.end(); ++it) {
210 associating_types_.Remove(it->first);
211 }
212
213 // Done if no types to associate.
214 if (associating_types_.Empty()) {
215 ModelAssociationDone();
216 return;
217 }
218
219 timer_.Start(FROM_HERE,
220 base::TimeDelta::FromSeconds(kAssociationTimeOutInSeconds),
221 this,
222 &ModelAssociationManager::ModelAssociationDone);
223
224 // Start association of types that are loaded in specified order.
225 for (size_t i = 0; i < arraysize(kStartOrder); i++) {
226 syncer::ModelType type = kStartOrder[i];
227 if (!associating_types_.Has(type) || !loaded_types_.Has(type))
228 continue;
229
230 DataTypeController* dtc = controllers_->find(type)->second.get();
231 DCHECK(DataTypeController::MODEL_LOADED == dtc->state() ||
232 DataTypeController::ASSOCIATING == dtc->state());
233 if (dtc->state() == DataTypeController::MODEL_LOADED) {
234 TRACE_EVENT_ASYNC_BEGIN1("sync", "ModelAssociation",
235 dtc,
236 "DataType",
237 ModelTypeToString(type));
238
239 dtc->StartAssociating(
240 base::Bind(&ModelAssociationManager::TypeStartCallback,
241 weak_ptr_factory_.GetWeakPtr(),
242 type, base::TimeTicks::Now()));
243 }
244 }
245 }
246
247 void ModelAssociationManager::ResetForNextAssociation() {
248 DVLOG(1) << "ModelAssociationManager: Reseting for next configuration";
249 // |loaded_types_| and |associated_types_| are not cleared. So
250 // reconfiguration won't restart types that are already started.
251 requested_types_.Clear();
252 failed_data_types_info_.clear();
253 associating_types_.Clear();
254 needs_crypto_types_.Clear();
255 }
256
257 void ModelAssociationManager::Stop() {
258 // Ignore callbacks from controllers.
259 weak_ptr_factory_.InvalidateWeakPtrs();
260
261 // Stop started data types.
262 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
263 it != controllers_->end(); ++it) {
264 DataTypeController* dtc = (*it).second.get();
265 if (dtc->state() != DataTypeController::NOT_RUNNING) {
266 dtc->Stop();
267 DVLOG(1) << "ModelAssociationManager: Stopped " << dtc->name();
268 }
269 }
270
271 desired_types_.Clear();
272 loaded_types_.Clear();
273 associated_types_.Clear();
274 slow_types_.Clear();
275
276 if (state_ == CONFIGURING) {
277 if (configure_status_ == DataTypeManager::OK)
278 configure_status_ = DataTypeManager::ABORTED;
279 DVLOG(1) << "ModelAssociationManager: Calling OnModelAssociationDone";
280 ModelAssociationDone();
281 }
282
283 ResetForNextAssociation();
284
285 state_ = IDLE;
286 }
287
288 void ModelAssociationManager::AppendToFailedDatatypesAndLogError(
289 const syncer::SyncError& error) {
290 failed_data_types_info_[error.model_type()] = error;
291 LOG(ERROR) << "Failed to associate models for "
292 << syncer::ModelTypeToString(error.model_type());
293 UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed",
294 ModelTypeToHistogramInt(error.model_type()),
295 syncer::MODEL_TYPE_COUNT);
296 }
297
298 void ModelAssociationManager::ModelLoadCallback(syncer::ModelType type,
299 syncer::SyncError error) {
300 DVLOG(1) << "ModelAssociationManager: ModelLoadCallback for "
301 << syncer::ModelTypeToString(type);
302
303 // TODO(haitaol): temporary fix for 335606.
304 if (slow_types_.Has(type))
305 return;
306
307 // This happens when slow loading type is disabled by new configuration.
308 if (!desired_types_.Has(type))
309 return;
310
311 DCHECK(!loaded_types_.Has(type));
312 if (error.IsSet()) {
313 syncer::SyncMergeResult local_merge_result(type);
314 local_merge_result.set_error(error);
315 TypeStartCallback(type,
316 base::TimeTicks::Now(),
317 DataTypeController::ASSOCIATION_FAILED,
318 local_merge_result,
319 syncer::SyncMergeResult(type));
320 return;
321 }
322
323 loaded_types_.Put(type);
324 if (associating_types_.Has(type) || slow_types_.Has(type)) {
325 DataTypeController* dtc = controllers_->find(type)->second.get();
326 dtc->StartAssociating(
327 base::Bind(&ModelAssociationManager::TypeStartCallback,
328 weak_ptr_factory_.GetWeakPtr(),
329 type, base::TimeTicks::Now()));
330 }
331 }
332
333 void ModelAssociationManager::TypeStartCallback(
334 syncer::ModelType type,
335 base::TimeTicks type_start_time,
336 DataTypeController::StartResult start_result,
337 const syncer::SyncMergeResult& local_merge_result,
338 const syncer::SyncMergeResult& syncer_merge_result) {
339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
340
341 // TODO(haitaol): temporary fix for 335606.
342 if (slow_types_.Has(type))
343 return;
344
345 // This happens when slow associating type is disabled by new configuration.
346 if (!desired_types_.Has(type))
347 return;
348
349 slow_types_.Remove(type);
350
351 DCHECK(!associated_types_.Has(type));
352 if (DataTypeController::IsSuccessfulResult(start_result)) {
353 associated_types_.Put(type);
354 } else if (state_ == IDLE) {
355 // For type that failed in IDLE mode, simply stop the controller. Next
356 // configuration will try to restart from scratch if the type is still
357 // enabled.
358 DataTypeController* dtc = controllers_->find(type)->second.get();
359 if (dtc->state() != DataTypeController::NOT_RUNNING)
360 dtc->Stop();
361 loaded_types_.Remove(type);
362 } else {
363 // Record error in CONFIGURING or INITIALIZED_TO_CONFIGURE mode. The error
364 // will be reported when data types association finishes.
365 if (start_result == DataTypeController::NEEDS_CRYPTO) {
366 DVLOG(1) << "ModelAssociationManager: Encountered an undecryptable type";
367 needs_crypto_types_.Put(type);
368 } else {
369 DVLOG(1) << "ModelAssociationManager: Encountered a failed type";
370 AppendToFailedDatatypesAndLogError(local_merge_result.error());
371 }
372 }
373
374 if (state_ != CONFIGURING)
375 return;
376
377 TRACE_EVENT_ASYNC_END1("sync", "ModelAssociation",
378 controllers_->find(type)->second.get(),
379 "DataType",
380 ModelTypeToString(type));
381
382 // Track the merge results if we succeeded or an association failure
383 // occurred.
384 if ((DataTypeController::IsSuccessfulResult(start_result) ||
385 start_result == DataTypeController::ASSOCIATION_FAILED) &&
386 syncer::ProtocolTypes().Has(type)) {
387 base::TimeDelta association_wait_time =
388 std::max(base::TimeDelta(), type_start_time - association_start_time_);
389 base::TimeDelta association_time =
390 base::TimeTicks::Now() - type_start_time;;
391 syncer::DataTypeAssociationStats stats =
392 BuildAssociationStatsFromMergeResults(local_merge_result,
393 syncer_merge_result,
394 association_wait_time,
395 association_time);
396 result_processor_->OnSingleDataTypeAssociationDone(type, stats);
397 }
398
399 // Update configuration result.
400 if (configure_status_ == DataTypeManager::OK &&
401 start_result == DataTypeController::ASSOCIATION_FAILED) {
402 configure_status_ = DataTypeManager::PARTIAL_SUCCESS;
403 }
404 if (start_result == DataTypeController::UNRECOVERABLE_ERROR)
405 configure_status_ = DataTypeManager::UNRECOVERABLE_ERROR;
406
407 associating_types_.Remove(type);
408
409 if (associating_types_.Empty())
410 ModelAssociationDone();
411 }
412
413 void ModelAssociationManager::ModelAssociationDone() {
414 CHECK_EQ(CONFIGURING, state_);
415
416 timer_.Stop();
417
418 slow_types_.PutAll(associating_types_);
419
420 // TODO(haitaol): temporary fix for 335606.
421 for (syncer::ModelTypeSet::Iterator it = associating_types_.First();
422 it.Good(); it.Inc()) {
423 AppendToFailedDatatypesAndLogError(
424 syncer::SyncError(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
425 "Association timed out.", it.Get()));
426 }
427
428 // Stop controllers of failed types.
429 StopDisabledTypes();
430
431 if (configure_status_ == DataTypeManager::OK &&
432 (!associating_types_.Empty() || !failed_data_types_info_.empty() ||
433 !needs_crypto_types_.Empty())) {
434 // We have not configured all types that we have been asked to configure.
435 // Either we have failed types or types that have not completed loading
436 // yet.
437 DVLOG(1) << "ModelAssociationManager: setting partial success";
438 configure_status_ = DataTypeManager::PARTIAL_SUCCESS;
439 }
440
441 DataTypeManager::ConfigureResult result(configure_status_,
442 requested_types_,
443 failed_data_types_info_,
444 associating_types_,
445 needs_crypto_types_);
446
447 // Reset state before notifying |result_processor_| because that might
448 // trigger a new round of configuration.
449 ResetForNextAssociation();
450 state_ = IDLE;
451
452 result_processor_->OnModelAssociationDone(result);
453 }
454
455 base::OneShotTimer<ModelAssociationManager>*
456 ModelAssociationManager::GetTimerForTesting() {
457 return &timer_;
458 }
459
460 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698