summaryrefslogtreecommitdiffstats
path: root/sync/engine/conflict_resolver.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sync/engine/conflict_resolver.cc')
-rw-r--r--sync/engine/conflict_resolver.cc100
1 files changed, 15 insertions, 85 deletions
diff --git a/sync/engine/conflict_resolver.cc b/sync/engine/conflict_resolver.cc
index 736e668..73c25ea 100644
--- a/sync/engine/conflict_resolver.cc
+++ b/sync/engine/conflict_resolver.cc
@@ -11,9 +11,9 @@
#include "base/location.h"
#include "base/metrics/histogram.h"
+#include "sync/engine/conflict_util.h"
#include "sync/engine/syncer.h"
#include "sync/engine/syncer_util.h"
-#include "sync/protocol/nigori_specifics.pb.h"
#include "sync/sessions/status_controller.h"
#include "sync/syncable/directory.h"
#include "sync/syncable/mutable_entry.h"
@@ -48,25 +48,6 @@ ConflictResolver::ConflictResolver() {
ConflictResolver::~ConflictResolver() {
}
-void ConflictResolver::IgnoreLocalChanges(MutableEntry* entry) {
- // An update matches local actions, merge the changes.
- // This is a little fishy because we don't actually merge them.
- // In the future we should do a 3-way merge.
- // With IS_UNSYNCED false, changes should be merged.
- entry->Put(syncable::IS_UNSYNCED, false);
-}
-
-void ConflictResolver::OverwriteServerChanges(WriteTransaction* trans,
- MutableEntry * entry) {
- // This is similar to an overwrite from the old client.
- // This is equivalent to a scenario where we got the update before we'd
- // made our local client changes.
- // TODO(chron): This is really a general property clobber. We clobber
- // the server side property. Perhaps we should actually do property merging.
- entry->Put(syncable::BASE_VERSION, entry->Get(syncable::SERVER_VERSION));
- entry->Put(syncable::IS_UNAPPLIED_UPDATE, false);
-}
-
ConflictResolver::ProcessSimpleConflictResult
ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
const Id& id,
@@ -221,70 +202,11 @@ ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
base_server_specifics_match = true;
}
- // We manually merge nigori data.
- if (entry.GetModelType() == NIGORI) {
- // Create a new set of specifics based on the server specifics (which
- // preserves their encryption keys).
- sync_pb::EntitySpecifics specifics =
- entry.Get(syncable::SERVER_SPECIFICS);
- sync_pb::NigoriSpecifics* server_nigori = specifics.mutable_nigori();
- // Store the merged set of encrypted types (cryptographer->Update(..) will
- // have merged the local types already).
- trans->directory()->GetNigoriHandler()->UpdateNigoriFromEncryptedTypes(
- server_nigori,
- trans);
- // The cryptographer has the both the local and remote encryption keys
- // (added at cryptographer->Update(..) time).
- // If the cryptographer is ready, then it already merged both sets of keys
- // and we can store them back in. In that case, the remote key was already
- // part of the local keybag, so we preserve the local key as the default
- // (including whether it's an explicit key).
- // If the cryptographer is not ready, then the user will have to provide
- // the passphrase to decrypt the pending keys. When they do so, the
- // SetDecryptionPassphrase code will act based on whether the server
- // update has an explicit passphrase or not.
- // - If the server had an explicit passphrase, that explicit passphrase
- // will be preserved as the default encryption key.
- // - If the server did not have an explicit passphrase, we assume the
- // local passphrase is the most up to date and preserve the local
- // default encryption key marked as an implicit passphrase.
- // This works fine except for the case where we had locally set an
- // explicit passphrase. In that case the nigori node will have the default
- // key based on the local explicit passphassphrase, but will not have it
- // marked as explicit. To fix this we'd have to track whether we have a
- // explicit passphrase or not separate from the nigori, which would
- // introduce even more complexity, so we leave it up to the user to
- // reset that passphrase as an explicit one via settings. The goal here
- // is to ensure both sets of encryption keys are preserved.
- if (cryptographer->is_ready()) {
- cryptographer->GetKeys(server_nigori->mutable_encrypted());
- server_nigori->set_using_explicit_passphrase(
- entry.Get(syncable::SPECIFICS).nigori().
- using_explicit_passphrase());
- }
- // We deliberately leave the server's device information. This client will
- // add its own device information on restart.
- entry.Put(syncable::SPECIFICS, specifics);
- DVLOG(1) << "Resolving simple conflict, merging nigori nodes: " << entry;
- status->increment_num_server_overwrites();
- OverwriteServerChanges(trans, &entry);
- UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
- NIGORI_MERGE,
- CONFLICT_RESOLUTION_SIZE);
- } else if (!entry_deleted && name_matches && parent_matches &&
- specifics_match && !needs_reinsertion) {
+ if (!entry_deleted && name_matches && parent_matches && specifics_match &&
+ !needs_reinsertion) {
DVLOG(1) << "Resolving simple conflict, everything matches, ignoring "
<< "changes for: " << entry;
- // This unsets both IS_UNSYNCED and IS_UNAPPLIED_UPDATE, and sets the
- // BASE_VERSION to match the SERVER_VERSION. If we didn't also unset
- // IS_UNAPPLIED_UPDATE, then we would lose unsynced positional data from
- // adjacent entries when the server update gets applied and the item is
- // re-inserted into the PREV_ID/NEXT_ID linked list. This is primarily
- // an issue because we commit after applying updates, and is most
- // commonly seen when positional changes are made while a passphrase
- // is required (and hence there will be many encryption conflicts).
- OverwriteServerChanges(trans, &entry);
- IgnoreLocalChanges(&entry);
+ IgnoreConflict(&entry);
UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
CHANGES_MATCH,
CONFLICT_RESOLUTION_SIZE);
@@ -292,12 +214,12 @@ ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
DVLOG(1) << "Resolving simple conflict, ignoring server encryption "
<< " changes for: " << entry;
status->increment_num_server_overwrites();
- OverwriteServerChanges(trans, &entry);
+ OverwriteServerChanges(&entry);
UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
IGNORE_ENCRYPTION,
CONFLICT_RESOLUTION_SIZE);
} else if (entry_deleted || !name_matches || !parent_matches) {
- OverwriteServerChanges(trans, &entry);
+ OverwriteServerChanges(&entry);
status->increment_num_server_overwrites();
DVLOG(1) << "Resolving simple conflict, overwriting server changes "
<< "for: " << entry;
@@ -341,7 +263,7 @@ ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
DCHECK_EQ(entry.Get(syncable::SERVER_VERSION), 0) << "For the server to "
"know to re-create, client-tagged items should revert to version 0 "
"when server-deleted.";
- OverwriteServerChanges(trans, &entry);
+ OverwriteServerChanges(&entry);
status->increment_num_server_overwrites();
DVLOG(1) << "Resolving simple conflict, undeleting server entry: "
<< entry;
@@ -384,6 +306,14 @@ bool ConflictResolver::ResolveConflicts(syncable::WriteTransaction* trans,
if (processed_items.count(id) > 0)
continue;
+ // We don't resolve conflicts for control types here.
+ Entry conflicting_node(trans, syncable::GET_BY_ID, id);
+ CHECK(conflicting_node.good());
+ if (IsControlType(
+ GetModelTypeFromSpecifics(conflicting_node.Get(syncable::SPECIFICS)))) {
+ continue;
+ }
+
// We have a simple conflict. In order check if positions have changed,
// we need to process conflicting predecessors before successors. Traverse
// backwards through all continuous conflicting predecessors, building a