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 auto iter = in_flight_nav_linked_events_.begin(); | |
112 while (iter != in_flight_nav_linked_events_.end()) { | |
Patrick Noland
2017/06/28 22:44:37
I think you can use base::EraseIf here
skym
2017/07/05 19:14:28
Done. Not sure if it's any simpler now, but it is
| |
113 if (base::ContainsKey(deleted_event_times, | |
114 iter->second.event_time_usec())) { | |
115 iter = in_flight_nav_linked_events_.erase(iter); | |
116 } else { | |
117 ++iter; | |
118 } | |
119 } | |
120 | |
92 batch->TransferMetadataChanges(std::move(metadata_change_list)); | 121 batch->TransferMetadataChanges(std::move(metadata_change_list)); |
93 store_->CommitWriteBatch( | 122 store_->CommitWriteBatch( |
94 std::move(batch), | 123 std::move(batch), |
95 base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); | 124 base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); |
96 return {}; | 125 return {}; |
97 } | 126 } |
98 | 127 |
99 void UserEventSyncBridge::GetData(StorageKeyList storage_keys, | 128 void UserEventSyncBridge::GetData(StorageKeyList storage_keys, |
100 DataCallback callback) { | 129 DataCallback callback) { |
101 store_->ReadData(storage_keys, base::Bind(&UserEventSyncBridge::OnReadData, | 130 store_->ReadData(storage_keys, base::Bind(&UserEventSyncBridge::OnReadData, |
(...skipping 15 matching lines...) Expand all Loading... | |
117 | 146 |
118 void UserEventSyncBridge::DisableSync() { | 147 void UserEventSyncBridge::DisableSync() { |
119 // No data should be retained through sign out. | 148 // No data should be retained through sign out. |
120 store_->ReadAllData(base::Bind(&UserEventSyncBridge::OnReadAllDataToDelete, | 149 store_->ReadAllData(base::Bind(&UserEventSyncBridge::OnReadAllDataToDelete, |
121 base::AsWeakPtr(this))); | 150 base::AsWeakPtr(this))); |
122 } | 151 } |
123 | 152 |
124 void UserEventSyncBridge::RecordUserEvent( | 153 void UserEventSyncBridge::RecordUserEvent( |
125 std::unique_ptr<UserEventSpecifics> specifics) { | 154 std::unique_ptr<UserEventSpecifics> specifics) { |
126 std::string storage_key = GetStorageKeyFromSpecifics(*specifics); | 155 std::string storage_key = GetStorageKeyFromSpecifics(*specifics); |
156 | |
157 // There are two scenarios we need to guard against here. First, the given | |
158 // user even may have been read from an old global_id timestamp off of a | |
159 // navigation, which has already been re-written. In this case, we should be | |
160 // able to look up the latest/best global_id to use right now, and update as | |
161 // such. The other scenario is that the navigation is going to be updated in | |
162 // the future, and the current global_id, while valid for now, is never going | |
163 // to make it to the server, and will need to be fixed. To handle this | |
164 // scenario, we store a specifics copy in |in in_flight_nav_linked_events_|, | |
165 // and will re-record in HandleGlobalIdChange. | |
166 if (specifics->has_navigation_id()) { | |
167 int64_t latest_global_id = | |
168 global_id_mapper_->GetLatestGlobalId(specifics->navigation_id()); | |
169 specifics->set_navigation_id(latest_global_id); | |
170 in_flight_nav_linked_events_.insert( | |
171 std::make_pair(latest_global_id, *specifics)); | |
172 } | |
173 | |
127 std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); | 174 std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); |
128 batch->WriteData(storage_key, specifics->SerializeAsString()); | 175 batch->WriteData(storage_key, specifics->SerializeAsString()); |
176 | |
129 change_processor()->Put(storage_key, MoveToEntityData(std::move(specifics)), | 177 change_processor()->Put(storage_key, MoveToEntityData(std::move(specifics)), |
130 batch->GetMetadataChangeList()); | 178 batch->GetMetadataChangeList()); |
131 store_->CommitWriteBatch( | 179 store_->CommitWriteBatch( |
132 std::move(batch), | 180 std::move(batch), |
133 base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); | 181 base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); |
134 } | 182 } |
135 | 183 |
136 void UserEventSyncBridge::OnStoreCreated( | 184 void UserEventSyncBridge::OnStoreCreated( |
137 Result result, | 185 Result result, |
138 std::unique_ptr<ModelTypeStore> store) { | 186 std::unique_ptr<ModelTypeStore> store) { |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
212 | 260 |
213 std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); | 261 std::unique_ptr<WriteBatch> batch = store_->CreateWriteBatch(); |
214 for (const Record& r : *data_records) { | 262 for (const Record& r : *data_records) { |
215 batch->DeleteData(r.id); | 263 batch->DeleteData(r.id); |
216 } | 264 } |
217 store_->CommitWriteBatch( | 265 store_->CommitWriteBatch( |
218 std::move(batch), | 266 std::move(batch), |
219 base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); | 267 base::Bind(&UserEventSyncBridge::OnCommit, base::AsWeakPtr(this))); |
220 } | 268 } |
221 | 269 |
270 void UserEventSyncBridge::HandleGlobalIdChange(int64_t old_global_id, | |
271 int64_t new_global_id) { | |
272 DCHECK_NE(old_global_id, new_global_id); | |
273 auto iter = in_flight_nav_linked_events_.find(old_global_id); | |
274 while (iter != in_flight_nav_linked_events_.end()) { | |
275 auto specifics = base::MakeUnique<UserEventSpecifics>(iter->second); | |
276 DCHECK_EQ(old_global_id, specifics->navigation_id()); | |
277 | |
278 iter = in_flight_nav_linked_events_.erase(iter); | |
279 | |
280 specifics->set_navigation_id(new_global_id); | |
281 RecordUserEvent(std::move(specifics)); | |
282 } | |
283 } | |
284 | |
222 } // namespace syncer | 285 } // namespace syncer |
OLD | NEW |