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 |
index ba5559e96bc43de8dcf6adf3ebf04af735b92e4c..fe469ccad9457f3e7a0033c7f7be6f13705b64bb 100644 |
--- a/components/sync/user_events/user_event_sync_bridge.cc |
+++ b/components/sync/user_events/user_event_sync_bridge.cc |
@@ -4,6 +4,7 @@ |
#include "components/sync/user_events/user_event_sync_bridge.h" |
+#include <set> |
#include <utility> |
#include "base/big_endian.h" |
@@ -11,6 +12,7 @@ |
#include "base/location.h" |
#include "base/logging.h" |
#include "base/memory/ptr_util.h" |
+#include "base/stl_util.h" |
#include "base/strings/string_number_conversions.h" |
#include "components/sync/model/entity_change.h" |
#include "components/sync/model/metadata_batch.h" |
@@ -39,6 +41,12 @@ std::string GetStorageKeyFromSpecifics(const UserEventSpecifics& specifics) { |
return key; |
} |
+int64_t GetEventTimeFromStorageKey(const std::string& storage_key) { |
+ int64_t event_time; |
+ base::ReadBigEndian(&storage_key[0], &event_time); |
+ return event_time; |
+} |
+ |
std::unique_ptr<EntityData> MoveToEntityData( |
std::unique_ptr<UserEventSpecifics> specifics) { |
auto entity_data = base::MakeUnique<EntityData>(); |
@@ -61,10 +69,14 @@ std::unique_ptr<EntityData> CopyToEntityData( |
UserEventSyncBridge::UserEventSyncBridge( |
const ModelTypeStoreFactory& store_factory, |
- const ChangeProcessorFactory& change_processor_factory) |
- : ModelTypeSyncBridge(change_processor_factory, USER_EVENTS) { |
+ const ChangeProcessorFactory& change_processor_factory, |
+ GlobalIdMapper* global_id_mapper) |
+ : ModelTypeSyncBridge(change_processor_factory, USER_EVENTS), |
+ global_id_mapper_(global_id_mapper) { |
store_factory.Run( |
base::Bind(&UserEventSyncBridge::OnStoreCreated, base::AsWeakPtr(this))); |
+ global_id_mapper_->AddGlobalIdChangeObserver(base::Bind( |
+ &UserEventSyncBridge::HandleGlobalIdChange, base::AsWeakPtr(this))); |
} |
UserEventSyncBridge::~UserEventSyncBridge() {} |
@@ -85,10 +97,24 @@ base::Optional<ModelError> UserEventSyncBridge::ApplySyncChanges( |
std::unique_ptr<MetadataChangeList> metadata_change_list, |
EntityChangeList entity_changes) { |
std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); |
+ std::set<int64_t> deleted_event_times; |
for (EntityChange& change : entity_changes) { |
DCHECK_EQ(EntityChange::ACTION_DELETE, change.type()); |
batch->DeleteData(change.storage_key()); |
+ deleted_event_times.insert( |
+ GetEventTimeFromStorageKey(change.storage_key())); |
} |
+ |
+ // Because we receive ApplySyncChanges with deletions when our commits are |
+ // confirmed, this is the perfect time to cleanup our in flight objects which |
+ // are no longer in flight. |
+ base::EraseIf(in_flight_nav_linked_events_, |
+ [&deleted_event_times]( |
+ const std::pair<int64_t, sync_pb::UserEventSpecifics> kv) { |
+ return base::ContainsKey(deleted_event_times, |
+ kv.second.event_time_usec()); |
+ }); |
+ |
batch->TransferMetadataChanges(std::move(metadata_change_list)); |
store_->CommitWriteBatch( |
std::move(batch), |
@@ -124,8 +150,27 @@ void UserEventSyncBridge::DisableSync() { |
void UserEventSyncBridge::RecordUserEvent( |
std::unique_ptr<UserEventSpecifics> specifics) { |
std::string storage_key = GetStorageKeyFromSpecifics(*specifics); |
+ |
+ // There are two scenarios we need to guard against here. First, the given |
+ // user even may have been read from an old global_id timestamp off of a |
+ // navigation, which has already been re-written. In this case, we should be |
+ // able to look up the latest/best global_id to use right now, and update as |
+ // such. The other scenario is that the navigation is going to be updated in |
+ // the future, and the current global_id, while valid for now, is never going |
+ // to make it to the server, and will need to be fixed. To handle this |
+ // scenario, we store a specifics copy in |in in_flight_nav_linked_events_|, |
+ // and will re-record in HandleGlobalIdChange. |
+ if (specifics->has_navigation_id()) { |
+ int64_t latest_global_id = |
+ global_id_mapper_->GetLatestGlobalId(specifics->navigation_id()); |
+ specifics->set_navigation_id(latest_global_id); |
+ in_flight_nav_linked_events_.insert( |
+ std::make_pair(latest_global_id, *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( |
@@ -219,4 +264,19 @@ void UserEventSyncBridge::OnReadAllDataToDelete( |
base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); |
} |
+void UserEventSyncBridge::HandleGlobalIdChange(int64_t old_global_id, |
+ int64_t new_global_id) { |
+ DCHECK_NE(old_global_id, new_global_id); |
+ auto iter = in_flight_nav_linked_events_.find(old_global_id); |
+ while (iter != in_flight_nav_linked_events_.end()) { |
+ auto specifics = base::MakeUnique<UserEventSpecifics>(iter->second); |
+ DCHECK_EQ(old_global_id, specifics->navigation_id()); |
+ |
+ iter = in_flight_nav_linked_events_.erase(iter); |
+ |
+ specifics->set_navigation_id(new_global_id); |
+ RecordUserEvent(std::move(specifics)); |
+ } |
+} |
+ |
} // namespace syncer |