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

Side by Side Diff: components/sync/engine_impl/process_updates_util.cc

Issue 2130453004: [Sync] Move //sync to //components/sync. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 4 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 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "sync/engine/process_updates_util.h" 5 #include "components/sync/engine_impl/process_updates_util.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <string> 10 #include <string>
11 11
12 #include "base/location.h" 12 #include "base/location.h"
13 #include "base/metrics/sparse_histogram.h" 13 #include "base/metrics/sparse_histogram.h"
14 #include "sync/engine/syncer_proto_util.h" 14 #include "components/sync/base/cryptographer.h"
15 #include "sync/engine/syncer_types.h" 15 #include "components/sync/base/data_type_histogram.h"
16 #include "sync/engine/syncer_util.h" 16 #include "components/sync/engine_impl/syncer_proto_util.h"
17 #include "sync/internal_api/public/sessions/update_counters.h" 17 #include "components/sync/engine_impl/syncer_types.h"
18 #include "sync/syncable/directory.h" 18 #include "components/sync/engine_impl/syncer_util.h"
19 #include "sync/syncable/model_neutral_mutable_entry.h" 19 #include "components/sync/sessions/update_counters.h"
20 #include "sync/syncable/syncable_model_neutral_write_transaction.h" 20 #include "components/sync/syncable/directory.h"
21 #include "sync/syncable/syncable_proto_util.h" 21 #include "components/sync/syncable/model_neutral_mutable_entry.h"
22 #include "sync/syncable/syncable_util.h" 22 #include "components/sync/syncable/syncable_model_neutral_write_transaction.h"
23 #include "sync/util/cryptographer.h" 23 #include "components/sync/syncable/syncable_proto_util.h"
24 #include "sync/util/data_type_histogram.h" 24 #include "components/sync/syncable/syncable_util.h"
25 25
26 namespace syncer { 26 namespace syncer {
27 27
28 using sessions::StatusController; 28 using sessions::StatusController;
29 29
30 using syncable::GET_BY_ID; 30 using syncable::GET_BY_ID;
31 31
32 namespace { 32 namespace {
33 33
34 // This function attempts to determine whether or not this update is genuinely 34 // This function attempts to determine whether or not this update is genuinely
(...skipping 10 matching lines...) Expand all
45 // server-returned new ID to the database before we shut down. On the GetUpdate 45 // server-returned new ID to the database before we shut down. On the GetUpdate
46 // following the next restart, we will receive an update from the server that 46 // following the next restart, we will receive an update from the server that
47 // updates its local ID. 47 // updates its local ID.
48 // - When two attempts to create an item with identical UNIQUE_CLIENT_TAG values 48 // - When two attempts to create an item with identical UNIQUE_CLIENT_TAG values
49 // collide at the server. I have seen this in testing. When it happens, the 49 // collide at the server. I have seen this in testing. When it happens, the
50 // test server will send one of the clients a response to upate its local ID so 50 // test server will send one of the clients a response to upate its local ID so
51 // that both clients will refer to the item using the same ID going forward. In 51 // that both clients will refer to the item using the same ID going forward. In
52 // this case, we're right to assume that the update is not a reflection. 52 // this case, we're right to assume that the update is not a reflection.
53 // 53 //
54 // For more information, see FindLocalIdToUpdate(). 54 // For more information, see FindLocalIdToUpdate().
55 bool UpdateContainsNewVersion(syncable::BaseTransaction *trans, 55 bool UpdateContainsNewVersion(syncable::BaseTransaction* trans,
56 const sync_pb::SyncEntity &update) { 56 const sync_pb::SyncEntity& update) {
57 int64_t existing_version = -1; // The server always sends positive versions. 57 int64_t existing_version = -1; // The server always sends positive versions.
58 syncable::Entry existing_entry(trans, GET_BY_ID, 58 syncable::Entry existing_entry(trans, GET_BY_ID,
59 SyncableIdFromProto(update.id_string())); 59 SyncableIdFromProto(update.id_string()));
60 if (existing_entry.good()) 60 if (existing_entry.good())
61 existing_version = existing_entry.GetBaseVersion(); 61 existing_version = existing_entry.GetBaseVersion();
62 62
63 if (!existing_entry.good() && update.deleted()) { 63 if (!existing_entry.good() && update.deleted()) {
64 // There are several possible explanations for this. The most common cases 64 // There are several possible explanations for this. The most common cases
65 // will be first time sync and the redelivery of deletions we've already 65 // will be first time sync and the redelivery of deletions we've already
66 // synced, accepted, and purged from our database. In either case, the 66 // synced, accepted, and purged from our database. In either case, the
67 // update is useless to us. Let's count them all as "not new", even though 67 // update is useless to us. Let's count them all as "not new", even though
68 // that may not always be entirely accurate. 68 // that may not always be entirely accurate.
69 return false; 69 return false;
70 } 70 }
71 71
72 if (existing_entry.good() && 72 if (existing_entry.good() && !existing_entry.GetUniqueClientTag().empty() &&
73 !existing_entry.GetUniqueClientTag().empty() && 73 existing_entry.GetIsDel() && update.deleted()) {
74 existing_entry.GetIsDel() &&
75 update.deleted()) {
76 // Unique client tags will have their version set to zero when they're 74 // Unique client tags will have their version set to zero when they're
77 // deleted. The usual version comparison logic won't be able to detect 75 // deleted. The usual version comparison logic won't be able to detect
78 // reflections of these items. Instead, we assume any received tombstones 76 // reflections of these items. Instead, we assume any received tombstones
79 // are reflections. That should be correct most of the time. 77 // are reflections. That should be correct most of the time.
80 return false; 78 return false;
81 } 79 }
82 80
83 return existing_version < update.version(); 81 return existing_version < update.version();
84 } 82 }
85 83
86 // In the event that IDs match, but tags differ AttemptReuniteClient tag 84 // In the event that IDs match, but tags differ AttemptReuniteClient tag
87 // will have refused to unify the update. 85 // will have refused to unify the update.
88 // We should not attempt to apply it at all since it violates consistency 86 // We should not attempt to apply it at all since it violates consistency
89 // rules. 87 // rules.
90 VerifyResult VerifyTagConsistency( 88 VerifyResult VerifyTagConsistency(
91 const sync_pb::SyncEntity& entry, 89 const sync_pb::SyncEntity& entry,
92 const syncable::ModelNeutralMutableEntry& same_id) { 90 const syncable::ModelNeutralMutableEntry& same_id) {
93 if (entry.has_client_defined_unique_tag() && 91 if (entry.has_client_defined_unique_tag() &&
94 entry.client_defined_unique_tag() != 92 entry.client_defined_unique_tag() != same_id.GetUniqueClientTag()) {
95 same_id.GetUniqueClientTag()) {
96 return VERIFY_FAIL; 93 return VERIFY_FAIL;
97 } 94 }
98 return VERIFY_UNDECIDED; 95 return VERIFY_UNDECIDED;
99 } 96 }
100 97
101 // Checks whether or not an update is fit for processing. 98 // Checks whether or not an update is fit for processing.
102 // 99 //
103 // The answer may be "no" if the update appears invalid, or it's not releveant 100 // The answer may be "no" if the update appears invalid, or it's not releveant
104 // (ie. a delete for an item we've never heard of), or other reasons. 101 // (ie. a delete for an item we've never heard of), or other reasons.
105 VerifyResult VerifyUpdate( 102 VerifyResult VerifyUpdate(syncable::ModelNeutralWriteTransaction* trans,
106 syncable::ModelNeutralWriteTransaction* trans, 103 const sync_pb::SyncEntity& entry,
107 const sync_pb::SyncEntity& entry, 104 ModelType requested_type) {
108 ModelType requested_type) {
109 syncable::Id id = SyncableIdFromProto(entry.id_string()); 105 syncable::Id id = SyncableIdFromProto(entry.id_string());
110 VerifyResult result = VERIFY_FAIL; 106 VerifyResult result = VERIFY_FAIL;
111 107
112 const bool deleted = entry.has_deleted() && entry.deleted(); 108 const bool deleted = entry.has_deleted() && entry.deleted();
113 const bool is_directory = IsFolder(entry); 109 const bool is_directory = IsFolder(entry);
114 const ModelType model_type = GetModelType(entry); 110 const ModelType model_type = GetModelType(entry);
115 111
116 if (!id.ServerKnows()) { 112 if (!id.ServerKnows()) {
117 LOG(ERROR) << "Illegal negative id in received updates"; 113 LOG(ERROR) << "Illegal negative id in received updates";
118 return result; 114 return result;
119 } 115 }
120 { 116 {
121 const std::string name = SyncerProtoUtil::NameFromSyncEntity(entry); 117 const std::string name = SyncerProtoUtil::NameFromSyncEntity(entry);
122 if (name.empty() && !deleted) { 118 if (name.empty() && !deleted) {
123 LOG(ERROR) << "Zero length name in non-deleted update"; 119 LOG(ERROR) << "Zero length name in non-deleted update";
124 return result; 120 return result;
125 } 121 }
126 } 122 }
127 123
128 syncable::ModelNeutralMutableEntry same_id(trans, GET_BY_ID, id); 124 syncable::ModelNeutralMutableEntry same_id(trans, GET_BY_ID, id);
129 result = VerifyNewEntry(entry, &same_id, deleted); 125 result = VerifyNewEntry(entry, &same_id, deleted);
130 126
131 ModelType placement_type = !deleted ? GetModelType(entry) 127 ModelType placement_type =
132 : same_id.good() ? same_id.GetModelType() : UNSPECIFIED; 128 !deleted ? GetModelType(entry) : same_id.good() ? same_id.GetModelType()
129 : UNSPECIFIED;
133 130
134 if (VERIFY_UNDECIDED == result) { 131 if (VERIFY_UNDECIDED == result) {
135 result = VerifyTagConsistency(entry, same_id); 132 result = VerifyTagConsistency(entry, same_id);
136 } 133 }
137 134
138 if (VERIFY_UNDECIDED == result) { 135 if (VERIFY_UNDECIDED == result) {
139 if (deleted) { 136 if (deleted) {
140 // For deletes the server could send tombostones for items that 137 // For deletes the server could send tombostones for items that
141 // the client did not request. If so ignore those items. 138 // the client did not request. If so ignore those items.
142 if (IsRealDataType(placement_type) && requested_type != placement_type) { 139 if (IsRealDataType(placement_type) && requested_type != placement_type) {
143 result = VERIFY_SKIP; 140 result = VERIFY_SKIP;
144 } else { 141 } else {
145 result = VERIFY_SUCCESS; 142 result = VERIFY_SUCCESS;
146 } 143 }
147 } 144 }
148 } 145 }
149 146
150 // If we have an existing entry, we check here for updates that break 147 // If we have an existing entry, we check here for updates that break
151 // consistency rules. 148 // consistency rules.
152 if (VERIFY_UNDECIDED == result) { 149 if (VERIFY_UNDECIDED == result) {
153 result = VerifyUpdateConsistency(trans, entry, deleted, 150 result = VerifyUpdateConsistency(trans, entry, deleted, is_directory,
154 is_directory, model_type, &same_id); 151 model_type, &same_id);
155 } 152 }
156 153
157 if (VERIFY_UNDECIDED == result) 154 if (VERIFY_UNDECIDED == result)
158 result = VERIFY_SUCCESS; // No news is good news. 155 result = VERIFY_SUCCESS; // No news is good news.
159 156
160 return result; // This might be VERIFY_SUCCESS as well 157 return result; // This might be VERIFY_SUCCESS as well
161 } 158 }
162 159
163 // Returns true if the entry is still ok to process. 160 // Returns true if the entry is still ok to process.
164 bool ReverifyEntry(syncable::ModelNeutralWriteTransaction* trans, 161 bool ReverifyEntry(syncable::ModelNeutralWriteTransaction* trans,
165 const sync_pb::SyncEntity& entry, 162 const sync_pb::SyncEntity& entry,
166 syncable::ModelNeutralMutableEntry* same_id) { 163 syncable::ModelNeutralMutableEntry* same_id) {
167 const bool deleted = entry.has_deleted() && entry.deleted(); 164 const bool deleted = entry.has_deleted() && entry.deleted();
168 const bool is_directory = IsFolder(entry); 165 const bool is_directory = IsFolder(entry);
169 const ModelType model_type = GetModelType(entry); 166 const ModelType model_type = GetModelType(entry);
170 167
171 return VERIFY_SUCCESS == VerifyUpdateConsistency(trans, 168 return VERIFY_SUCCESS == VerifyUpdateConsistency(trans, entry, deleted,
172 entry, 169 is_directory, model_type,
173 deleted,
174 is_directory,
175 model_type,
176 same_id); 170 same_id);
177 } 171 }
178 172
179 // Process a single update. Will avoid touching global state. 173 // Process a single update. Will avoid touching global state.
180 // 174 //
181 // If the update passes a series of checks, this function will copy 175 // If the update passes a series of checks, this function will copy
182 // the SyncEntity's data into the SERVER side of the syncable::Directory. 176 // the SyncEntity's data into the SERVER side of the syncable::Directory.
183 void ProcessUpdate( 177 void ProcessUpdate(const sync_pb::SyncEntity& update,
184 const sync_pb::SyncEntity& update, 178 const Cryptographer* cryptographer,
185 const Cryptographer* cryptographer, 179 syncable::ModelNeutralWriteTransaction* const trans) {
186 syncable::ModelNeutralWriteTransaction* const trans) {
187 const syncable::Id& server_id = SyncableIdFromProto(update.id_string()); 180 const syncable::Id& server_id = SyncableIdFromProto(update.id_string());
188 const std::string name = SyncerProtoUtil::NameFromSyncEntity(update); 181 const std::string name = SyncerProtoUtil::NameFromSyncEntity(update);
189 182
190 // Look to see if there's a local item that should recieve this update, 183 // Look to see if there's a local item that should recieve this update,
191 // maybe due to a duplicate client tag or a lost commit response. 184 // maybe due to a duplicate client tag or a lost commit response.
192 syncable::Id local_id = FindLocalIdToUpdate(trans, update); 185 syncable::Id local_id = FindLocalIdToUpdate(trans, update);
193 186
194 // FindLocalEntryToUpdate has veto power. 187 // FindLocalEntryToUpdate has veto power.
195 if (local_id.IsNull()) { 188 if (local_id.IsNull()) {
196 return; // The entry has become irrelevant. 189 return; // The entry has become irrelevant.
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 // If this is a newly received undecryptable update, and the only thing that 228 // If this is a newly received undecryptable update, and the only thing that
236 // has changed are the specifics, store the original decryptable specifics, 229 // has changed are the specifics, store the original decryptable specifics,
237 // (on which any current or future local changes are based) before we 230 // (on which any current or future local changes are based) before we
238 // overwrite SERVER_SPECIFICS. 231 // overwrite SERVER_SPECIFICS.
239 // MTIME, CTIME, and NON_UNIQUE_NAME are not enforced. 232 // MTIME, CTIME, and NON_UNIQUE_NAME are not enforced.
240 233
241 bool position_matches = false; 234 bool position_matches = false;
242 if (target_entry.ShouldMaintainPosition() && !update.deleted()) { 235 if (target_entry.ShouldMaintainPosition() && !update.deleted()) {
243 std::string update_tag = GetUniqueBookmarkTagFromUpdate(update); 236 std::string update_tag = GetUniqueBookmarkTagFromUpdate(update);
244 if (UniquePosition::IsValidSuffix(update_tag)) { 237 if (UniquePosition::IsValidSuffix(update_tag)) {
245 position_matches = GetUpdatePosition(update, update_tag).Equals( 238 position_matches = GetUpdatePosition(update, update_tag)
246 target_entry.GetServerUniquePosition()); 239 .Equals(target_entry.GetServerUniquePosition());
247 } else { 240 } else {
248 NOTREACHED(); 241 NOTREACHED();
249 } 242 }
250 } else { 243 } else {
251 // If this item doesn't care about positions, then set this flag to true. 244 // If this item doesn't care about positions, then set this flag to true.
252 position_matches = true; 245 position_matches = true;
253 } 246 }
254 247
255 if (!update.deleted() && !target_entry.GetServerIsDel() && 248 if (!update.deleted() && !target_entry.GetServerIsDel() &&
256 (SyncableIdFromProto(update.parent_id_string()) == 249 (SyncableIdFromProto(update.parent_id_string()) ==
257 target_entry.GetServerParentId()) && 250 target_entry.GetServerParentId()) &&
258 position_matches && 251 position_matches && update.has_specifics() &&
259 update.has_specifics() && update.specifics().has_encrypted() && 252 update.specifics().has_encrypted() &&
260 !cryptographer->CanDecrypt(update.specifics().encrypted())) { 253 !cryptographer->CanDecrypt(update.specifics().encrypted())) {
261 sync_pb::EntitySpecifics prev_specifics = 254 sync_pb::EntitySpecifics prev_specifics = target_entry.GetServerSpecifics();
262 target_entry.GetServerSpecifics();
263 // We only store the old specifics if they were decryptable and applied and 255 // We only store the old specifics if they were decryptable and applied and
264 // there is no BASE_SERVER_SPECIFICS already. Else do nothing. 256 // there is no BASE_SERVER_SPECIFICS already. Else do nothing.
265 if (!target_entry.GetIsUnappliedUpdate() && 257 if (!target_entry.GetIsUnappliedUpdate() &&
266 !IsRealDataType(GetModelTypeFromSpecifics( 258 !IsRealDataType(
267 target_entry.GetBaseServerSpecifics())) && 259 GetModelTypeFromSpecifics(target_entry.GetBaseServerSpecifics())) &&
268 (!prev_specifics.has_encrypted() || 260 (!prev_specifics.has_encrypted() ||
269 cryptographer->CanDecrypt(prev_specifics.encrypted()))) { 261 cryptographer->CanDecrypt(prev_specifics.encrypted()))) {
270 DVLOG(2) << "Storing previous server specifcs: " 262 DVLOG(2) << "Storing previous server specifcs: "
271 << prev_specifics.SerializeAsString(); 263 << prev_specifics.SerializeAsString();
272 target_entry.PutBaseServerSpecifics(prev_specifics); 264 target_entry.PutBaseServerSpecifics(prev_specifics);
273 } 265 }
274 } else if (IsRealDataType(GetModelTypeFromSpecifics( 266 } else if (IsRealDataType(GetModelTypeFromSpecifics(
275 target_entry.GetBaseServerSpecifics()))) { 267 target_entry.GetBaseServerSpecifics()))) {
276 // We have a BASE_SERVER_SPECIFICS, but a subsequent non-specifics-only 268 // We have a BASE_SERVER_SPECIFICS, but a subsequent non-specifics-only
277 // change arrived. As a result, we can't use the specifics alone to detect 269 // change arrived. As a result, we can't use the specifics alone to detect
278 // changes, so we clear BASE_SERVER_SPECIFICS. 270 // changes, so we clear BASE_SERVER_SPECIFICS.
279 target_entry.PutBaseServerSpecifics( 271 target_entry.PutBaseServerSpecifics(sync_pb::EntitySpecifics());
280 sync_pb::EntitySpecifics());
281 } 272 }
282 273
283 UpdateServerFieldsFromUpdate(&target_entry, update, name); 274 UpdateServerFieldsFromUpdate(&target_entry, update, name);
284 275
285 return; 276 return;
286 } 277 }
287 278
288 } // namespace 279 } // namespace
289 280
290 void ProcessDownloadedUpdates( 281 void ProcessDownloadedUpdates(syncable::Directory* dir,
291 syncable::Directory* dir, 282 syncable::ModelNeutralWriteTransaction* trans,
292 syncable::ModelNeutralWriteTransaction* trans, 283 ModelType type,
293 ModelType type, 284 const SyncEntityList& applicable_updates,
294 const SyncEntityList& applicable_updates, 285 sessions::StatusController* status,
295 sessions::StatusController* status, 286 UpdateCounters* counters) {
296 UpdateCounters* counters) {
297 for (SyncEntityList::const_iterator update_it = applicable_updates.begin(); 287 for (SyncEntityList::const_iterator update_it = applicable_updates.begin();
298 update_it != applicable_updates.end(); ++update_it) { 288 update_it != applicable_updates.end(); ++update_it) {
299 DCHECK_EQ(type, GetModelType(**update_it)); 289 DCHECK_EQ(type, GetModelType(**update_it));
300 if (!UpdateContainsNewVersion(trans, **update_it)) { 290 if (!UpdateContainsNewVersion(trans, **update_it)) {
301 status->increment_num_reflected_updates_downloaded_by(1); 291 status->increment_num_reflected_updates_downloaded_by(1);
302 counters->num_reflected_updates_received++; 292 counters->num_reflected_updates_received++;
303 } 293 }
304 if ((*update_it)->deleted()) { 294 if ((*update_it)->deleted()) {
305 status->increment_num_tombstone_updates_downloaded_by(1); 295 status->increment_num_tombstone_updates_downloaded_by(1);
306 counters->num_tombstone_updates_received++; 296 counters->num_tombstone_updates_received++;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 328
339 // Mark entry as unapplied update first to ensure journaling the deletion. 329 // Mark entry as unapplied update first to ensure journaling the deletion.
340 entry.PutIsUnappliedUpdate(true); 330 entry.PutIsUnappliedUpdate(true);
341 // Mark entry as deleted by server. 331 // Mark entry as deleted by server.
342 entry.PutServerIsDel(true); 332 entry.PutServerIsDel(true);
343 entry.PutServerVersion(version_watermark); 333 entry.PutServerVersion(version_watermark);
344 } 334 }
345 } 335 }
346 336
347 } // namespace syncer 337 } // namespace syncer
OLDNEW
« no previous file with comments | « components/sync/engine_impl/process_updates_util.h ('k') | components/sync/engine_impl/sync_cycle_event.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698