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

Side by Side Diff: components/sync/engine_impl/conflict_resolver.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 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 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/conflict_resolver.h" 5 #include "components/sync/engine_impl/conflict_resolver.h"
6 6
7 #include <list> 7 #include <list>
8 #include <set> 8 #include <set>
9 #include <string> 9 #include <string>
10 10
11 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
12 #include "sync/engine/conflict_util.h" 12 #include "components/sync/base/cryptographer.h"
13 #include "sync/engine/syncer_util.h" 13 #include "components/sync/engine_impl/conflict_util.h"
14 #include "sync/internal_api/public/sessions/update_counters.h" 14 #include "components/sync/engine_impl/syncer_util.h"
15 #include "sync/sessions/status_controller.h" 15 #include "components/sync/sessions/update_counters.h"
16 #include "sync/syncable/directory.h" 16 #include "components/sync/sessions_impl/status_controller.h"
17 #include "sync/syncable/mutable_entry.h" 17 #include "components/sync/syncable/directory.h"
18 #include "sync/syncable/syncable_write_transaction.h" 18 #include "components/sync/syncable/mutable_entry.h"
19 #include "sync/util/cryptographer.h" 19 #include "components/sync/syncable/syncable_write_transaction.h"
20 20
21 using std::list; 21 using std::list;
22 using std::set; 22 using std::set;
23 23
24 namespace syncer { 24 namespace syncer {
25 25
26 using sessions::StatusController; 26 using sessions::StatusController;
27 using syncable::Directory; 27 using syncable::Directory;
28 using syncable::Entry; 28 using syncable::Entry;
29 using syncable::Id; 29 using syncable::Id;
(...skipping 26 matching lines...) Expand all
56 if (local_ids.find(record.id().SerializeAsString()) == local_ids.end()) { 56 if (local_ids.find(record.id().SerializeAsString()) == local_ids.end()) {
57 return false; 57 return false;
58 } 58 }
59 } 59 }
60 60
61 return true; 61 return true;
62 } 62 }
63 63
64 } // namespace 64 } // namespace
65 65
66 ConflictResolver::ConflictResolver() { 66 ConflictResolver::ConflictResolver() {}
67 }
68 67
69 ConflictResolver::~ConflictResolver() { 68 ConflictResolver::~ConflictResolver() {}
70 }
71 69
72 void ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans, 70 void ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
73 const Id& id, 71 const Id& id,
74 const Cryptographer* cryptographer, 72 const Cryptographer* cryptographer,
75 StatusController* status, 73 StatusController* status,
76 UpdateCounters* counters) { 74 UpdateCounters* counters) {
77 MutableEntry entry(trans, syncable::GET_BY_ID, id); 75 MutableEntry entry(trans, syncable::GET_BY_ID, id);
78 // Must be good as the entry won't have been cleaned up. 76 // Must be good as the entry won't have been cleaned up.
79 CHECK(entry.good()); 77 CHECK(entry.good());
80 78
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 // where the non_unique_name or parent don't match. 116 // where the non_unique_name or parent don't match.
119 // e) Except for the case of extensions and apps, where we want uninstalls to 117 // e) Except for the case of extensions and apps, where we want uninstalls to
120 // win over local modifications to avoid "back from the dead" reinstalls. 118 // win over local modifications to avoid "back from the dead" reinstalls.
121 if (!entry.GetServerIsDel()) { 119 if (!entry.GetServerIsDel()) {
122 // TODO(nick): The current logic is arbitrary; instead, it ought to be made 120 // TODO(nick): The current logic is arbitrary; instead, it ought to be made
123 // consistent with the ModelAssociator behavior for a datatype. It would 121 // consistent with the ModelAssociator behavior for a datatype. It would
124 // be nice if we could route this back to ModelAssociator code to pick one 122 // be nice if we could route this back to ModelAssociator code to pick one
125 // of three options: CLIENT, SERVER, or MERGE. Some datatypes (autofill) 123 // of three options: CLIENT, SERVER, or MERGE. Some datatypes (autofill)
126 // are easily mergeable. 124 // are easily mergeable.
127 // See http://crbug.com/77339. 125 // See http://crbug.com/77339.
128 bool name_matches = entry.GetNonUniqueName() == 126 bool name_matches =
129 entry.GetServerNonUniqueName(); 127 entry.GetNonUniqueName() == entry.GetServerNonUniqueName();
130 // The parent is implicit type root folder or the parent ID matches. 128 // The parent is implicit type root folder or the parent ID matches.
131 bool parent_matches = entry.GetServerParentId().IsNull() || 129 bool parent_matches = entry.GetServerParentId().IsNull() ||
132 entry.GetParentId() == entry.GetServerParentId(); 130 entry.GetParentId() == entry.GetServerParentId();
133 bool entry_deleted = entry.GetIsDel(); 131 bool entry_deleted = entry.GetIsDel();
134 // The position check might fail spuriously if one of the positions was 132 // The position check might fail spuriously if one of the positions was
135 // based on a legacy random suffix, rather than a deterministic one based on 133 // based on a legacy random suffix, rather than a deterministic one based on
136 // originator_cache_guid and originator_item_id. If an item is being 134 // originator_cache_guid and originator_item_id. If an item is being
137 // modified regularly, it shouldn't take long for the suffix and position to 135 // modified regularly, it shouldn't take long for the suffix and position to
138 // be updated, so such false failures shouldn't be a problem for long. 136 // be updated, so such false failures shouldn't be a problem for long.
139 // 137 //
140 // Lucky for us, it's OK to be wrong here. The position_matches check is 138 // Lucky for us, it's OK to be wrong here. The position_matches check is
141 // allowed to return false negatives, as long as it returns no false 139 // allowed to return false negatives, as long as it returns no false
142 // positives. 140 // positives.
143 bool position_matches = parent_matches && 141 bool position_matches =
144 entry.GetServerUniquePosition().Equals(entry.GetUniquePosition()); 142 parent_matches &&
143 entry.GetServerUniquePosition().Equals(entry.GetUniquePosition());
145 const sync_pb::EntitySpecifics& specifics = entry.GetSpecifics(); 144 const sync_pb::EntitySpecifics& specifics = entry.GetSpecifics();
146 const sync_pb::EntitySpecifics& server_specifics = 145 const sync_pb::EntitySpecifics& server_specifics =
147 entry.GetServerSpecifics(); 146 entry.GetServerSpecifics();
148 const sync_pb::EntitySpecifics& base_server_specifics = 147 const sync_pb::EntitySpecifics& base_server_specifics =
149 entry.GetBaseServerSpecifics(); 148 entry.GetBaseServerSpecifics();
150 std::string decrypted_specifics, decrypted_server_specifics; 149 std::string decrypted_specifics, decrypted_server_specifics;
151 bool specifics_match = false; 150 bool specifics_match = false;
152 bool server_encrypted_with_default_key = false; 151 bool server_encrypted_with_default_key = false;
153 if (specifics.has_encrypted()) { 152 if (specifics.has_encrypted()) {
154 DCHECK(cryptographer->CanDecryptUsingDefaultKey(specifics.encrypted())); 153 DCHECK(cryptographer->CanDecryptUsingDefaultKey(specifics.encrypted()));
155 decrypted_specifics = cryptographer->DecryptToString( 154 decrypted_specifics =
156 specifics.encrypted()); 155 cryptographer->DecryptToString(specifics.encrypted());
157 } else { 156 } else {
158 decrypted_specifics = specifics.SerializeAsString(); 157 decrypted_specifics = specifics.SerializeAsString();
159 } 158 }
160 if (server_specifics.has_encrypted()) { 159 if (server_specifics.has_encrypted()) {
161 server_encrypted_with_default_key = 160 server_encrypted_with_default_key =
162 cryptographer->CanDecryptUsingDefaultKey( 161 cryptographer->CanDecryptUsingDefaultKey(
163 server_specifics.encrypted()); 162 server_specifics.encrypted());
164 decrypted_server_specifics = cryptographer->DecryptToString( 163 decrypted_server_specifics =
165 server_specifics.encrypted()); 164 cryptographer->DecryptToString(server_specifics.encrypted());
166 } else { 165 } else {
167 decrypted_server_specifics = server_specifics.SerializeAsString(); 166 decrypted_server_specifics = server_specifics.SerializeAsString();
168 } 167 }
169 if (decrypted_server_specifics == decrypted_specifics && 168 if (decrypted_server_specifics == decrypted_specifics &&
170 server_encrypted_with_default_key == specifics.has_encrypted()) { 169 server_encrypted_with_default_key == specifics.has_encrypted()) {
171 specifics_match = true; 170 specifics_match = true;
172 } 171 }
173 bool base_server_specifics_match = false; 172 bool base_server_specifics_match = false;
174 if (server_specifics.has_encrypted() && 173 if (server_specifics.has_encrypted() &&
175 IsRealDataType(GetModelTypeFromSpecifics(base_server_specifics))) { 174 IsRealDataType(GetModelTypeFromSpecifics(base_server_specifics))) {
176 std::string decrypted_base_server_specifics; 175 std::string decrypted_base_server_specifics;
177 if (!base_server_specifics.has_encrypted()) { 176 if (!base_server_specifics.has_encrypted()) {
178 decrypted_base_server_specifics = 177 decrypted_base_server_specifics =
179 base_server_specifics.SerializeAsString(); 178 base_server_specifics.SerializeAsString();
180 } else { 179 } else {
181 decrypted_base_server_specifics = cryptographer->DecryptToString( 180 decrypted_base_server_specifics =
182 base_server_specifics.encrypted()); 181 cryptographer->DecryptToString(base_server_specifics.encrypted());
183 } 182 }
184 if (decrypted_server_specifics == decrypted_base_server_specifics) 183 if (decrypted_server_specifics == decrypted_base_server_specifics)
185 base_server_specifics_match = true; 184 base_server_specifics_match = true;
186 } 185 }
187 186
188 bool attachment_metadata_matches = AttachmentMetadataMatches(entry); 187 bool attachment_metadata_matches = AttachmentMetadataMatches(entry);
189 if (!entry_deleted && name_matches && parent_matches && specifics_match && 188 if (!entry_deleted && name_matches && parent_matches && specifics_match &&
190 position_matches && attachment_metadata_matches) { 189 position_matches && attachment_metadata_matches) {
191 DVLOG(1) << "Resolving simple conflict, everything matches, ignoring " 190 DVLOG(1) << "Resolving simple conflict, everything matches, ignoring "
192 << "changes for: " << entry; 191 << "changes for: " << entry;
193 conflict_util::IgnoreConflict(&entry); 192 conflict_util::IgnoreConflict(&entry);
194 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 193 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", CHANGES_MATCH,
195 CHANGES_MATCH,
196 CONFLICT_RESOLUTION_SIZE); 194 CONFLICT_RESOLUTION_SIZE);
197 } else if (base_server_specifics_match) { 195 } else if (base_server_specifics_match) {
198 DVLOG(1) << "Resolving simple conflict, ignoring server encryption " 196 DVLOG(1) << "Resolving simple conflict, ignoring server encryption "
199 << " changes for: " << entry; 197 << " changes for: " << entry;
200 status->increment_num_server_overwrites(); 198 status->increment_num_server_overwrites();
201 counters->num_server_overwrites++; 199 counters->num_server_overwrites++;
202 conflict_util::OverwriteServerChanges(&entry); 200 conflict_util::OverwriteServerChanges(&entry);
203 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 201 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", IGNORE_ENCRYPTION,
204 IGNORE_ENCRYPTION,
205 CONFLICT_RESOLUTION_SIZE); 202 CONFLICT_RESOLUTION_SIZE);
206 } else if (entry_deleted || !name_matches || !parent_matches) { 203 } else if (entry_deleted || !name_matches || !parent_matches) {
207 // NOTE: The update application logic assumes that conflict resolution 204 // NOTE: The update application logic assumes that conflict resolution
208 // will never result in changes to the local hierarchy. The entry_deleted 205 // will never result in changes to the local hierarchy. The entry_deleted
209 // and !parent_matches cases here are critical to maintaining that 206 // and !parent_matches cases here are critical to maintaining that
210 // assumption. 207 // assumption.
211 conflict_util::OverwriteServerChanges(&entry); 208 conflict_util::OverwriteServerChanges(&entry);
212 status->increment_num_server_overwrites(); 209 status->increment_num_server_overwrites();
213 counters->num_server_overwrites++; 210 counters->num_server_overwrites++;
214 DVLOG(1) << "Resolving simple conflict, overwriting server changes " 211 DVLOG(1) << "Resolving simple conflict, overwriting server changes "
215 << "for: " << entry; 212 << "for: " << entry;
216 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 213 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", OVERWRITE_SERVER,
217 OVERWRITE_SERVER,
218 CONFLICT_RESOLUTION_SIZE); 214 CONFLICT_RESOLUTION_SIZE);
219 } else { 215 } else {
220 DVLOG(1) << "Resolving simple conflict, ignoring local changes for: " 216 DVLOG(1) << "Resolving simple conflict, ignoring local changes for: "
221 << entry; 217 << entry;
222 conflict_util::IgnoreLocalChanges(&entry); 218 conflict_util::IgnoreLocalChanges(&entry);
223 status->increment_num_local_overwrites(); 219 status->increment_num_local_overwrites();
224 counters->num_local_overwrites++; 220 counters->num_local_overwrites++;
225 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 221 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", OVERWRITE_LOCAL,
226 OVERWRITE_LOCAL,
227 CONFLICT_RESOLUTION_SIZE); 222 CONFLICT_RESOLUTION_SIZE);
228 } 223 }
229 // Now that we've resolved the conflict, clear the prev server 224 // Now that we've resolved the conflict, clear the prev server
230 // specifics. 225 // specifics.
231 entry.PutBaseServerSpecifics(sync_pb::EntitySpecifics()); 226 entry.PutBaseServerSpecifics(sync_pb::EntitySpecifics());
232 } else { // SERVER_IS_DEL is true 227 } else { // SERVER_IS_DEL is true
233 ModelType type = entry.GetModelType(); 228 ModelType type = entry.GetModelType();
234 if (type == EXTENSIONS || type == APPS) { 229 if (type == EXTENSIONS || type == APPS) {
235 // Ignore local changes for extensions/apps when server had a delete, to 230 // Ignore local changes for extensions/apps when server had a delete, to
236 // avoid unwanted reinstall of an uninstalled extension. 231 // avoid unwanted reinstall of an uninstalled extension.
237 DVLOG(1) << "Resolving simple conflict, ignoring local changes for " 232 DVLOG(1) << "Resolving simple conflict, ignoring local changes for "
238 << "extension/app: " << entry; 233 << "extension/app: " << entry;
239 conflict_util::IgnoreLocalChanges(&entry); 234 conflict_util::IgnoreLocalChanges(&entry);
240 status->increment_num_local_overwrites(); 235 status->increment_num_local_overwrites();
241 counters->num_local_overwrites++; 236 counters->num_local_overwrites++;
242 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 237 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", OVERWRITE_LOCAL,
243 OVERWRITE_LOCAL,
244 CONFLICT_RESOLUTION_SIZE); 238 CONFLICT_RESOLUTION_SIZE);
245 } else { 239 } else {
246 if (entry.GetIsDir()) { 240 if (entry.GetIsDir()) {
247 Directory::Metahandles children; 241 Directory::Metahandles children;
248 trans->directory()->GetChildHandlesById(trans, 242 trans->directory()->GetChildHandlesById(trans, entry.GetId(),
249 entry.GetId(),
250 &children); 243 &children);
251 // If a server deleted folder has local contents it should be a 244 // If a server deleted folder has local contents it should be a
252 // hierarchy conflict. Hierarchy conflicts should not be processed by 245 // hierarchy conflict. Hierarchy conflicts should not be processed by
253 // this function. 246 // this function.
254 DCHECK(children.empty()); 247 DCHECK(children.empty());
255 } 248 }
256 249
257 // The entry is deleted on the server but still exists locally. 250 // The entry is deleted on the server but still exists locally.
258 // We undelete it by overwriting the server's tombstone with the local 251 // We undelete it by overwriting the server's tombstone with the local
259 // data. 252 // data.
260 conflict_util::OverwriteServerChanges(&entry); 253 conflict_util::OverwriteServerChanges(&entry);
261 status->increment_num_server_overwrites(); 254 status->increment_num_server_overwrites();
262 counters->num_server_overwrites++; 255 counters->num_server_overwrites++;
263 DVLOG(1) << "Resolving simple conflict, undeleting server entry: " 256 DVLOG(1) << "Resolving simple conflict, undeleting server entry: "
264 << entry; 257 << entry;
265 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 258 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", UNDELETE,
266 UNDELETE,
267 CONFLICT_RESOLUTION_SIZE); 259 CONFLICT_RESOLUTION_SIZE);
268 } 260 }
269 } 261 }
270 } 262 }
271 263
272 void ConflictResolver::ResolveConflicts( 264 void ConflictResolver::ResolveConflicts(
273 syncable::WriteTransaction* trans, 265 syncable::WriteTransaction* trans,
274 const Cryptographer* cryptographer, 266 const Cryptographer* cryptographer,
275 const std::set<syncable::Id>& simple_conflict_ids, 267 const std::set<syncable::Id>& simple_conflict_ids,
276 sessions::StatusController* status, 268 sessions::StatusController* status,
277 UpdateCounters* counters) { 269 UpdateCounters* counters) {
278 // Iterate over simple conflict items. 270 // Iterate over simple conflict items.
279 set<Id>::const_iterator it; 271 set<Id>::const_iterator it;
280 for (it = simple_conflict_ids.begin(); 272 for (it = simple_conflict_ids.begin(); it != simple_conflict_ids.end();
281 it != simple_conflict_ids.end();
282 ++it) { 273 ++it) {
283 // We don't resolve conflicts for control types here. 274 // We don't resolve conflicts for control types here.
284 Entry conflicting_node(trans, syncable::GET_BY_ID, *it); 275 Entry conflicting_node(trans, syncable::GET_BY_ID, *it);
285 CHECK(conflicting_node.good()); 276 CHECK(conflicting_node.good());
286 if (IsControlType( 277 if (IsControlType(
287 GetModelTypeFromSpecifics(conflicting_node.GetSpecifics()))) { 278 GetModelTypeFromSpecifics(conflicting_node.GetSpecifics()))) {
288 continue; 279 continue;
289 } 280 }
290 281
291 ProcessSimpleConflict(trans, *it, cryptographer, status, counters); 282 ProcessSimpleConflict(trans, *it, cryptographer, status, counters);
292 } 283 }
293 return; 284 return;
294 } 285 }
295 286
296 } // namespace syncer 287 } // namespace syncer
OLDNEW
« no previous file with comments | « components/sync/engine_impl/conflict_resolver.h ('k') | components/sync/engine_impl/conflict_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698