Index: chrome/browser/sync/engine/process_updates_command.cc |
diff --git a/chrome/browser/sync/engine/process_updates_command.cc b/chrome/browser/sync/engine/process_updates_command.cc |
index 6e42b1b37266e45b4d9a6642ca798b2a54dc20a0..d55582ead6e94fa04a186e78f9c5463863288c81 100644 |
--- a/chrome/browser/sync/engine/process_updates_command.cc |
+++ b/chrome/browser/sync/engine/process_updates_command.cc |
@@ -124,29 +124,38 @@ ServerUpdateProcessingResult ProcessUpdatesCommand::ProcessUpdate( |
// If we're repurposing an existing local entry with a new server ID, |
// change the ID now, after we're sure that the update can succeed. |
if (local_id != server_id) { |
+ DCHECK(!update.deleted()); |
SyncerUtil::ChangeEntryIDAndUpdateChildren(&trans, &target_entry, |
server_id); |
// When IDs change, versions become irrelevant. Forcing BASE_VERSION |
- // to zero would ensure that this update gets applied, but historically, |
- // that's an illegal state unless the item is using the client tag. |
- // Alternatively, we can force BASE_VERSION to entry.version(), but |
- // this has the effect of suppressing update application. |
- // TODO(nick): Make the treatment of these two cases consistent. |
- int64 new_version = target_entry.Get(UNIQUE_CLIENT_TAG).empty() ? |
- update.version() : 0; |
- target_entry.Put(BASE_VERSION, new_version); |
+ // to zero would ensure that this update gets applied, but would indicate |
+ // creation or undeletion if it were committed that way. Instead, prefer |
+ // forcing BASE_VERSION to entry.version() while also forcing |
+ // IS_UNAPPLIED_UPDATE to true. If the item is UNSYNCED, it's committable |
+ // from the new state; it may commit before the conflict resolver gets |
+ // a crack at it. |
+ if (target_entry.Get(IS_UNSYNCED) || target_entry.Get(BASE_VERSION) > 0) { |
+ // If either of these conditions are met, then we can expect valid client |
+ // fields for this entry. When BASE_VERSION is positive, consistency is |
+ // enforced on the client fields at update-application time. Otherwise, |
+ // we leave the BASE_VERSION field alone; it'll get updated the first time |
+ // we successfully apply this update. |
+ target_entry.Put(BASE_VERSION, update.version()); |
+ } |
+ // Force application of this update, no matter what. |
+ target_entry.Put(IS_UNAPPLIED_UPDATE, true); |
} |
SyncerUtil::UpdateServerFieldsFromUpdate(&target_entry, update, name); |
if (target_entry.Get(SERVER_VERSION) == target_entry.Get(BASE_VERSION) && |
- !target_entry.Get(IS_UNSYNCED)) { |
- // It's largely OK if data doesn't match exactly since a future update |
- // will just clobber the data. Conflict resolution will overwrite and |
- // take one side as the winner and does not try to merge, so strict |
- // equality isn't necessary. |
- LOG_IF(ERROR, !SyncerUtil::ServerAndLocalEntriesMatch(&target_entry)) |
- << target_entry; |
+ !target_entry.Get(IS_UNSYNCED) && |
+ !target_entry.Get(IS_UNAPPLIED_UPDATE)) { |
+ // If these don't match, it means that we have a different view of the |
+ // truth from other clients. That's a sync bug, though we may be able |
+ // to recover the next time this item commits. |
+ LOG_IF(ERROR, !SyncerUtil::ServerAndLocalEntriesMatch(&target_entry)) |
+ << target_entry; |
} |
return SUCCESS_PROCESSED; |
} |