Chromium Code Reviews| Index: components/sync/user_events/user_event_sync_bridge.cc |
| diff --git a/components/sync/user_events/user_event_sync_bridge.cc b/components/sync/user_events/user_event_sync_bridge.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..44f7fb760da461cdf5478a2973f81e382d7fe7e9 |
| --- /dev/null |
| +++ b/components/sync/user_events/user_event_sync_bridge.cc |
| @@ -0,0 +1,213 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "components/sync/user_events/user_event_sync_bridge.h" |
| + |
| +#include <utility> |
| + |
| +#include "base/big_endian.h" |
| +#include "base/bind.h" |
| +#include "base/location.h" |
| +#include "base/logging.h" |
| +#include "base/memory/ptr_util.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "components/sync/model/entity_change.h" |
| +#include "components/sync/model/metadata_batch.h" |
| +#include "components/sync/model/mutable_data_batch.h" |
| +#include "components/sync/protocol/sync.pb.h" |
| + |
| +namespace syncer { |
| + |
| +using sync_pb::UserEventSpecifics; |
| +using sync_pb::ModelTypeState; |
| +using IdList = ModelTypeStore::IdList; |
| +using Record = ModelTypeStore::Record; |
| +using RecordList = ModelTypeStore::RecordList; |
| +using Result = ModelTypeStore::Result; |
| +using WriteBatch = ModelTypeStore::WriteBatch; |
| + |
| +namespace { |
| + |
| +std::string GetStorageKeyFromSpecifics(const UserEventSpecifics& specifics) { |
| + // Force Big Endian, this means newly created keys are last in sort order, |
| + // which allows leveldb to append new writes, which it is best at. |
| + // TODO(skym): Until we force |event_time_usec| to never conflict, this has |
| + // the potential for errors. |
| + std::string key(8, 0); |
| + base::WriteBigEndian(&key[0], specifics.event_time_usec()); |
|
Patrick Noland
2017/05/04 19:43:18
For my own curiosity, why does this (and other use
skym
2017/05/04 20:34:00
It would seem c_str() is too const.
../../compone
|
| + return key; |
| +} |
| + |
| +std::unique_ptr<EntityData> MoveToEntityData( |
| + std::unique_ptr<UserEventSpecifics> specifics) { |
| + auto entity_data = base::MakeUnique<EntityData>(); |
| + entity_data->non_unique_name = |
| + base::Int64ToString(specifics->event_time_usec()); |
| + entity_data->specifics.set_allocated_user_event(specifics.release()); |
| + return entity_data; |
| +} |
| + |
| +std::unique_ptr<EntityData> CopyToEntityData( |
| + const UserEventSpecifics specifics) { |
| + auto entity_data = base::MakeUnique<EntityData>(); |
| + entity_data->non_unique_name = |
| + base::Int64ToString(specifics.event_time_usec()); |
| + *entity_data->specifics.mutable_user_event() = specifics; |
| + return entity_data; |
| +} |
| + |
| +} // namespace |
| + |
| +UserEventSyncBridge::UserEventSyncBridge( |
| + const ModelTypeStoreFactory& store_factory, |
| + const ChangeProcessorFactory& change_processor_factory) |
| + : ModelTypeSyncBridge(change_processor_factory, USER_EVENTS) { |
| + store_factory.Run( |
| + base::Bind(&UserEventSyncBridge::OnStoreCreated, base::AsWeakPtr(this))); |
| +} |
| + |
| +UserEventSyncBridge::~UserEventSyncBridge() {} |
| + |
| +std::unique_ptr<MetadataChangeList> |
| +UserEventSyncBridge::CreateMetadataChangeList() { |
| + return WriteBatch::CreateMetadataChangeList(); |
| +} |
| + |
| +base::Optional<ModelError> UserEventSyncBridge::MergeSyncData( |
| + std::unique_ptr<MetadataChangeList> metadata_change_list, |
| + EntityDataMap entity_data_map) { |
| + NOTREACHED(); |
| + return {}; |
| +} |
| + |
| +base::Optional<ModelError> UserEventSyncBridge::ApplySyncChanges( |
| + std::unique_ptr<MetadataChangeList> metadata_change_list, |
| + EntityChangeList entity_changes) { |
| + NOTREACHED(); |
| + return {}; |
| +} |
| + |
| +void UserEventSyncBridge::GetData(StorageKeyList storage_keys, |
| + DataCallback callback) { |
| + store_->ReadData(storage_keys, base::Bind(&UserEventSyncBridge::OnReadData, |
| + base::AsWeakPtr(this), callback)); |
| +} |
| + |
| +void UserEventSyncBridge::GetAllData(DataCallback callback) { |
| + store_->ReadAllData(base::Bind(&UserEventSyncBridge::OnReadAllData, |
| + base::AsWeakPtr(this), callback)); |
| +} |
| + |
| +std::string UserEventSyncBridge::GetClientTag(const EntityData& entity_data) { |
| + return GetStorageKey(entity_data); |
| +} |
| + |
| +std::string UserEventSyncBridge::GetStorageKey(const EntityData& entity_data) { |
| + return GetStorageKeyFromSpecifics(entity_data.specifics.user_event()); |
| +} |
| + |
| +void UserEventSyncBridge::DisableSync() { |
| + // No data should be retained through sign out. |
| + store_->ReadAllData(base::Bind(&UserEventSyncBridge::OnReadAllDataToDelete, |
| + base::AsWeakPtr(this))); |
| +} |
| + |
| +void UserEventSyncBridge::RecordUserEvent( |
| + std::unique_ptr<UserEventSpecifics> specifics) { |
| + std::string storage_key = GetStorageKeyFromSpecifics(*specifics); |
| + std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); |
| + batch->WriteData(storage_key, specifics->SerializeAsString()); |
| + change_processor()->Put(storage_key, MoveToEntityData(std::move(specifics)), |
| + batch->GetMetadataChangeList()); |
| + store_->CommitWriteBatch( |
| + std::move(batch), |
| + base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); |
| +} |
| + |
| +void UserEventSyncBridge::OnStoreCreated( |
| + Result result, |
| + std::unique_ptr<ModelTypeStore> store) { |
| + if (result == Result::SUCCESS) { |
| + std::swap(store_, store); |
| + store_->ReadAllMetadata(base::Bind(&UserEventSyncBridge::OnReadAllMetadata, |
| + base::AsWeakPtr(this))); |
| + } else { |
| + change_processor()->ReportError(FROM_HERE, |
| + "ModelTypeStore creation failed."); |
| + } |
| +} |
| + |
| +void UserEventSyncBridge::OnReadAllMetadata( |
| + base::Optional<ModelError> error, |
| + std::unique_ptr<MetadataBatch> metadata_batch) { |
| + if (error) { |
| + change_processor()->ReportError(error.value()); |
| + } else { |
| + if (!metadata_batch->GetModelTypeState().initial_sync_done()) { |
| + // We have never initialized before, force it to true. We are not going to |
| + // ever have a GetUpdates because our type is commit only. |
| + // TODO(skym): Do we need to worry about saving this back ourselves? Or |
| + // does that get taken care for us? |
| + ModelTypeState state = metadata_batch->GetModelTypeState(); |
| + state.set_initial_sync_done(true); |
| + metadata_batch->SetModelTypeState(state); |
| + } |
| + change_processor()->ModelReadyToSync(std::move(metadata_batch)); |
| + } |
| +} |
| + |
| +void UserEventSyncBridge::OnCommit(Result result) { |
| + if (result != Result::SUCCESS) { |
| + change_processor()->ReportError(FROM_HERE, "Failed writing user events."); |
| + } |
| +} |
| + |
| +void UserEventSyncBridge::OnReadData(DataCallback callback, |
| + Result result, |
| + std::unique_ptr<RecordList> data_records, |
| + std::unique_ptr<IdList> missing_id_list) { |
| + OnReadAllData(callback, result, std::move(data_records)); |
| +} |
| + |
| +void UserEventSyncBridge::OnReadAllData( |
| + DataCallback callback, |
| + Result result, |
| + std::unique_ptr<RecordList> data_records) { |
| + if (result != Result::SUCCESS) { |
| + change_processor()->ReportError(FROM_HERE, "Failed reading user events."); |
| + return; |
| + } |
| + |
| + auto batch = base::MakeUnique<MutableDataBatch>(); |
| + UserEventSpecifics specifics; |
|
Patrick Noland
2017/05/04 19:43:18
Again for my own curiosity, any reason this is dec
skym
2017/05/04 20:34:00
I'm mostly copying this pattern from other places
|
| + for (const Record& r : *data_records) { |
| + if (specifics.ParseFromString(r.value)) { |
| + DCHECK_EQ(r.id, GetStorageKeyFromSpecifics(specifics)); |
| + batch->Put(r.id, CopyToEntityData(specifics)); |
| + } else { |
| + change_processor()->ReportError(FROM_HERE, |
|
Patrick Noland
2017/05/04 19:43:18
Do we want to keep the loop going if serialization
skym
2017/05/04 20:34:00
Probably not! Added an early return.
|
| + "Failed deserializing user events."); |
| + } |
| + } |
| + callback.Run(std::move(batch)); |
| +} |
| + |
| +void UserEventSyncBridge::OnReadAllDataToDelete( |
| + Result result, |
| + std::unique_ptr<RecordList> data_records) { |
| + if (result != Result::SUCCESS) { |
| + change_processor()->ReportError(FROM_HERE, "Failed reading user events."); |
| + return; |
| + } |
| + |
| + std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); |
| + for (const Record& r : *data_records) { |
| + batch->DeleteData(r.id); |
| + } |
| + store_->CommitWriteBatch( |
| + std::move(batch), |
| + base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); |
| +} |
| + |
| +} // namespace syncer |