Chromium Code Reviews| Index: chrome/browser/sync/glue/model_association_manager.cc |
| diff --git a/chrome/browser/sync/glue/model_association_manager.cc b/chrome/browser/sync/glue/model_association_manager.cc |
| index bd74db75890f8b7f8f2d0aa2e7e87b52bf222462..60699ef5a566bc28b9cd2fe115782fba8807df74 100644 |
| --- a/chrome/browser/sync/glue/model_association_manager.cc |
| +++ b/chrome/browser/sync/glue/model_association_manager.cc |
| @@ -2,6 +2,15 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| +#include <algorithm> |
| +#include <functional> |
| + |
| +#include "base/debug/trace_event.h" |
| + |
| +#include "base/logging.h" |
| +#include "base/message_loop.h" |
| +#include "base/metrics/histogram.h" |
| + |
| #include "chrome/browser/sync/glue/model_association_manager.h" |
| #include "content/public/browser/browser_thread.h" |
| @@ -19,6 +28,11 @@ using content::BrowserThread; |
| using syncable::ModelTypeSet; |
| namespace browser_sync { |
| +// The amount of time we wait for a datatype to load. If the type has |
| +// not finished loading we move on to the next type. Once this type |
| +// finishes loading we will do a configure to associate this type. Note |
| +// that in most cases types finish loading before this timeout. |
| +const int64 kDataTypeLoadWaitTimeInSeconds = 120; |
| namespace { |
| static const syncable::ModelType kStartOrder[] = { |
| @@ -94,6 +108,25 @@ void ModelAssociationManager::Initialize( |
| desired_types_ = desired_types; |
| state_ = INITIAILIZED_TO_CONFIGURE; |
| + VLOG(0) << "ModelAssociationManager: Initializing"; |
| + |
| + // Stop the types that are still loading from the previous configuration. |
| + // If they are enabled we will start them here once again. |
| + for (std::vector<DataTypeController*>::const_iterator it = |
| + pending_model_load_.begin(); |
| + it != pending_model_load_.end(); |
| + ++it) { |
| + VLOG(0) << "ModelAssociationManager: Stopping " |
| + << (*it)->name() |
| + << " before initialization"; |
| + (*it)->Stop(); |
| + } |
| + |
| + pending_model_load_.clear(); |
| + waiting_to_associate_.clear(); |
| + currently_associating_ = NULL; |
| + |
|
tim (not reviewing)
2012/05/23 03:18:52
extra newline
lipalani1
2012/05/23 17:47:20
Done.
|
| + |
| // We need to calculate our |needs_start_| and |needs_stop_| list. |
| GetControllersNeedingStart(&needs_start_); |
| // Sort these according to kStartOrder. |
| @@ -112,7 +145,7 @@ void ModelAssociationManager::Initialize( |
| dtc->state() == DataTypeController::RUNNING || |
| dtc->state() == DataTypeController::DISABLED)) { |
| needs_stop_.push_back(dtc); |
| - DVLOG(1) << "Will stop " << dtc->name(); |
| + VLOG(0) << "ModelTypeToString: Will stop " << dtc->name(); |
| } |
| } |
| // Sort these according to kStartOrder. |
| @@ -124,12 +157,14 @@ void ModelAssociationManager::Initialize( |
| void ModelAssociationManager::StartAssociationAsync() { |
| DCHECK_EQ(state_, INITIAILIZED_TO_CONFIGURE); |
| state_ = CONFIGURING; |
| + VLOG(0) << "ModelAssociationManager: Going to start model association"; |
| LoadModelForNextType(); |
| } |
| void ModelAssociationManager::ResetForReconfiguration() { |
| DCHECK_EQ(state_, INITIAILIZED_TO_CONFIGURE); |
| state_ = IDLE; |
| + VLOG(0) << "ModelAssociationManager: Reseting for reconfiguration"; |
| needs_start_.clear(); |
| needs_stop_.clear(); |
| failed_datatypes_info_.clear(); |
| @@ -137,9 +172,10 @@ void ModelAssociationManager::ResetForReconfiguration() { |
| void ModelAssociationManager::StopDisabledTypes() { |
| DCHECK_EQ(state_, INITIAILIZED_TO_CONFIGURE); |
| + VLOG(0) << "ModelAssociationManager: Stopping disabled types."; |
|
tim (not reviewing)
2012/05/23 03:18:52
DVLOG(1) (here and elsewhere)?
lipalani1
2012/05/23 17:47:20
Done.
|
| // Stop requested data types. |
| for (size_t i = 0; i < needs_stop_.size(); ++i) { |
| - DVLOG(1) << "Stopping " << needs_stop_[i]->name(); |
| + VLOG(0) << "ModelAssociationManager: Stopping " << needs_stop_[i]->name(); |
| needs_stop_[i]->Stop(); |
| } |
| needs_stop_.clear(); |
| @@ -147,7 +183,10 @@ void ModelAssociationManager::StopDisabledTypes() { |
| void ModelAssociationManager::Stop() { |
| bool need_to_call_model_association_done = false; |
| + VLOG(0) << "ModelAssociationManager: Stopping MAM"; |
| if (state_ == CONFIGURING) { |
| + VLOG(0) << "ModelAssociationManager: In the middle of configuratio while" |
| + << " stopping"; |
| state_ = ABORTED; |
| DCHECK(currently_associating_ != NULL || |
| needs_start_.size() > 0 || |
| @@ -155,6 +194,8 @@ void ModelAssociationManager::Stop() { |
| waiting_to_associate_.size() > 0); |
| if (currently_associating_) { |
| + VLOG(0) << "ModelAssociationManager: stopping " |
| + << currently_associating_->name(); |
| currently_associating_->Stop(); |
| } else { |
| // DTCs in other lists would be stopped below. |
| @@ -177,14 +218,16 @@ void ModelAssociationManager::Stop() { |
| if (dtc->state() != DataTypeController::NOT_RUNNING && |
| dtc->state() != DataTypeController::STOPPING) { |
| dtc->Stop(); |
| - DVLOG(1) << "Stopped " << dtc->name(); |
| + VLOG(0) << "ModelAssociationManager: Stopped " << dtc->name(); |
| } |
| } |
| if (need_to_call_model_association_done) { |
| + VLOG(0) << "ModelAssociationManager: Calling OnModelAssociationDone"; |
| DataTypeManager::ConfigureResult result(DataTypeManager::ABORTED, |
| desired_types_, |
| - failed_datatypes_info_); |
| + failed_datatypes_info_, |
| + syncable::ModelTypeSet()); |
| result_processor_->OnModelAssociationDone(result); |
| } |
| @@ -193,6 +236,7 @@ void ModelAssociationManager::Stop() { |
| bool ModelAssociationManager::GetControllersNeedingStart( |
| std::vector<DataTypeController*>* needs_start) { |
| + VLOG(0) << "ModelAssociationManager: GetControllersNeedingStart"; |
| // Add any data type controllers into the needs_start_ list that are |
| // currently NOT_RUNNING or STOPPING. |
| bool found_any = false; |
| @@ -207,7 +251,8 @@ bool ModelAssociationManager::GetControllersNeedingStart( |
| if (needs_start) |
| needs_start->push_back(dtc->second.get()); |
| if (dtc->second->state() == DataTypeController::DISABLED) { |
| - DVLOG(1) << "Found " << syncable::ModelTypeToString(dtc->second->type()) |
| + VLOG(0) << "ModelAssociationManager: Found "\ |
| + << syncable::ModelTypeToString(dtc->second->type()) |
| << " in disabled state."; |
| } |
| } |
| @@ -215,14 +260,28 @@ bool ModelAssociationManager::GetControllersNeedingStart( |
| return found_any; |
| } |
| +void ModelAssociationManager::HandleFailedTypes( |
|
tim (not reviewing)
2012/05/23 03:18:52
Actually, since this doesn't totally "handle" fail
lipalani1
2012/05/23 17:47:20
Done.
|
| + DataTypeController::StartResult result, |
| + const SyncError& error) { |
| + failed_datatypes_info_.push_back(error); |
| + LOG(ERROR) << "Failed to associate models for " |
| + << syncable::ModelTypeToString(error.type()); |
| + UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed", |
| + error.type(), |
| + syncable::MODEL_TYPE_COUNT); |
| +} |
| + |
| void ModelAssociationManager::TypeStartCallback( |
| DataTypeController::StartResult result, |
| const SyncError& error) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + VLOG(0) << "ModelAssociationManager: TypeStartCallback"; |
| if (state_ == ABORTED) { |
| // Now that we have finished with the current type we can stop |
| // if abort was called. |
| + VLOG(0) << "ModelAssociationManager: Doing an early return" |
| + << " because of abort"; |
| state_ = IDLE; |
| return; |
| } |
| @@ -234,12 +293,8 @@ void ModelAssociationManager::TypeStartCallback( |
| currently_associating_ = NULL; |
| if (result == DataTypeController::ASSOCIATION_FAILED) { |
| - failed_datatypes_info_.push_back(error); |
| - LOG(ERROR) << "Failed to associate models for " |
| - << syncable::ModelTypeToString(error.type()); |
| - UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed", |
| - error.type(), |
| - syncable::MODEL_TYPE_COUNT); |
| + VLOG(0) << "ModelAssociationManager: Encountered a failed type"; |
| + HandleFailedTypes(result, error); |
| } |
| // If the type started normally, continue to the next type. |
| @@ -250,6 +305,8 @@ void ModelAssociationManager::TypeStartCallback( |
| result == DataTypeController::OK || |
| result == DataTypeController::OK_FIRST_RUN || |
| result == DataTypeController::ASSOCIATION_FAILED) { |
| + VLOG(0) << "ModelAssociationManager: type start callback returned " |
| + << result << " so calling LoadModelForNextType"; |
| LoadModelForNextType(); |
| return; |
| } |
| @@ -280,24 +337,34 @@ void ModelAssociationManager::TypeStartCallback( |
| DataTypeManager::ConfigureResult configure_result(configure_status, |
| desired_types_, |
| - errors); |
| + errors, |
| + syncable::ModelTypeSet()); |
| result_processor_->OnModelAssociationDone(configure_result); |
| } |
| void ModelAssociationManager::LoadModelForNextType() { |
| + VLOG(0) << "ModelAssociationManager: LoadModelForNextType"; |
| if (!needs_start_.empty()) { |
| - DVLOG(1) << "Starting " << needs_start_[0]->name(); |
| + VLOG(0) << "ModelAssociationManager: Starting " << needs_start_[0]->name(); |
| DataTypeController* dtc = needs_start_[0]; |
| needs_start_.erase(needs_start_.begin()); |
| // Move from |needs_start_| to |pending_model_load_|. |
| - pending_model_load_.push_back(dtc); |
| + pending_model_load_.insert(pending_model_load_.begin(), dtc); |
| + timer_.Start(FROM_HERE, |
| + base::TimeDelta::FromSeconds(kDataTypeLoadWaitTimeInSeconds), |
| + this, |
| + &ModelAssociationManager::LoadModelForNextType); |
| dtc->LoadModels(base::Bind( |
| &ModelAssociationManager::ModelLoadCallback, |
| weak_ptr_factory_.GetWeakPtr())); |
| + |
| return; |
| } |
| + VLOG(0) << "ModelAssociationManager: All types have models loaded." |
| + << "Moving on to StartAssociatingNextType."; |
| + |
| // If all controllers have their |LoadModels| invoked then pass onto |
| // |StartAssociatingNextType|. |
| StartAssociatingNextType(); |
| @@ -305,37 +372,66 @@ void ModelAssociationManager::LoadModelForNextType() { |
| void ModelAssociationManager::ModelLoadCallback( |
| syncable::ModelType type, SyncError error) { |
| - DCHECK_EQ(state_, CONFIGURING); |
| - |
| - for (std::vector<DataTypeController*>::iterator it = |
| - pending_model_load_.begin(); |
| - it != pending_model_load_.end(); |
| - ++it) { |
| - if ((*it)->type() == type) { |
| - DataTypeController* dtc = *it; |
| - pending_model_load_.erase(it); |
| - if (!error.IsSet()) { |
| - waiting_to_associate_.push_back(dtc); |
| - StartAssociatingNextType(); |
| - } else { |
| - // Treat it like a regular error. |
| - DCHECK(currently_associating_ == NULL); |
| - currently_associating_ = dtc; |
| - TypeStartCallback(DataTypeController::ASSOCIATION_FAILED, error); |
| + VLOG(0) << "ModelAssociationManager: ModelLoadCallback for " |
| + << syncable::ModelTypeToString(type); |
| + if (state_ == CONFIGURING) { |
| + VLOG(0) << "ModelAssociationManager: ModelLoadCallback while configuring"; |
| + for (std::vector<DataTypeController*>::iterator it = |
| + pending_model_load_.begin(); |
| + it != pending_model_load_.end(); |
| + ++it) { |
| + if ((*it)->type() == type) { |
| + // Each type is given |kDataTypeLoadWaitTimeInSeconds| time to load |
| + // (as controlled by the timer.). If the type does not load in that |
| + // time we move on to the next type. However if the type does |
| + // finish loading in that time we want to stop the timer. We stop |
| + // the timer, if the type that loaded is the same as the type that |
| + // we started the timer for(as indicated by the type on the head |
| + // of the list). |
| + // Note: Regardless of this timer value the associations will always |
| + // take place serially. The only thing this timer controls is how serial |
| + // the model load is. If this timer has a value of zero seconds then |
| + // the model loads will all be parallel. |
| + if (it == pending_model_load_.begin()) { |
| + VLOG(0) << "ModelAssociationManager: Stopping timer"; |
| + timer_.Stop(); |
| + } |
| + DataTypeController* dtc = *it; |
| + pending_model_load_.erase(it); |
| + if (!error.IsSet()) { |
| + VLOG(0) << "ModelAssociationManager:" |
| + << " Calling StartAssociatingNextType"; |
| + waiting_to_associate_.push_back(dtc); |
| + StartAssociatingNextType(); |
| + } else { |
| + VLOG(0) << "ModelAssociationManager: Encountered error loading"; |
| + // Treat it like a regular error. |
| + HandleFailedTypes(DataTypeController::ASSOCIATION_FAILED, error); |
| + } |
| + return; |
| } |
| - return; |
| } |
| + NOTREACHED(); |
| + return; |
| + } else { |
| + VLOG(0) << "ModelAssociationManager: Models loaded after configure cycle" |
| + << "Informing DTM"; |
| + // This datatype finished loading after the deadline imposed by the |
| + // originating configuration cycle. Inform the DataTypeManager that the |
| + // type has loaded, so that association may begin. |
| + result_processor_->OnTypesLoaded(); |
| } |
| - NOTREACHED(); |
| } |
| - |
| void ModelAssociationManager::StartAssociatingNextType() { |
| DCHECK_EQ(state_, CONFIGURING); |
| DCHECK_EQ(currently_associating_, static_cast<DataTypeController*>(NULL)); |
| + |
| + VLOG(0) << "ModelAssociationManager: StartAssociatingNextType"; |
| if (!waiting_to_associate_.empty()) { |
| - DVLOG(1) << "Starting " << waiting_to_associate_[0]->name(); |
| + VLOG(0) << "ModelAssociationManager: Starting " |
| + << waiting_to_associate_[0]->name(); |
| TRACE_EVENT_BEGIN1("sync", "ModelAssociation", |
| "DataType", |
| ModelTypeToString(waiting_to_associate_[0]->type())); |
| @@ -354,28 +450,53 @@ void ModelAssociationManager::StartAssociatingNextType() { |
| // things like encryption, which may still need to be sorted out before we |
| // can announce we're "Done" configuration entirely. |
| if (GetControllersNeedingStart(NULL)) { |
| - DVLOG(1) << "GetControllersNeedingStart returned true." |
| - << " Blocking DataTypeManager"; |
| + VLOG(0) << "ModelAssociationManager: GetControllersNeedingStart" |
| + << " returned true. Blocking DataTypeManager"; |
| DataTypeManager::ConfigureResult configure_result( |
| DataTypeManager::CONFIGURE_BLOCKED, |
| desired_types_, |
| - failed_datatypes_info_); |
| + failed_datatypes_info_, |
| + syncable::ModelTypeSet()); |
| state_ = IDLE; |
| result_processor_->OnModelAssociationDone(configure_result); |
| return; |
| } |
| DataTypeManager::ConfigureStatus configure_status = DataTypeManager::OK; |
| - if (!failed_datatypes_info_.empty()) |
| + |
| + if (!failed_datatypes_info_.empty() || |
| + !GetTypesWaitingToLoad().Empty()) { |
| + // We have not configured all types that we have been asked to configure. |
| + // Either we have failed types or types that have not completed loading |
| + // yet. |
| + VLOG(0) << "ModelAssociationManager: setting partial success"; |
| configure_status = DataTypeManager::PARTIAL_SUCCESS; |
| + } |
| DataTypeManager::ConfigureResult result(configure_status, |
| desired_types_, |
| - failed_datatypes_info_); |
| + failed_datatypes_info_, |
| + GetTypesWaitingToLoad()); |
| result_processor_->OnModelAssociationDone(result); |
| return; |
| } |
| +syncable::ModelTypeSet ModelAssociationManager::GetTypesWaitingToLoad() { |
| + syncable::ModelTypeSet result; |
| + for (std::vector<DataTypeController*>::const_iterator it = |
| + pending_model_load_.begin(); |
| + it != pending_model_load_.end(); |
| + ++it) { |
| + result.Put((*it)->type()); |
| + } |
| + return result; |
| +} |
| + |
| +base::OneShotTimer<ModelAssociationManager>* |
| + ModelAssociationManager::GetTimerForTesting() { |
| + return &timer_; |
| +} |
| + |
| } // namespace browser_sync |