14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "sync/engine/commit_util.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <limits>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/strings/string_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/engine/syncer_proto_util.h"
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "sync/internal_api/public/base/attachment_id_proto.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "sync/internal_api/public/base/unique_position.h"
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "sync/protocol/bookmark_specifics.pb.h"
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "sync/protocol/sync.pb.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/sessions/sync_session.h"
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "sync/syncable/directory.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/entry.h"
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "sync/syncable/model_neutral_mutable_entry.h"
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "sync/syncable/syncable_base_transaction.h"
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "sync/syncable/syncable_base_write_transaction.h"
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "sync/syncable/syncable_changes_version.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/syncable_proto_util.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/syncable_util.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/util/time.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::set;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::string;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::vector;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncer {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using sessions::SyncSession;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncable::Entry;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncable::IS_DEL;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncable::IS_UNAPPLIED_UPDATE;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncable::IS_UNSYNCED;
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using syncable::Id;
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using syncable::SPECIFICS;
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using syncable::UNIQUE_POSITION;
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace commit_util {
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void AddExtensionsActivityToMessage(
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ExtensionsActivity* activity,
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ExtensionsActivity::Records* extensions_activity_buffer,
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    sync_pb::CommitMessage* message) {
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // This isn't perfect, since the set of extensions activity may not correlate
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // exactly with the items being committed.  That's OK as long as we're looking
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // for a rough estimate of extensions activity, not an precise mapping of
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // which commits were triggered by which extension.
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  //
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // We will push this list of extensions activity back into the
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // ExtensionsActivityMonitor if this commit fails.  That's why we must keep a
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // copy of these records in the session.
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  activity->GetAndClearRecords(extensions_activity_buffer);
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const ExtensionsActivity::Records& records = *extensions_activity_buffer;
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (ExtensionsActivity::Records::const_iterator it =
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       records.begin();
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       it != records.end(); ++it) {
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    sync_pb::ChromiumExtensionsActivity* activity_message =
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        message->add_extensions_activity();
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    activity_message->set_extension_id(it->second.extension_id);
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    activity_message->set_bookmark_writes_since_last_commit(
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        it->second.bookmark_write_count);
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void AddClientConfigParamsToMessage(
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ModelTypeSet enabled_types,
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    sync_pb::CommitMessage* message) {
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_pb::ClientConfigParams* config_params = message->mutable_config_params();
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (ModelTypeSet::Iterator it = enabled_types.First(); it.Good(); it.Inc()) {
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (ProxyTypes().Has(it.Get()))
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      continue;
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    int field_number = GetSpecificsFieldNumberFromModelType(it.Get());
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    config_params->mutable_enabled_type_ids()->Add(field_number);
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  config_params->set_tabs_datatype_enabled(
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      enabled_types.Has(syncer::PROXY_TABS));
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace {
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void SetEntrySpecifics(const Entry& meta_entry,
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                       sync_pb::SyncEntity* sync_entry) {
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Add the new style extension and the folder bit.
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_entry->mutable_specifics()->CopyFrom(meta_entry.GetSpecifics());
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_entry->set_folder(meta_entry.GetIsDir());
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  CHECK(!sync_entry->specifics().password().has_client_only_encrypted_data());
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_EQ(meta_entry.GetModelType(), GetModelType(*sync_entry));
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid SetAttachmentIds(const Entry& meta_entry,
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                      sync_pb::SyncEntity* sync_entry) {
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const sync_pb::AttachmentMetadata& attachment_metadata =
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      meta_entry.GetAttachmentMetadata();
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (int i = 0; i < attachment_metadata.record_size(); ++i) {
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    *sync_entry->add_attachment_id() = attachment_metadata.record(i).id();
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void BuildCommitItem(
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const syncable::Entry& meta_entry,
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    sync_pb::SyncEntity* sync_entry) {
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  syncable::Id id = meta_entry.GetId();
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_entry->set_id_string(SyncableIdToProto(id));
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  string name = meta_entry.GetNonUniqueName();
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  CHECK(!name.empty());  // Make sure this isn't an update.
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Note: Truncation is also performed in WriteNode::SetTitle(..). But this
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // call is still necessary to handle any title changes that might originate
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // elsewhere, or already be persisted in the directory.
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::TruncateUTF8ToByteSize(name, 255, &name);
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_entry->set_name(name);
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Set the non_unique_name.  If we do, the server ignores
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // the |name| value (using |non_unique_name| instead), and will return
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // in the CommitResponse a unique name if one is generated.
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // We send both because it may aid in logging.
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_entry->set_non_unique_name(name);
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!meta_entry.GetUniqueClientTag().empty()) {
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    sync_entry->set_client_defined_unique_tag(
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        meta_entry.GetUniqueClientTag());
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Deleted items with server-unknown parent ids can be a problem so we set
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // the parent to 0. (TODO(sync): Still true in protocol?).
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Id new_parent_id;
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (meta_entry.GetIsDel() &&
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      !meta_entry.GetParentId().ServerKnows()) {
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    new_parent_id = syncable::BaseTransaction::root_id();
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    new_parent_id = meta_entry.GetParentId();
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (meta_entry.ShouldMaintainHierarchy()) {
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    sync_entry->set_parent_id_string(SyncableIdToProto(new_parent_id));
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // If our parent has changed, send up the old one so the server
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // can correctly deal with multiple parents.
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // TODO(nick): With the server keeping track of the primary sync parent,
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // it should not be necessary to provide the old_parent_id: the version
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // number should suffice.
1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (new_parent_id != meta_entry.GetServerParentId() &&
1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      0 != meta_entry.GetBaseVersion() &&
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      syncable::CHANGES_VERSION != meta_entry.GetBaseVersion()) {
1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    sync_entry->set_old_parent_id(
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        SyncableIdToProto(meta_entry.GetServerParentId()));
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  int64 version = meta_entry.GetBaseVersion();
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (syncable::CHANGES_VERSION == version || 0 == version) {
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Undeletions are only supported for items that have a client tag.
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DCHECK(!id.ServerKnows() ||
1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           !meta_entry.GetUniqueClientTag().empty())
1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        << meta_entry;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Version 0 means to create or undelete an object.
1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    sync_entry->set_version(0);
1694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else {
1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DCHECK(id.ServerKnows()) << meta_entry;
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    sync_entry->set_version(meta_entry.GetBaseVersion());
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_entry->set_ctime(TimeToProtoTime(meta_entry.GetCtime()));
1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_entry->set_mtime(TimeToProtoTime(meta_entry.GetMtime()));
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SetAttachmentIds(meta_entry, sync_entry);
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Handle bookmarks separately.
1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (meta_entry.GetSpecifics().has_bookmark()) {
1800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (meta_entry.GetIsDel()) {
1810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      sync_entry->set_deleted(true);
1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    } else {
1834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // Both insert_after_item_id and position_in_parent fields are set only
1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // for legacy reasons.  See comments in sync.proto for more information.
1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const Id& prev_id = meta_entry.GetPredecessorId();
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      string prev_id_string =
1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          prev_id.IsRoot() ? string() : prev_id.GetServerId();
1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      sync_entry->set_insert_after_item_id(prev_id_string);
1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      sync_entry->set_position_in_parent(
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          meta_entry.GetUniquePosition().ToInt64());
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      meta_entry.GetUniquePosition().ToProto(
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          sync_entry->mutable_unique_position());
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
1940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Always send specifics for bookmarks.
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    SetEntrySpecifics(meta_entry, sync_entry);
1960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Deletion is final on the server, let's move things and then delete them.
2000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (meta_entry.GetIsDel()) {
2010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    sync_entry->set_deleted(true);
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    sync_pb::EntitySpecifics type_only_specifics;
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    AddDefaultFieldValue(meta_entry.GetModelType(),
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         sync_entry->mutable_specifics());
2060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  } else {
2070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    SetEntrySpecifics(meta_entry, sync_entry);
2080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
2104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Helpers for ProcessSingleCommitResponse.
2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace {
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LogServerError(const sync_pb::CommitResponse_EntryResponse& res) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (res.has_error_message())
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "  " << res.error_message();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "  No detailed error message returned from server";
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const string& GetResultingPostCommitName(
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::SyncEntity& committed_entry,
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::CommitResponse_EntryResponse& entry_response) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const string& response_name =
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SyncerProtoUtil::NameFromCommitEntryResponse(entry_response);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!response_name.empty())
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return response_name;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SyncerProtoUtil::NameFromSyncEntity(committed_entry);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool UpdateVersionAfterCommit(
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::SyncEntity& committed_entry,
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::CommitResponse_EntryResponse& entry_response,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const syncable::Id& pre_commit_id,
2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    syncable::ModelNeutralMutableEntry* local_entry) {
236d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  int64 old_version = local_entry->GetBaseVersion();
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 new_version = entry_response.version();
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool bad_commit_version = false;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (committed_entry.deleted() &&
240d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      !local_entry->GetUniqueClientTag().empty()) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the item was deleted, and it's undeletable (uses the client tag),
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // change the version back to zero.  We must set the version to zero so
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that the server knows to re-create the item if it gets committed
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // later for undeletion.
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_version = 0;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!pre_commit_id.ServerKnows()) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bad_commit_version = 0 == new_version;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bad_commit_version = old_version > new_version;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bad_commit_version) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Bad version in commit return for " << *local_entry
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " new_id:" << SyncableIdFromProto(entry_response.id_string())
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " new_version:" << entry_response.version();
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the base version and server version.  The base version must change
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // here, even if syncing_was_set is false; that's because local changes were
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // on top of the successfully committed version.
261d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_entry->PutBaseVersion(new_version);
262d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DVLOG(1) << "Commit is changing base version of " << local_entry->GetId()
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           << " to: " << new_version;
264d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_entry->PutServerVersion(new_version);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool ChangeIdAfterCommit(
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::CommitResponse_EntryResponse& entry_response,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const syncable::Id& pre_commit_id,
2714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    syncable::ModelNeutralMutableEntry* local_entry) {
2724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  syncable::BaseWriteTransaction* trans = local_entry->base_write_transaction();
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const syncable::Id& entry_response_id =
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SyncableIdFromProto(entry_response.id_string());
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (entry_response_id != pre_commit_id) {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pre_commit_id.ServerKnows()) {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The server can sometimes generate a new ID on commit; for example,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // when committing an undeletion.
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DVLOG(1) << " ID changed while committing an old entry. "
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << pre_commit_id << " became " << entry_response_id << ".";
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    syncable::ModelNeutralMutableEntry same_id(
2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        trans,
2844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        syncable::GET_BY_ID,
2854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        entry_response_id);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We should trap this before this function.
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (same_id.good()) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "ID clash with id " << entry_response_id
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " during commit " << same_id;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ChangeEntryIDAndUpdateChildren(trans, local_entry, entry_response_id);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Changing ID to " << entry_response_id;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void UpdateServerFieldsAfterCommit(
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::SyncEntity& committed_entry,
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::CommitResponse_EntryResponse& entry_response,
3014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    syncable::ModelNeutralMutableEntry* local_entry) {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We just committed an entry successfully, and now we want to make our view
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of the server state consistent with the server state. We must be careful;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |entry_response| and |committed_entry| have some identically named
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // fields.  We only want to consider fields from |committed_entry| when there
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is not an overriding field in the |entry_response|.  We do not want to
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // update the server data from the local data in the entry -- it's possible
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that the local data changed during the commit, and even if not, the server
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // has the last word on the values of several properties.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
312d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_entry->PutServerIsDel(committed_entry.deleted());
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (committed_entry.deleted()) {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Don't clobber any other fields of deleted objects.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
318d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_entry->PutServerIsDir(
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (committed_entry.folder() ||
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       committed_entry.bookmarkdata().bookmark_folder()));
321d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_entry->PutServerSpecifics(committed_entry.specifics());
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  local_entry->PutServerAttachmentMetadata(
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      CreateAttachmentMetadata(committed_entry.attachment_id()));
324d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_entry->PutServerMtime(ProtoTimeToTime(committed_entry.mtime()));
325d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_entry->PutServerCtime(ProtoTimeToTime(committed_entry.ctime()));
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (committed_entry.has_unique_position()) {
327d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    local_entry->PutServerUniquePosition(
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     UniquePosition::FromProto(
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         committed_entry.unique_position()));
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(nick): The server doesn't set entry_response.server_parent_id in
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // practice; to update SERVER_PARENT_ID appropriately here we'd need to
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // get the post-commit ID of the parent indicated by
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // committed_entry.parent_id_string(). That should be inferrable from the
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // information we have, but it's a bit convoluted to pull it out directly.
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Getting this right is important: SERVER_PARENT_ID gets fed back into
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // old_parent_id during the next commit.
339d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_entry->PutServerParentId(local_entry->GetParentId());
340d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  local_entry->PutServerNonUniqueName(
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetResultingPostCommitName(committed_entry, entry_response));
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
343d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (local_entry->GetIsUnappliedUpdate()) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This shouldn't happen; an unapplied update shouldn't be committed, and
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // if it were, the commit should have failed.  But if it does happen: we've
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // just overwritten the update info, so clear the flag.
347d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    local_entry->PutIsUnappliedUpdate(false);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void ProcessSuccessfulCommitResponse(
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::SyncEntity& committed_entry,
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::CommitResponse_EntryResponse& entry_response,
3544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const syncable::Id& pre_commit_id,
3554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    syncable::ModelNeutralMutableEntry* local_entry,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool syncing_was_set, set<syncable::Id>* deleted_folders) {
357d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(local_entry->GetIsUnsynced());
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update SERVER_VERSION and BASE_VERSION.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!UpdateVersionAfterCommit(committed_entry, entry_response, pre_commit_id,
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                local_entry)) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Bad version in commit return for " << *local_entry
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " new_id:" << SyncableIdFromProto(entry_response.id_string())
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " new_version:" << entry_response.version();
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the server gave us a new ID, apply it.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ChangeIdAfterCommit(entry_response, pre_commit_id, local_entry)) {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update our stored copy of the server state.
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateServerFieldsAfterCommit(committed_entry, entry_response, local_entry);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the item doesn't need to be committed again (an item might need to be
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // committed again if it changed locally during the commit), we can remove
37858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // it from the unsynced list.
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (syncing_was_set) {
380d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    local_entry->PutIsUnsynced(false);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make a note of any deleted folders, whose children would have
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // been recursively deleted.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(nick): Here, commit_message.deleted() would be more correct than
386d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // local_entry->GetIsDel().  For example, an item could be renamed, and then
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // deleted during the commit of the rename.  Unit test & fix.
388d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (local_entry->GetIsDir() && local_entry->GetIsDel()) {
389d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    deleted_folders->insert(local_entry->GetId());
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace
3944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)sync_pb::CommitResponse::ResponseType
3964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ProcessSingleCommitResponse(
3974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    syncable::BaseWriteTransaction* trans,
3984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const sync_pb::CommitResponse_EntryResponse& server_entry,
3994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const sync_pb::SyncEntity& commit_request_entry,
4004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    int64 metahandle,
4014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    set<syncable::Id>* deleted_folders) {
4024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  syncable::ModelNeutralMutableEntry local_entry(
4034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      trans,
4044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      syncable::GET_BY_HANDLE,
4054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      metahandle);
4064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  CHECK(local_entry.good());
4074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bool syncing_was_set = local_entry.GetSyncing();
4084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  local_entry.PutSyncing(false);
4094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  sync_pb::CommitResponse::ResponseType response = server_entry.response_type();
4114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!sync_pb::CommitResponse::ResponseType_IsValid(response)) {
4124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(ERROR) << "Commit response has unknown response type! Possibly out "
4134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)               "of date client?";
4144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return sync_pb::CommitResponse::INVALID_MESSAGE;
4154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (sync_pb::CommitResponse::TRANSIENT_ERROR == response) {
4174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DVLOG(1) << "Transient Error Committing: " << local_entry;
4184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LogServerError(server_entry);
4194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return sync_pb::CommitResponse::TRANSIENT_ERROR;
4204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (sync_pb::CommitResponse::INVALID_MESSAGE == response) {
4224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(ERROR) << "Error Commiting: " << local_entry;
4234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LogServerError(server_entry);
4244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return response;
4254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (sync_pb::CommitResponse::CONFLICT == response) {
4274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DVLOG(1) << "Conflict Committing: " << local_entry;
4284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return response;
4294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (sync_pb::CommitResponse::RETRY == response) {
4314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DVLOG(1) << "Retry Committing: " << local_entry;
4324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return response;
4334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (sync_pb::CommitResponse::OVER_QUOTA == response) {
4354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(WARNING) << "Hit deprecated OVER_QUOTA Committing: " << local_entry;
4364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return response;
4374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!server_entry.has_id_string()) {
4394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(ERROR) << "Commit response has no id";
4404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return sync_pb::CommitResponse::INVALID_MESSAGE;
4414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Implied by the IsValid call above, but here for clarity.
4444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_EQ(sync_pb::CommitResponse::SUCCESS, response) << response;
4454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Check to see if we've been given the ID of an existing entry. If so treat
4464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // it as an error response and retry later.
4474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const syncable::Id& server_entry_id =
4484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      SyncableIdFromProto(server_entry.id_string());
4494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (local_entry.GetId() != server_entry_id) {
4504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    Entry e(trans, syncable::GET_BY_ID, server_entry_id);
4514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (e.good()) {
4524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      LOG(ERROR)
4534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          << "Got duplicate id when commiting id: "
4544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          << local_entry.GetId()
4554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          << ". Treating as an error return";
4564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return sync_pb::CommitResponse::INVALID_MESSAGE;
4574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
4584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (server_entry.version() == 0) {
4614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(WARNING) << "Server returned a zero version on a commit response.";
4624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ProcessSuccessfulCommitResponse(commit_request_entry, server_entry,
4654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      local_entry.GetId(), &local_entry, syncing_was_set, deleted_folders);
4664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return response;
4674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace commit_util
4704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace syncer
472