OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/sync/user_events/user_event_sync_bridge.h" | 5 #include "components/sync/user_events/user_event_sync_bridge.h" |
6 | 6 |
| 7 #include <set> |
7 #include <utility> | 8 #include <utility> |
8 | 9 |
9 #include "base/big_endian.h" | 10 #include "base/big_endian.h" |
10 #include "base/bind.h" | 11 #include "base/bind.h" |
11 #include "base/location.h" | 12 #include "base/location.h" |
12 #include "base/logging.h" | 13 #include "base/logging.h" |
13 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/stl_util.h" |
14 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
15 #include "components/sync/model/entity_change.h" | 17 #include "components/sync/model/entity_change.h" |
16 #include "components/sync/model/metadata_batch.h" | 18 #include "components/sync/model/metadata_batch.h" |
17 #include "components/sync/model/mutable_data_batch.h" | 19 #include "components/sync/model/mutable_data_batch.h" |
18 #include "components/sync/protocol/sync.pb.h" | 20 #include "components/sync/protocol/sync.pb.h" |
19 | 21 |
20 namespace syncer { | 22 namespace syncer { |
21 | 23 |
22 using sync_pb::UserEventSpecifics; | 24 using sync_pb::UserEventSpecifics; |
23 using sync_pb::ModelTypeState; | 25 using sync_pb::ModelTypeState; |
24 using IdList = ModelTypeStore::IdList; | 26 using IdList = ModelTypeStore::IdList; |
25 using Record = ModelTypeStore::Record; | 27 using Record = ModelTypeStore::Record; |
26 using RecordList = ModelTypeStore::RecordList; | 28 using RecordList = ModelTypeStore::RecordList; |
27 using Result = ModelTypeStore::Result; | 29 using Result = ModelTypeStore::Result; |
28 using WriteBatch = ModelTypeStore::WriteBatch; | 30 using WriteBatch = ModelTypeStore::WriteBatch; |
29 | 31 |
30 namespace { | 32 namespace { |
31 | 33 |
32 std::string GetStorageKeyFromSpecifics(const UserEventSpecifics& specifics) { | 34 std::string GetStorageKeyFromSpecifics(const UserEventSpecifics& specifics) { |
33 // Force Big Endian, this means newly created keys are last in sort order, | 35 // Force Big Endian, this means newly created keys are last in sort order, |
34 // which allows leveldb to append new writes, which it is best at. | 36 // which allows leveldb to append new writes, which it is best at. |
35 // TODO(skym): Until we force |event_time_usec| to never conflict, this has | 37 // TODO(skym): Until we force |event_time_usec| to never conflict, this has |
36 // the potential for errors. | 38 // the potential for errors. |
37 std::string key(8, 0); | 39 std::string key(8, 0); |
38 base::WriteBigEndian(&key[0], specifics.event_time_usec()); | 40 base::WriteBigEndian(&key[0], specifics.event_time_usec()); |
39 return key; | 41 return key; |
40 } | 42 } |
41 | 43 |
| 44 int64_t GetEventTimeFromStorageKey(const std::string& storage_key) { |
| 45 int64_t event_time; |
| 46 base::ReadBigEndian(&storage_key[0], &event_time); |
| 47 return event_time; |
| 48 } |
| 49 |
42 std::unique_ptr<EntityData> MoveToEntityData( | 50 std::unique_ptr<EntityData> MoveToEntityData( |
43 std::unique_ptr<UserEventSpecifics> specifics) { | 51 std::unique_ptr<UserEventSpecifics> specifics) { |
44 auto entity_data = base::MakeUnique<EntityData>(); | 52 auto entity_data = base::MakeUnique<EntityData>(); |
45 entity_data->non_unique_name = | 53 entity_data->non_unique_name = |
46 base::Int64ToString(specifics->event_time_usec()); | 54 base::Int64ToString(specifics->event_time_usec()); |
47 entity_data->specifics.set_allocated_user_event(specifics.release()); | 55 entity_data->specifics.set_allocated_user_event(specifics.release()); |
48 return entity_data; | 56 return entity_data; |
49 } | 57 } |
50 | 58 |
51 std::unique_ptr<EntityData> CopyToEntityData( | 59 std::unique_ptr<EntityData> CopyToEntityData( |
52 const UserEventSpecifics specifics) { | 60 const UserEventSpecifics specifics) { |
53 auto entity_data = base::MakeUnique<EntityData>(); | 61 auto entity_data = base::MakeUnique<EntityData>(); |
54 entity_data->non_unique_name = | 62 entity_data->non_unique_name = |
55 base::Int64ToString(specifics.event_time_usec()); | 63 base::Int64ToString(specifics.event_time_usec()); |
56 *entity_data->specifics.mutable_user_event() = specifics; | 64 *entity_data->specifics.mutable_user_event() = specifics; |
57 return entity_data; | 65 return entity_data; |
58 } | 66 } |
59 | 67 |
60 } // namespace | 68 } // namespace |
61 | 69 |
62 UserEventSyncBridge::UserEventSyncBridge( | 70 UserEventSyncBridge::UserEventSyncBridge( |
63 const ModelTypeStoreFactory& store_factory, | 71 const ModelTypeStoreFactory& store_factory, |
64 const ChangeProcessorFactory& change_processor_factory) | 72 const ChangeProcessorFactory& change_processor_factory, |
65 : ModelTypeSyncBridge(change_processor_factory, USER_EVENTS) { | 73 GlobalIdMapper* global_id_mapper) |
| 74 : ModelTypeSyncBridge(change_processor_factory, USER_EVENTS), |
| 75 global_id_mapper_(global_id_mapper) { |
66 store_factory.Run( | 76 store_factory.Run( |
67 base::Bind(&UserEventSyncBridge::OnStoreCreated, base::AsWeakPtr(this))); | 77 base::Bind(&UserEventSyncBridge::OnStoreCreated, base::AsWeakPtr(this))); |
| 78 global_id_mapper_->AddGlobalIdChangeObserver(base::Bind( |
| 79 &UserEventSyncBridge::HandleGlobalIdChange, base::AsWeakPtr(this))); |
68 } | 80 } |
69 | 81 |
70 UserEventSyncBridge::~UserEventSyncBridge() {} | 82 UserEventSyncBridge::~UserEventSyncBridge() {} |
71 | 83 |
72 std::unique_ptr<MetadataChangeList> | 84 std::unique_ptr<MetadataChangeList> |
73 UserEventSyncBridge::CreateMetadataChangeList() { | 85 UserEventSyncBridge::CreateMetadataChangeList() { |
74 return WriteBatch::CreateMetadataChangeList(); | 86 return WriteBatch::CreateMetadataChangeList(); |
75 } | 87 } |
76 | 88 |
77 base::Optional<ModelError> UserEventSyncBridge::MergeSyncData( | 89 base::Optional<ModelError> UserEventSyncBridge::MergeSyncData( |
78 std::unique_ptr<MetadataChangeList> metadata_change_list, | 90 std::unique_ptr<MetadataChangeList> metadata_change_list, |
79 EntityChangeList entity_data) { | 91 EntityChangeList entity_data) { |
80 NOTREACHED(); | 92 NOTREACHED(); |
81 return {}; | 93 return {}; |
82 } | 94 } |
83 | 95 |
84 base::Optional<ModelError> UserEventSyncBridge::ApplySyncChanges( | 96 base::Optional<ModelError> UserEventSyncBridge::ApplySyncChanges( |
85 std::unique_ptr<MetadataChangeList> metadata_change_list, | 97 std::unique_ptr<MetadataChangeList> metadata_change_list, |
86 EntityChangeList entity_changes) { | 98 EntityChangeList entity_changes) { |
87 std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); | 99 std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); |
| 100 std::set<int64_t> deleted_event_times; |
88 for (EntityChange& change : entity_changes) { | 101 for (EntityChange& change : entity_changes) { |
89 DCHECK_EQ(EntityChange::ACTION_DELETE, change.type()); | 102 DCHECK_EQ(EntityChange::ACTION_DELETE, change.type()); |
90 batch->DeleteData(change.storage_key()); | 103 batch->DeleteData(change.storage_key()); |
| 104 deleted_event_times.insert( |
| 105 GetEventTimeFromStorageKey(change.storage_key())); |
91 } | 106 } |
| 107 |
| 108 // Because we receive ApplySyncChanges with deletions when our commits are |
| 109 // confirmed, this is the perfect time to cleanup our in flight objects which |
| 110 // are no longer in flight. |
| 111 base::EraseIf(in_flight_nav_linked_events_, |
| 112 [&deleted_event_times]( |
| 113 const std::pair<int64_t, sync_pb::UserEventSpecifics> kv) { |
| 114 return base::ContainsKey(deleted_event_times, |
| 115 kv.second.event_time_usec()); |
| 116 }); |
| 117 |
92 batch->TransferMetadataChanges(std::move(metadata_change_list)); | 118 batch->TransferMetadataChanges(std::move(metadata_change_list)); |
93 store_->CommitWriteBatch( | 119 store_->CommitWriteBatch( |
94 std::move(batch), | 120 std::move(batch), |
95 base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); | 121 base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); |
96 return {}; | 122 return {}; |
97 } | 123 } |
98 | 124 |
99 void UserEventSyncBridge::GetData(StorageKeyList storage_keys, | 125 void UserEventSyncBridge::GetData(StorageKeyList storage_keys, |
100 DataCallback callback) { | 126 DataCallback callback) { |
101 store_->ReadData(storage_keys, base::Bind(&UserEventSyncBridge::OnReadData, | 127 store_->ReadData(storage_keys, base::Bind(&UserEventSyncBridge::OnReadData, |
(...skipping 15 matching lines...) Expand all Loading... |
117 | 143 |
118 void UserEventSyncBridge::DisableSync() { | 144 void UserEventSyncBridge::DisableSync() { |
119 // No data should be retained through sign out. | 145 // No data should be retained through sign out. |
120 store_->ReadAllData(base::Bind(&UserEventSyncBridge::OnReadAllDataToDelete, | 146 store_->ReadAllData(base::Bind(&UserEventSyncBridge::OnReadAllDataToDelete, |
121 base::AsWeakPtr(this))); | 147 base::AsWeakPtr(this))); |
122 } | 148 } |
123 | 149 |
124 void UserEventSyncBridge::RecordUserEvent( | 150 void UserEventSyncBridge::RecordUserEvent( |
125 std::unique_ptr<UserEventSpecifics> specifics) { | 151 std::unique_ptr<UserEventSpecifics> specifics) { |
126 std::string storage_key = GetStorageKeyFromSpecifics(*specifics); | 152 std::string storage_key = GetStorageKeyFromSpecifics(*specifics); |
| 153 |
| 154 // There are two scenarios we need to guard against here. First, the given |
| 155 // user even may have been read from an old global_id timestamp off of a |
| 156 // navigation, which has already been re-written. In this case, we should be |
| 157 // able to look up the latest/best global_id to use right now, and update as |
| 158 // such. The other scenario is that the navigation is going to be updated in |
| 159 // the future, and the current global_id, while valid for now, is never going |
| 160 // to make it to the server, and will need to be fixed. To handle this |
| 161 // scenario, we store a specifics copy in |in in_flight_nav_linked_events_|, |
| 162 // and will re-record in HandleGlobalIdChange. |
| 163 if (specifics->has_navigation_id()) { |
| 164 int64_t latest_global_id = |
| 165 global_id_mapper_->GetLatestGlobalId(specifics->navigation_id()); |
| 166 specifics->set_navigation_id(latest_global_id); |
| 167 in_flight_nav_linked_events_.insert( |
| 168 std::make_pair(latest_global_id, *specifics)); |
| 169 } |
| 170 |
127 std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); | 171 std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); |
128 batch->WriteData(storage_key, specifics->SerializeAsString()); | 172 batch->WriteData(storage_key, specifics->SerializeAsString()); |
| 173 |
129 change_processor()->Put(storage_key, MoveToEntityData(std::move(specifics)), | 174 change_processor()->Put(storage_key, MoveToEntityData(std::move(specifics)), |
130 batch->GetMetadataChangeList()); | 175 batch->GetMetadataChangeList()); |
131 store_->CommitWriteBatch( | 176 store_->CommitWriteBatch( |
132 std::move(batch), | 177 std::move(batch), |
133 base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); | 178 base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); |
134 } | 179 } |
135 | 180 |
136 void UserEventSyncBridge::OnStoreCreated( | 181 void UserEventSyncBridge::OnStoreCreated( |
137 Result result, | 182 Result result, |
138 std::unique_ptr<ModelTypeStore> store) { | 183 std::unique_ptr<ModelTypeStore> store) { |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 | 257 |
213 std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); | 258 std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); |
214 for (const Record& r : *data_records) { | 259 for (const Record& r : *data_records) { |
215 batch->DeleteData(r.id); | 260 batch->DeleteData(r.id); |
216 } | 261 } |
217 store_->CommitWriteBatch( | 262 store_->CommitWriteBatch( |
218 std::move(batch), | 263 std::move(batch), |
219 base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); | 264 base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); |
220 } | 265 } |
221 | 266 |
| 267 void UserEventSyncBridge::HandleGlobalIdChange(int64_t old_global_id, |
| 268 int64_t new_global_id) { |
| 269 DCHECK_NE(old_global_id, new_global_id); |
| 270 auto iter = in_flight_nav_linked_events_.find(old_global_id); |
| 271 while (iter != in_flight_nav_linked_events_.end()) { |
| 272 auto specifics = base::MakeUnique<UserEventSpecifics>(iter->second); |
| 273 DCHECK_EQ(old_global_id, specifics->navigation_id()); |
| 274 |
| 275 iter = in_flight_nav_linked_events_.erase(iter); |
| 276 |
| 277 specifics->set_navigation_id(new_global_id); |
| 278 RecordUserEvent(std::move(specifics)); |
| 279 } |
| 280 } |
| 281 |
222 } // namespace syncer | 282 } // namespace syncer |
OLD | NEW |