OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <algorithm> | 5 #include <algorithm> |
6 #include <functional> | 6 #include <functional> |
7 | 7 |
8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
13 | 13 |
14 #include "chrome/browser/sync/glue/model_association_manager.h" | 14 #include "chrome/browser/sync/glue/model_association_manager.h" |
15 | 15 |
16 #include "content/public/browser/browser_thread.h" | 16 #include "content/public/browser/browser_thread.h" |
17 | 17 |
18 using content::BrowserThread; | 18 using content::BrowserThread; |
19 using syncable::ModelTypeSet; | 19 using syncable::ModelTypeSet; |
20 | 20 |
21 namespace browser_sync { | 21 namespace browser_sync { |
22 const int64 kDataTypeLoadWaitTimeInSeconds = 120; | |
22 namespace { | 23 namespace { |
23 | 24 |
24 static const syncable::ModelType kStartOrder[] = { | 25 static const syncable::ModelType kStartOrder[] = { |
25 syncable::NIGORI, // Listed for completeness. | 26 syncable::NIGORI, // Listed for completeness. |
26 syncable::BOOKMARKS, | 27 syncable::BOOKMARKS, |
27 syncable::PREFERENCES, | 28 syncable::PREFERENCES, |
28 syncable::AUTOFILL, | 29 syncable::AUTOFILL, |
29 syncable::AUTOFILL_PROFILE, | 30 syncable::AUTOFILL_PROFILE, |
30 syncable::EXTENSION_SETTINGS, | 31 syncable::EXTENSION_SETTINGS, |
31 syncable::EXTENSIONS, | 32 syncable::EXTENSIONS, |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
80 // Build a ModelType -> order map for sorting. | 81 // Build a ModelType -> order map for sorting. |
81 for (int i = 0; i < static_cast<int>(arraysize(kStartOrder)); i++) | 82 for (int i = 0; i < static_cast<int>(arraysize(kStartOrder)); i++) |
82 start_order_[kStartOrder[i]] = i; | 83 start_order_[kStartOrder[i]] = i; |
83 } | 84 } |
84 | 85 |
85 ModelAssociationManager::~ModelAssociationManager() { | 86 ModelAssociationManager::~ModelAssociationManager() { |
86 } | 87 } |
87 | 88 |
88 void ModelAssociationManager::Initialize( | 89 void ModelAssociationManager::Initialize( |
89 syncable::ModelTypeSet desired_types) { | 90 syncable::ModelTypeSet desired_types) { |
90 DCHECK(state_ == IDLE); | 91 DCHECK(state_ == IDLE); |
tim (not reviewing)
2012/05/21 23:18:57
DCHECK_EQ
lipalani1
2012/05/22 01:23:58
Done.
| |
91 needs_start_.clear(); | 92 needs_start_.clear(); |
92 needs_stop_.clear(); | 93 needs_stop_.clear(); |
93 failed_datatypes_info_.clear(); | 94 failed_datatypes_info_.clear(); |
94 desired_types_ = desired_types; | 95 desired_types_ = desired_types; |
95 state_ = INITIAILIZED_TO_CONFIGURE; | 96 state_ = INITIAILIZED_TO_CONFIGURE; |
96 | 97 |
98 // Stop the types that are still loading from the previous configuration. | |
99 // If they are enabled we will start them here once again. | |
100 | |
101 for (std::vector<DataTypeController*>::const_iterator it = | |
102 pending_model_load_.begin(); | |
103 it != pending_model_load_.end(); | |
104 ++it) { | |
105 (*it)->Stop(); | |
106 } | |
107 | |
108 pending_model_load_.clear(); | |
109 waiting_to_associate_.clear(); | |
110 currently_associating_ = NULL; | |
111 | |
112 | |
97 // We need to calculate our |needs_start_| and |needs_stop_| list. | 113 // We need to calculate our |needs_start_| and |needs_stop_| list. |
98 GetControllersNeedingStart(&needs_start_); | 114 GetControllersNeedingStart(&needs_start_); |
99 // Sort these according to kStartOrder. | 115 // Sort these according to kStartOrder. |
100 std::sort(needs_start_.begin(), | 116 std::sort(needs_start_.begin(), |
101 needs_start_.end(), | 117 needs_start_.end(), |
102 SortComparator(&start_order_)); | 118 SortComparator(&start_order_)); |
103 | 119 |
104 // Add any data type controllers into that needs_stop_ list that are | 120 // Add any data type controllers into that needs_stop_ list that are |
105 // currently MODEL_STARTING, ASSOCIATING, RUNNING or DISABLED. | 121 // currently MODEL_STARTING, ASSOCIATING, RUNNING or DISABLED. |
106 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin(); | 122 for (DataTypeController::TypeMap::const_iterator it = controllers_->begin(); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
171 if (dtc->state() != DataTypeController::NOT_RUNNING && | 187 if (dtc->state() != DataTypeController::NOT_RUNNING && |
172 dtc->state() != DataTypeController::STOPPING) { | 188 dtc->state() != DataTypeController::STOPPING) { |
173 dtc->Stop(); | 189 dtc->Stop(); |
174 DVLOG(1) << "Stopped " << dtc->name(); | 190 DVLOG(1) << "Stopped " << dtc->name(); |
175 } | 191 } |
176 } | 192 } |
177 | 193 |
178 if (need_to_call_model_association_done) { | 194 if (need_to_call_model_association_done) { |
179 DataTypeManager::ConfigureResult result(DataTypeManager::ABORTED, | 195 DataTypeManager::ConfigureResult result(DataTypeManager::ABORTED, |
180 desired_types_, | 196 desired_types_, |
181 failed_datatypes_info_); | 197 failed_datatypes_info_, |
198 syncable::ModelTypeSet()); | |
182 result_processor_->OnModelAssociationDone(result); | 199 result_processor_->OnModelAssociationDone(result); |
183 } | 200 } |
184 | 201 |
185 failed_datatypes_info_.clear(); | 202 failed_datatypes_info_.clear(); |
186 } | 203 } |
187 | 204 |
188 bool ModelAssociationManager::GetControllersNeedingStart( | 205 bool ModelAssociationManager::GetControllersNeedingStart( |
189 std::vector<DataTypeController*>* needs_start) { | 206 std::vector<DataTypeController*>* needs_start) { |
190 // Add any data type controllers into the needs_start_ list that are | 207 // Add any data type controllers into the needs_start_ list that are |
191 // currently NOT_RUNNING or STOPPING. | 208 // currently NOT_RUNNING or STOPPING. |
(...skipping 10 matching lines...) Expand all Loading... | |
202 needs_start->push_back(dtc->second.get()); | 219 needs_start->push_back(dtc->second.get()); |
203 if (dtc->second->state() == DataTypeController::DISABLED) { | 220 if (dtc->second->state() == DataTypeController::DISABLED) { |
204 DVLOG(1) << "Found " << syncable::ModelTypeToString(dtc->second->type()) | 221 DVLOG(1) << "Found " << syncable::ModelTypeToString(dtc->second->type()) |
205 << " in disabled state."; | 222 << " in disabled state."; |
206 } | 223 } |
207 } | 224 } |
208 } | 225 } |
209 return found_any; | 226 return found_any; |
210 } | 227 } |
211 | 228 |
229 void ModelAssociationManager::HandleFailedTypes( | |
230 DataTypeController::StartResult result, | |
231 const SyncError& error) { | |
232 failed_datatypes_info_.push_back(error); | |
233 LOG(ERROR) << "Failed to associate models for " | |
234 << syncable::ModelTypeToString(error.type()); | |
235 UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed", | |
236 error.type(), | |
237 syncable::MODEL_TYPE_COUNT); | |
238 | |
239 } | |
240 | |
212 void ModelAssociationManager::TypeStartCallback( | 241 void ModelAssociationManager::TypeStartCallback( |
213 DataTypeController::StartResult result, | 242 DataTypeController::StartResult result, |
214 const SyncError& error) { | 243 const SyncError& error) { |
215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
216 | 245 |
217 if (state_ == ABORT) { | 246 if (state_ == ABORT) { |
218 // Now that we have finished with the current type we can stop | 247 // Now that we have finished with the current type we can stop |
219 // if abort was called. | 248 // if abort was called. |
220 state_ = IDLE; | 249 state_ = IDLE; |
221 return; | 250 return; |
222 } | 251 } |
223 | 252 |
224 DCHECK(state_ == CONFIGURING); | 253 DCHECK(state_ == CONFIGURING); |
225 | 254 |
226 // We are done with this type. Clear it. | 255 // We are done with this type. Clear it. |
227 DataTypeController* started_dtc = currently_associating_; | 256 DataTypeController* started_dtc = currently_associating_; |
228 currently_associating_ = NULL; | 257 currently_associating_ = NULL; |
229 | 258 |
230 if (result == DataTypeController::ASSOCIATION_FAILED) { | 259 if (result == DataTypeController::ASSOCIATION_FAILED) { |
231 failed_datatypes_info_.push_back(error); | 260 HandleFailedTypes(result, error); |
232 LOG(ERROR) << "Failed to associate models for " | |
233 << syncable::ModelTypeToString(error.type()); | |
234 UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed", | |
235 error.type(), | |
236 syncable::MODEL_TYPE_COUNT); | |
237 } | 261 } |
238 | 262 |
239 // If the type started normally, continue to the next type. | 263 // If the type started normally, continue to the next type. |
240 // If the type is waiting for the cryptographer, continue to the next type. | 264 // If the type is waiting for the cryptographer, continue to the next type. |
241 // Once the cryptographer is ready, we'll attempt to restart this type. | 265 // Once the cryptographer is ready, we'll attempt to restart this type. |
242 // If this type encountered a type specific error continue to the next type. | 266 // If this type encountered a type specific error continue to the next type. |
243 if (result == DataTypeController::NEEDS_CRYPTO || | 267 if (result == DataTypeController::NEEDS_CRYPTO || |
244 result == DataTypeController::OK || | 268 result == DataTypeController::OK || |
245 result == DataTypeController::OK_FIRST_RUN || | 269 result == DataTypeController::OK_FIRST_RUN || |
246 result == DataTypeController::ASSOCIATION_FAILED) { | 270 result == DataTypeController::ASSOCIATION_FAILED) { |
(...skipping 20 matching lines...) Expand all Loading... | |
267 } | 291 } |
268 | 292 |
269 std::list<SyncError> errors; | 293 std::list<SyncError> errors; |
270 errors.push_back(error); | 294 errors.push_back(error); |
271 | 295 |
272 // Put our state to idle. | 296 // Put our state to idle. |
273 state_ = IDLE; | 297 state_ = IDLE; |
274 | 298 |
275 DataTypeManager::ConfigureResult configure_result(configure_status, | 299 DataTypeManager::ConfigureResult configure_result(configure_status, |
276 desired_types_, | 300 desired_types_, |
277 errors); | 301 errors, |
302 syncable::ModelTypeSet()); | |
278 result_processor_->OnModelAssociationDone(configure_result); | 303 result_processor_->OnModelAssociationDone(configure_result); |
279 } | 304 } |
280 | 305 |
281 void ModelAssociationManager::LoadModelForNextType() { | 306 void ModelAssociationManager::LoadModelForNextType() { |
282 if (!needs_start_.empty()) { | 307 if (!needs_start_.empty()) { |
283 DVLOG(1) << "Starting " << needs_start_[0]->name(); | 308 DVLOG(1) << "Starting " << needs_start_[0]->name(); |
284 | 309 |
285 DataTypeController* dtc = needs_start_[0]; | 310 DataTypeController* dtc = needs_start_[0]; |
286 needs_start_.erase(needs_start_.begin()); | 311 needs_start_.erase(needs_start_.begin()); |
287 // Move from |needs_start_| to |pending_model_load_|. | 312 // Move from |needs_start_| to |pending_model_load_|. |
288 pending_model_load_.push_back(dtc); | 313 pending_model_load_.insert(pending_model_load_.begin(), dtc); |
314 timer_.Start(FROM_HERE, | |
315 base::TimeDelta::FromSeconds(kDataTypeLoadWaitTimeInSeconds), | |
316 this, | |
317 &ModelAssociationManager::ModelLoadTimedOut); | |
289 dtc->LoadModels(base::Bind( | 318 dtc->LoadModels(base::Bind( |
290 &ModelAssociationManager::ModelLoadCallback, | 319 &ModelAssociationManager::ModelLoadCallback, |
291 weak_ptr_factory_.GetWeakPtr())); | 320 weak_ptr_factory_.GetWeakPtr())); |
321 | |
292 return; | 322 return; |
293 } | 323 } |
294 | 324 |
295 // If all controllers have their |LoadModels| invoked then pass onto | 325 // If all controllers have their |LoadModels| invoked then pass onto |
296 // |StartAssociatingNextType|. | 326 // |StartAssociatingNextType|. |
297 StartAssociatingNextType(); | 327 StartAssociatingNextType(); |
298 } | 328 } |
299 | 329 |
300 void ModelAssociationManager::ModelLoadCallback( | 330 void ModelAssociationManager::ModelLoadCallback( |
301 syncable::ModelType type, SyncError error) { | 331 syncable::ModelType type, SyncError error) { |
302 DCHECK_EQ(state_, CONFIGURING); | 332 if (state_ == CONFIGURING) { |
303 | 333 for (std::vector<DataTypeController*>::iterator it = |
304 for (std::vector<DataTypeController*>::iterator it = | 334 pending_model_load_.begin(); |
305 pending_model_load_.begin(); | 335 it != pending_model_load_.end(); |
306 it != pending_model_load_.end(); | 336 ++it) { |
307 ++it) { | 337 if ((*it)->type() == type) { |
308 if ((*it)->type() == type) { | 338 // If the type that got loaded was the type that was started |
tim (not reviewing)
2012/05/21 23:18:57
'If the type that just finished loading was the la
lipalani1
2012/05/22 01:23:58
Done.
| |
309 DataTypeController* dtc = *it; | 339 // last, then we could stop the timer. |
310 pending_model_load_.erase(it); | 340 if (it == pending_model_load_.begin()) { |
311 if (!error.IsSet()) { | 341 timer_.Stop(); |
312 waiting_to_associate_.push_back(dtc); | 342 } |
313 StartAssociatingNextType(); | 343 DataTypeController* dtc = *it; |
314 } else { | 344 pending_model_load_.erase(it); |
315 // Treat it like a regular error. | 345 if (!error.IsSet()) { |
316 DCHECK(currently_associating_ == NULL); | 346 waiting_to_associate_.push_back(dtc); |
317 currently_associating_ = dtc; | 347 StartAssociatingNextType(); |
318 TypeStartCallback(DataTypeController::ASSOCIATION_FAILED, error); | 348 } else { |
319 } | 349 // Treat it like a regular error. |
320 return; | 350 HandleFailedTypes(DataTypeController::ASSOCIATION_FAILED, error); |
351 } | |
352 return; | |
353 } | |
321 } | 354 } |
355 NOTREACHED(); | |
356 return; | |
357 } | |
358 else { | |
359 // We got a callback on type that we started loading during the | |
tim (not reviewing)
2012/05/21 23:18:57
"This data type finished loading after the deadlin
lipalani1
2012/05/22 01:23:58
Done.
| |
360 // previous configuration. Inform the DTM that the type has loaded. | |
361 result_processor_->OnTypesLoaded(); | |
322 } | 362 } |
323 | 363 |
324 NOTREACHED(); | |
325 } | 364 } |
326 | 365 |
327 | 366 |
328 void ModelAssociationManager::StartAssociatingNextType() { | 367 void ModelAssociationManager::StartAssociatingNextType() { |
329 DCHECK(state_ == CONFIGURING); | 368 DCHECK(state_ == CONFIGURING); |
330 DCHECK(currently_associating_ == NULL); | 369 DCHECK(currently_associating_ == NULL); |
331 if (!waiting_to_associate_.empty()) { | 370 if (!waiting_to_associate_.empty()) { |
332 DVLOG(1) << "Starting " << waiting_to_associate_[0]->name(); | 371 DVLOG(1) << "Starting " << waiting_to_associate_[0]->name(); |
333 TRACE_EVENT_BEGIN1("sync", "ModelAssociation", | 372 TRACE_EVENT_BEGIN1("sync", "ModelAssociation", |
334 "DataType", | 373 "DataType", |
(...skipping 10 matching lines...) Expand all Loading... | |
345 state_ = IDLE; | 384 state_ = IDLE; |
346 // Do a fresh calculation to see if controllers need starting to account for | 385 // Do a fresh calculation to see if controllers need starting to account for |
347 // things like encryption, which may still need to be sorted out before we | 386 // things like encryption, which may still need to be sorted out before we |
348 // can announce we're "Done" configuration entirely. | 387 // can announce we're "Done" configuration entirely. |
349 if (GetControllersNeedingStart(NULL)) { | 388 if (GetControllersNeedingStart(NULL)) { |
350 DVLOG(1) << "GetControllersNeedingStart returned true. DTM blocked"; | 389 DVLOG(1) << "GetControllersNeedingStart returned true. DTM blocked"; |
351 | 390 |
352 DataTypeManager::ConfigureResult configure_result( | 391 DataTypeManager::ConfigureResult configure_result( |
353 DataTypeManager::CONFIGURE_BLOCKED, | 392 DataTypeManager::CONFIGURE_BLOCKED, |
354 desired_types_, | 393 desired_types_, |
355 failed_datatypes_info_); | 394 failed_datatypes_info_, |
395 syncable::ModelTypeSet()); | |
356 state_ = IDLE; | 396 state_ = IDLE; |
357 result_processor_->OnModelAssociationDone(configure_result); | 397 result_processor_->OnModelAssociationDone(configure_result); |
358 return; | 398 return; |
359 } | 399 } |
360 | 400 |
361 DataTypeManager::ConfigureStatus configure_status = DataTypeManager::OK; | 401 DataTypeManager::ConfigureStatus configure_status = DataTypeManager::OK; |
362 if (!failed_datatypes_info_.empty()) { | 402 if (!failed_datatypes_info_.empty() || |
403 !GetTypesWaitingToLoad().Empty()) { | |
363 configure_status = DataTypeManager::PARTIAL_SUCCESS; | 404 configure_status = DataTypeManager::PARTIAL_SUCCESS; |
364 } | 405 } |
365 DataTypeManager::ConfigureResult result(configure_status, | 406 DataTypeManager::ConfigureResult result(configure_status, |
366 desired_types_, | 407 desired_types_, |
367 failed_datatypes_info_); | 408 failed_datatypes_info_, |
409 GetTypesWaitingToLoad()); | |
368 result_processor_->OnModelAssociationDone(result); | 410 result_processor_->OnModelAssociationDone(result); |
369 return; | 411 return; |
370 } | 412 } |
371 | 413 |
414 void ModelAssociationManager::ModelLoadTimedOut() { | |
tim (not reviewing)
2012/05/21 23:18:57
Is this method actually needed?
lipalani1
2012/05/22 01:23:58
Just for clarity purpose... Compiler probably opti
tim (not reviewing)
2012/05/22 16:50:05
Hmm, to me the extra indirection makes it less cle
lipalani1
2012/05/22 20:20:46
Done.
| |
415 LoadModelForNextType(); | |
416 } | |
417 | |
418 syncable::ModelTypeSet ModelAssociationManager::GetTypesWaitingToLoad() { | |
419 syncable::ModelTypeSet result; | |
420 for (std::vector<DataTypeController*>::const_iterator it = | |
421 pending_model_load_.begin(); | |
422 it != pending_model_load_.end(); | |
423 ++it) { | |
424 result.Put((*it)->type()); | |
425 } | |
426 return result; | |
427 } | |
428 | |
429 void ModelAssociationManager::TestSimulateDataTypeLoadTimeout() { | |
tim (not reviewing)
2012/05/21 23:18:57
I think there is a way to do this that doesn't req
lipalani1
2012/05/22 01:23:58
I think the eventual direction you are advocating
tim (not reviewing)
2012/05/22 16:50:05
It sounds like we're in agreement that it would be
lipalani1
2012/05/22 20:20:46
I have addressed this. Let me know what you think.
| |
430 timer_.Stop(); | |
431 ModelLoadTimedOut(); | |
432 } | |
433 | |
434 | |
435 | |
372 } // namespace browser_sync | 436 } // namespace browser_sync |
373 | 437 |
OLD | NEW |