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

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: Rebase + pass trans/cryptographer directly through 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 if (entry.GetModelType() == syncable::NIGORI) {
133 // Create a new set of specifics based on the server specifics (which
134 // preserves their encryption keys).
135 sync_pb::EntitySpecifics specifics =
136 entry.Get(syncable::SERVER_SPECIFICS);
137 sync_pb::NigoriSpecifics* nigori =
138 specifics.MutableExtension(sync_pb::nigori);
139 // Store the merged set of encrypted types (cryptographer->Update(..) will
140 // have merged the local types already).
141 cryptographer->UpdateNigoriFromEncryptedTypes(nigori);
142 // The local set of keys is already merged with the server's set within
143 // the cryptographer. If we don't have pending keys we can store the
144 // merged set back immediately. Else we preserve the server keys and will
145 // update the nigori when the user provides the pending passphrase via
146 // SetPassphrase(..).
147 if (cryptographer->is_ready()) {
148 cryptographer->GetKeys(nigori->mutable_encrypted());
149 }
150 // TODO(zea): Find a better way of doing this. As it stands, we have to
151 // update this code whenever we add a new non-cryptographer related field
152 // to the nigori node.
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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 << server_update << entry; 223 << server_update << entry;
187 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 224 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
188 UNDELETE, 225 UNDELETE,
189 CONFLICT_RESOLUTION_SIZE); 226 CONFLICT_RESOLUTION_SIZE);
190 } 227 }
191 return SYNC_PROGRESS; 228 return SYNC_PROGRESS;
192 } 229 }
193 } 230 }
194 231
195 bool ConflictResolver::ResolveSimpleConflicts( 232 bool ConflictResolver::ResolveSimpleConflicts(
196 const ScopedDirLookup& dir, 233 syncable::WriteTransaction* trans,
234 const Cryptographer* cryptographer,
197 const ConflictProgress& progress, 235 const ConflictProgress& progress,
198 sessions::StatusController* status) { 236 sessions::StatusController* status) {
199 WriteTransaction trans(FROM_HERE, syncable::SYNCER, dir);
200 bool forward_progress = false; 237 bool forward_progress = false;
201 // First iterate over simple conflict items (those that belong to no set). 238 // First iterate over simple conflict items (those that belong to no set).
202 set<Id>::const_iterator conflicting_item_it; 239 set<Id>::const_iterator conflicting_item_it;
203 for (conflicting_item_it = progress.ConflictingItemsBegin(); 240 for (conflicting_item_it = progress.ConflictingItemsBegin();
204 conflicting_item_it != progress.ConflictingItemsEnd(); 241 conflicting_item_it != progress.ConflictingItemsEnd();
205 ++conflicting_item_it) { 242 ++conflicting_item_it) {
206 Id id = *conflicting_item_it; 243 Id id = *conflicting_item_it;
207 map<Id, ConflictSet*>::const_iterator item_set_it = 244 map<Id, ConflictSet*>::const_iterator item_set_it =
208 progress.IdToConflictSetFind(id); 245 progress.IdToConflictSetFind(id);
209 if (item_set_it == progress.IdToConflictSetEnd() || 246 if (item_set_it == progress.IdToConflictSetEnd() ||
210 0 == item_set_it->second) { 247 0 == item_set_it->second) {
211 // We have a simple conflict. 248 // We have a simple conflict.
212 switch (ProcessSimpleConflict(&trans, id, status)) { 249 switch (ProcessSimpleConflict(trans, id, cryptographer, status)) {
213 case NO_SYNC_PROGRESS: 250 case NO_SYNC_PROGRESS:
214 break; 251 break;
215 case SYNC_PROGRESS: 252 case SYNC_PROGRESS:
216 forward_progress = true; 253 forward_progress = true;
217 break; 254 break;
218 } 255 }
219 } 256 }
220 } 257 }
221 return forward_progress; 258 return forward_progress;
222 } 259 }
223 260
224 bool ConflictResolver::ResolveConflicts(const ScopedDirLookup& dir, 261 bool ConflictResolver::ResolveConflicts(syncable::WriteTransaction* trans,
262 const Cryptographer* cryptographer,
225 const ConflictProgress& progress, 263 const ConflictProgress& progress,
226 sessions::StatusController* status) { 264 sessions::StatusController* status) {
227 // TODO(rlarocque): A good amount of code related to the resolution of 265 // TODO(rlarocque): A good amount of code related to the resolution of
228 // conflict sets has been deleted here. This was done because the code had 266 // conflict sets has been deleted here. This was done because the code had
229 // not been used in years. An unrelated bug fix accidentally re-enabled the 267 // not been used in years. An unrelated bug fix accidentally re-enabled the
230 // code, forcing us to make a decision about what we should do with the code. 268 // code, forcing us to make a decision about what we should do with the code.
231 // We decided to do the safe thing and delete it for now. This restores the 269 // We decided to do the safe thing and delete it for now. This restores the
232 // behaviour we've relied on for quite some time. We should think about what 270 // behaviour we've relied on for quite some time. We should think about what
233 // that code was trying to do and consider re-enabling parts of it. 271 // that code was trying to do and consider re-enabling parts of it.
234 272
235 if (progress.ConflictSetsSize() > 0) { 273 if (progress.ConflictSetsSize() > 0) {
236 DVLOG(1) << "Detected " << progress.IdToConflictSetSize() 274 DVLOG(1) << "Detected " << progress.IdToConflictSetSize()
237 << " non-simple conflicting entries in " << progress.ConflictSetsSize() 275 << " non-simple conflicting entries in " << progress.ConflictSetsSize()
238 << " unprocessed conflict sets."; 276 << " unprocessed conflict sets.";
239 } 277 }
240 278
241 return ResolveSimpleConflicts(dir, progress, status); 279 return ResolveSimpleConflicts(trans, cryptographer, progress, status);
242 } 280 }
243 281
244 } // namespace browser_sync 282 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/engine/conflict_resolver.h ('k') | chrome/browser/sync/engine/resolve_conflicts_command.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698