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

Side by Side Diff: sync/engine/conflict_resolver.cc

Issue 11192071: sync: Merge apply updates and resolve conflicts (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Retry (base files were missing) Created 8 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « sync/engine/conflict_resolver.h ('k') | sync/engine/resolve_conflicts_command.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 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 "sync/engine/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
(...skipping 17 matching lines...) Expand all
28 using syncable::Id; 28 using syncable::Id;
29 using syncable::MutableEntry; 29 using syncable::MutableEntry;
30 using syncable::WriteTransaction; 30 using syncable::WriteTransaction;
31 31
32 ConflictResolver::ConflictResolver() { 32 ConflictResolver::ConflictResolver() {
33 } 33 }
34 34
35 ConflictResolver::~ConflictResolver() { 35 ConflictResolver::~ConflictResolver() {
36 } 36 }
37 37
38 ConflictResolver::ProcessSimpleConflictResult 38 void ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
39 ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans, 39 const Id& id,
40 const Id& id, 40 const Cryptographer* cryptographer,
41 const Cryptographer* cryptographer, 41 StatusController* status) {
42 StatusController* status) {
43 MutableEntry entry(trans, syncable::GET_BY_ID, id); 42 MutableEntry entry(trans, syncable::GET_BY_ID, id);
44 // Must be good as the entry won't have been cleaned up. 43 // Must be good as the entry won't have been cleaned up.
45 CHECK(entry.good()); 44 CHECK(entry.good());
46 45
47 // This function can only resolve simple conflicts. Simple conflicts have 46 // This function can only resolve simple conflicts. Simple conflicts have
48 // both IS_UNSYNCED and IS_UNAPPLIED_UDPATE set. 47 // both IS_UNSYNCED and IS_UNAPPLIED_UDPATE set.
49 if (!entry.Get(syncable::IS_UNAPPLIED_UPDATE) || 48 if (!entry.Get(syncable::IS_UNAPPLIED_UPDATE) ||
50 !entry.Get(syncable::IS_UNSYNCED)) { 49 !entry.Get(syncable::IS_UNSYNCED)) {
51 // This is very unusual, but it can happen in tests. We may be able to 50 // This is very unusual, but it can happen in tests. We may be able to
52 // assert NOTREACHED() here when those tests are updated. 51 // assert NOTREACHED() here when those tests are updated.
53 return NO_SYNC_PROGRESS; 52 return;
54 } 53 }
55 54
56 if (entry.Get(syncable::IS_DEL) && entry.Get(syncable::SERVER_IS_DEL)) { 55 if (entry.Get(syncable::IS_DEL) && entry.Get(syncable::SERVER_IS_DEL)) {
57 // we've both deleted it, so lets just drop the need to commit/update this 56 // we've both deleted it, so lets just drop the need to commit/update this
58 // entry. 57 // entry.
59 entry.Put(syncable::IS_UNSYNCED, false); 58 entry.Put(syncable::IS_UNSYNCED, false);
60 entry.Put(syncable::IS_UNAPPLIED_UPDATE, false); 59 entry.Put(syncable::IS_UNAPPLIED_UPDATE, false);
61 // we've made changes, but they won't help syncing progress. 60 // we've made changes, but they won't help syncing progress.
62 // METRIC simple conflict resolved by merge. 61 // METRIC simple conflict resolved by merge.
63 return NO_SYNC_PROGRESS; 62 return;
64 } 63 }
65 64
66 // This logic determines "client wins" vs. "server wins" strategy picking. 65 // This logic determines "client wins" vs. "server wins" strategy picking.
67 // By the time we get to this point, we rely on the following to be true: 66 // By the time we get to this point, we rely on the following to be true:
68 // a) We can decrypt both the local and server data (else we'd be in 67 // a) We can decrypt both the local and server data (else we'd be in
69 // conflict encryption and not attempting to resolve). 68 // conflict encryption and not attempting to resolve).
70 // b) All unsynced changes have been re-encrypted with the default key ( 69 // b) All unsynced changes have been re-encrypted with the default key (
71 // occurs either in AttemptToUpdateEntry, SetEncryptionPassphrase, 70 // occurs either in AttemptToUpdateEntry, SetEncryptionPassphrase,
72 // SetDecryptionPassphrase, or RefreshEncryption). 71 // SetDecryptionPassphrase, or RefreshEncryption).
73 // c) Base_server_specifics having a valid datatype means that we received 72 // c) Base_server_specifics having a valid datatype means that we received
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 CONFLICT_RESOLUTION_SIZE); 198 CONFLICT_RESOLUTION_SIZE);
200 } else if (base_server_specifics_match) { 199 } else if (base_server_specifics_match) {
201 DVLOG(1) << "Resolving simple conflict, ignoring server encryption " 200 DVLOG(1) << "Resolving simple conflict, ignoring server encryption "
202 << " changes for: " << entry; 201 << " changes for: " << entry;
203 status->increment_num_server_overwrites(); 202 status->increment_num_server_overwrites();
204 conflict_util::OverwriteServerChanges(&entry); 203 conflict_util::OverwriteServerChanges(&entry);
205 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 204 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
206 IGNORE_ENCRYPTION, 205 IGNORE_ENCRYPTION,
207 CONFLICT_RESOLUTION_SIZE); 206 CONFLICT_RESOLUTION_SIZE);
208 } else if (entry_deleted || !name_matches || !parent_matches) { 207 } else if (entry_deleted || !name_matches || !parent_matches) {
208 // NOTE: The update application logic assumes that conflict resolution
209 // will never result in changes to the local hierarchy. The entry_deleted
210 // and !parent_matches cases here are critical to maintaining that
211 // assumption.
209 conflict_util::OverwriteServerChanges(&entry); 212 conflict_util::OverwriteServerChanges(&entry);
210 status->increment_num_server_overwrites(); 213 status->increment_num_server_overwrites();
211 DVLOG(1) << "Resolving simple conflict, overwriting server changes " 214 DVLOG(1) << "Resolving simple conflict, overwriting server changes "
212 << "for: " << entry; 215 << "for: " << entry;
213 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 216 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
214 OVERWRITE_SERVER, 217 OVERWRITE_SERVER,
215 CONFLICT_RESOLUTION_SIZE); 218 CONFLICT_RESOLUTION_SIZE);
216 } else { 219 } else {
217 DVLOG(1) << "Resolving simple conflict, ignoring local changes for: " 220 DVLOG(1) << "Resolving simple conflict, ignoring local changes for: "
218 << entry; 221 << entry;
219 conflict_util::IgnoreLocalChanges(&entry); 222 conflict_util::IgnoreLocalChanges(&entry);
220 status->increment_num_local_overwrites(); 223 status->increment_num_local_overwrites();
221 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 224 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
222 OVERWRITE_LOCAL, 225 OVERWRITE_LOCAL,
223 CONFLICT_RESOLUTION_SIZE); 226 CONFLICT_RESOLUTION_SIZE);
224 } 227 }
225 // Now that we've resolved the conflict, clear the prev server 228 // Now that we've resolved the conflict, clear the prev server
226 // specifics. 229 // specifics.
227 entry.Put(syncable::BASE_SERVER_SPECIFICS, sync_pb::EntitySpecifics()); 230 entry.Put(syncable::BASE_SERVER_SPECIFICS, sync_pb::EntitySpecifics());
228 return SYNC_PROGRESS;
229 } else { // SERVER_IS_DEL is true 231 } else { // SERVER_IS_DEL is true
230 // If a server deleted folder has local contents it should be a hierarchy
231 // conflict. Hierarchy conflicts should not be processed by this function.
232 // We could end up here if a change was made since we last tried to detect
233 // conflicts, which was during update application.
234 if (entry.Get(syncable::IS_DIR)) { 232 if (entry.Get(syncable::IS_DIR)) {
235 Directory::ChildHandles children; 233 Directory::ChildHandles children;
236 trans->directory()->GetChildHandlesById(trans, 234 trans->directory()->GetChildHandlesById(trans,
237 entry.Get(syncable::ID), 235 entry.Get(syncable::ID),
238 &children); 236 &children);
239 if (0 != children.size()) { 237 // If a server deleted folder has local contents it should be a hierarchy
240 DVLOG(1) << "Entry is a server deleted directory with local contents, " 238 // conflict. Hierarchy conflicts should not be processed by this
241 << "should be a hierarchy conflict. (race condition)."; 239 // function.
242 return NO_SYNC_PROGRESS; 240 DCHECK(children.empty());
243 }
244 } 241 }
245 242
246 // The entry is deleted on the server but still exists locally. 243 // The entry is deleted on the server but still exists locally.
247 // We undelete it by overwriting the server's tombstone with the local 244 // We undelete it by overwriting the server's tombstone with the local
248 // data. 245 // data.
249 conflict_util::OverwriteServerChanges(&entry); 246 conflict_util::OverwriteServerChanges(&entry);
250 status->increment_num_server_overwrites(); 247 status->increment_num_server_overwrites();
251 DVLOG(1) << "Resolving simple conflict, undeleting server entry: " 248 DVLOG(1) << "Resolving simple conflict, undeleting server entry: "
252 << entry; 249 << entry;
253 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 250 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
254 UNDELETE, 251 UNDELETE,
255 CONFLICT_RESOLUTION_SIZE); 252 CONFLICT_RESOLUTION_SIZE);
256
257 return SYNC_PROGRESS;
258 } 253 }
259 } 254 }
260 255
261 bool ConflictResolver::ResolveConflicts( 256 void ConflictResolver::ResolveConflicts(
262 syncable::WriteTransaction* trans, 257 syncable::WriteTransaction* trans,
263 const Cryptographer* cryptographer, 258 const Cryptographer* cryptographer,
264 const std::set<syncable::Id>& simple_conflict_ids, 259 const std::set<syncable::Id>& simple_conflict_ids,
265 sessions::StatusController* status) { 260 sessions::StatusController* status) {
266 bool forward_progress = false;
267 // Iterate over simple conflict items. 261 // Iterate over simple conflict items.
268 set<Id>::const_iterator conflicting_item_it; 262 set<Id>::const_iterator conflicting_item_it;
269 set<Id> processed_items; 263 set<Id> processed_items;
270 for (conflicting_item_it = simple_conflict_ids.begin(); 264 for (conflicting_item_it = simple_conflict_ids.begin();
271 conflicting_item_it != simple_conflict_ids.end(); 265 conflicting_item_it != simple_conflict_ids.end();
272 ++conflicting_item_it) { 266 ++conflicting_item_it) {
273 Id id = *conflicting_item_it; 267 Id id = *conflicting_item_it;
274 if (processed_items.count(id) > 0) 268 if (processed_items.count(id) > 0)
275 continue; 269 continue;
276 270
(...skipping 19 matching lines...) Expand all
296 CHECK(entry.good()); 290 CHECK(entry.good());
297 Id new_prev_id = entry.Get(syncable::PREV_ID); 291 Id new_prev_id = entry.Get(syncable::PREV_ID);
298 if (new_prev_id == prev_id) 292 if (new_prev_id == prev_id)
299 break; 293 break;
300 prev_id = new_prev_id; 294 prev_id = new_prev_id;
301 } while (processed_items.count(prev_id) == 0 && 295 } while (processed_items.count(prev_id) == 0 &&
302 simple_conflict_ids.count(prev_id) > 0); // Excludes root. 296 simple_conflict_ids.count(prev_id) > 0); // Excludes root.
303 while (!predecessors.empty()) { 297 while (!predecessors.empty()) {
304 id = predecessors.back(); 298 id = predecessors.back();
305 predecessors.pop_back(); 299 predecessors.pop_back();
306 switch (ProcessSimpleConflict(trans, id, cryptographer, status)) { 300 ProcessSimpleConflict(trans, id, cryptographer, status);
307 case NO_SYNC_PROGRESS:
308 break;
309 case SYNC_PROGRESS:
310 forward_progress = true;
311 break;
312 }
313 processed_items.insert(id); 301 processed_items.insert(id);
314 } 302 }
315 } 303 }
316 return forward_progress; 304 return;
317 } 305 }
318 306
319 } // namespace syncer 307 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/engine/conflict_resolver.h ('k') | sync/engine/resolve_conflicts_command.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698