Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / components / sync_driver / data_type_manager_impl.cc
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/data_type_manager_impl.h"
6
7 #include <algorithm>
8 #include <functional>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/callback.h"
13 #include "base/compiler_specific.h"
14 #include "base/debug/trace_event.h"
15 #include "base/logging.h"
16 #include "base/metrics/histogram.h"
17 #include "base/strings/stringprintf.h"
18 #include "components/sync_driver/data_type_controller.h"
19 #include "components/sync_driver/data_type_encryption_handler.h"
20 #include "components/sync_driver/data_type_manager_observer.h"
21 #include "components/sync_driver/failed_data_types_handler.h"
22 #include "sync/internal_api/public/data_type_debug_info_listener.h"
23
24 namespace sync_driver {
25
26 namespace {
27
28 FailedDataTypesHandler::TypeErrorMap
29 GenerateCryptoErrorsForTypes(syncer::ModelTypeSet encrypted_types) {
30   FailedDataTypesHandler::TypeErrorMap crypto_errors;
31   for (syncer::ModelTypeSet::Iterator iter = encrypted_types.First();
32          iter.Good(); iter.Inc()) {
33     crypto_errors[iter.Get()] = syncer::SyncError(
34         FROM_HERE,
35         syncer::SyncError::CRYPTO_ERROR,
36         "",
37         iter.Get());
38   }
39   return crypto_errors;
40 }
41
42 }  // namespace
43
44 DataTypeManagerImpl::AssociationTypesInfo::AssociationTypesInfo() {}
45 DataTypeManagerImpl::AssociationTypesInfo::~AssociationTypesInfo() {}
46
47 DataTypeManagerImpl::DataTypeManagerImpl(
48     const base::Closure& unrecoverable_error_method,
49     const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
50         debug_info_listener,
51     const DataTypeController::TypeMap* controllers,
52     const DataTypeEncryptionHandler* encryption_handler,
53     BackendDataTypeConfigurer* configurer,
54     DataTypeManagerObserver* observer,
55     FailedDataTypesHandler* failed_data_types_handler)
56     : configurer_(configurer),
57       controllers_(controllers),
58       state_(DataTypeManager::STOPPED),
59       needs_reconfigure_(false),
60       last_configure_reason_(syncer::CONFIGURE_REASON_UNKNOWN),
61       debug_info_listener_(debug_info_listener),
62       model_association_manager_(controllers, this),
63       observer_(observer),
64       failed_data_types_handler_(failed_data_types_handler),
65       encryption_handler_(encryption_handler),
66       unrecoverable_error_method_(unrecoverable_error_method),
67       weak_ptr_factory_(this) {
68   DCHECK(failed_data_types_handler_);
69   DCHECK(configurer_);
70   DCHECK(observer_);
71 }
72
73 DataTypeManagerImpl::~DataTypeManagerImpl() {}
74
75 void DataTypeManagerImpl::Configure(syncer::ModelTypeSet desired_types,
76                                     syncer::ConfigureReason reason) {
77   if (reason == syncer::CONFIGURE_REASON_BACKUP_ROLLBACK)
78     desired_types.PutAll(syncer::ControlTypes());
79   else
80     desired_types.PutAll(syncer::CoreTypes());
81
82   // Only allow control types and types that have controllers.
83   syncer::ModelTypeSet filtered_desired_types;
84   for (syncer::ModelTypeSet::Iterator type = desired_types.First();
85       type.Good(); type.Inc()) {
86     DataTypeController::TypeMap::const_iterator iter =
87         controllers_->find(type.Get());
88     if (syncer::IsControlType(type.Get()) ||
89         iter != controllers_->end()) {
90       if (iter != controllers_->end()) {
91         if (!iter->second->ReadyForStart() &&
92             !failed_data_types_handler_->GetUnreadyErrorTypes().Has(
93                 type.Get())) {
94           // Add the type to the unready types set to prevent purging it. It's
95           // up to the datatype controller to, if necessary, explicitly
96           // mark the type as broken to trigger a purge.
97           syncer::SyncError error(FROM_HERE,
98                                   syncer::SyncError::UNREADY_ERROR,
99                                   "Datatype not ready at config time.",
100                                   type.Get());
101           std::map<syncer::ModelType, syncer::SyncError> errors;
102           errors[type.Get()] = error;
103           failed_data_types_handler_->UpdateFailedDataTypes(errors);
104         } else if (iter->second->ReadyForStart()) {
105           failed_data_types_handler_->ResetUnreadyErrorFor(type.Get());
106         }
107       }
108       filtered_desired_types.Put(type.Get());
109     }
110   }
111   ConfigureImpl(filtered_desired_types, reason);
112 }
113
114 void DataTypeManagerImpl::PurgeForMigration(
115     syncer::ModelTypeSet undesired_types,
116     syncer::ConfigureReason reason) {
117   syncer::ModelTypeSet remainder = Difference(last_requested_types_,
118                                               undesired_types);
119   ConfigureImpl(remainder, reason);
120 }
121
122 void DataTypeManagerImpl::ConfigureImpl(
123     syncer::ModelTypeSet desired_types,
124     syncer::ConfigureReason reason) {
125   DCHECK_NE(reason, syncer::CONFIGURE_REASON_UNKNOWN);
126   DVLOG(1) << "Configuring for " << syncer::ModelTypeSetToString(desired_types)
127            << " with reason " << reason;
128   if (state_ == STOPPING) {
129     // You can not set a configuration while stopping.
130     LOG(ERROR) << "Configuration set while stopping.";
131     return;
132   }
133
134   // TODO(zea): consider not performing a full configuration once there's a
135   // reliable way to determine if the requested set of enabled types matches the
136   // current set.
137
138   last_requested_types_ = desired_types;
139   last_configure_reason_ = reason;
140   // Only proceed if we're in a steady state or retrying.
141   if (state_ != STOPPED && state_ != CONFIGURED && state_ != RETRYING) {
142     DVLOG(1) << "Received configure request while configuration in flight. "
143              << "Postponing until current configuration complete.";
144     needs_reconfigure_ = true;
145     return;
146   }
147
148   Restart(reason);
149 }
150
151 BackendDataTypeConfigurer::DataTypeConfigStateMap
152 DataTypeManagerImpl::BuildDataTypeConfigStateMap(
153     const syncer::ModelTypeSet& types_being_configured) const {
154   // 1. Get the failed types (due to fatal, crypto, and unready errors).
155   // 2. Add the difference between last_requested_types_ and the failed types
156   //    as CONFIGURE_INACTIVE.
157   // 3. Flip |types_being_configured| to CONFIGURE_ACTIVE.
158   // 4. Set non-enabled user types as DISABLED.
159   // 5. Set the fatal, crypto, and unready types to their respective states.
160   syncer::ModelTypeSet error_types =
161       failed_data_types_handler_->GetFailedTypes();
162   syncer::ModelTypeSet fatal_types =
163       failed_data_types_handler_->GetFatalErrorTypes();
164   syncer::ModelTypeSet crypto_types =
165       failed_data_types_handler_->GetCryptoErrorTypes();
166   syncer::ModelTypeSet unready_types=
167       failed_data_types_handler_->GetUnreadyErrorTypes();
168
169   // Types with persistence errors are only purged/resynced when they're
170   // actively being configured.
171   syncer::ModelTypeSet persistence_types =
172       failed_data_types_handler_->GetPersistenceErrorTypes();
173   persistence_types.RetainAll(types_being_configured);
174
175   // Types with unready errors do not count as unready if they've been disabled.
176   unready_types.RetainAll(last_requested_types_);
177
178   syncer::ModelTypeSet enabled_types = last_requested_types_;
179   enabled_types.RemoveAll(error_types);
180   syncer::ModelTypeSet disabled_types =
181       syncer::Difference(
182           syncer::Union(syncer::UserTypes(), syncer::ControlTypes()),
183           enabled_types);
184   syncer::ModelTypeSet to_configure = syncer::Intersection(
185       enabled_types, types_being_configured);
186   DVLOG(1) << "Enabling: " << syncer::ModelTypeSetToString(enabled_types);
187   DVLOG(1) << "Configuring: " << syncer::ModelTypeSetToString(to_configure);
188   DVLOG(1) << "Disabling: " << syncer::ModelTypeSetToString(disabled_types);
189
190   BackendDataTypeConfigurer::DataTypeConfigStateMap config_state_map;
191   BackendDataTypeConfigurer::SetDataTypesState(
192       BackendDataTypeConfigurer::CONFIGURE_INACTIVE, enabled_types,
193       &config_state_map);
194   BackendDataTypeConfigurer::SetDataTypesState(
195       BackendDataTypeConfigurer::CONFIGURE_ACTIVE, to_configure,
196       &config_state_map);
197   BackendDataTypeConfigurer::SetDataTypesState(
198       BackendDataTypeConfigurer::CONFIGURE_CLEAN, persistence_types,
199         &config_state_map);
200   BackendDataTypeConfigurer::SetDataTypesState(
201       BackendDataTypeConfigurer::DISABLED, disabled_types,
202       &config_state_map);
203   BackendDataTypeConfigurer::SetDataTypesState(
204       BackendDataTypeConfigurer::FATAL, fatal_types,
205       &config_state_map);
206   BackendDataTypeConfigurer::SetDataTypesState(
207       BackendDataTypeConfigurer::CRYPTO, crypto_types,
208         &config_state_map);
209   BackendDataTypeConfigurer::SetDataTypesState(
210       BackendDataTypeConfigurer::UNREADY, unready_types,
211         &config_state_map);
212   return config_state_map;
213 }
214
215 void DataTypeManagerImpl::Restart(syncer::ConfigureReason reason) {
216   DVLOG(1) << "Restarting...";
217
218   // Check for new or resolved data type crypto errors.
219   if (encryption_handler_->IsPassphraseRequired()) {
220     syncer::ModelTypeSet encrypted_types =
221         encryption_handler_->GetEncryptedDataTypes();
222     encrypted_types.RetainAll(last_requested_types_);
223     encrypted_types.RemoveAll(
224         failed_data_types_handler_->GetCryptoErrorTypes());
225     FailedDataTypesHandler::TypeErrorMap crypto_errors =
226         GenerateCryptoErrorsForTypes(encrypted_types);
227     failed_data_types_handler_->UpdateFailedDataTypes(crypto_errors);
228   } else {
229     failed_data_types_handler_->ResetCryptoErrors();
230   }
231
232   syncer::ModelTypeSet failed_types =
233       failed_data_types_handler_->GetFailedTypes();
234   syncer::ModelTypeSet enabled_types =
235       syncer::Difference(last_requested_types_, failed_types);
236
237   last_restart_time_ = base::Time::Now();
238   configuration_stats_.clear();
239
240   DCHECK(state_ == STOPPED || state_ == CONFIGURED || state_ == RETRYING);
241
242   // Starting from a "steady state" (stopped or configured) state
243   // should send a start notification.
244   if (state_ == STOPPED || state_ == CONFIGURED)
245     NotifyStart();
246
247   model_association_manager_.Initialize(enabled_types);
248
249   download_types_queue_ = PrioritizeTypes(enabled_types);
250   association_types_queue_ = std::queue<AssociationTypesInfo>();
251
252   // Tell the backend about the new set of data types we wish to sync.
253   // The task will be invoked when updates are downloaded.
254   state_ = DOWNLOAD_PENDING;
255   configurer_->ConfigureDataTypes(
256       reason,
257       BuildDataTypeConfigStateMap(download_types_queue_.front()),
258       base::Bind(&DataTypeManagerImpl::DownloadReady,
259                  weak_ptr_factory_.GetWeakPtr(),
260                  base::Time::Now(),
261                  download_types_queue_.front(),
262                  syncer::ModelTypeSet()),
263       base::Bind(&DataTypeManagerImpl::OnDownloadRetry,
264                  weak_ptr_factory_.GetWeakPtr()));
265 }
266
267 syncer::ModelTypeSet DataTypeManagerImpl::GetPriorityTypes() const {
268   syncer::ModelTypeSet high_priority_types;
269   high_priority_types.PutAll(syncer::PriorityCoreTypes());
270   high_priority_types.PutAll(syncer::PriorityUserTypes());
271   return high_priority_types;
272 }
273
274 TypeSetPriorityList DataTypeManagerImpl::PrioritizeTypes(
275     const syncer::ModelTypeSet& types) {
276   syncer::ModelTypeSet high_priority_types = GetPriorityTypes();
277   high_priority_types.RetainAll(types);
278
279   syncer::ModelTypeSet low_priority_types =
280       syncer::Difference(types, high_priority_types);
281
282   TypeSetPriorityList result;
283   if (!high_priority_types.Empty())
284     result.push(high_priority_types);
285   if (!low_priority_types.Empty())
286     result.push(low_priority_types);
287
288   // Could be empty in case of purging for migration, sync nothing, etc.
289   // Configure empty set to purge data from backend.
290   if (result.empty())
291     result.push(syncer::ModelTypeSet());
292
293   return result;
294 }
295
296 void DataTypeManagerImpl::ProcessReconfigure() {
297   DCHECK(needs_reconfigure_);
298
299   // Wait for current download and association to finish.
300   if (!(download_types_queue_.empty() && association_types_queue_.empty()))
301     return;
302
303   // An attempt was made to reconfigure while we were already configuring.
304   // This can be because a passphrase was accepted or the user changed the
305   // set of desired types. Either way, |last_requested_types_| will contain
306   // the most recent set of desired types, so we just call configure.
307   // Note: we do this whether or not GetControllersNeedingStart is true,
308   // because we may need to stop datatypes.
309   DVLOG(1) << "Reconfiguring due to previous configure attempt occuring while"
310            << " busy.";
311
312   // Note: ConfigureImpl is called directly, rather than posted, in order to
313   // ensure that any purging/unapplying/journaling happens while the set of
314   // failed types is still up to date. If stack unwinding were to be done
315   // via PostTask, the failed data types may be reset before the purging was
316   // performed.
317   state_ = RETRYING;
318   needs_reconfigure_ = false;
319   ConfigureImpl(last_requested_types_, last_configure_reason_);
320 }
321
322 void DataTypeManagerImpl::OnDownloadRetry() {
323   DCHECK(state_ == DOWNLOAD_PENDING || state_ == CONFIGURING);
324   observer_->OnConfigureRetry();
325 }
326
327 void DataTypeManagerImpl::DownloadReady(
328     base::Time download_start_time,
329     syncer::ModelTypeSet types_to_download,
330     syncer::ModelTypeSet high_priority_types_before,
331     syncer::ModelTypeSet first_sync_types,
332     syncer::ModelTypeSet failed_configuration_types) {
333   DCHECK(state_ == DOWNLOAD_PENDING || state_ == CONFIGURING);
334
335   // Persistence errors are reset after each backend configuration attempt
336   // during which they would have been purged.
337   failed_data_types_handler_->ResetPersistenceErrorsFrom(types_to_download);
338
339   // Ignore |failed_configuration_types| if we need to reconfigure
340   // anyway.
341   if (needs_reconfigure_) {
342     download_types_queue_ = TypeSetPriorityList();
343     ProcessReconfigure();
344     return;
345   }
346
347   if (!failed_configuration_types.Empty()) {
348     if (!unrecoverable_error_method_.is_null())
349       unrecoverable_error_method_.Run();
350     FailedDataTypesHandler::TypeErrorMap errors;
351     for (syncer::ModelTypeSet::Iterator iter =
352              failed_configuration_types.First(); iter.Good(); iter.Inc()) {
353       syncer::SyncError error(
354           FROM_HERE,
355           syncer::SyncError::UNRECOVERABLE_ERROR,
356           "Backend failed to download type.",
357           iter.Get());
358       errors[iter.Get()] = error;
359     }
360     failed_data_types_handler_->UpdateFailedDataTypes(errors);
361     Abort(UNRECOVERABLE_ERROR);
362     return;
363   }
364
365   state_ = CONFIGURING;
366
367   // Pop and associate download-ready types.
368   syncer::ModelTypeSet ready_types = types_to_download;
369   download_types_queue_.pop();
370   syncer::ModelTypeSet new_types_to_download;
371   if (!download_types_queue_.empty())
372     new_types_to_download = download_types_queue_.front();
373
374   AssociationTypesInfo association_info;
375   association_info.types = ready_types;
376   association_info.first_sync_types = first_sync_types;
377   association_info.download_start_time = download_start_time;
378   association_info.download_ready_time = base::Time::Now();
379   association_info.high_priority_types_before = high_priority_types_before;
380   association_types_queue_.push(association_info);
381   if (association_types_queue_.size() == 1u)
382     StartNextAssociation();
383
384   // Download types of low priority while configuring types of high priority.
385   if (!new_types_to_download.Empty()) {
386     configurer_->ConfigureDataTypes(
387         last_configure_reason_,
388         BuildDataTypeConfigStateMap(new_types_to_download),
389         base::Bind(&DataTypeManagerImpl::DownloadReady,
390                    weak_ptr_factory_.GetWeakPtr(),
391                    base::Time::Now(),
392                    new_types_to_download,
393                    syncer::Union(ready_types, high_priority_types_before)),
394         base::Bind(&DataTypeManagerImpl::OnDownloadRetry,
395                    weak_ptr_factory_.GetWeakPtr()));
396   }
397 }
398
399 void DataTypeManagerImpl::StartNextAssociation() {
400   CHECK(!association_types_queue_.empty());
401
402   association_types_queue_.front().association_request_time =
403       base::Time::Now();
404   model_association_manager_.StartAssociationAsync(
405       association_types_queue_.front().types);
406 }
407
408 void DataTypeManagerImpl::OnSingleDataTypeWillStop(
409     syncer::ModelType type,
410     const syncer::SyncError& error) {
411   configurer_->DeactivateDataType(type);
412   if (error.IsSet()) {
413     FailedDataTypesHandler::TypeErrorMap failed_types;
414     failed_types[type] = error;
415     failed_data_types_handler_->UpdateFailedDataTypes(
416             failed_types);
417
418     // Unrecoverable errors will shut down the entire backend, so no need to
419     // reconfigure.
420     if (error.error_type() != syncer::SyncError::UNRECOVERABLE_ERROR) {
421       needs_reconfigure_ = true;
422       ProcessReconfigure();
423     } else {
424       DCHECK_EQ(state_, CONFIGURING);
425     }
426   }
427 }
428
429 void DataTypeManagerImpl::OnSingleDataTypeAssociationDone(
430     syncer::ModelType type,
431     const syncer::DataTypeAssociationStats& association_stats) {
432   DCHECK(!association_types_queue_.empty());
433   DataTypeController::TypeMap::const_iterator c_it = controllers_->find(type);
434   DCHECK(c_it != controllers_->end());
435   if (c_it->second->state() == DataTypeController::RUNNING) {
436     // Tell the backend about the change processor for this type so it can
437     // begin routing changes to it.
438     configurer_->ActivateDataType(type, c_it->second->model_safe_group(),
439                                   c_it->second->GetChangeProcessor());
440   }
441
442   if (!debug_info_listener_.IsInitialized())
443     return;
444
445   AssociationTypesInfo& info = association_types_queue_.front();
446   configuration_stats_.push_back(syncer::DataTypeConfigurationStats());
447   configuration_stats_.back().model_type = type;
448   configuration_stats_.back().association_stats = association_stats;
449   if (info.types.Has(type)) {
450     // Times in |info| only apply to non-slow types.
451     configuration_stats_.back().download_wait_time =
452         info.download_start_time - last_restart_time_;
453     if (info.first_sync_types.Has(type)) {
454       configuration_stats_.back().download_time =
455           info.download_ready_time - info.download_start_time;
456     }
457     configuration_stats_.back().association_wait_time_for_high_priority =
458         info.association_request_time - info.download_ready_time;
459     configuration_stats_.back().high_priority_types_configured_before =
460         info.high_priority_types_before;
461     configuration_stats_.back().same_priority_types_configured_before =
462         info.configured_types;
463     info.configured_types.Put(type);
464   }
465 }
466
467 void DataTypeManagerImpl::OnModelAssociationDone(
468     const DataTypeManager::ConfigureResult& result) {
469   DCHECK(state_ == STOPPING || state_ == CONFIGURING);
470
471   if (state_ == STOPPING)
472     return;
473
474   // Ignore abort/unrecoverable error if we need to reconfigure anyways.
475   if (needs_reconfigure_) {
476     association_types_queue_ = std::queue<AssociationTypesInfo>();
477     ProcessReconfigure();
478     return;
479   }
480
481   if (result.status == ABORTED || result.status == UNRECOVERABLE_ERROR) {
482     Abort(result.status);
483     return;
484   }
485
486   DCHECK(result.status == OK);
487
488   association_types_queue_.pop();
489   if (!association_types_queue_.empty()) {
490     StartNextAssociation();
491   } else if (download_types_queue_.empty()) {
492     state_ = CONFIGURED;
493     NotifyDone(result);
494   }
495 }
496
497 void DataTypeManagerImpl::Stop() {
498   if (state_ == STOPPED)
499     return;
500
501   bool need_to_notify =
502       state_ == DOWNLOAD_PENDING || state_ == CONFIGURING;
503   StopImpl();
504
505   if (need_to_notify) {
506     ConfigureResult result(ABORTED,
507                            last_requested_types_);
508     NotifyDone(result);
509   }
510 }
511
512 void DataTypeManagerImpl::Abort(ConfigureStatus status) {
513   DCHECK(state_ == DOWNLOAD_PENDING || state_ == CONFIGURING);
514
515   StopImpl();
516
517   DCHECK_NE(OK, status);
518   ConfigureResult result(status,
519                          last_requested_types_);
520   NotifyDone(result);
521 }
522
523 void DataTypeManagerImpl::StopImpl() {
524   state_ = STOPPING;
525
526   // Invalidate weak pointer to drop download callbacks.
527   weak_ptr_factory_.InvalidateWeakPtrs();
528
529   // Stop all data types. This may trigger association callback but the
530   // callback will do nothing because state is set to STOPPING above.
531   model_association_manager_.Stop();
532
533   state_ = STOPPED;
534 }
535
536 void DataTypeManagerImpl::NotifyStart() {
537   observer_->OnConfigureStart();
538 }
539
540 void DataTypeManagerImpl::NotifyDone(const ConfigureResult& result) {
541   AddToConfigureTime();
542
543   DVLOG(1) << "Total time spent configuring: "
544            << configure_time_delta_.InSecondsF() << "s";
545   switch (result.status) {
546     case DataTypeManager::OK:
547       DVLOG(1) << "NotifyDone called with result: OK";
548       UMA_HISTOGRAM_LONG_TIMES("Sync.ConfigureTime_Long.OK",
549                                configure_time_delta_);
550       if (debug_info_listener_.IsInitialized() &&
551           !configuration_stats_.empty()) {
552         debug_info_listener_.Call(
553             FROM_HERE,
554             &syncer::DataTypeDebugInfoListener::OnDataTypeConfigureComplete,
555             configuration_stats_);
556       }
557       configuration_stats_.clear();
558       break;
559     case DataTypeManager::ABORTED:
560       DVLOG(1) << "NotifyDone called with result: ABORTED";
561       UMA_HISTOGRAM_LONG_TIMES("Sync.ConfigureTime_Long.ABORTED",
562                                configure_time_delta_);
563       break;
564     case DataTypeManager::UNRECOVERABLE_ERROR:
565       DVLOG(1) << "NotifyDone called with result: UNRECOVERABLE_ERROR";
566       UMA_HISTOGRAM_LONG_TIMES("Sync.ConfigureTime_Long.UNRECOVERABLE_ERROR",
567                                configure_time_delta_);
568       break;
569     case DataTypeManager::UNKNOWN:
570       NOTREACHED();
571       break;
572   }
573   observer_->OnConfigureDone(result);
574 }
575
576 DataTypeManager::State DataTypeManagerImpl::state() const {
577   return state_;
578 }
579
580 void DataTypeManagerImpl::AddToConfigureTime() {
581   DCHECK(!last_restart_time_.is_null());
582   configure_time_delta_ += (base::Time::Now() - last_restart_time_);
583 }
584
585 }  // namespace sync_driver