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

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

Issue 8917031: [Sync] Add nigori node conflict resolution. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Re-add some lines lost in the split Created 9 years 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) 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/location.h" 11 #include "base/location.h"
12 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
13 #include "chrome/browser/sync/engine/syncer.h" 13 #include "chrome/browser/sync/engine/syncer.h"
14 #include "chrome/browser/sync/engine/syncer_util.h" 14 #include "chrome/browser/sync/engine/syncer_util.h"
15 #include "chrome/browser/sync/protocol/nigori_specifics.pb.h"
15 #include "chrome/browser/sync/protocol/service_constants.h" 16 #include "chrome/browser/sync/protocol/service_constants.h"
16 #include "chrome/browser/sync/sessions/status_controller.h" 17 #include "chrome/browser/sync/sessions/status_controller.h"
17 #include "chrome/browser/sync/syncable/directory_manager.h" 18 #include "chrome/browser/sync/syncable/directory_manager.h"
18 #include "chrome/browser/sync/syncable/syncable.h" 19 #include "chrome/browser/sync/syncable/syncable.h"
20 #include "chrome/browser/sync/util/cryptographer.h"
19 21
20 using std::map; 22 using std::map;
21 using std::set; 23 using std::set;
22 using syncable::BaseTransaction; 24 using syncable::BaseTransaction;
23 using syncable::Directory; 25 using syncable::Directory;
24 using syncable::Entry; 26 using syncable::Entry;
25 using syncable::Id; 27 using syncable::Id;
26 using syncable::MutableEntry; 28 using syncable::MutableEntry;
27 using syncable::ScopedDirLookup; 29 using syncable::ScopedDirLookup;
28 using syncable::WriteTransaction; 30 using syncable::WriteTransaction;
29 31
30 namespace browser_sync { 32 namespace browser_sync {
31 33
32 using sessions::ConflictProgress; 34 using sessions::ConflictProgress;
33 using sessions::StatusController; 35 using sessions::StatusController;
34 36
35 namespace { 37 namespace {
36 38
37 const int SYNC_CYCLES_BEFORE_ADMITTING_DEFEAT = 8; 39 const int SYNC_CYCLES_BEFORE_ADMITTING_DEFEAT = 8;
38 40
39 // Enumeration of different conflict resolutions. Used for histogramming. 41 // Enumeration of different conflict resolutions. Used for histogramming.
40 enum SimpleConflictResolutions { 42 enum SimpleConflictResolutions {
41 OVERWRITE_LOCAL, // Resolved by overwriting local changes. 43 OVERWRITE_LOCAL, // Resolved by overwriting local changes.
42 OVERWRITE_SERVER, // Resolved by overwriting server changes. 44 OVERWRITE_SERVER, // Resolved by overwriting server changes.
43 UNDELETE, // Resolved by undeleting local item. 45 UNDELETE, // Resolved by undeleting local item.
44 IGNORE_ENCRYPTION, // Resolved by ignoring an encryption-only server 46 IGNORE_ENCRYPTION, // Resolved by ignoring an encryption-only server
45 // change. TODO(zea): implement and use this. 47 // change. TODO(zea): implement and use this.
48 NIGORI_MERGE, // Resolved by merging nigori nodes.
46 CONFLICT_RESOLUTION_SIZE, 49 CONFLICT_RESOLUTION_SIZE,
47 }; 50 };
48 51
49 } // namespace 52 } // namespace
50 53
51 ConflictResolver::ConflictResolver() { 54 ConflictResolver::ConflictResolver() {
52 } 55 }
53 56
54 ConflictResolver::~ConflictResolver() { 57 ConflictResolver::~ConflictResolver() {
55 } 58 }
(...skipping 15 matching lines...) Expand all
71 // TODO(chron): This is really a general property clobber. We clobber 74 // TODO(chron): This is really a general property clobber. We clobber
72 // the server side property. Perhaps we should actually do property merging. 75 // the server side property. Perhaps we should actually do property merging.
73 DVLOG(1) << "Resolving conflict by ignoring server changes:" << entry; 76 DVLOG(1) << "Resolving conflict by ignoring server changes:" << entry;
74 entry->Put(syncable::BASE_VERSION, entry->Get(syncable::SERVER_VERSION)); 77 entry->Put(syncable::BASE_VERSION, entry->Get(syncable::SERVER_VERSION));
75 entry->Put(syncable::IS_UNAPPLIED_UPDATE, false); 78 entry->Put(syncable::IS_UNAPPLIED_UPDATE, false);
76 } 79 }
77 80
78 ConflictResolver::ProcessSimpleConflictResult 81 ConflictResolver::ProcessSimpleConflictResult
79 ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans, 82 ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
80 const Id& id, 83 const Id& id,
84 const Cryptographer* cryptographer,
81 StatusController* status) { 85 StatusController* status) {
82 MutableEntry entry(trans, syncable::GET_BY_ID, id); 86 MutableEntry entry(trans, syncable::GET_BY_ID, id);
83 // Must be good as the entry won't have been cleaned up. 87 // Must be good as the entry won't have been cleaned up.
84 CHECK(entry.good()); 88 CHECK(entry.good());
85 // If an update fails, locally we have to be in a set or unsynced. We're not 89 // If an update fails, locally we have to be in a set or unsynced. We're not
86 // in a set here, so we must be unsynced. 90 // in a set here, so we must be unsynced.
87 if (!entry.Get(syncable::IS_UNSYNCED)) { 91 if (!entry.Get(syncable::IS_UNSYNCED)) {
88 return NO_SYNC_PROGRESS; 92 return NO_SYNC_PROGRESS;
89 } 93 }
90 94
(...skipping 26 matching lines...) Expand all
117 // be nice if we could route this back to ModelAssociator code to pick one 121 // be nice if we could route this back to ModelAssociator code to pick one
118 // of three options: CLIENT, SERVER, or MERGE. Some datatypes (autofill) 122 // of three options: CLIENT, SERVER, or MERGE. Some datatypes (autofill)
119 // are easily mergeable. 123 // are easily mergeable.
120 // See http://crbug.com/77339. 124 // See http://crbug.com/77339.
121 bool name_matches = entry.Get(syncable::NON_UNIQUE_NAME) == 125 bool name_matches = entry.Get(syncable::NON_UNIQUE_NAME) ==
122 entry.Get(syncable::SERVER_NON_UNIQUE_NAME); 126 entry.Get(syncable::SERVER_NON_UNIQUE_NAME);
123 bool parent_matches = entry.Get(syncable::PARENT_ID) == 127 bool parent_matches = entry.Get(syncable::PARENT_ID) ==
124 entry.Get(syncable::SERVER_PARENT_ID); 128 entry.Get(syncable::SERVER_PARENT_ID);
125 bool entry_deleted = entry.Get(syncable::IS_DEL); 129 bool entry_deleted = entry.Get(syncable::IS_DEL);
126 130
127 if (!entry_deleted && name_matches && parent_matches) { 131 // We manually merge nigori data.
132 // TODO(zea): Find a better way of doing this. As it stands, we have to
tim (not reviewing) 2011/12/20 17:54:05 Maybe move this comment down to the set_sync_tabs
Nicolas Zea 2011/12/20 19:54:10 Done.
133 // update this code whenever we add a new non-cryptographer related field to
134 // the nigori node.
135 if (entry.GetModelType() == syncable::NIGORI) {
136 // Create a new set of specifics based on the server specifics (which
137 // preserves their encryption keys).
138 sync_pb::EntitySpecifics specifics =
139 entry.Get(syncable::SERVER_SPECIFICS);
140 sync_pb::NigoriSpecifics* nigori =
141 specifics.MutableExtension(sync_pb::nigori);
142 // Store the merged set of encrypted types (cryptographer->Update(..) will
143 // have merged the local types already).
144 cryptographer->UpdateNigoriFromEncryptedTypes(nigori);
145 // The local set of keys is already merged with the server's set within
146 // the cryptographer. If we don't have pending keys we can store the
147 // merged set back immediately. Else we preserve the server keys and will
148 // update the nigori when the user provides the pending passphrase via
149 // SetPassphrase(..).
150 if (cryptographer->is_ready()) {
151 cryptographer->GetKeys(nigori->mutable_encrypted());
152 }
153 if (entry.Get(syncable::SPECIFICS).GetExtension(sync_pb::nigori)
154 .sync_tabs()) {
155 nigori->set_sync_tabs(true);
156 }
157 entry.Put(syncable::SPECIFICS, specifics);
158 DVLOG(1) << "Resovling simple conflict, merging nigori nodes: " << entry;
159 status->increment_num_server_overwrites();
160 OverwriteServerChanges(trans, &entry);
161 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
162 NIGORI_MERGE,
163 CONFLICT_RESOLUTION_SIZE);
164 } else if (!entry_deleted && name_matches && parent_matches) {
128 // TODO(zea): We may prefer to choose the local changes over the server 165 // TODO(zea): We may prefer to choose the local changes over the server
129 // if we know the local changes happened before (or vice versa). 166 // if we know the local changes happened before (or vice versa).
130 // See http://crbug.com/76596 167 // See http://crbug.com/76596
131 DVLOG(1) << "Resolving simple conflict, ignoring local changes for:" 168 DVLOG(1) << "Resolving simple conflict, ignoring local changes for:"
132 << entry; 169 << entry;
133 IgnoreLocalChanges(&entry); 170 IgnoreLocalChanges(&entry);
134 status->increment_num_local_overwrites(); 171 status->increment_num_local_overwrites();
135 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 172 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
136 OVERWRITE_LOCAL, 173 OVERWRITE_LOCAL,
137 CONFLICT_RESOLUTION_SIZE); 174 CONFLICT_RESOLUTION_SIZE);
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 // TODO(sync): If we're stuck for a while we need to alert the user, clear 490 // TODO(sync): If we're stuck for a while we need to alert the user, clear
454 // cache or reset syncing. At the very least we should stop trying something 491 // cache or reset syncing. At the very least we should stop trying something
455 // that's obviously not working. 492 // that's obviously not working.
456 } 493 }
457 494
458 bool ConflictResolver::ResolveSimpleConflicts( 495 bool ConflictResolver::ResolveSimpleConflicts(
459 const ScopedDirLookup& dir, 496 const ScopedDirLookup& dir,
460 const ConflictProgress& progress, 497 const ConflictProgress& progress,
461 sessions::StatusController* status) { 498 sessions::StatusController* status) {
462 WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir); 499 WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir);
500 Cryptographer* cryptographer = dir.manager()->GetCryptographer(&trans);
tim (not reviewing) 2011/12/20 17:54:05 Is manager() or the cryptographer really not avail
Nicolas Zea 2011/12/20 19:54:10 Neither the status controller nor the conflict pro
463 bool forward_progress = false; 501 bool forward_progress = false;
464 // First iterate over simple conflict items (those that belong to no set). 502 // First iterate over simple conflict items (those that belong to no set).
465 set<Id>::const_iterator conflicting_item_it; 503 set<Id>::const_iterator conflicting_item_it;
466 for (conflicting_item_it = progress.ConflictingItemsBegin(); 504 for (conflicting_item_it = progress.ConflictingItemsBegin();
467 conflicting_item_it != progress.ConflictingItemsEnd(); 505 conflicting_item_it != progress.ConflictingItemsEnd();
468 ++conflicting_item_it) { 506 ++conflicting_item_it) {
469 Id id = *conflicting_item_it; 507 Id id = *conflicting_item_it;
470 map<Id, ConflictSet*>::const_iterator item_set_it = 508 map<Id, ConflictSet*>::const_iterator item_set_it =
471 progress.IdToConflictSetFind(id); 509 progress.IdToConflictSetFind(id);
472 if (item_set_it == progress.IdToConflictSetEnd() || 510 if (item_set_it == progress.IdToConflictSetEnd() ||
473 0 == item_set_it->second) { 511 0 == item_set_it->second) {
474 // We have a simple conflict. 512 // We have a simple conflict.
475 switch (ProcessSimpleConflict(&trans, id, status)) { 513 switch (ProcessSimpleConflict(&trans, id, cryptographer, status)) {
476 case NO_SYNC_PROGRESS: 514 case NO_SYNC_PROGRESS:
477 { 515 {
478 int conflict_count = (simple_conflict_count_map_[id] += 2); 516 int conflict_count = (simple_conflict_count_map_[id] += 2);
479 LogAndSignalIfConflictStuck(&trans, conflict_count, 517 LogAndSignalIfConflictStuck(&trans, conflict_count,
480 &id, &id + 1, status); 518 &id, &id + 1, status);
481 break; 519 break;
482 } 520 }
483 case SYNC_PROGRESS: 521 case SYNC_PROGRESS:
484 forward_progress = true; 522 forward_progress = true;
485 break; 523 break;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 conflict_set_count_map_.erase(i++); 577 conflict_set_count_map_.erase(i++);
540 // METRIC self resolved conflict sets ++. 578 // METRIC self resolved conflict sets ++.
541 } else { 579 } else {
542 ++i; 580 ++i;
543 } 581 }
544 } 582 }
545 return rv; 583 return rv;
546 } 584 }
547 585
548 } // namespace browser_sync 586 } // namespace browser_sync
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698