| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <map> | 8 #include <map> |
| 9 #include <set> | 9 #include <set> |
| 10 | 10 |
| 11 #include "base/metrics/histogram.h" |
| 11 #include "chrome/browser/sync/engine/syncer.h" | 12 #include "chrome/browser/sync/engine/syncer.h" |
| 12 #include "chrome/browser/sync/engine/syncer_util.h" | 13 #include "chrome/browser/sync/engine/syncer_util.h" |
| 13 #include "chrome/browser/sync/protocol/service_constants.h" | 14 #include "chrome/browser/sync/protocol/service_constants.h" |
| 14 #include "chrome/browser/sync/sessions/status_controller.h" | 15 #include "chrome/browser/sync/sessions/status_controller.h" |
| 15 #include "chrome/browser/sync/syncable/directory_manager.h" | 16 #include "chrome/browser/sync/syncable/directory_manager.h" |
| 16 #include "chrome/browser/sync/syncable/syncable.h" | 17 #include "chrome/browser/sync/syncable/syncable.h" |
| 17 #include "chrome/common/deprecated/event_sys-inl.h" | 18 #include "chrome/common/deprecated/event_sys-inl.h" |
| 18 | 19 |
| 19 using std::map; | 20 using std::map; |
| 20 using std::set; | 21 using std::set; |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 std::stringstream rv; | 177 std::stringstream rv; |
| 177 for (ConflictSet::iterator i = set->begin() ; i != set->end() ; ++i ) | 178 for (ConflictSet::iterator i = set->begin() ; i != set->end() ; ++i ) |
| 178 rv << *i << "."; | 179 rv << *i << "."; |
| 179 return rv.str(); | 180 return rv.str(); |
| 180 } | 181 } |
| 181 | 182 |
| 182 namespace { | 183 namespace { |
| 183 | 184 |
| 184 bool AttemptToFixCircularConflict(WriteTransaction* trans, | 185 bool AttemptToFixCircularConflict(WriteTransaction* trans, |
| 185 ConflictSet* conflict_set) { | 186 ConflictSet* conflict_set) { |
| 187 UMA_HISTOGRAM_COUNTS("Sync.ConflictFixCircularity", 1); |
| 186 ConflictSet::const_iterator i, j; | 188 ConflictSet::const_iterator i, j; |
| 187 for (i = conflict_set->begin() ; i != conflict_set->end() ; ++i) { | 189 for (i = conflict_set->begin() ; i != conflict_set->end() ; ++i) { |
| 188 MutableEntry entryi(trans, syncable::GET_BY_ID, *i); | 190 MutableEntry entryi(trans, syncable::GET_BY_ID, *i); |
| 189 if (entryi.Get(syncable::PARENT_ID) == | 191 if (entryi.Get(syncable::PARENT_ID) == |
| 190 entryi.Get(syncable::SERVER_PARENT_ID) || | 192 entryi.Get(syncable::SERVER_PARENT_ID) || |
| 191 !entryi.Get(syncable::IS_UNAPPLIED_UPDATE) || | 193 !entryi.Get(syncable::IS_UNAPPLIED_UPDATE) || |
| 192 !entryi.Get(syncable::IS_DIR)) { | 194 !entryi.Get(syncable::IS_DIR)) { |
| 193 continue; | 195 continue; |
| 194 } | 196 } |
| 195 Id parentid = entryi.Get(syncable::SERVER_PARENT_ID); | 197 Id parentid = entryi.Get(syncable::SERVER_PARENT_ID); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 entry.Put(syncable::PARENT_ID, parent_id); | 342 entry.Put(syncable::PARENT_ID, parent_id); |
| 341 entry.Put(syncable::IS_DEL, false); | 343 entry.Put(syncable::IS_DEL, false); |
| 342 id = entry.Get(syncable::PARENT_ID); | 344 id = entry.Get(syncable::PARENT_ID); |
| 343 // METRIC conflict resolved by recreating dir tree. | 345 // METRIC conflict resolved by recreating dir tree. |
| 344 } | 346 } |
| 345 return true; | 347 return true; |
| 346 } | 348 } |
| 347 | 349 |
| 348 bool AttemptToFixRemovedDirectoriesWithContent(WriteTransaction* trans, | 350 bool AttemptToFixRemovedDirectoriesWithContent(WriteTransaction* trans, |
| 349 ConflictSet* conflict_set) { | 351 ConflictSet* conflict_set) { |
| 352 UMA_HISTOGRAM_COUNTS("Sync.ConflictFixRemovedDirectoriesWithContent", 1); |
| 350 ConflictSet::const_iterator i, j; | 353 ConflictSet::const_iterator i, j; |
| 351 for (i = conflict_set->begin() ; i != conflict_set->end() ; ++i) { | 354 for (i = conflict_set->begin() ; i != conflict_set->end() ; ++i) { |
| 352 Entry entry(trans, syncable::GET_BY_ID, *i); | 355 Entry entry(trans, syncable::GET_BY_ID, *i); |
| 353 if (AttemptToFixUnsyncedEntryInDeletedServerTree(trans, | 356 if (AttemptToFixUnsyncedEntryInDeletedServerTree(trans, |
| 354 conflict_set, entry)) { | 357 conflict_set, entry)) { |
| 355 return true; | 358 return true; |
| 356 } | 359 } |
| 357 if (AttemptToFixUpdateEntryInDeletedLocalTree(trans, conflict_set, entry)) | 360 if (AttemptToFixUpdateEntryInDeletedLocalTree(trans, conflict_set, entry)) |
| 358 return true; | 361 return true; |
| 359 } | 362 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 << end - begin << " items:"; | 415 << end - begin << " items:"; |
| 413 for (InputIt i = begin ; i != end ; ++i) { | 416 for (InputIt i = begin ; i != end ; ++i) { |
| 414 Entry e(trans, syncable::GET_BY_ID, *i); | 417 Entry e(trans, syncable::GET_BY_ID, *i); |
| 415 if (e.good()) | 418 if (e.good()) |
| 416 LOG(ERROR) << " " << e; | 419 LOG(ERROR) << " " << e; |
| 417 else | 420 else |
| 418 LOG(ERROR) << " Bad ID:" << *i; | 421 LOG(ERROR) << " Bad ID:" << *i; |
| 419 } | 422 } |
| 420 | 423 |
| 421 status->set_syncer_stuck(true); | 424 status->set_syncer_stuck(true); |
| 425 UMA_HISTOGRAM_COUNTS("Sync.SyncerConflictStuck", 1); |
| 422 | 426 |
| 423 return true; | 427 return true; |
| 424 // TODO(sync): If we're stuck for a while we need to alert the user, clear | 428 // TODO(sync): If we're stuck for a while we need to alert the user, clear |
| 425 // cache or reset syncing. At the very least we should stop trying something | 429 // cache or reset syncing. At the very least we should stop trying something |
| 426 // that's obviously not working. | 430 // that's obviously not working. |
| 427 } | 431 } |
| 428 | 432 |
| 429 bool ConflictResolver::ResolveSimpleConflicts(const ScopedDirLookup& dir, | 433 bool ConflictResolver::ResolveSimpleConflicts(const ScopedDirLookup& dir, |
| 430 StatusController* status) { | 434 StatusController* status) { |
| 431 WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__); | 435 WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 467 return forward_progress; | 471 return forward_progress; |
| 468 } | 472 } |
| 469 | 473 |
| 470 bool ConflictResolver::ResolveConflicts(const ScopedDirLookup& dir, | 474 bool ConflictResolver::ResolveConflicts(const ScopedDirLookup& dir, |
| 471 StatusController* status) { | 475 StatusController* status) { |
| 472 const ConflictProgress& progress = status->conflict_progress(); | 476 const ConflictProgress& progress = status->conflict_progress(); |
| 473 bool rv = false; | 477 bool rv = false; |
| 474 if (ResolveSimpleConflicts(dir, status)) | 478 if (ResolveSimpleConflicts(dir, status)) |
| 475 rv = true; | 479 rv = true; |
| 476 WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__); | 480 WriteTransaction trans(dir, syncable::SYNCER, __FILE__, __LINE__); |
| 477 set<Id> children_of_dirs_merged_last_round; | |
| 478 std::swap(children_of_merged_dirs_, children_of_dirs_merged_last_round); | |
| 479 set<ConflictSet*>::const_iterator set_it; | 481 set<ConflictSet*>::const_iterator set_it; |
| 480 for (set_it = progress.ConflictSetsBegin(); | 482 for (set_it = progress.ConflictSetsBegin(); |
| 481 set_it != progress.ConflictSetsEnd(); | 483 set_it != progress.ConflictSetsEnd(); |
| 482 set_it++) { | 484 set_it++) { |
| 483 ConflictSet* conflict_set = *set_it; | 485 ConflictSet* conflict_set = *set_it; |
| 484 ConflictSetCountMapKey key = GetSetKey(conflict_set); | 486 ConflictSetCountMapKey key = GetSetKey(conflict_set); |
| 485 conflict_set_count_map_[key] += 2; | 487 conflict_set_count_map_[key] += 2; |
| 486 int conflict_count = conflict_set_count_map_[key]; | 488 int conflict_count = conflict_set_count_map_[key]; |
| 487 // Keep a metric for new sets. | 489 // Keep a metric for new sets. |
| 488 if (2 == conflict_count) { | 490 if (2 == conflict_count) { |
| 489 // METRIC conflict sets seen ++ | 491 // METRIC conflict sets seen ++ |
| 490 } | 492 } |
| 491 // See if this set contains entries whose parents were merged last round. | |
| 492 if (SortedCollectionsIntersect(children_of_dirs_merged_last_round.begin(), | |
| 493 children_of_dirs_merged_last_round.end(), | |
| 494 conflict_set->begin(), | |
| 495 conflict_set->end())) { | |
| 496 VLOG(1) << "Accelerating resolution for hierarchical merge."; | |
| 497 conflict_count += 2; | |
| 498 } | |
| 499 // See if we should process this set. | 493 // See if we should process this set. |
| 500 if (ProcessConflictSet(&trans, conflict_set, conflict_count)) { | 494 if (ProcessConflictSet(&trans, conflict_set, conflict_count)) { |
| 501 rv = true; | 495 rv = true; |
| 502 } | 496 } |
| 503 LogAndSignalIfConflictStuck(&trans, conflict_count, | 497 LogAndSignalIfConflictStuck(&trans, conflict_count, |
| 504 conflict_set->begin(), | 498 conflict_set->begin(), |
| 505 conflict_set->end(), status); | 499 conflict_set->end(), status); |
| 506 } | 500 } |
| 507 if (rv) { | 501 if (rv) { |
| 508 // This code means we don't signal that syncing is stuck when any conflict | 502 // This code means we don't signal that syncing is stuck when any conflict |
| (...skipping 10 matching lines...) Expand all Loading... |
| 519 conflict_set_count_map_.erase(i++); | 513 conflict_set_count_map_.erase(i++); |
| 520 // METRIC self resolved conflict sets ++. | 514 // METRIC self resolved conflict sets ++. |
| 521 } else { | 515 } else { |
| 522 ++i; | 516 ++i; |
| 523 } | 517 } |
| 524 } | 518 } |
| 525 return rv; | 519 return rv; |
| 526 } | 520 } |
| 527 | 521 |
| 528 } // namespace browser_sync | 522 } // namespace browser_sync |
| OLD | NEW |