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

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

Issue 9305001: sync: Remove the remaining conflict sets code (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review updates and renames Created 8 years, 10 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 | Annotate | Revision Log
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 "chrome/browser/sync/engine/conflict_resolver.h" 5 #include "chrome/browser/sync/engine/conflict_resolver.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <list> 8 #include <list>
9 #include <map> 9 #include <map>
10 #include <set> 10 #include <set>
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 } 70 }
71 71
72 ConflictResolver::ProcessSimpleConflictResult 72 ConflictResolver::ProcessSimpleConflictResult
73 ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans, 73 ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
74 const Id& id, 74 const Id& id,
75 const Cryptographer* cryptographer, 75 const Cryptographer* cryptographer,
76 StatusController* status) { 76 StatusController* status) {
77 MutableEntry entry(trans, syncable::GET_BY_ID, id); 77 MutableEntry entry(trans, syncable::GET_BY_ID, id);
78 // Must be good as the entry won't have been cleaned up. 78 // Must be good as the entry won't have been cleaned up.
79 CHECK(entry.good()); 79 CHECK(entry.good());
80 // If an update fails, locally we have to be in a set or unsynced. We're not 80
81 // in a set here, so we must be unsynced. 81 // This function can only resolve simple conflicts. Simple conflicts are
82 if (!entry.Get(syncable::IS_UNSYNCED)) { 82 // both UNSYNCED and UNAPPLIED_UDPATEs.
Nicolas Zea 2012/02/02 21:53:41 are both -> have both IS_UNSYNCED and IS_UNAPPLIED
rlarocque 2012/02/03 22:31:15 Done.
83 if (!entry.Get(syncable::IS_UNAPPLIED_UPDATE) ||
84 !entry.Get(syncable::IS_UNSYNCED)) {
85 NOTREACHED();
83 return NO_SYNC_PROGRESS; 86 return NO_SYNC_PROGRESS;
84 } 87 }
85 88
86 if (!entry.Get(syncable::IS_UNAPPLIED_UPDATE)) {
87 if (!entry.Get(syncable::PARENT_ID).ServerKnows()) {
88 DVLOG(1) << "Item conflicting because its parent not yet committed. Id: "
89 << id;
90 } else {
91 DVLOG(1) << "No set for conflicting entry id " << id << ". There should "
92 << "be an update/commit that will fix this soon. This message "
93 << "should not repeat.";
94 }
95 return NO_SYNC_PROGRESS;
96 }
97
98 if (entry.Get(syncable::IS_DEL) && entry.Get(syncable::SERVER_IS_DEL)) { 89 if (entry.Get(syncable::IS_DEL) && entry.Get(syncable::SERVER_IS_DEL)) {
99 // we've both deleted it, so lets just drop the need to commit/update this 90 // we've both deleted it, so lets just drop the need to commit/update this
100 // entry. 91 // entry.
101 entry.Put(syncable::IS_UNSYNCED, false); 92 entry.Put(syncable::IS_UNSYNCED, false);
102 entry.Put(syncable::IS_UNAPPLIED_UPDATE, false); 93 entry.Put(syncable::IS_UNAPPLIED_UPDATE, false);
103 // we've made changes, but they won't help syncing progress. 94 // we've made changes, but they won't help syncing progress.
104 // METRIC simple conflict resolved by merge. 95 // METRIC simple conflict resolved by merge.
105 return NO_SYNC_PROGRESS; 96 return NO_SYNC_PROGRESS;
106 } 97 }
107 98
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 status->increment_num_local_overwrites(); 297 status->increment_num_local_overwrites();
307 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 298 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
308 OVERWRITE_LOCAL, 299 OVERWRITE_LOCAL,
309 CONFLICT_RESOLUTION_SIZE); 300 CONFLICT_RESOLUTION_SIZE);
310 } 301 }
311 // Now that we've resolved the conflict, clear the prev server 302 // Now that we've resolved the conflict, clear the prev server
312 // specifics. 303 // specifics.
313 entry.Put(syncable::BASE_SERVER_SPECIFICS, sync_pb::EntitySpecifics()); 304 entry.Put(syncable::BASE_SERVER_SPECIFICS, sync_pb::EntitySpecifics());
314 return SYNC_PROGRESS; 305 return SYNC_PROGRESS;
315 } else { // SERVER_IS_DEL is true 306 } else { // SERVER_IS_DEL is true
316 // If a server deleted folder has local contents we should be in a set. 307 // If a server deleted folder has local contents it should be a hierarchy
308 // conflict. Hierarchy conflicts should not be processed by this function.
309 // We could end up here if a change was made since we last tried to detect
310 // conflicts, which was during update application.
317 if (entry.Get(syncable::IS_DIR)) { 311 if (entry.Get(syncable::IS_DIR)) {
318 Directory::ChildHandles children; 312 Directory::ChildHandles children;
319 trans->directory()->GetChildHandlesById(trans, 313 trans->directory()->GetChildHandlesById(trans,
320 entry.Get(syncable::ID), 314 entry.Get(syncable::ID),
321 &children); 315 &children);
322 if (0 != children.size()) { 316 if (0 != children.size()) {
323 DVLOG(1) << "Entry is a server deleted directory with local contents, " 317 DVLOG(1) << "Entry is a server deleted directory with local contents, "
324 << "should be in a set. (race condition)."; 318 << "should be a hierarchy conflict. (race condition).";
325 return NO_SYNC_PROGRESS; 319 return NO_SYNC_PROGRESS;
326 } 320 }
327 } 321 }
328 322
329 // The entry is deleted on the server but still exists locally. 323 // The entry is deleted on the server but still exists locally.
330 if (!entry.Get(syncable::UNIQUE_CLIENT_TAG).empty()) { 324 if (!entry.Get(syncable::UNIQUE_CLIENT_TAG).empty()) {
331 // If we've got a client-unique tag, we can undelete while retaining 325 // If we've got a client-unique tag, we can undelete while retaining
332 // our present ID. 326 // our present ID.
333 DCHECK_EQ(entry.Get(syncable::SERVER_VERSION), 0) << "For the server to " 327 DCHECK_EQ(entry.Get(syncable::SERVER_VERSION), 0) << "For the server to "
334 "know to re-create, client-tagged items should revert to version 0 " 328 "know to re-create, client-tagged items should revert to version 0 "
(...skipping 19 matching lines...) Expand all
354 entry.Get(syncable::META_HANDLE)) 348 entry.Get(syncable::META_HANDLE))
355 << server_update << entry; 349 << server_update << entry;
356 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 350 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
357 UNDELETE, 351 UNDELETE,
358 CONFLICT_RESOLUTION_SIZE); 352 CONFLICT_RESOLUTION_SIZE);
359 } 353 }
360 return SYNC_PROGRESS; 354 return SYNC_PROGRESS;
361 } 355 }
362 } 356 }
363 357
364 bool ConflictResolver::ResolveSimpleConflicts(
365 syncable::WriteTransaction* trans,
366 const Cryptographer* cryptographer,
367 const ConflictProgress& progress,
368 sessions::StatusController* status) {
369 bool forward_progress = false;
370 // First iterate over simple conflict items (those that belong to no set).
371 set<Id>::const_iterator conflicting_item_it;
372 set<Id> processed_items;
373 for (conflicting_item_it = progress.ConflictingItemsBegin();
374 conflicting_item_it != progress.ConflictingItemsEnd();
375 ++conflicting_item_it) {
376 Id id = *conflicting_item_it;
377 if (processed_items.count(id) > 0)
378 continue;
379 map<Id, ConflictSet*>::const_iterator item_set_it =
380 progress.IdToConflictSetFind(id);
381 if (item_set_it == progress.IdToConflictSetEnd() ||
382 0 == item_set_it->second) {
383 // We have a simple conflict. In order check if positions have changed,
384 // we need to process conflicting predecessors before successors. Traverse
385 // backwards through all continuous conflicting predecessors, building a
386 // stack of items to resolve in predecessor->successor order, then process
387 // each item individually.
388 list<Id> predecessors;
389 Id prev_id = id;
390 do {
391 predecessors.push_back(prev_id);
392 Entry entry(trans, syncable::GET_BY_ID, prev_id);
393 // Any entry in conflict must be valid.
394 CHECK(entry.good());
395 Id new_prev_id = entry.Get(syncable::PREV_ID);
396 if (new_prev_id == prev_id)
397 break;
398 prev_id = new_prev_id;
399 } while (processed_items.count(prev_id) == 0 &&
400 progress.HasSimpleConflictItem(prev_id)); // Excludes root.
401 while (!predecessors.empty()) {
402 id = predecessors.back();
403 predecessors.pop_back();
404 switch (ProcessSimpleConflict(trans, id, cryptographer, status)) {
405 case NO_SYNC_PROGRESS:
406 break;
407 case SYNC_PROGRESS:
408 forward_progress = true;
409 break;
410 }
411 processed_items.insert(id);
412 }
413 }
414 }
415 return forward_progress;
416 }
417
418 bool ConflictResolver::ResolveConflicts(syncable::WriteTransaction* trans, 358 bool ConflictResolver::ResolveConflicts(syncable::WriteTransaction* trans,
419 const Cryptographer* cryptographer, 359 const Cryptographer* cryptographer,
420 const ConflictProgress& progress, 360 const ConflictProgress& progress,
421 sessions::StatusController* status) { 361 sessions::StatusController* status) {
422 // TODO(rlarocque): A good amount of code related to the resolution of 362 bool forward_progress = false;
423 // conflict sets has been deleted here. This was done because the code had 363 // Iterate over simple conflict items.
424 // not been used in years. An unrelated bug fix accidentally re-enabled the 364 set<Id>::const_iterator conflicting_item_it;
425 // code, forcing us to make a decision about what we should do with the code. 365 set<Id> processed_items;
426 // We decided to do the safe thing and delete it for now. This restores the 366 for (conflicting_item_it = progress.SimpleConflictingItemsBegin();
427 // behaviour we've relied on for quite some time. We should think about what 367 conflicting_item_it != progress.SimpleConflictingItemsEnd();
428 // that code was trying to do and consider re-enabling parts of it. 368 ++conflicting_item_it) {
369 Id id = *conflicting_item_it;
370 if (processed_items.count(id) > 0)
371 continue;
429 372
430 if (progress.ConflictSetsSize() > 0) { 373 // We have a simple conflict. In order check if positions have changed,
431 DVLOG(1) << "Detected " << progress.IdToConflictSetSize() 374 // we need to process conflicting predecessors before successors. Traverse
432 << " non-simple conflicting entries in " << progress.ConflictSetsSize() 375 // backwards through all continuous conflicting predecessors, building a
433 << " unprocessed conflict sets."; 376 // stack of items to resolve in predecessor->successor order, then process
377 // each item individually.
378 list<Id> predecessors;
379 Id prev_id = id;
380 do {
381 predecessors.push_back(prev_id);
382 Entry entry(trans, syncable::GET_BY_ID, prev_id);
383 // Any entry in conflict must be valid.
384 CHECK(entry.good());
385 Id new_prev_id = entry.Get(syncable::PREV_ID);
386 if (new_prev_id == prev_id)
387 break;
388 prev_id = new_prev_id;
389 } while (processed_items.count(prev_id) == 0 &&
390 progress.HasSimpleConflictItem(prev_id)); // Excludes root.
391 while (!predecessors.empty()) {
392 id = predecessors.back();
393 predecessors.pop_back();
394 switch (ProcessSimpleConflict(trans, id, cryptographer, status)) {
395 case NO_SYNC_PROGRESS:
396 break;
397 case SYNC_PROGRESS:
398 forward_progress = true;
399 break;
400 }
401 processed_items.insert(id);
402 }
434 } 403 }
435 404 return forward_progress;
436 return ResolveSimpleConflicts(trans, cryptographer, progress, status);
437 } 405 }
438 406
439 } // namespace browser_sync 407 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698