| Index: sync/engine/conflict_resolver.cc
|
| diff --git a/sync/engine/conflict_resolver.cc b/sync/engine/conflict_resolver.cc
|
| index 4d91b0fc879bde1303bd2d353a50d7ae577cfce0..9c4d66ac6bc24dde9f649dec0808181a90597755 100644
|
| --- a/sync/engine/conflict_resolver.cc
|
| +++ b/sync/engine/conflict_resolver.cc
|
| @@ -95,55 +95,14 @@ void ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
|
| entry.Get(syncable::SERVER_PARENT_ID);
|
| bool entry_deleted = entry.Get(syncable::IS_DEL);
|
|
|
| - // This positional check is meant to be necessary but not sufficient. As a
|
| - // result, it may be false even when the position hasn't changed, possibly
|
| - // resulting in unnecessary commits, but if it's true the position has
|
| - // definitely not changed. The check works by verifying that the prev id
|
| - // as calculated from the server position (which will ignore any
|
| - // unsynced/unapplied predecessors and be root for non-bookmark datatypes)
|
| - // matches the client prev id. Because we traverse chains of conflicting
|
| - // items in predecessor -> successor order, we don't need to also verify the
|
| - // successor matches (If it's in conflict, we'll verify it next. If it's
|
| - // not, then it should be taken into account already in the
|
| - // ComputePrevIdFromServerPosition calculation). This works even when there
|
| - // are chains of conflicting items.
|
| - //
|
| - // Example: Original sequence was abcde. Server changes to aCDbe, while
|
| - // client changes to aDCbe (C and D are in conflict). Locally, D's prev id
|
| - // is a, while C's prev id is D. On the other hand, the server prev id will
|
| - // ignore unsynced/unapplied items, so D's server prev id will also be a,
|
| - // just like C's. Because we traverse in client predecessor->successor
|
| - // order, we evaluate D first. Since prev id and server id match, we
|
| - // consider the position to have remained the same for D, and will unset
|
| - // it's UNSYNCED/UNAPPLIED bits. When we evaluate C though, we'll see that
|
| - // the prev id is D locally while the server's prev id is a. C will
|
| - // therefore count as a positional conflict (and the local data will be
|
| - // overwritten by the server data typically). The final result will be
|
| - // aCDbe (the same as the server's view). Even though both C and D were
|
| - // modified, only one counted as being in actual conflict and was resolved
|
| - // with local/server wins.
|
| - //
|
| - // In general, when there are chains of positional conflicts, only the first
|
| - // item in chain (based on the clients point of view) will have both its
|
| - // server prev id and local prev id match. For all the rest the server prev
|
| - // id will be the predecessor of the first item in the chain, and therefore
|
| - // not match the local prev id.
|
| - //
|
| - // Similarly, chains of conflicts where the server and client info are the
|
| - // same are supported due to the predecessor->successor ordering. In this
|
| - // case, from the first item onward, we unset the UNSYNCED/UNAPPLIED bits as
|
| - // we decide that nothing changed. The subsequent item's server prev id will
|
| - // accurately match the local prev id because the predecessor is no longer
|
| - // UNSYNCED/UNAPPLIED.
|
| - // TODO(zea): simplify all this once we can directly compare server position
|
| - // to client position.
|
| - syncable::Id server_prev_id = entry.ComputePrevIdFromServerPosition(
|
| - entry.Get(syncable::SERVER_PARENT_ID));
|
| - bool needs_reinsertion = !parent_matches ||
|
| - server_prev_id != entry.Get(syncable::PREV_ID);
|
| - DVLOG_IF(1, needs_reinsertion) << "Insertion needed, server prev id "
|
| - << " is " << server_prev_id << ", local prev id is "
|
| - << entry.Get(syncable::PREV_ID);
|
| + // The position check might fail spuriously if one of the positions was
|
| + // based on a legacy random suffix, rather than a deterministic one based on
|
| + // originator_cache_guid and originator_item_id. If an item is being
|
| + // modified regularly, it shouldn't take long for the suffix and position to
|
| + // be updated, so such false failures shouldn't be a problem for long.
|
| + bool position_matches = parent_matches &&
|
| + entry.Get(syncable::SERVER_UNIQUE_POSITION).Equals(
|
| + entry.Get(syncable::UNIQUE_POSITION));
|
| const sync_pb::EntitySpecifics& specifics =
|
| entry.Get(syncable::SPECIFICS);
|
| const sync_pb::EntitySpecifics& server_specifics =
|
| @@ -189,7 +148,7 @@ void ConflictResolver::ProcessSimpleConflict(WriteTransaction* trans,
|
| }
|
|
|
| if (!entry_deleted && name_matches && parent_matches && specifics_match &&
|
| - !needs_reinsertion) {
|
| + position_matches) {
|
| DVLOG(1) << "Resolving simple conflict, everything matches, ignoring "
|
| << "changes for: " << entry;
|
| conflict_util::IgnoreConflict(&entry);
|
| @@ -260,13 +219,10 @@ void ConflictResolver::ResolveConflicts(
|
| sessions::StatusController* status) {
|
| // Iterate over simple conflict items.
|
| set<Id>::const_iterator conflicting_item_it;
|
| - set<Id> processed_items;
|
| for (conflicting_item_it = simple_conflict_ids.begin();
|
| conflicting_item_it != simple_conflict_ids.end();
|
| ++conflicting_item_it) {
|
| Id id = *conflicting_item_it;
|
| - 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);
|
| @@ -276,30 +232,7 @@ void ConflictResolver::ResolveConflicts(
|
| 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
|
| - // stack of items to resolve in predecessor->successor order, then process
|
| - // each item individually.
|
| - list<Id> predecessors;
|
| - Id prev_id = id;
|
| - do {
|
| - predecessors.push_back(prev_id);
|
| - Entry entry(trans, syncable::GET_BY_ID, prev_id);
|
| - // Any entry in conflict must be valid.
|
| - CHECK(entry.good());
|
| - Id new_prev_id = entry.Get(syncable::PREV_ID);
|
| - if (new_prev_id == prev_id)
|
| - break;
|
| - prev_id = new_prev_id;
|
| - } while (processed_items.count(prev_id) == 0 &&
|
| - simple_conflict_ids.count(prev_id) > 0); // Excludes root.
|
| - while (!predecessors.empty()) {
|
| - id = predecessors.back();
|
| - predecessors.pop_back();
|
| - ProcessSimpleConflict(trans, id, cryptographer, status);
|
| - processed_items.insert(id);
|
| - }
|
| + ProcessSimpleConflict(trans, id, cryptographer, status);
|
| }
|
| return;
|
| }
|
|
|