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

Side by Side Diff: components/sync/user_events/user_event_sync_bridge.cc

Issue 2958303002: [Sync] Maintain a global_id mapping to update UserEvents that references navigations (Closed)
Patch Set: Actually save global_id_mapper.h changes Created 3 years, 5 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 unified diff | Download patch
OLDNEW
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) {
Patrick Noland 2017/07/05 23:59:32 Can you use auto here?
skym 2017/07/06 17:28:55 In C++14 you can https://en.wikipedia.org/wiki/C%2
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698