Chromium Code Reviews| 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 |