Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / components / sync_driver / model_association_manager.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/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 "sync/internal_api/public/base/model_type.h"
15
16 using syncer::ModelTypeSet;
17
18 namespace sync_driver {
19
20 namespace {
21
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.
27
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,
39
40   // UI thread data types.
41   syncer::BOOKMARKS,
42   syncer::SUPERVISED_USERS,     //  Syncing supervised users on initial login
43                                 //  might block creating a new supervised user,
44                                 //  so we want to do it early.
45   syncer::PREFERENCES,
46   syncer::PRIORITY_PREFERENCES,
47   syncer::EXTENSIONS,
48   syncer::APPS,
49   syncer::APP_LIST,
50   syncer::THEMES,
51   syncer::SEARCH_ENGINES,
52   syncer::SESSIONS,
53   syncer::APP_NOTIFICATIONS,
54   syncer::DICTIONARY,
55   syncer::FAVICON_IMAGES,
56   syncer::FAVICON_TRACKING,
57   syncer::SUPERVISED_USER_SETTINGS,
58   syncer::SUPERVISED_USER_SHARED_SETTINGS,
59   syncer::ARTICLES,
60   syncer::WIFI_CREDENTIALS,
61 };
62
63 COMPILE_ASSERT(arraysize(kStartOrder) ==
64                syncer::MODEL_TYPE_COUNT - syncer::FIRST_REAL_MODEL_TYPE,
65                kStartOrder_IncorrectSize);
66
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;
71
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;
108 }
109
110 }  // namespace
111
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());
124   }
125 }
126
127 ModelAssociationManager::~ModelAssociationManager() {
128 }
129
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_);
135
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());
142   }
143
144   DVLOG(1) << "ModelAssociationManager: Initializing for "
145            << syncer::ModelTypeSetToString(desired_types_);
146
147   state_ = INITIALIZED_TO_CONFIGURE;
148
149   StopDisabledTypes();
150   LoadEnabledTypes();
151 }
152
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());
159
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();
164   }
165 }
166
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);
176     }
177   }
178 }
179
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;
186
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()));
194     }
195   }
196 }
197
198 void ModelAssociationManager::StartAssociationAsync(
199     const syncer::ModelTypeSet& types_to_associate) {
200   DCHECK_NE(CONFIGURING, state_);
201   state_ = CONFIGURING;
202
203   association_start_time_ = base::TimeTicks::Now();
204
205   requested_types_ = types_to_associate;
206
207   associating_types_ = types_to_associate;
208   associating_types_.RetainAll(desired_types_);
209   associating_types_.RemoveAll(associated_types_);
210
211   // Assume success.
212   configure_status_ = DataTypeManager::OK;
213
214   // Done if no types to associate.
215   if (associating_types_.Empty()) {
216     ModelAssociationDone();
217     return;
218   }
219
220   timer_.Start(FROM_HERE,
221                base::TimeDelta::FromSeconds(kAssociationTimeOutInSeconds),
222                this,
223                &ModelAssociationManager::ModelAssociationDone);
224
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;
230
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));
239
240       dtc->StartAssociating(
241           base::Bind(&ModelAssociationManager::TypeStartCallback,
242                      weak_ptr_factory_.GetWeakPtr(),
243                      type, base::TimeTicks::Now()));
244     }
245   }
246 }
247
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();
254 }
255
256 void ModelAssociationManager::Stop() {
257   // Ignore callbacks from controllers.
258   weak_ptr_factory_.InvalidateWeakPtrs();
259
260   desired_types_.Clear();
261   loaded_types_.Clear();
262   associated_types_.Clear();
263   associating_types_.Clear();
264
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();
272     }
273   }
274
275   if (state_ == CONFIGURING) {
276     if (configure_status_ == DataTypeManager::OK)
277       configure_status_ = DataTypeManager::ABORTED;
278     DVLOG(1) << "ModelAssociationManager: Calling OnModelAssociationDone";
279     ModelAssociationDone();
280   }
281
282   ResetForNextAssociation();
283
284   state_ = IDLE;
285 }
286
287 void ModelAssociationManager::ModelLoadCallback(syncer::ModelType type,
288                                                 syncer::SyncError error) {
289   DVLOG(1) << "ModelAssociationManager: ModelLoadCallback for "
290       << syncer::ModelTypeToString(type);
291
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;
301   }
302
303   // This happens when slow loading type is disabled by new configuration.
304   if (!desired_types_.Has(type))
305     return;
306
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()));
315   }
316 }
317
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);
330
331     // Update configuration result.
332     if (start_result == DataTypeController::UNRECOVERABLE_ERROR)
333       configure_status_ = DataTypeManager::UNRECOVERABLE_ERROR;
334   }
335
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;
344   }
345
346   DCHECK(!associated_types_.Has(type));
347   DCHECK(DataTypeController::IsSuccessfulResult(start_result));
348   associated_types_.Put(type);
349
350   if (state_ != CONFIGURING)
351     return;
352
353   TRACE_EVENT_ASYNC_END1("sync", "ModelAssociation",
354                          controllers_->find(type)->second.get(),
355                          "DataType",
356                          ModelTypeToString(type));
357
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);
371   }
372
373   associating_types_.Remove(type);
374
375   if (associating_types_.Empty())
376     ModelAssociationDone();
377 }
378
379 void ModelAssociationManager::ModelAssociationDone() {
380   CHECK_EQ(CONFIGURING, state_);
381
382   timer_.Stop();
383
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);
399     }
400   }
401
402   DataTypeManager::ConfigureResult result(configure_status_,
403                                           requested_types_);
404
405   // Reset state before notifying |delegate_| because that might
406   // trigger a new round of configuration.
407   ResetForNextAssociation();
408   state_ = IDLE;
409
410   delegate_->OnModelAssociationDone(result);
411 }
412
413 base::OneShotTimer<ModelAssociationManager>*
414     ModelAssociationManager::GetTimerForTesting() {
415   return &timer_;
416 }
417
418 }  // namespace sync_driver