1731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/process_commit_response_command.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/basictypes.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncer_proto_util.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncer_util.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncproto.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/sessions/sync_session.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/syncable/directory_manager.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/syncable/syncable.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::ScopedDirLookup;
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::WriteTransaction;
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::MutableEntry;
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::Entry;
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::set;
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::string;
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::vector;
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::BASE_VERSION;
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::GET_BY_ID;
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::ID;
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::IS_DEL;
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::IS_DIR;
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::IS_UNAPPLIED_UPDATE;
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::IS_UNSYNCED;
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::PARENT_ID;
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::SERVER_IS_DEL;
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::SERVER_PARENT_ID;
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::SERVER_POSITION_IN_PARENT;
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::SERVER_VERSION;
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::SYNCER;
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::SYNCING;
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync {
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::OrderedCommitSet;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::StatusController;
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::SyncSession;
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing sessions::ConflictProgress;
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid IncrementErrorCounters(StatusController* status) {
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  status->increment_num_consecutive_errors();
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ResetErrorCounters(StatusController* status) {
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  status->set_num_consecutive_errors(0);
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochProcessCommitResponseCommand::ProcessCommitResponseCommand() {}
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochProcessCommitResponseCommand::~ProcessCommitResponseCommand() {}
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ProcessCommitResponseCommand::ModelNeutralExecuteImpl(
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sessions::SyncSession* session) {
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedDirLookup dir(session->context()->directory_manager(),
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      session->context()->account_name());
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!dir.good()) {
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Scoped dir lookup failed!";
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StatusController* status = session->status_controller();
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const ClientToServerResponse& response(status->commit_response());
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const vector<syncable::Id>& commit_ids(status->commit_ids());
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!response.has_commit()) {
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(sync): What if we didn't try to commit anything?
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Commit response has no commit body!";
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IncrementErrorCounters(status);
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const CommitResponse& cr = response.commit();
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int commit_count = commit_ids.size();
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (cr.entryresponse_size() != commit_count) {
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Commit response has wrong number of entries! Expected:" <<
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               commit_count << " Got:" << cr.entryresponse_size();
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = 0 ; i < cr.entryresponse_size() ; i++) {
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "Response #" << i << " Value: " <<
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 cr.entryresponse(i).response_type();
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (cr.entryresponse(i).has_error_message())
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LOG(ERROR) << "  " << cr.entryresponse(i).error_message();
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IncrementErrorCounters(status);
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ProcessCommitResponseCommand::ModelChangingExecuteImpl(
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SyncSession* session) {
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ProcessCommitResponse(session);
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExtensionsActivityMonitor* monitor = session->context()->extensions_monitor();
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (session->status_controller()->HasBookmarkCommitActivity() &&
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      session->status_controller()->syncer_status()
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          .num_successful_bookmark_commits == 0) {
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    monitor->PutRecords(session->extensions_activity());
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    session->mutable_extensions_activity()->clear();
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ProcessCommitResponseCommand::ProcessCommitResponse(
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SyncSession* session) {
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(sync): This function returns if it sees problems. We probably want
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to flag the need for an update or similar.
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedDirLookup dir(session->context()->directory_manager(),
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      session->context()->account_name());
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!dir.good()) {
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Scoped dir lookup failed!";
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StatusController* status = session->status_controller();
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const ClientToServerResponse& response(status->commit_response());
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const CommitResponse& cr = response.commit();
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const sync_pb::CommitMessage& commit_message =
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      status->commit_message().commit();
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we try to commit a parent and child together and the parent conflicts
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the child will have a bad parent causing an error. As this is not a
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // critical error, we trap it and don't LOG(ERROR). To enable this we keep
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // a map of conflicting new folders.
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int transient_error_commits = 0;
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int conflicting_commits = 0;
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int error_commits = 0;
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int successes = 0;
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set<syncable::Id> conflicting_new_folder_ids;
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set<syncable::Id> deleted_folders;
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ConflictProgress* conflict_progress = status->mutable_conflict_progress();
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OrderedCommitSet::Projection proj = status->commit_id_projection();
138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!proj.empty()) { // Scope for WriteTransaction.
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WriteTransaction trans(dir, SYNCER, __FILE__, __LINE__);
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < proj.size(); i++) {
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CommitResponse::ResponseType response_type =
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ProcessSingleCommitResponse(&trans, cr.entryresponse(proj[i]),
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      commit_message.entries(proj[i]),
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      status->GetCommitIdAt(proj[i]),
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      &conflicting_new_folder_ids,
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      &deleted_folders);
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      switch (response_type) {
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case CommitResponse::INVALID_MESSAGE:
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ++error_commits;
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case CommitResponse::CONFLICT:
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ++conflicting_commits;
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // Only server CONFLICT responses will activate conflict resolution.
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          conflict_progress->AddConflictingItemById(
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              status->GetCommitIdAt(proj[i]));
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case CommitResponse::SUCCESS:
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // TODO(sync): worry about sync_rate_ rate calc?
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ++successes;
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (status->GetCommitIdModelTypeAt(proj[i]) == syncable::BOOKMARKS)
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            status->increment_num_successful_bookmark_commits();
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          status->increment_num_successful_commits();
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case CommitResponse::OVER_QUOTA:
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // We handle over quota like a retry, which is same as transient.
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case CommitResponse::RETRY:
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        case CommitResponse::TRANSIENT_ERROR:
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // TODO(tim): Now that we have SyncSession::Delegate, we
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // should plumb this directly for exponential backoff purposes rather
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // than trying to infer from HasMoreToSync(). See
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // SyncerThread::CalculatePollingWaitTime.
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ++transient_error_commits;
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        default:
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          LOG(FATAL) << "Bad return from ProcessSingleCommitResponse";
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(sync): move status reporting elsewhere.
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  status->increment_num_conflicting_commits_by(conflicting_commits);
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (0 == successes) {
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    status->increment_num_consecutive_transient_error_commits_by(
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        transient_error_commits);
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    status->increment_num_consecutive_errors_by(transient_error_commits);
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    status->set_num_consecutive_transient_error_commits(0);
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    status->set_num_consecutive_errors(0);
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int commit_count = static_cast<int>(proj.size());
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (commit_count != (conflicting_commits + error_commits +
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       transient_error_commits)) {
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ResetErrorCounters(status);
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SyncerUtil::MarkDeletedChildrenSynced(dir, &deleted_folders);
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return;
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid LogServerError(const CommitResponse_EntryResponse& res) {
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (res.has_error_message())
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "  " << res.error_message();
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "  No detailed error message returned from server";
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCommitResponse::ResponseType
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochProcessCommitResponseCommand::ProcessSingleCommitResponse(
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::WriteTransaction* trans,
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::CommitResponse_EntryResponse& pb_server_entry,
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::SyncEntity& commit_request_entry,
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const syncable::Id& pre_commit_id,
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::set<syncable::Id>* conflicting_new_folder_ids,
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    set<syncable::Id>* deleted_folders) {
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const CommitResponse_EntryResponse& server_entry =
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *static_cast<const CommitResponse_EntryResponse*>(&pb_server_entry);
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MutableEntry local_entry(trans, GET_BY_ID, pre_commit_id);
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(local_entry.good());
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool syncing_was_set = local_entry.Get(SYNCING);
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_entry.Put(SYNCING, false);
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CommitResponse::ResponseType response = (CommitResponse::ResponseType)
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      server_entry.response_type();
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!CommitResponse::ResponseType_IsValid(response)) {
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Commit response has unknown response type! Possibly out "
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               "of date client?";
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return CommitResponse::INVALID_MESSAGE;
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (CommitResponse::TRANSIENT_ERROR == response) {
231731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Transient Error Committing: " << local_entry;
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LogServerError(server_entry);
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return CommitResponse::TRANSIENT_ERROR;
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (CommitResponse::INVALID_MESSAGE == response) {
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Error Commiting: " << local_entry;
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LogServerError(server_entry);
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return response;
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (CommitResponse::CONFLICT == response) {
241731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Conflict Committing: " << local_entry;
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(nick): conflicting_new_folder_ids is a purposeless anachronism.
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!pre_commit_id.ServerKnows() && local_entry.Get(IS_DIR)) {
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      conflicting_new_folder_ids->insert(pre_commit_id);
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return response;
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (CommitResponse::RETRY == response) {
249731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Retry Committing: " << local_entry;
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return response;
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (CommitResponse::OVER_QUOTA == response) {
253731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    LOG(WARNING) << "Hit deprecated OVER_QUOTA Committing: " << local_entry;
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return response;
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!server_entry.has_id_string()) {
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Commit response has no id";
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return CommitResponse::INVALID_MESSAGE;
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Implied by the IsValid call above, but here for clarity.
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(CommitResponse::SUCCESS, response) << response;
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check to see if we've been given the ID of an existing entry. If so treat
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // it as an error response and retry later.
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (pre_commit_id != server_entry.id()) {
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Entry e(trans, GET_BY_ID, server_entry.id());
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (e.good()) {
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "Got duplicate id when commiting id: " << pre_commit_id <<
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 ". Treating as an error return";
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return CommitResponse::INVALID_MESSAGE;
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (server_entry.version() == 0) {
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Server returned a zero version on a commit response.";
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ProcessSuccessfulCommitResponse(commit_request_entry, server_entry,
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      pre_commit_id, &local_entry, syncing_was_set, deleted_folders);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return response;
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst string& ProcessCommitResponseCommand::GetResultingPostCommitName(
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::SyncEntity& committed_entry,
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const CommitResponse_EntryResponse& entry_response) {
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const string& response_name =
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SyncerProtoUtil::NameFromCommitEntryResponse(entry_response);
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!response_name.empty())
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return response_name;
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return SyncerProtoUtil::NameFromSyncEntity(committed_entry);
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ProcessCommitResponseCommand::UpdateVersionAfterCommit(
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::SyncEntity& committed_entry,
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const CommitResponse_EntryResponse& entry_response,
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const syncable::Id& pre_commit_id,
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::MutableEntry* local_entry) {
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 old_version = local_entry->Get(BASE_VERSION);
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 new_version = entry_response.version();
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool bad_commit_version = false;
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (committed_entry.deleted() &&
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !local_entry->Get(syncable::UNIQUE_CLIENT_TAG).empty()) {
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the item was deleted, and it's undeletable (uses the client tag),
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // change the version back to zero.  We must set the version to zero so
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // that the server knows to re-create the item if it gets committed
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // later for undeletion.
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_version = 0;
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (!pre_commit_id.ServerKnows()) {
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bad_commit_version = 0 == new_version;
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bad_commit_version = old_version > new_version;
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (bad_commit_version) {
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Bad version in commit return for " << *local_entry
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << " new_id:" << entry_response.id() << " new_version:"
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << entry_response.version();
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Update the base version and server version.  The base version must change
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // here, even if syncing_was_set is false; that's because local changes were
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // on top of the successfully committed version.
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_entry->Put(BASE_VERSION, new_version);
324731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "Commit is changing base version of " << local_entry->Get(ID)
325731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          << " to: " << new_version;
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_entry->Put(SERVER_VERSION, new_version);
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ProcessCommitResponseCommand::ChangeIdAfterCommit(
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const CommitResponse_EntryResponse& entry_response,
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const syncable::Id& pre_commit_id,
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::MutableEntry* local_entry) {
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  syncable::WriteTransaction* trans = local_entry->write_transaction();
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (entry_response.id() != pre_commit_id) {
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (pre_commit_id.ServerKnows()) {
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The server can sometimes generate a new ID on commit; for example,
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // when committing an undeletion.
339731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      VLOG(1) << " ID changed while committing an old entry. "
340731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              << pre_commit_id << " became " << entry_response.id() << ".";
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MutableEntry same_id(trans, GET_BY_ID, entry_response.id());
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We should trap this before this function.
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (same_id.good()) {
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "ID clash with id " << entry_response.id()
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 << " during commit " << same_id;
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SyncerUtil::ChangeEntryIDAndUpdateChildren(
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        trans, local_entry, entry_response.id());
351731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "Changing ID to " << entry_response.id();
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ProcessCommitResponseCommand::UpdateServerFieldsAfterCommit(
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::SyncEntity& committed_entry,
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const CommitResponse_EntryResponse& entry_response,
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::MutableEntry* local_entry) {
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We just committed an entry successfully, and now we want to make our view
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // of the server state consistent with the server state. We must be careful;
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |entry_response| and |committed_entry| have some identically named
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // fields.  We only want to consider fields from |committed_entry| when there
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is not an overriding field in the |entry_response|.  We do not want to
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // update the server data from the local data in the entry -- it's possible
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // that the local data changed during the commit, and even if not, the server
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // has the last word on the values of several properties.
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_entry->Put(SERVER_IS_DEL, committed_entry.deleted());
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (committed_entry.deleted()) {
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Don't clobber any other fields of deleted objects.
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_entry->Put(syncable::SERVER_IS_DIR,
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (committed_entry.folder() ||
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       committed_entry.bookmarkdata().bookmark_folder()));
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_entry->Put(syncable::SERVER_SPECIFICS,
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      committed_entry.specifics());
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_entry->Put(syncable::SERVER_MTIME,
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      committed_entry.mtime());
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_entry->Put(syncable::SERVER_CTIME,
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      committed_entry.ctime());
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_entry->Put(syncable::SERVER_POSITION_IN_PARENT,
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      entry_response.position_in_parent());
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(nick): The server doesn't set entry_response.server_parent_id in
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // practice; to update SERVER_PARENT_ID appropriately here we'd need to
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // get the post-commit ID of the parent indicated by
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // committed_entry.parent_id_string(). That should be inferrable from the
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // information we have, but it's a bit convoluted to pull it out directly.
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Getting this right is important: SERVER_PARENT_ID gets fed back into
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // old_parent_id during the next commit.
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_entry->Put(syncable::SERVER_PARENT_ID,
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      local_entry->Get(syncable::PARENT_ID));
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_entry->Put(syncable::SERVER_NON_UNIQUE_NAME,
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GetResultingPostCommitName(committed_entry, entry_response));
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (local_entry->Get(IS_UNAPPLIED_UPDATE)) {
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This shouldn't happen; an unapplied update shouldn't be committed, and
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // if it were, the commit should have failed.  But if it does happen: we've
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // just overwritten the update info, so clear the flag.
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    local_entry->Put(IS_UNAPPLIED_UPDATE, false);
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ProcessCommitResponseCommand::OverrideClientFieldsAfterCommit(
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::SyncEntity& committed_entry,
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const CommitResponse_EntryResponse& entry_response,
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    syncable::MutableEntry* local_entry) {
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (committed_entry.deleted()) {
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If an entry's been deleted, nothing else matters.
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(local_entry->Get(IS_DEL));
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Update the name.
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const string& server_name =
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GetResultingPostCommitName(committed_entry, entry_response);
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const string& old_name =
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      local_entry->Get(syncable::NON_UNIQUE_NAME);
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!server_name.empty() && old_name != server_name) {
424731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VLOG(1) << "During commit, server changed name: " << old_name
425731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick            << " to new name: " << server_name;
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    local_entry->Put(syncable::NON_UNIQUE_NAME, server_name);
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The server has the final say on positioning, so apply the absolute
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // position that it returns.
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (entry_response.has_position_in_parent()) {
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The SERVER_ field should already have been written.
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK_EQ(entry_response.position_in_parent(),
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        local_entry->Get(SERVER_POSITION_IN_PARENT));
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We just committed successfully, so we assume that the position
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // value we got applies to the PARENT_ID we submitted.
438dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    syncable::Id new_prev = local_entry->ComputePrevIdFromServerPosition(
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        local_entry->Get(PARENT_ID));
440731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!local_entry->PutPredecessor(new_prev))
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(WARNING) << "PutPredecessor failed after successful commit";
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ProcessCommitResponseCommand::ProcessSuccessfulCommitResponse(
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::SyncEntity& committed_entry,
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const CommitResponse_EntryResponse& entry_response,
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const syncable::Id& pre_commit_id, syncable::MutableEntry* local_entry,
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool syncing_was_set, set<syncable::Id>* deleted_folders) {
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(local_entry->Get(IS_UNSYNCED));
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Update SERVER_VERSION and BASE_VERSION.
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!UpdateVersionAfterCommit(committed_entry, entry_response, pre_commit_id,
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                local_entry)) {
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Bad version in commit return for " << *local_entry
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << " new_id:" << entry_response.id() << " new_version:"
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << entry_response.version();
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the server gave us a new ID, apply it.
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ChangeIdAfterCommit(entry_response, pre_commit_id, local_entry)) {
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Update our stored copy of the server state.
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UpdateServerFieldsAfterCommit(committed_entry, entry_response, local_entry);
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the item doesn't need to be committed again (an item might need to be
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // committed again if it changed locally during the commit), we can remove
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // it from the unsynced list.  Also, we should change the locally-
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // visible properties to apply any canonicalizations or fixups
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // that the server introduced during the commit.
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (syncing_was_set) {
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OverrideClientFieldsAfterCommit(committed_entry, entry_response,
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    local_entry);
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    local_entry->Put(IS_UNSYNCED, false);
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make a note of any deleted folders, whose children would have
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // been recursively deleted.
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(nick): Here, commit_message.deleted() would be more correct than
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // local_entry->Get(IS_DEL).  For example, an item could be renamed, and then
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // deleted during the commit of the rename.  Unit test & fix.
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (local_entry->Get(IS_DIR) && local_entry->Get(IS_DEL)) {
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    deleted_folders->insert(local_entry->Get(ID));
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace browser_sync
491