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

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

Issue 386030: Relieve SyncerSession,SyncCycleState, SyncProcessState, SyncerSession, Syncer... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 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
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 entry. 3 // found in the LICENSE entry.
4 4
5 #include "chrome/browser/sync/engine/conflict_resolver.h" 5 #include "chrome/browser/sync/engine/conflict_resolver.h"
6 6
7 #include <map> 7 #include <map>
8 #include <set> 8 #include <set>
9 9
10 #include "chrome/browser/sync/engine/syncer.h" 10 #include "chrome/browser/sync/engine/syncer.h"
11 #include "chrome/browser/sync/engine/syncer_util.h" 11 #include "chrome/browser/sync/engine/syncer_util.h"
12 #include "chrome/browser/sync/protocol/service_constants.h" 12 #include "chrome/browser/sync/protocol/service_constants.h"
13 #include "chrome/browser/sync/sessions/status_controller.h"
13 #include "chrome/browser/sync/syncable/directory_manager.h" 14 #include "chrome/browser/sync/syncable/directory_manager.h"
14 #include "chrome/browser/sync/syncable/syncable.h" 15 #include "chrome/browser/sync/syncable/syncable.h"
15 #include "chrome/browser/sync/util/character_set_converters.h" 16 #include "chrome/browser/sync/util/character_set_converters.h"
16 #include "chrome/browser/sync/util/event_sys-inl.h" 17 #include "chrome/browser/sync/util/event_sys-inl.h"
17 #include "chrome/browser/sync/util/path_helpers.h" 18 #include "chrome/browser/sync/util/path_helpers.h"
18 19
19 using std::map; 20 using std::map;
20 using std::set; 21 using std::set;
21 using syncable::BaseTransaction; 22 using syncable::BaseTransaction;
22 using syncable::Directory; 23 using syncable::Directory;
23 using syncable::Entry; 24 using syncable::Entry;
24 using syncable::Id; 25 using syncable::Id;
25 using syncable::MutableEntry; 26 using syncable::MutableEntry;
26 using syncable::ScopedDirLookup; 27 using syncable::ScopedDirLookup;
27 using syncable::WriteTransaction; 28 using syncable::WriteTransaction;
28 29
29 namespace browser_sync { 30 namespace browser_sync {
30 31
32 using sessions::ConflictProgress;
33 using sessions::StatusController;
34
31 const int SYNC_CYCLES_BEFORE_ADMITTING_DEFEAT = 8; 35 const int SYNC_CYCLES_BEFORE_ADMITTING_DEFEAT = 8;
32 36
33 ConflictResolver::ConflictResolver() { 37 ConflictResolver::ConflictResolver() {
34 } 38 }
35 39
36 ConflictResolver::~ConflictResolver() { 40 ConflictResolver::~ConflictResolver() {
37 } 41 }
38 42
39 void ConflictResolver::IgnoreLocalChanges(MutableEntry* entry) { 43 void ConflictResolver::IgnoreLocalChanges(MutableEntry* entry) {
40 // An update matches local actions, merge the changes. 44 // An update matches local actions, merge the changes.
(...skipping 12 matching lines...) Expand all
53 // made our local client changes. 57 // made our local client changes.
54 // TODO(chron): This is really a general property clobber. We clobber 58 // TODO(chron): This is really a general property clobber. We clobber
55 // the server side property. Perhaps we should actually do property merging. 59 // the server side property. Perhaps we should actually do property merging.
56 entry->Put(syncable::BASE_VERSION, entry->Get(syncable::SERVER_VERSION)); 60 entry->Put(syncable::BASE_VERSION, entry->Get(syncable::SERVER_VERSION));
57 entry->Put(syncable::IS_UNAPPLIED_UPDATE, false); 61 entry->Put(syncable::IS_UNAPPLIED_UPDATE, false);
58 // METRIC conflict resolved by overwrite. 62 // METRIC conflict resolved by overwrite.
59 } 63 }
60 64
61 ConflictResolver::ProcessSimpleConflictResult 65 ConflictResolver::ProcessSimpleConflictResult
62 ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans, 66 ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
63 Id id, 67 const Id& id) {
64 SyncerSession* session) {
65 MutableEntry entry(trans, syncable::GET_BY_ID, id); 68 MutableEntry entry(trans, syncable::GET_BY_ID, id);
66 // Must be good as the entry won't have been cleaned up. 69 // Must be good as the entry won't have been cleaned up.
67 CHECK(entry.good()); 70 CHECK(entry.good());
68 // If an update fails, locally we have to be in a set or unsynced. We're not 71 // If an update fails, locally we have to be in a set or unsynced. We're not
69 // in a set here, so we must be unsynced. 72 // in a set here, so we must be unsynced.
70 if (!entry.Get(syncable::IS_UNSYNCED)) { 73 if (!entry.Get(syncable::IS_UNSYNCED)) {
71 return NO_SYNC_PROGRESS; 74 return NO_SYNC_PROGRESS;
72 } 75 }
73 76
74 if (!entry.Get(syncable::IS_UNAPPLIED_UPDATE)) { 77 if (!entry.Get(syncable::IS_UNAPPLIED_UPDATE)) {
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 return true; 341 return true;
339 } 342 }
340 return false; 343 return false;
341 } 344 }
342 345
343 } // namespace 346 } // namespace
344 347
345 // TODO(sync): Eliminate conflict sets. They're not necessary. 348 // TODO(sync): Eliminate conflict sets. They're not necessary.
346 bool ConflictResolver::ProcessConflictSet(WriteTransaction* trans, 349 bool ConflictResolver::ProcessConflictSet(WriteTransaction* trans,
347 ConflictSet* conflict_set, 350 ConflictSet* conflict_set,
348 int conflict_count, 351 int conflict_count) {
349 SyncerSession* session) {
350 int set_size = conflict_set->size(); 352 int set_size = conflict_set->size();
351 if (set_size < 2) { 353 if (set_size < 2) {
352 LOG(WARNING) << "Skipping conflict set because it has size " << set_size; 354 LOG(WARNING) << "Skipping conflict set because it has size " << set_size;
353 // We can end up with sets of size one if we have a new item in a set that 355 // We can end up with sets of size one if we have a new item in a set that
354 // we tried to commit transactionally. This should not be a persistent 356 // we tried to commit transactionally. This should not be a persistent
355 // situation. 357 // situation.
356 return false; 358 return false;
357 } 359 }
358 if (conflict_count < 3) { 360 if (conflict_count < 3) {
359 // Avoid resolving sets that could be the result of transient conflicts. 361 // Avoid resolving sets that could be the result of transient conflicts.
(...skipping 12 matching lines...) Expand all
372 return true; 374 return true;
373 return false; 375 return false;
374 } 376 }
375 377
376 template <typename InputIt> 378 template <typename InputIt>
377 bool ConflictResolver::LogAndSignalIfConflictStuck( 379 bool ConflictResolver::LogAndSignalIfConflictStuck(
378 BaseTransaction* trans, 380 BaseTransaction* trans,
379 int attempt_count, 381 int attempt_count,
380 InputIt begin, 382 InputIt begin,
381 InputIt end, 383 InputIt end,
382 ConflictResolutionView* view) { 384 StatusController* status) {
383 if (attempt_count < SYNC_CYCLES_BEFORE_ADMITTING_DEFEAT) { 385 if (attempt_count < SYNC_CYCLES_BEFORE_ADMITTING_DEFEAT) {
384 return false; 386 return false;
385 } 387 }
386 388
387 // Don't signal stuck if we're not up to date. 389 // Don't signal stuck if we're not up to date.
388 if (view->num_server_changes_remaining() > 0) { 390 if (status->change_progress().num_server_changes_remaining > 0) {
389 return false; 391 return false;
390 } 392 }
391 393
392 LOG(ERROR) << "[BUG] Conflict set cannot be resolved, has " 394 LOG(ERROR) << "[BUG] Conflict set cannot be resolved, has "
393 << end - begin << " items:"; 395 << end - begin << " items:";
394 for (InputIt i = begin ; i != end ; ++i) { 396 for (InputIt i = begin ; i != end ; ++i) {
395 Entry e(trans, syncable::GET_BY_ID, *i); 397 Entry e(trans, syncable::GET_BY_ID, *i);
396 if (e.good()) 398 if (e.good())
397 LOG(ERROR) << " " << e; 399 LOG(ERROR) << " " << e;
398 else 400 else
399 LOG(ERROR) << " Bad ID:" << *i; 401 LOG(ERROR) << " Bad ID:" << *i;
400 } 402 }
401 403
402 view->set_syncer_stuck(true); 404 status->set_syncer_stuck(true);
403 405
404 return true; 406 return true;
405 // TODO(sync): If we're stuck for a while we need to alert the user, clear 407 // TODO(sync): If we're stuck for a while we need to alert the user, clear
406 // cache or reset syncing. At the very least we should stop trying something 408 // cache or reset syncing. At the very least we should stop trying something
407 // that's obviously not working. 409 // that's obviously not working.
408 } 410 }
409 411
410 bool ConflictResolver::ResolveSimpleConflicts(const ScopedDirLookup& dir, 412 bool ConflictResolver::ResolveSimpleConflicts(const ScopedDirLookup& dir,
411 ConflictResolutionView* view, 413 StatusController* status) {
412 SyncerSession* session) {
413 WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__); 414 WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__);
414 bool forward_progress = false; 415 bool forward_progress = false;
416 ConflictProgress const* progress = status->conflict_progress();
415 // First iterate over simple conflict items (those that belong to no set). 417 // First iterate over simple conflict items (those that belong to no set).
416 set<Id>::const_iterator conflicting_item_it; 418 set<Id>::const_iterator conflicting_item_it;
417 for (conflicting_item_it = view->CommitConflictsBegin(); 419 for (conflicting_item_it = progress->ConflictingItemsBeginConst();
418 conflicting_item_it != view->CommitConflictsEnd(); 420 conflicting_item_it != progress->ConflictingItemsEnd();
419 ++conflicting_item_it) { 421 ++conflicting_item_it) {
420 Id id = *conflicting_item_it; 422 Id id = *conflicting_item_it;
421 map<Id, ConflictSet*>::const_iterator item_set_it = 423 map<Id, ConflictSet*>::const_iterator item_set_it =
422 view->IdToConflictSetFind(id); 424 progress->IdToConflictSetFind(id);
423 if (item_set_it == view->IdToConflictSetEnd() || 425 if (item_set_it == progress->IdToConflictSetEnd() ||
424 0 == item_set_it->second) { 426 0 == item_set_it->second) {
425 // We have a simple conflict. 427 // We have a simple conflict.
426 switch (ProcessSimpleConflict(&trans, id, session)) { 428 switch (ProcessSimpleConflict(&trans, id)) {
427 case NO_SYNC_PROGRESS: 429 case NO_SYNC_PROGRESS:
428 { 430 {
429 int conflict_count = (simple_conflict_count_map_[id] += 2); 431 int conflict_count = (simple_conflict_count_map_[id] += 2);
430 LogAndSignalIfConflictStuck(&trans, conflict_count, 432 LogAndSignalIfConflictStuck(&trans, conflict_count,
431 &id, &id + 1, view); 433 &id, &id + 1, status);
432 break; 434 break;
433 } 435 }
434 case SYNC_PROGRESS: 436 case SYNC_PROGRESS:
435 forward_progress = true; 437 forward_progress = true;
436 break; 438 break;
437 } 439 }
438 } 440 }
439 } 441 }
440 // Reduce the simple_conflict_count for each item currently tracked. 442 // Reduce the simple_conflict_count for each item currently tracked.
441 SimpleConflictCountMap::iterator i = simple_conflict_count_map_.begin(); 443 SimpleConflictCountMap::iterator i = simple_conflict_count_map_.begin();
442 while (i != simple_conflict_count_map_.end()) { 444 while (i != simple_conflict_count_map_.end()) {
443 if (0 == --(i->second)) 445 if (0 == --(i->second))
444 simple_conflict_count_map_.erase(i++); 446 simple_conflict_count_map_.erase(i++);
445 else 447 else
446 ++i; 448 ++i;
447 } 449 }
448 return forward_progress; 450 return forward_progress;
449 } 451 }
450 452
451 bool ConflictResolver::ResolveConflicts(const ScopedDirLookup& dir, 453 bool ConflictResolver::ResolveConflicts(const ScopedDirLookup& dir,
452 ConflictResolutionView* view, 454 StatusController* status) {
453 SyncerSession* session) { 455 ConflictProgress const* progress = status->conflict_progress();
454 bool rv = false; 456 bool rv = false;
455 if (ResolveSimpleConflicts(dir, view, session)) 457 if (ResolveSimpleConflicts(dir, status))
456 rv = true; 458 rv = true;
457 WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__); 459 WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__);
458 set<Id> children_of_dirs_merged_last_round; 460 set<Id> children_of_dirs_merged_last_round;
459 std::swap(children_of_merged_dirs_, children_of_dirs_merged_last_round); 461 std::swap(children_of_merged_dirs_, children_of_dirs_merged_last_round);
460 set<ConflictSet*>::const_iterator set_it; 462 set<ConflictSet*>::const_iterator set_it;
461 for (set_it = view->ConflictSetsBegin(); 463 for (set_it = progress->ConflictSetsBegin();
462 set_it != view->ConflictSetsEnd(); 464 set_it != progress->ConflictSetsEnd();
463 set_it++) { 465 set_it++) {
464 ConflictSet* conflict_set = *set_it; 466 ConflictSet* conflict_set = *set_it;
465 ConflictSetCountMapKey key = GetSetKey(conflict_set); 467 ConflictSetCountMapKey key = GetSetKey(conflict_set);
466 conflict_set_count_map_[key] += 2; 468 conflict_set_count_map_[key] += 2;
467 int conflict_count = conflict_set_count_map_[key]; 469 int conflict_count = conflict_set_count_map_[key];
468 // Keep a metric for new sets. 470 // Keep a metric for new sets.
469 if (2 == conflict_count) { 471 if (2 == conflict_count) {
470 // METRIC conflict sets seen ++ 472 // METRIC conflict sets seen ++
471 } 473 }
472 // See if this set contains entries whose parents were merged last round. 474 // See if this set contains entries whose parents were merged last round.
473 if (SortedCollectionsIntersect(children_of_dirs_merged_last_round.begin(), 475 if (SortedCollectionsIntersect(children_of_dirs_merged_last_round.begin(),
474 children_of_dirs_merged_last_round.end(), 476 children_of_dirs_merged_last_round.end(),
475 conflict_set->begin(), 477 conflict_set->begin(),
476 conflict_set->end())) { 478 conflict_set->end())) {
477 LOG(INFO) << "Accelerating resolution for hierarchical merge."; 479 LOG(INFO) << "Accelerating resolution for hierarchical merge.";
478 conflict_count += 2; 480 conflict_count += 2;
479 } 481 }
480 // See if we should process this set. 482 // See if we should process this set.
481 if (ProcessConflictSet(&trans, conflict_set, conflict_count, session)) { 483 if (ProcessConflictSet(&trans, conflict_set, conflict_count)) {
482 rv = true; 484 rv = true;
483 } 485 }
484 LogAndSignalIfConflictStuck(&trans, conflict_count, 486 LogAndSignalIfConflictStuck(&trans, conflict_count,
485 conflict_set->begin(), 487 conflict_set->begin(),
486 conflict_set->end(), view); 488 conflict_set->end(), status);
487 } 489 }
488 if (rv) { 490 if (rv) {
489 // This code means we don't signal that syncing is stuck when any conflict 491 // This code means we don't signal that syncing is stuck when any conflict
490 // resolution has occured. 492 // resolution has occured.
491 // TODO(sync): As this will also reduce our sensitivity to problem 493 // TODO(sync): As this will also reduce our sensitivity to problem
492 // conditions and increase the time for cascading resolutions we may have to 494 // conditions and increase the time for cascading resolutions we may have to
493 // revisit this code later, doing something more intelligent. 495 // revisit this code later, doing something more intelligent.
494 conflict_set_count_map_.clear(); 496 conflict_set_count_map_.clear();
495 simple_conflict_count_map_.clear(); 497 simple_conflict_count_map_.clear();
496 } 498 }
497 ConflictSetCountMap::iterator i = conflict_set_count_map_.begin(); 499 ConflictSetCountMap::iterator i = conflict_set_count_map_.begin();
498 while (i != conflict_set_count_map_.end()) { 500 while (i != conflict_set_count_map_.end()) {
499 if (0 == --i->second) { 501 if (0 == --i->second) {
500 conflict_set_count_map_.erase(i++); 502 conflict_set_count_map_.erase(i++);
501 // METRIC self resolved conflict sets ++. 503 // METRIC self resolved conflict sets ++.
502 } else { 504 } else {
503 ++i; 505 ++i;
504 } 506 }
505 } 507 }
506 return rv; 508 return rv;
507 } 509 }
508 510
509 } // namespace browser_sync 511 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/engine/conflict_resolver.h ('k') | chrome/browser/sync/engine/download_updates_command.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698