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

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: Remove failing assertion. 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 have
82 if (!entry.Get(syncable::IS_UNSYNCED)) { 82 // both IS_UNSYNCED and IS_UNAPPLIED_UDPATE set.
83 if (!entry.Get(syncable::IS_UNAPPLIED_UPDATE) ||
84 !entry.Get(syncable::IS_UNSYNCED)) {
85 // This is very unusual, but it can happen in tests. We may be able to
86 // assert NOTREACHED() here when those tests are updated.
83 return NO_SYNC_PROGRESS; 87 return NO_SYNC_PROGRESS;
84 } 88 }
85 89
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)) { 90 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 91 // we've both deleted it, so lets just drop the need to commit/update this
100 // entry. 92 // entry.
101 entry.Put(syncable::IS_UNSYNCED, false); 93 entry.Put(syncable::IS_UNSYNCED, false);
102 entry.Put(syncable::IS_UNAPPLIED_UPDATE, false); 94 entry.Put(syncable::IS_UNAPPLIED_UPDATE, false);
103 // we've made changes, but they won't help syncing progress. 95 // we've made changes, but they won't help syncing progress.
104 // METRIC simple conflict resolved by merge. 96 // METRIC simple conflict resolved by merge.
105 return NO_SYNC_PROGRESS; 97 return NO_SYNC_PROGRESS;
106 } 98 }
107 99
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 status->increment_num_local_overwrites(); 298 status->increment_num_local_overwrites();
307 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 299 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
308 OVERWRITE_LOCAL, 300 OVERWRITE_LOCAL,
309 CONFLICT_RESOLUTION_SIZE); 301 CONFLICT_RESOLUTION_SIZE);
310 } 302 }
311 // Now that we've resolved the conflict, clear the prev server 303 // Now that we've resolved the conflict, clear the prev server
312 // specifics. 304 // specifics.
313 entry.Put(syncable::BASE_SERVER_SPECIFICS, sync_pb::EntitySpecifics()); 305 entry.Put(syncable::BASE_SERVER_SPECIFICS, sync_pb::EntitySpecifics());
314 return SYNC_PROGRESS; 306 return SYNC_PROGRESS;
315 } else { // SERVER_IS_DEL is true 307 } else { // SERVER_IS_DEL is true
316 // If a server deleted folder has local contents we should be in a set. 308 // If a server deleted folder has local contents it should be a hierarchy
309 // conflict. Hierarchy conflicts should not be processed by this function.
310 // We could end up here if a change was made since we last tried to detect
311 // conflicts, which was during update application.
317 if (entry.Get(syncable::IS_DIR)) { 312 if (entry.Get(syncable::IS_DIR)) {
318 Directory::ChildHandles children; 313 Directory::ChildHandles children;
319 trans->directory()->GetChildHandlesById(trans, 314 trans->directory()->GetChildHandlesById(trans,
320 entry.Get(syncable::ID), 315 entry.Get(syncable::ID),
321 &children); 316 &children);
322 if (0 != children.size()) { 317 if (0 != children.size()) {
323 DVLOG(1) << "Entry is a server deleted directory with local contents, " 318 DVLOG(1) << "Entry is a server deleted directory with local contents, "
324 << "should be in a set. (race condition)."; 319 << "should be a hierarchy conflict. (race condition).";
325 return NO_SYNC_PROGRESS; 320 return NO_SYNC_PROGRESS;
326 } 321 }
327 } 322 }
328 323
329 // The entry is deleted on the server but still exists locally. 324 // The entry is deleted on the server but still exists locally.
330 if (!entry.Get(syncable::UNIQUE_CLIENT_TAG).empty()) { 325 if (!entry.Get(syncable::UNIQUE_CLIENT_TAG).empty()) {
331 // If we've got a client-unique tag, we can undelete while retaining 326 // If we've got a client-unique tag, we can undelete while retaining
332 // our present ID. 327 // our present ID.
333 DCHECK_EQ(entry.Get(syncable::SERVER_VERSION), 0) << "For the server to " 328 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 " 329 "know to re-create, client-tagged items should revert to version 0 "
(...skipping 19 matching lines...) Expand all
354 entry.Get(syncable::META_HANDLE)) 349 entry.Get(syncable::META_HANDLE))
355 << server_update << entry; 350 << server_update << entry;
356 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 351 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
357 UNDELETE, 352 UNDELETE,
358 CONFLICT_RESOLUTION_SIZE); 353 CONFLICT_RESOLUTION_SIZE);
359 } 354 }
360 return SYNC_PROGRESS; 355 return SYNC_PROGRESS;
361 } 356 }
362 } 357 }
363 358
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, 359 bool ConflictResolver::ResolveConflicts(syncable::WriteTransaction* trans,
419 const Cryptographer* cryptographer, 360 const Cryptographer* cryptographer,
420 const ConflictProgress& progress, 361 const ConflictProgress& progress,
421 sessions::StatusController* status) { 362 sessions::StatusController* status) {
422 // TODO(rlarocque): A good amount of code related to the resolution of 363 bool forward_progress = false;
423 // conflict sets has been deleted here. This was done because the code had 364 // Iterate over simple conflict items.
424 // not been used in years. An unrelated bug fix accidentally re-enabled the 365 set<Id>::const_iterator conflicting_item_it;
425 // code, forcing us to make a decision about what we should do with the code. 366 set<Id> processed_items;
426 // We decided to do the safe thing and delete it for now. This restores the 367 for (conflicting_item_it = progress.SimpleConflictingItemsBegin();
427 // behaviour we've relied on for quite some time. We should think about what 368 conflicting_item_it != progress.SimpleConflictingItemsEnd();
428 // that code was trying to do and consider re-enabling parts of it. 369 ++conflicting_item_it) {
370 Id id = *conflicting_item_it;
371 if (processed_items.count(id) > 0)
372 continue;
429 373
430 if (progress.ConflictSetsSize() > 0) { 374 // We have a simple conflict. In order check if positions have changed,
431 DVLOG(1) << "Detected " << progress.IdToConflictSetSize() 375 // we need to process conflicting predecessors before successors. Traverse
432 << " non-simple conflicting entries in " << progress.ConflictSetsSize() 376 // backwards through all continuous conflicting predecessors, building a
433 << " unprocessed conflict sets."; 377 // stack of items to resolve in predecessor->successor order, then process
378 // each item individually.
379 list<Id> predecessors;
380 Id prev_id = id;
381 do {
382 predecessors.push_back(prev_id);
383 Entry entry(trans, syncable::GET_BY_ID, prev_id);
384 // Any entry in conflict must be valid.
385 CHECK(entry.good());
386 Id new_prev_id = entry.Get(syncable::PREV_ID);
387 if (new_prev_id == prev_id)
388 break;
389 prev_id = new_prev_id;
390 } while (processed_items.count(prev_id) == 0 &&
391 progress.HasSimpleConflictItem(prev_id)); // Excludes root.
392 while (!predecessors.empty()) {
393 id = predecessors.back();
394 predecessors.pop_back();
395 switch (ProcessSimpleConflict(trans, id, cryptographer, status)) {
396 case NO_SYNC_PROGRESS:
397 break;
398 case SYNC_PROGRESS:
399 forward_progress = true;
400 break;
401 }
402 processed_items.insert(id);
403 }
434 } 404 }
435 405 return forward_progress;
436 return ResolveSimpleConflicts(trans, cryptographer, progress, status);
437 } 406 }
438 407
439 } // namespace browser_sync 408 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698