Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Unified Diff: components/sync_driver/device_info_service.cc

Issue 1991023002: [Sync] USS: Fix race condition in DeviceInfoService + add error handling (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/sync_driver/device_info_service.cc
diff --git a/components/sync_driver/device_info_service.cc b/components/sync_driver/device_info_service.cc
index f7292f91336dc9eb89d61ebf238f6d31a777369d..ff084d69a135dc6a357396c9d24af3f53873afaa 100644
--- a/components/sync_driver/device_info_service.cc
+++ b/components/sync_driver/device_info_service.cc
@@ -80,13 +80,9 @@ DeviceInfoService::CreateMetadataChangeList() {
SyncError DeviceInfoService::MergeSyncData(
std::unique_ptr<MetadataChangeList> metadata_change_list,
EntityDataMap entity_data_map) {
- if (!has_provider_initialized_ || !has_metadata_loaded_ ||
- !change_processor()) {
- return SyncError(
- FROM_HERE, SyncError::DATATYPE_ERROR,
- "Cannot call MergeSyncData without provider, data, and processor.",
- syncer::DEVICE_INFO);
- }
+ DCHECK(has_provider_initialized_);
+ DCHECK(has_metadata_loaded_);
+ DCHECK(change_processor());
// Local data should typically be near empty, with the only possible value
// corresponding to this device. This is because on signout all device info
@@ -134,18 +130,14 @@ SyncError DeviceInfoService::MergeSyncData(
CommitAndNotify(std::move(batch), std::move(metadata_change_list),
has_changes);
- return syncer::SyncError();
+ return SyncError();
}
SyncError DeviceInfoService::ApplySyncChanges(
std::unique_ptr<MetadataChangeList> metadata_change_list,
EntityChangeList entity_changes) {
- if (!has_provider_initialized_ || !has_metadata_loaded_) {
- return SyncError(
- FROM_HERE, SyncError::DATATYPE_ERROR,
- "Cannot call ApplySyncChanges before provider and data have loaded.",
- syncer::DEVICE_INFO);
- }
+ DCHECK(has_provider_initialized_);
+ DCHECK(has_metadata_loaded_);
std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch();
bool has_changes = false;
@@ -177,14 +169,7 @@ SyncError DeviceInfoService::ApplySyncChanges(
void DeviceInfoService::GetData(ClientTagList client_tags,
DataCallback callback) {
- if (!has_metadata_loaded_) {
- callback.Run(
- SyncError(FROM_HERE, SyncError::DATATYPE_ERROR,
- "Should not call GetData before metadata has loaded.",
- syncer::DEVICE_INFO),
- std::unique_ptr<DataBatchImpl>());
- return;
- }
+ DCHECK(has_metadata_loaded_);
std::unique_ptr<DataBatchImpl> batch(new DataBatchImpl());
for (const auto& tag : client_tags) {
@@ -194,25 +179,20 @@ void DeviceInfoService::GetData(ClientTagList client_tags,
batch->Put(tag, CopyToEntityData(*iter->second));
}
}
- callback.Run(syncer::SyncError(), std::move(batch));
+
+ callback.Run(SyncError(), std::move(batch));
}
void DeviceInfoService::GetAllData(DataCallback callback) {
- if (!has_metadata_loaded_) {
- callback.Run(
- SyncError(FROM_HERE, SyncError::DATATYPE_ERROR,
- "Should not call GetAllData before metadata has loaded.",
- syncer::DEVICE_INFO),
- std::unique_ptr<DataBatchImpl>());
- return;
- }
+ DCHECK(has_metadata_loaded_);
std::unique_ptr<DataBatchImpl> batch(new DataBatchImpl());
for (const auto& kv : all_data_) {
batch->Put(DeviceInfoUtil::SpecificsToTag(*kv.second),
CopyToEntityData(*kv.second));
}
- callback.Run(syncer::SyncError(), std::move(batch));
+
+ callback.Run(SyncError(), std::move(batch));
}
std::string DeviceInfoService::GetClientTag(const EntityData& entity_data) {
@@ -228,9 +208,9 @@ void DeviceInfoService::OnChangeProcessorSet() {
// have created the processor ourselves because we had no metadata. So there
// must not be any metadata on disk.
if (has_metadata_loaded_) {
- change_processor()->OnMetadataLoaded(syncer::SyncError(),
+ change_processor()->OnMetadataLoaded(SyncError(),
base::WrapUnique(new MetadataBatch()));
- TryReconcileLocalAndStored();
+ ReconcileLocalAndStored();
}
}
@@ -333,7 +313,7 @@ bool DeviceInfoService::DeleteSpecifics(const std::string& guid,
void DeviceInfoService::OnProviderInitialized() {
has_provider_initialized_ = true;
- TryReconcileLocalAndStored();
+ LoadMetadataIfReady();
}
void DeviceInfoService::OnStoreCreated(Result result,
@@ -343,7 +323,7 @@ void DeviceInfoService::OnStoreCreated(Result result,
store_->ReadAllData(base::Bind(&DeviceInfoService::OnReadAllData,
weak_factory_.GetWeakPtr()));
} else {
- LOG(WARNING) << "ModelTypeStore creation failed.";
+ ReportStartupErrorToSync("ModelTypeStore creation failed.");
// TODO(skym, crbug.com/582460): Handle unrecoverable initialization
// failure.
}
@@ -352,7 +332,7 @@ void DeviceInfoService::OnStoreCreated(Result result,
void DeviceInfoService::OnReadAllData(Result result,
std::unique_ptr<RecordList> record_list) {
if (result != Result::SUCCESS) {
- LOG(WARNING) << "Initial load of data failed.";
+ ReportStartupErrorToSync("Initial load of data failed.");
// TODO(skym, crbug.com/582460): Handle unrecoverable initialization
// failure.
return;
@@ -364,25 +344,34 @@ void DeviceInfoService::OnReadAllData(Result result,
if (specifics->ParseFromString(r.value)) {
all_data_[specifics->cache_guid()] = std::move(specifics);
} else {
- LOG(WARNING) << "Failed to deserialize specifics.";
+ ReportStartupErrorToSync("Failed to deserialize specifics.");
// TODO(skym, crbug.com/582460): Handle unrecoverable initialization
// failure.
}
}
- store_->ReadAllMetadata(base::Bind(&DeviceInfoService::OnReadAllMetadata,
- weak_factory_.GetWeakPtr()));
+
+ has_data_loaded_ = true;
+ LoadMetadataIfReady();
+}
+
+void DeviceInfoService::LoadMetadataIfReady() {
+ if (has_data_loaded_ && has_provider_initialized_) {
+ store_->ReadAllMetadata(base::Bind(&DeviceInfoService::OnReadAllMetadata,
+ weak_factory_.GetWeakPtr()));
+ }
}
void DeviceInfoService::OnReadAllMetadata(
Result result,
std::unique_ptr<RecordList> metadata_records,
const std::string& global_metadata) {
+ DCHECK(!has_metadata_loaded_);
+
if (result != Result::SUCCESS) {
// Store has encountered some serious error. We should still be able to
// continue as a read only service, since if we got this far we must have
- // loaded all data out succesfully. TODO(skym): Should we communicate this
- // to sync somehow?
- LOG(WARNING) << "Load of metadata completely failed.";
+ // loaded all data out succesfully.
+ ReportStartupErrorToSync("Load of metadata completely failed.");
return;
}
@@ -402,8 +391,8 @@ void DeviceInfoService::OnReadAllMetadata(
has_metadata_loaded_ = true;
if (!change_processor()) {
- // This means we haven't been told to start sycning and we don't have any
- // local metadata
+ // This means we haven't been told to start syncing and we don't have any
+ // local metadata.
return;
}
@@ -418,7 +407,10 @@ void DeviceInfoService::OnReadAllMetadata(
// the entity metadata to the batch or completely skip that step? We're
// going to have to perform a merge shortly. Does this decision/logic even
// belong in this service?
- LOG(WARNING) << "Failed to deserialize global metadata.";
+ change_processor()->OnMetadataLoaded(
+ change_processor()->CreateAndUploadError(
+ FROM_HERE, "Failed to deserialize global metadata."),
+ nullptr);
}
for (const Record& r : *metadata_records.get()) {
sync_pb::EntityMetadata entity_metadata;
@@ -427,12 +419,12 @@ void DeviceInfoService::OnReadAllMetadata(
} else {
// TODO(skym): This really isn't too bad. We just want to regenerate
// metadata for this particular entity. Unfortunately there isn't a
- // convinient way to tell the processor to do this.
+ // convenient way to tell the processor to do this.
LOG(WARNING) << "Failed to deserialize entity metadata.";
}
}
- change_processor()->OnMetadataLoaded(syncer::SyncError(), std::move(batch));
- TryReconcileLocalAndStored();
+ change_processor()->OnMetadataLoaded(SyncError(), std::move(batch));
+ ReconcileLocalAndStored();
}
void DeviceInfoService::OnCommit(Result result) {
@@ -441,57 +433,60 @@ void DeviceInfoService::OnCommit(Result result) {
}
}
-void DeviceInfoService::TryReconcileLocalAndStored() {
+void DeviceInfoService::ReconcileLocalAndStored() {
// On initial syncing we will have a change processor here, but it will not be
// tracking changes. We need to persist a copy of our local device info to
// disk, but the Put call to the processor will be ignored. That should be
// fine however, as the discrepancy will be picked up later in merge. We don't
// bother trying to track this case and act intelligently because simply not
// much of a benefit in doing so.
- if (has_provider_initialized_ && has_metadata_loaded_ && change_processor()) {
- const DeviceInfo* current_info =
- local_device_info_provider_->GetLocalDeviceInfo();
- auto iter = all_data_.find(current_info->guid());
-
- // Convert to DeviceInfo for Equals function.
- if (iter != all_data_.end() &&
- current_info->Equals(*CopyToModel(*iter->second))) {
- const TimeDelta pulse_delay(DeviceInfoUtil::CalculatePulseDelay(
- GetLastUpdateTime(*iter->second), Time::Now()));
- if (!pulse_delay.is_zero()) {
- pulse_timer_.Start(FROM_HERE, pulse_delay,
- base::Bind(&DeviceInfoService::SendLocalData,
- base::Unretained(this)));
- return;
- }
+ DCHECK(has_provider_initialized_);
+ DCHECK(has_metadata_loaded_);
+ DCHECK(change_processor());
+ const DeviceInfo* current_info =
+ local_device_info_provider_->GetLocalDeviceInfo();
+ auto iter = all_data_.find(current_info->guid());
+
+ // Convert to DeviceInfo for Equals function.
+ if (iter != all_data_.end() &&
+ current_info->Equals(*CopyToModel(*iter->second))) {
+ const TimeDelta pulse_delay(DeviceInfoUtil::CalculatePulseDelay(
+ GetLastUpdateTime(*iter->second), Time::Now()));
+ if (!pulse_delay.is_zero()) {
+ pulse_timer_.Start(FROM_HERE, pulse_delay,
+ base::Bind(&DeviceInfoService::SendLocalData,
+ base::Unretained(this)));
+ return;
}
- SendLocalData();
}
+ SendLocalData();
}
void DeviceInfoService::SendLocalData() {
DCHECK(has_provider_initialized_);
// TODO(skym): Handle disconnecting and reconnecting, this will currently halt
// the pulse timer and never restart it.
- if (change_processor()) {
- std::unique_ptr<DeviceInfoSpecifics> specifics =
- CopyToSpecifics(*local_device_info_provider_->GetLocalDeviceInfo());
- specifics->set_last_updated_timestamp(syncer::TimeToProtoTime(Time::Now()));
-
- std::unique_ptr<MetadataChangeList> metadata_change_list =
- CreateMetadataChangeList();
- change_processor()->Put(DeviceInfoUtil::SpecificsToTag(*specifics),
- CopyToEntityData(*specifics),
- metadata_change_list.get());
+ if (!change_processor()) {
+ return;
+ }
+
+ std::unique_ptr<DeviceInfoSpecifics> specifics =
+ CopyToSpecifics(*local_device_info_provider_->GetLocalDeviceInfo());
+ specifics->set_last_updated_timestamp(syncer::TimeToProtoTime(Time::Now()));
- std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch();
- StoreSpecifics(std::move(specifics), batch.get());
+ std::unique_ptr<MetadataChangeList> metadata_change_list =
+ CreateMetadataChangeList();
+ change_processor()->Put(DeviceInfoUtil::SpecificsToTag(*specifics),
+ CopyToEntityData(*specifics),
+ metadata_change_list.get());
- CommitAndNotify(std::move(batch), std::move(metadata_change_list), true);
- pulse_timer_.Start(
- FROM_HERE, DeviceInfoUtil::kPulseInterval,
- base::Bind(&DeviceInfoService::SendLocalData, base::Unretained(this)));
- }
+ std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch();
+ StoreSpecifics(std::move(specifics), batch.get());
+
+ CommitAndNotify(std::move(batch), std::move(metadata_change_list), true);
+ pulse_timer_.Start(
+ FROM_HERE, DeviceInfoUtil::kPulseInterval,
+ base::Bind(&DeviceInfoService::SendLocalData, base::Unretained(this)));
}
void DeviceInfoService::CommitAndNotify(
@@ -516,6 +511,18 @@ int DeviceInfoService::CountActiveDevices(const Time now) const {
});
}
+void DeviceInfoService::ReportStartupErrorToSync(const std::string& msg) {
+ DCHECK(!has_metadata_loaded_);
+ LOG(WARNING) << msg;
+
+ // Create a processor and give it the error in case sync tries to start.
+ if (!change_processor()) {
+ CreateChangeProcessor();
+ }
+ change_processor()->OnMetadataLoaded(
+ change_processor()->CreateAndUploadError(FROM_HERE, msg), nullptr);
+}
+
// static
Time DeviceInfoService::GetLastUpdateTime(
const DeviceInfoSpecifics& specifics) {
« no previous file with comments | « components/sync_driver/device_info_service.h ('k') | components/sync_driver/device_info_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698