#include "components/sync/service/data_type_manager_impl.h"
#include <memory>
#include <string>
#include <utility>
#include "base/barrier_callback.h"
#include "base/containers/contains.h"
#include "base/containers/enum_set.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/strings/strcat.h"
#include "base/task/sequenced_task_runner.h"
#include "components/sync/base/data_type.h"
#include "components/sync/base/features.h"
#include "components/sync/engine/data_type_activation_response.h"
#include "components/sync/model/type_entities_count.h"
#include "components/sync/protocol/data_type_state_helper.h"
#include "components/sync/service/configure_context.h"
#include "components/sync/service/data_type_encryption_handler.h"
#include "components/sync/service/data_type_manager_observer.h"
#include "components/sync/service/data_type_status_table.h"
#include "components/sync/service/get_all_nodes_request_barrier.h"
#include "components/sync/service/get_types_with_unsynced_data_request_barrier.h"
#include "components/sync/service/local_data_description.h"
namespace syncer {
namespace {
DataTypeController::TypeMap BuildControllerMap(
DataTypeController::TypeVector controllers) {
DataTypeController::TypeMap type_map;
for (std::unique_ptr<DataTypeController>& controller : controllers) {
CHECK(controller);
DataType type = controller->type();
CHECK_EQ(0U, type_map.count(type));
type_map[type] = std::move(controller);
}
return type_map;
}
ConfigureReason GetReasonForProgrammaticReconfigure(
ConfigureReason original_reason) {
return (original_reason == ConfigureReason::CONFIGURE_REASON_NEW_CLIENT)
? ConfigureReason::CONFIGURE_REASON_NEW_CLIENT
: ConfigureReason::CONFIGURE_REASON_PROGRAMMATIC;
}
base::queue<DataTypeSet> PrioritizeTypes(const DataTypeSet& types) {
const DataTypeSet control_types = Intersection(ControlTypes(), types);
const DataTypeSet high_priority_types =
Intersection(HighPriorityUserTypes(), types);
const DataTypeSet low_priority_types =
Intersection(LowPriorityUserTypes(), types);
const DataTypeSet regular_types = Difference(
types,
Union(Union(control_types, high_priority_types), low_priority_types));
base::queue<DataTypeSet> result;
if (!control_types.empty()) {
result.push(control_types);
}
if (!high_priority_types.empty()) {
result.push(high_priority_types);
}
if (!regular_types.empty()) {
result.push(regular_types);
}
if (!low_priority_types.empty()) {
result.push(low_priority_types);
}
if (result.empty()) {
result.push(DataTypeSet());
}
return result;
}
std::map<DataType, LocalDataDescription> JoinAllTypesAndLocalDataDescriptions(
const std::vector<std::pair<DataType, LocalDataDescription>>& pairs) {
return std::map<DataType, LocalDataDescription>(pairs.begin(), pairs.end());
}
std::pair<DataType, LocalDataDescription> JoinTypeAndLocalDataDescription(
DataType type,
LocalDataDescription description) {
return {type, description};
}
}
DataTypeManagerImpl::DataTypeManagerImpl(
DataTypeController::TypeVector controllers,
const DataTypeEncryptionHandler* encryption_handler,
DataTypeManagerObserver* observer)
: controllers_(BuildControllerMap(std::move(controllers))),
observer_(observer),
encryption_handler_(encryption_handler),
model_load_manager_(&controllers_, this) {
DCHECK(observer_);
DCHECK_EQ(controllers_.count(NIGORI), 0u);
for (const auto& [type, controller] : controllers_) {
DataTypeController::State state = controller->state();
CHECK(state == DataTypeController::NOT_RUNNING ||
state == DataTypeController::FAILED)
<< " actual=" << DataTypeController::StateToString(state) << " for "
<< DataTypeToDebugString(type);
if (state == DataTypeController::FAILED) {
data_type_status_table_.UpdateFailedDataType(
type, SyncError(FROM_HERE, SyncError::MODEL_ERROR,
"Preexisting controller error on Sync startup"));
}
}
}
DataTypeManagerImpl::~DataTypeManagerImpl() = default;
void DataTypeManagerImpl::ClearMetadataWhileStoppedExceptFor(
DataTypeSet types) {
CHECK_EQ(state_, STOPPED);
for (const auto& [type, controller] : controllers_) {
if (!types.Has(type)) {
controller->Stop(CLEAR_METADATA, base::DoNothing());
}
}
}
void DataTypeManagerImpl::SetConfigurer(DataTypeConfigurer* configurer) {
CHECK_EQ(state_, STOPPED);
CHECK(!weak_ptr_factory_.HasWeakPtrs());
CHECK(configured_proxy_types_.empty());
CHECK(!needs_reconfigure_);
CHECK(configuration_types_queue_.empty());
configurer_ = configurer;
last_requested_context_ = ConfigureContext();
downloaded_types_ = ControlTypes();
force_redownload_types_.Clear();
ResetDataTypeErrors();
}
void DataTypeManagerImpl::Configure(DataTypeSet preferred_types,
const ConfigureContext& context) {
CHECK(configurer_);
preferred_types.PutAll(ControlTypes());
DataTypeSet allowed_types = ControlTypes();
for (const auto& [type, controller] : controllers_) {
allowed_types.Put(type);
}
ConfigureImpl(Intersection(preferred_types, allowed_types), context);
}
void DataTypeManagerImpl::DataTypePreconditionChanged(DataType type) {
if (!UpdatePreconditionError(type)) {
return;
}
if (state_ == STOPPED || state_ == STOPPING) {
return;
}
switch (controllers_.find(type)->second->GetPreconditionState()) {
case DataTypeController::PreconditionState::kPreconditionsMet:
if (preferred_types_.Has(type)) {
ForceReconfiguration();
}
break;
case DataTypeController::PreconditionState::kMustStopAndClearData:
model_load_manager_.StopDatatype(
type, SyncStopMetadataFate::CLEAR_METADATA,
SyncError(FROM_HERE, SyncError::PRECONDITION_ERROR_WITH_CLEAR_DATA,
""));
break;
case DataTypeController::PreconditionState::kMustStopAndKeepData:
model_load_manager_.StopDatatype(
type, SyncStopMetadataFate::KEEP_METADATA,
SyncError(FROM_HERE, SyncError::PRECONDITION_ERROR_WITH_KEEP_DATA,
""));
break;
}
}
void DataTypeManagerImpl::ForceReconfiguration() {
needs_reconfigure_ = true;
last_requested_context_.reason =
GetReasonForProgrammaticReconfigure(last_requested_context_.reason);
ProcessReconfigure();
}
void DataTypeManagerImpl::ResetDataTypeErrors() {
data_type_status_table_.Reset();
}
void DataTypeManagerImpl::PurgeForMigration(DataTypeSet undesired_types) {
CHECK(configurer_);
DataTypeSet remainder = Difference(preferred_types_, undesired_types);
last_requested_context_.reason = CONFIGURE_REASON_MIGRATION;
ConfigureImpl(remainder, last_requested_context_);
}
void DataTypeManagerImpl::ConfigureImpl(DataTypeSet preferred_types,
const ConfigureContext& context) {
CHECK(configurer_);
CHECK_NE(context.reason, CONFIGURE_REASON_UNKNOWN);
DVLOG(1) << "Configuring for " << DataTypeSetToDebugString(preferred_types)
<< " with reason " << context.reason;
if (state_ == STOPPING) {
LOG(ERROR) << "Configuration set while stopping.";
return;
}
if (state_ != STOPPED) {
DCHECK_EQ(context.authenticated_account_id,
last_requested_context_.authenticated_account_id);
DCHECK_EQ(context.cache_guid, last_requested_context_.cache_guid);
}
preferred_types_ = preferred_types;
last_requested_context_ = context;
switch (state_) {
case STOPPING:
NOTREACHED();
case STOPPED:
case CONFIGURED:
case RETRYING:
Restart();
break;
case CONFIGURING:
DVLOG(1) << "Received configure request while configuration in flight. "
<< "Postponing until current configuration complete.";
needs_reconfigure_ = true;
break;
}
}
void DataTypeManagerImpl::ConnectDataTypes() {
for (DataType type : preferred_types_without_errors_) {
auto dtc_iter = controllers_.find(type);
if (dtc_iter == controllers_.end()) {
continue;
}
DataTypeController* dtc = dtc_iter->second.get();
if (dtc->state() != DataTypeController::MODEL_LOADED) {
continue;
}
DCHECK(!data_type_status_table_.GetFailedTypes().Has(dtc->type()));
std::unique_ptr<DataTypeActivationResponse> activation_response =
dtc->Connect();
DCHECK(activation_response);
CHECK_EQ(dtc->state(), DataTypeController::RUNNING);
if (activation_response->skip_engine_connection) {
DCHECK(!activation_response->type_processor);
downloaded_types_.Put(type);
configured_proxy_types_.Put(type);
continue;
}
if (IsInitialSyncDone(
activation_response->data_type_state.initial_sync_state())) {
downloaded_types_.Put(type);
} else {
downloaded_types_.Remove(type);
}
if (force_redownload_types_.Has(type)) {
downloaded_types_.Remove(type);
}
configurer_->ConnectDataType(type, std::move(activation_response));
}
}
TypeStatusMapForDebugging DataTypeManagerImpl::GetTypeStatusMapForDebugging(
DataTypeSet throttled_types,
DataTypeSet backed_off_types) const {
const DataTypeStatusTable::TypeErrorMap data_type_error_map =
data_type_status_table_.GetAllErrors();
TypeStatusMapForDebugging result;
for (const auto& [type, controller] : controllers_) {
TypeStatusForDebugging& type_status = result[type];
type_status.state = DataTypeController::StateToString(controller->state());
if (base::Contains(data_type_error_map, type)) {
const SyncError& error = data_type_error_map.at(type);
switch (error.error_type()) {
case SyncError::MODEL_ERROR:
case SyncError::CONFIGURATION_ERROR:
case SyncError::CRYPTO_ERROR:
type_status.severity = TypeStatusForDebugging::Severity::kError;
type_status.message =
base::StrCat({"Error: ", error.location().ToString(), ", ",
error.GetMessagePrefix(), error.message()});
break;
case SyncError::PRECONDITION_ERROR_WITH_KEEP_DATA:
case SyncError::PRECONDITION_ERROR_WITH_CLEAR_DATA:
type_status.severity = TypeStatusForDebugging::Severity::kInfo;
type_status.message = error.message();
break;
}
} else if (throttled_types.Has(type)) {
type_status.severity = TypeStatusForDebugging::Severity::kWarning;
type_status.message = " Throttled";
} else if (backed_off_types.Has(type)) {
type_status.severity = TypeStatusForDebugging::Severity::kWarning;
type_status.message = "Backed off";
} else {
type_status.message = "";
switch (controller->state()) {
case DataTypeController::NOT_RUNNING:
type_status.severity = TypeStatusForDebugging::Severity::kInfo;
break;
case DataTypeController::MODEL_STARTING:
case DataTypeController::MODEL_LOADED:
case DataTypeController::STOPPING:
type_status.severity =
TypeStatusForDebugging::Severity::kTransitioning;
break;
case DataTypeController::RUNNING:
type_status.severity = TypeStatusForDebugging::Severity::kOk;
break;
case DataTypeController::FAILED:
type_status.severity = TypeStatusForDebugging::Severity::kError;
break;
}
}
}
return result;
}
void DataTypeManagerImpl::GetAllNodesForDebugging(
base::OnceCallback<void(base::Value::List)> callback) const {
const DataTypeSet active_types = GetActiveDataTypes();
if (active_types.empty()) {
std::move(callback).Run(base::Value::List());
return;
}
CHECK(configurer_);
CHECK_EQ(state_, CONFIGURED);
auto barrier = base::MakeRefCounted<GetAllNodesRequestBarrier>(
active_types, std::move(callback));
for (DataType type : active_types) {
if (type == NIGORI) {
configurer_->GetNigoriNodeForDebugging(base::BindOnce(
&GetAllNodesRequestBarrier::OnReceivedNodesForType, barrier, type));
continue;
}
CHECK(base::Contains(controllers_, type));
const std::unique_ptr<DataTypeController>& controller =
controllers_.at(type);
CHECK_EQ(controller->state(), DataTypeController::RUNNING,
base::NotFatalUntil::M134)
<< " actual=" << DataTypeController::StateToString(controller->state())
<< " for " << DataTypeToDebugString(type);
controller->GetAllNodesForDebugging(base::BindOnce(
&GetAllNodesRequestBarrier::OnReceivedNodesForType, barrier, type));
}
}
void DataTypeManagerImpl::GetEntityCountsForDebugging(
base::RepeatingCallback<void(const TypeEntitiesCount&)> callback) const {
for (const auto& [type, controller] : controllers_) {
controller->GetTypeEntitiesCount(callback);
}
}
DataTypeController* DataTypeManagerImpl::GetControllerForTest(DataType type) {
CHECK(base::Contains(controllers_, type));
return controllers_.at(type).get();
}
void DataTypeManagerImpl::Restart() {
CHECK(configurer_);
DVLOG(1) << "Restarting...";
const ConfigureReason reason = last_requested_context_.reason;
if (reason == CONFIGURE_REASON_RECONFIGURATION ||
reason == CONFIGURE_REASON_NEW_CLIENT ||
reason == CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE) {
for (DataType type : preferred_types_) {
UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureDataTypes",
DataTypeHistogramValue(type));
}
}
for (const auto& [type, controller] : controllers_) {
if (controller->state() == DataTypeController::FAILED) {
data_type_status_table_.UpdateFailedDataType(
type, SyncError(FROM_HERE, SyncError::MODEL_ERROR,
"Preexisting controller error on configuration"));
}
}
if (encryption_handler_->HasCryptoError()) {
DataTypeSet encrypted_types =
encryption_handler_->GetAllEncryptedDataTypes();
encrypted_types.RetainAll(preferred_types_);
encrypted_types.RemoveAll(data_type_status_table_.GetCryptoErrorTypes());
for (DataType type : encrypted_types) {
data_type_status_table_.UpdateFailedDataType(
type, SyncError(FROM_HERE, SyncError::CRYPTO_ERROR, ""));
}
} else {
data_type_status_table_.ResetCryptoErrors();
}
UpdatePreconditionErrors();
last_restart_time_ = base::Time::Now();
DCHECK(state_ == STOPPED || state_ == CONFIGURED || state_ == RETRYING);
const State old_state = state_;
state_ = CONFIGURING;
if (old_state == STOPPED || old_state == CONFIGURED) {
NotifyStart();
}
preferred_types_without_errors_ = GetEnabledTypes();
configuration_types_queue_ = PrioritizeTypes(preferred_types_without_errors_);
if (!preferred_types_without_errors_.Has(NIGORI)) {
configurer_->ClearNigoriDataForMigration();
}
model_load_manager_.Configure(
preferred_types_without_errors_,
preferred_types_, last_requested_context_);
}
void DataTypeManagerImpl::OnAllDataTypesReadyForConfigure() {
CHECK(configurer_);
if (needs_reconfigure_) {
configuration_types_queue_ = base::queue<DataTypeSet>();
ProcessReconfigure();
return;
}
ConnectDataTypes();
StartNextConfiguration();
}
void DataTypeManagerImpl::UpdatePreconditionErrors() {
for (DataType type : preferred_types_) {
UpdatePreconditionError(type);
}
}
bool DataTypeManagerImpl::UpdatePreconditionError(DataType type) {
auto iter = controllers_.find(type);
if (iter == controllers_.end()) {
return false;
}
switch (iter->second->GetPreconditionState()) {
case DataTypeController::PreconditionState::kPreconditionsMet: {
if (!data_type_status_table_.ResetPreconditionErrorFor(type)) {
return false;
}
force_redownload_types_.Put(type);
return true;
}
case DataTypeController::PreconditionState::kMustStopAndClearData: {
return data_type_status_table_.UpdateFailedDataType(
type, SyncError(FROM_HERE,
SyncError::PRECONDITION_ERROR_WITH_CLEAR_DATA, ""));
}
case DataTypeController::PreconditionState::kMustStopAndKeepData: {
return data_type_status_table_.UpdateFailedDataType(
type, SyncError(FROM_HERE,
SyncError::PRECONDITION_ERROR_WITH_KEEP_DATA, ""));
}
}
NOTREACHED();
}
void DataTypeManagerImpl::ProcessReconfigure() {
if (!needs_reconfigure_) {
return;
}
if (!configuration_types_queue_.empty()) {
return;
}
DVLOG(1) << "Reconfiguring due to previous configure attempt occurring while"
<< " busy.";
state_ = RETRYING;
needs_reconfigure_ = false;
ConfigureImpl(preferred_types_, last_requested_context_);
}
void DataTypeManagerImpl::ConfigurationCompleted(
DataTypeSet succeeded_configuration_types,
DataTypeSet failed_configuration_types) {
DCHECK_EQ(CONFIGURING, state_);
downloaded_types_.PutAll(succeeded_configuration_types);
if (!failed_configuration_types.empty()) {
for (DataType type : failed_configuration_types) {
data_type_status_table_.UpdateFailedDataType(
type, SyncError(FROM_HERE, SyncError::CONFIGURATION_ERROR,
"Backend failed to download and configure type."));
}
needs_reconfigure_ = true;
}
if (needs_reconfigure_) {
configuration_types_queue_ = base::queue<DataTypeSet>();
ProcessReconfigure();
return;
}
DCHECK(!configuration_types_queue_.empty());
configuration_types_queue_.pop();
if (configuration_types_queue_.empty()) {
state_ = CONFIGURED;
NotifyDone(OK);
return;
}
StartNextConfiguration();
}
void DataTypeManagerImpl::StartNextConfiguration() {
if (configuration_types_queue_.empty()) {
return;
}
configurer_->ConfigureDataTypes(PrepareConfigureParams());
}
DataTypeConfigurer::ConfigureParams
DataTypeManagerImpl::PrepareConfigureParams() {
const DataTypeSet enabled_types = GetEnabledTypes();
const DataTypeSet disabled_types =
Difference(Union(UserTypes(), ControlTypes()), enabled_types);
const DataTypeSet types_to_configure =
Intersection(enabled_types, configuration_types_queue_.front());
DVLOG(1) << "Enabling: " << DataTypeSetToDebugString(enabled_types);
DVLOG(1) << "Configuring: " << DataTypeSetToDebugString(types_to_configure);
DVLOG(1) << "Disabling: " << DataTypeSetToDebugString(disabled_types);
CHECK(disabled_types.HasAll(data_type_status_table_.GetFailedTypes()));
DataTypeSet types_to_download =
Difference(types_to_configure, downloaded_types_);
types_to_download.RemoveAll(CommitOnlyTypes());
if (!types_to_download.empty()) {
types_to_download.PutAll(ControlTypes());
}
DCHECK(ProtocolTypes().HasAll(types_to_download));
downloaded_types_.RemoveAll(disabled_types);
force_redownload_types_.RemoveAll(types_to_download);
DVLOG(1) << "Types " << DataTypeSetToDebugString(types_to_download)
<< " added; calling ConfigureDataTypes";
DataTypeConfigurer::ConfigureParams params;
params.reason = last_requested_context_.reason;
params.to_download = types_to_download;
params.ready_task =
base::BindOnce(&DataTypeManagerImpl::ConfigurationCompleted,
weak_ptr_factory_.GetWeakPtr());
params.is_sync_feature_enabled =
last_requested_context_.sync_mode == SyncMode::kFull;
return params;
}
void DataTypeManagerImpl::OnSingleDataTypeWillStop(
DataType type,
const std::optional<SyncError>& error) {
if (configurer_) {
configurer_->DisconnectDataType(type);
}
configured_proxy_types_.Remove(type);
if (!error.has_value()) {
return;
}
data_type_status_table_.UpdateFailedDataType(type, *error);
needs_reconfigure_ = true;
last_requested_context_.reason =
GetReasonForProgrammaticReconfigure(last_requested_context_.reason);
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&DataTypeManagerImpl::ProcessReconfigure,
weak_ptr_factory_.GetWeakPtr()));
}
void DataTypeManagerImpl::Stop(SyncStopMetadataFate metadata_fate) {
bool need_to_notify = state_ == CONFIGURING;
state_ = STOPPING;
weak_ptr_factory_.InvalidateWeakPtrs();
model_load_manager_.Stop(metadata_fate);
state_ = STOPPED;
configuration_types_queue_ = base::queue<DataTypeSet>();
needs_reconfigure_ = false;
if (need_to_notify) {
NotifyDone(ABORTED);
}
}
void DataTypeManagerImpl::NotifyStart() {
observer_->OnConfigureStart();
}
void DataTypeManagerImpl::NotifyDone(ConfigureStatus status) {
DCHECK(!last_restart_time_.is_null());
base::TimeDelta configure_time = base::Time::Now() - last_restart_time_;
ConfigureResult result = {.status = status,
.requested_types = preferred_types_};
const std::string prefix_uma =
(last_requested_context_.reason == CONFIGURE_REASON_NEW_CLIENT)
? "Sync.ConfigureTime_Initial"
: "Sync.ConfigureTime_Subsequent";
DVLOG(1) << "Total time spent configuring: " << configure_time.InSecondsF()
<< "s";
switch (result.status) {
case DataTypeManager::OK:
DVLOG(1) << "NotifyDone called with result: OK";
base::UmaHistogramLongTimes(prefix_uma + ".OK", configure_time);
RecordMemoryUsageAndCountsHistograms();
break;
case DataTypeManager::ABORTED:
DVLOG(1) << "NotifyDone called with result: ABORTED";
base::UmaHistogramLongTimes(prefix_uma + ".ABORTED", configure_time);
break;
}
observer_->OnConfigureDone(result);
}
DataTypeSet DataTypeManagerImpl::GetRegisteredDataTypes() const {
DataTypeSet registered_types;
for (const auto& [type, controller] : controllers_) {
registered_types.Put(type);
}
return registered_types;
}
DataTypeSet DataTypeManagerImpl::GetDataTypesForTransportOnlyMode() const {
DataTypeSet allowed_types = ControlTypes();
for (const auto& [type, controller] : controllers_) {
if (controller->ShouldRunInTransportOnlyMode()) {
allowed_types.Put(type);
}
}
return allowed_types;
}
DataTypeSet DataTypeManagerImpl::GetActiveDataTypes() const {
if (state_ != CONFIGURED) {
return DataTypeSet();
}
return GetEnabledTypes();
}
DataTypeSet DataTypeManagerImpl::GetTypesWithPendingDownloadForInitialSync()
const {
if (state_ != CONFIGURING) {
return DataTypeSet();
}
return Difference(GetEnabledTypes(), downloaded_types_);
}
DataTypeSet DataTypeManagerImpl::GetDataTypesWithPermanentErrors() const {
return data_type_status_table_.GetFatalErrorTypes();
}
DataTypeSet DataTypeManagerImpl::GetStoppedDataTypesExcludingNigori() const {
DataTypeSet stopped_types;
for (const auto& [type, controller] : controllers_) {
if (controller->state() == DataTypeController::NOT_RUNNING) {
stopped_types.Put(type);
}
}
return stopped_types;
}
DataTypeSet DataTypeManagerImpl::GetActiveProxyDataTypes() const {
if (state_ != CONFIGURED) {
return DataTypeSet();
}
return configured_proxy_types_;
}
void DataTypeManagerImpl::GetTypesWithUnsyncedData(
DataTypeSet requested_types,
base::OnceCallback<void(DataTypeSet)> callback) const {
CHECK(!requested_types.Has(NIGORI));
if (requested_types.empty()) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), DataTypeSet()));
return;
}
auto helper = base::MakeRefCounted<GetTypesWithUnsyncedDataRequestBarrier>(
requested_types, std::move(callback));
for (DataType type : requested_types) {
auto it = controllers_.find(type);
if (it == controllers_.end()) {
helper->OnReceivedResultForType(type, false);
continue;
}
DataTypeController* controller = it->second.get();
controller->HasUnsyncedData(base::BindOnce(
&GetTypesWithUnsyncedDataRequestBarrier::OnReceivedResultForType,
helper, type));
}
}
void DataTypeManagerImpl::GetLocalDataDescriptions(
DataTypeSet types,
base::OnceCallback<void(std::map<DataType, LocalDataDescription>)>
callback) {
types.RetainAll(GetDataTypesWithLocalDataBatchUploader());
types.RetainAll(GetActiveDataTypes());
auto barrier_callback =
base::BarrierCallback<std::pair<DataType, LocalDataDescription>>(
types.size(), base::BindOnce(&JoinAllTypesAndLocalDataDescriptions)
.Then(std::move(callback)));
for (DataType type : types) {
controllers_.at(type)->GetLocalDataBatchUploader()->GetLocalDataDescription(
base::BindOnce(&JoinTypeAndLocalDataDescription, type)
.Then(barrier_callback));
}
}
void DataTypeManagerImpl::TriggerLocalDataMigration(DataTypeSet types) {
types.RetainAll(GetDataTypesWithLocalDataBatchUploader());
types.RetainAll(GetActiveDataTypes());
for (DataType type : types) {
controllers_.at(type)
->GetLocalDataBatchUploader()
->TriggerLocalDataMigration();
}
}
void DataTypeManagerImpl::TriggerLocalDataMigration(
std::map<DataType, std::vector<syncer::LocalDataItemModel::DataId>> items) {
DataTypeSet supported_types = base::Intersection(
GetDataTypesWithLocalDataBatchUploader(), GetActiveDataTypes());
for (auto it = items.cbegin(); it != items.cend(); ) {
if (!supported_types.Has(it->first)) {
it = items.erase(it);
} else {
++it;
}
}
for (auto& [type, item_list] : items) {
controllers_.at(type)
->GetLocalDataBatchUploader()
->TriggerLocalDataMigration(std::move(item_list));
}
}
DataTypeManager::State DataTypeManagerImpl::state() const {
return state_;
}
DataTypeSet DataTypeManagerImpl::GetEnabledTypes() const {
return Difference(preferred_types_, data_type_status_table_.GetFailedTypes());
}
DataTypeSet DataTypeManagerImpl::GetDataTypesWithLocalDataBatchUploader()
const {
DataTypeSet types;
for (const auto& [type, controller] : controllers_) {
if (controller->GetLocalDataBatchUploader()) {
types.Put(type);
}
}
return types;
}
void DataTypeManagerImpl::RecordMemoryUsageAndCountsHistograms() {
CHECK(configurer_);
for (DataType type : GetActiveDataTypes()) {
if (type == NIGORI) {
configurer_->RecordNigoriMemoryUsageAndCountsHistograms();
continue;
}
CHECK(base::Contains(controllers_, type));
controllers_.at(type)->RecordMemoryUsageAndCountsHistograms();
}
}
}