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 |