Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(116)

Side by Side Diff: sync/engine/commit_util.cc

Issue 25638003: sync: Implement per-type commit interface (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Attempt to fix win compile Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sync/engine/commit_util.h ('k') | sync/engine/get_commit_ids.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sync/engine/process_commit_response_command.h" 5 #include "sync/engine/commit_util.h"
6 6
7 #include <cstddef> 7 #include <limits>
8 #include <set> 8 #include <set>
9 #include <string> 9 #include <string>
10 #include <vector> 10 #include <vector>
11 11
12 #include "base/basictypes.h" 12 #include "base/strings/string_util.h"
13 #include "base/location.h"
14 #include "sync/engine/syncer_proto_util.h" 13 #include "sync/engine/syncer_proto_util.h"
15 #include "sync/engine/syncer_util.h"
16 #include "sync/internal_api/public/base/unique_position.h" 14 #include "sync/internal_api/public/base/unique_position.h"
15 #include "sync/protocol/bookmark_specifics.pb.h"
16 #include "sync/protocol/sync.pb.h"
17 #include "sync/sessions/sync_session.h" 17 #include "sync/sessions/sync_session.h"
18 #include "sync/syncable/directory.h"
18 #include "sync/syncable/entry.h" 19 #include "sync/syncable/entry.h"
19 #include "sync/syncable/model_neutral_mutable_entry.h" 20 #include "sync/syncable/model_neutral_mutable_entry.h"
20 #include "sync/syncable/syncable_model_neutral_write_transaction.h" 21 #include "sync/syncable/syncable_base_transaction.h"
22 #include "sync/syncable/syncable_base_write_transaction.h"
23 #include "sync/syncable/syncable_changes_version.h"
21 #include "sync/syncable/syncable_proto_util.h" 24 #include "sync/syncable/syncable_proto_util.h"
22 #include "sync/syncable/syncable_read_transaction.h"
23 #include "sync/syncable/syncable_util.h" 25 #include "sync/syncable/syncable_util.h"
24 #include "sync/util/time.h" 26 #include "sync/util/time.h"
25 27
26 using std::set; 28 using std::set;
27 using std::string; 29 using std::string;
28 using std::vector; 30 using std::vector;
29 using sync_pb::CommitResponse;
30 31
31 namespace syncer { 32 namespace syncer {
32 33
33 using sessions::OrderedCommitSet;
34 using sessions::StatusController;
35 using sessions::SyncSession; 34 using sessions::SyncSession;
36 using syncable::ModelNeutralWriteTransaction;
37 using syncable::ModelNeutralMutableEntry;
38 using syncable::Entry; 35 using syncable::Entry;
39 using syncable::BASE_VERSION;
40 using syncable::GET_BY_ID;
41 using syncable::GET_BY_HANDLE;
42 using syncable::ID;
43 using syncable::IS_DEL; 36 using syncable::IS_DEL;
44 using syncable::IS_DIR;
45 using syncable::IS_UNAPPLIED_UPDATE; 37 using syncable::IS_UNAPPLIED_UPDATE;
46 using syncable::IS_UNSYNCED; 38 using syncable::IS_UNSYNCED;
47 using syncable::PARENT_ID; 39 using syncable::Id;
48 using syncable::SERVER_IS_DEL; 40 using syncable::SPECIFICS;
49 using syncable::SERVER_PARENT_ID; 41 using syncable::UNIQUE_POSITION;
50 using syncable::SERVER_VERSION;
51 using syncable::SYNCER;
52 using syncable::SYNCING;
53 42
54 ProcessCommitResponseCommand::ProcessCommitResponseCommand( 43 namespace commit_util {
55 const sessions::OrderedCommitSet& commit_set, 44
56 const sync_pb::ClientToServerMessage& commit_message, 45 void AddExtensionsActivityToMessage(
57 const sync_pb::ClientToServerResponse& commit_response) 46 ExtensionsActivity* activity,
58 : commit_set_(commit_set), 47 ExtensionsActivity::Records* extensions_activity_buffer,
59 commit_message_(commit_message), 48 sync_pb::CommitMessage* message) {
60 commit_response_(commit_response) { 49 // This isn't perfect, since the set of extensions activity may not correlate
50 // exactly with the items being committed. That's OK as long as we're looking
51 // for a rough estimate of extensions activity, not an precise mapping of
52 // which commits were triggered by which extension.
53 //
54 // We will push this list of extensions activity back into the
55 // ExtensionsActivityMonitor if this commit fails. That's why we must keep a
56 // copy of these records in the session.
57 activity->GetAndClearRecords(extensions_activity_buffer);
58
59 const ExtensionsActivity::Records& records = *extensions_activity_buffer;
60 for (ExtensionsActivity::Records::const_iterator it =
61 records.begin();
62 it != records.end(); ++it) {
63 sync_pb::ChromiumExtensionsActivity* activity_message =
64 message->add_extensions_activity();
65 activity_message->set_extension_id(it->second.extension_id);
66 activity_message->set_bookmark_writes_since_last_commit(
67 it->second.bookmark_write_count);
68 }
61 } 69 }
62 70
63 ProcessCommitResponseCommand::~ProcessCommitResponseCommand() {} 71 void AddClientConfigParamsToMessage(
72 ModelTypeSet enabled_types,
73 sync_pb::CommitMessage* message) {
74 sync_pb::ClientConfigParams* config_params = message->mutable_config_params();
75 for (ModelTypeSet::Iterator it = enabled_types.First(); it.Good(); it.Inc()) {
76 if (ProxyTypes().Has(it.Get()))
77 continue;
78 int field_number = GetSpecificsFieldNumberFromModelType(it.Get());
79 config_params->mutable_enabled_type_ids()->Add(field_number);
80 }
81 config_params->set_tabs_datatype_enabled(
82 enabled_types.Has(syncer::PROXY_TABS));
83 }
64 84
65 SyncerError ProcessCommitResponseCommand::ExecuteImpl(SyncSession* session) { 85 namespace {
66 syncable::Directory* dir = session->context()->directory(); 86 void SetEntrySpecifics(const Entry& meta_entry,
67 StatusController* status = session->mutable_status_controller(); 87 sync_pb::SyncEntity* sync_entry) {
68 const CommitResponse& cr = commit_response_.commit(); 88 // Add the new style extension and the folder bit.
69 const sync_pb::CommitMessage& commit_message = commit_message_.commit(); 89 sync_entry->mutable_specifics()->CopyFrom(meta_entry.GetSpecifics());
90 sync_entry->set_folder(meta_entry.GetIsDir());
70 91
71 int transient_error_commits = 0; 92 CHECK(!sync_entry->specifics().password().has_client_only_encrypted_data());
72 int conflicting_commits = 0; 93 DCHECK_EQ(meta_entry.GetModelType(), GetModelType(*sync_entry));
73 int error_commits = 0; 94 }
74 int successes = 0; 95 } // namespace
75 96
76 set<syncable::Id> deleted_folders; 97 void BuildCommitItem(
98 const syncable::Entry& meta_entry,
99 sync_pb::SyncEntity* sync_entry) {
100 syncable::Id id = meta_entry.GetId();
101 sync_entry->set_id_string(SyncableIdToProto(id));
77 102
78 { // Scope for ModelNeutralWriteTransaction. 103 string name = meta_entry.GetNonUniqueName();
79 ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir); 104 CHECK(!name.empty()); // Make sure this isn't an update.
80 for (size_t i = 0; i < commit_set_.Size(); i++) { 105 // Note: Truncation is also performed in WriteNode::SetTitle(..). But this
81 CommitResponse::ResponseType response_type = ProcessSingleCommitResponse( 106 // call is still necessary to handle any title changes that might originate
82 &trans, 107 // elsewhere, or already be persisted in the directory.
83 cr.entryresponse(i), 108 TruncateUTF8ToByteSize(name, 255, &name);
84 commit_message.entries(i), 109 sync_entry->set_name(name);
85 commit_set_.GetCommitHandleAt(i),
86 &deleted_folders);
87 switch (response_type) {
88 case CommitResponse::INVALID_MESSAGE:
89 ++error_commits;
90 break;
91 case CommitResponse::CONFLICT:
92 ++conflicting_commits;
93 status->increment_num_server_conflicts();
94 break;
95 case CommitResponse::SUCCESS:
96 // TODO(sync): worry about sync_rate_ rate calc?
97 ++successes;
98 if (commit_set_.GetModelTypeAt(i) == BOOKMARKS)
99 status->increment_num_successful_bookmark_commits();
100 status->increment_num_successful_commits();
101 break;
102 case CommitResponse::OVER_QUOTA:
103 // We handle over quota like a retry, which is same as transient.
104 case CommitResponse::RETRY:
105 case CommitResponse::TRANSIENT_ERROR:
106 ++transient_error_commits;
107 break;
108 default:
109 LOG(FATAL) << "Bad return from ProcessSingleCommitResponse";
110 }
111 }
112 110
113 MarkDeletedChildrenSynced(dir, &trans, &deleted_folders); 111 // Set the non_unique_name. If we do, the server ignores
112 // the |name| value (using |non_unique_name| instead), and will return
113 // in the CommitResponse a unique name if one is generated.
114 // We send both because it may aid in logging.
115 sync_entry->set_non_unique_name(name);
116
117 if (!meta_entry.GetUniqueClientTag().empty()) {
118 sync_entry->set_client_defined_unique_tag(
119 meta_entry.GetUniqueClientTag());
114 } 120 }
115 121
116 int commit_count = static_cast<int>(commit_set_.Size()); 122 // Deleted items with server-unknown parent ids can be a problem so we set
117 if (commit_count == successes) { 123 // the parent to 0. (TODO(sync): Still true in protocol?).
118 return SYNCER_OK; 124 Id new_parent_id;
119 } else if (error_commits > 0) { 125 if (meta_entry.GetIsDel() &&
120 return SERVER_RETURN_UNKNOWN_ERROR; 126 !meta_entry.GetParentId().ServerKnows()) {
121 } else if (transient_error_commits > 0) { 127 new_parent_id = syncable::BaseTransaction::root_id();
122 return SERVER_RETURN_TRANSIENT_ERROR;
123 } else if (conflicting_commits > 0) {
124 // This means that the server already has an item with this version, but
125 // we haven't seen that update yet.
126 //
127 // A well-behaved client should respond to this by proceeding to the
128 // download updates phase, fetching the conflicting items, then attempting
129 // to resolve the conflict. That's not what this client does.
130 //
131 // We don't currently have any code to support that exceptional control
132 // flow. Instead, we abort the current sync cycle and start a new one. The
133 // end result is the same.
134 return SERVER_RETURN_CONFLICT;
135 } else { 128 } else {
136 LOG(FATAL) << "Inconsistent counts when processing commit response"; 129 new_parent_id = meta_entry.GetParentId();
137 return SYNCER_OK; 130 }
131 sync_entry->set_parent_id_string(SyncableIdToProto(new_parent_id));
132
133 // If our parent has changed, send up the old one so the server
134 // can correctly deal with multiple parents.
135 // TODO(nick): With the server keeping track of the primary sync parent,
136 // it should not be necessary to provide the old_parent_id: the version
137 // number should suffice.
138 if (new_parent_id != meta_entry.GetServerParentId() &&
139 0 != meta_entry.GetBaseVersion() &&
140 syncable::CHANGES_VERSION != meta_entry.GetBaseVersion()) {
141 sync_entry->set_old_parent_id(
142 SyncableIdToProto(meta_entry.GetServerParentId()));
143 }
144
145 int64 version = meta_entry.GetBaseVersion();
146 if (syncable::CHANGES_VERSION == version || 0 == version) {
147 // Undeletions are only supported for items that have a client tag.
148 DCHECK(!id.ServerKnows() ||
149 !meta_entry.GetUniqueClientTag().empty())
150 << meta_entry;
151
152 // Version 0 means to create or undelete an object.
153 sync_entry->set_version(0);
154 } else {
155 DCHECK(id.ServerKnows()) << meta_entry;
156 sync_entry->set_version(meta_entry.GetBaseVersion());
157 }
158 sync_entry->set_ctime(TimeToProtoTime(meta_entry.GetCtime()));
159 sync_entry->set_mtime(TimeToProtoTime(meta_entry.GetMtime()));
160
161 // Deletion is final on the server, let's move things and then delete them.
162 if (meta_entry.GetIsDel()) {
163 sync_entry->set_deleted(true);
164 } else {
165 if (meta_entry.GetSpecifics().has_bookmark()) {
166 // Both insert_after_item_id and position_in_parent fields are set only
167 // for legacy reasons. See comments in sync.proto for more information.
168 const Id& prev_id = meta_entry.GetPredecessorId();
169 string prev_id_string =
170 prev_id.IsRoot() ? string() : prev_id.GetServerId();
171 sync_entry->set_insert_after_item_id(prev_id_string);
172 sync_entry->set_position_in_parent(
173 meta_entry.GetUniquePosition().ToInt64());
174 meta_entry.GetUniquePosition().ToProto(
175 sync_entry->mutable_unique_position());
176 }
177 SetEntrySpecifics(meta_entry, sync_entry);
138 } 178 }
139 } 179 }
140 180
181
182 // Helpers for ProcessSingleCommitResponse.
183 namespace {
184
141 void LogServerError(const sync_pb::CommitResponse_EntryResponse& res) { 185 void LogServerError(const sync_pb::CommitResponse_EntryResponse& res) {
142 if (res.has_error_message()) 186 if (res.has_error_message())
143 LOG(WARNING) << " " << res.error_message(); 187 LOG(WARNING) << " " << res.error_message();
144 else 188 else
145 LOG(WARNING) << " No detailed error message returned from server"; 189 LOG(WARNING) << " No detailed error message returned from server";
146 } 190 }
147 191
148 CommitResponse::ResponseType 192 const string& GetResultingPostCommitName(
149 ProcessCommitResponseCommand::ProcessSingleCommitResponse(
150 syncable::ModelNeutralWriteTransaction* trans,
151 const sync_pb::CommitResponse_EntryResponse& server_entry,
152 const sync_pb::SyncEntity& commit_request_entry,
153 const int64 metahandle,
154 set<syncable::Id>* deleted_folders) {
155 ModelNeutralMutableEntry local_entry(trans, GET_BY_HANDLE, metahandle);
156 CHECK(local_entry.good());
157 bool syncing_was_set = local_entry.GetSyncing();
158 local_entry.PutSyncing(false);
159
160 CommitResponse::ResponseType response = (CommitResponse::ResponseType)
161 server_entry.response_type();
162 if (!CommitResponse::ResponseType_IsValid(response)) {
163 LOG(ERROR) << "Commit response has unknown response type! Possibly out "
164 "of date client?";
165 return CommitResponse::INVALID_MESSAGE;
166 }
167 if (CommitResponse::TRANSIENT_ERROR == response) {
168 DVLOG(1) << "Transient Error Committing: " << local_entry;
169 LogServerError(server_entry);
170 return CommitResponse::TRANSIENT_ERROR;
171 }
172 if (CommitResponse::INVALID_MESSAGE == response) {
173 LOG(ERROR) << "Error Commiting: " << local_entry;
174 LogServerError(server_entry);
175 return response;
176 }
177 if (CommitResponse::CONFLICT == response) {
178 DVLOG(1) << "Conflict Committing: " << local_entry;
179 return response;
180 }
181 if (CommitResponse::RETRY == response) {
182 DVLOG(1) << "Retry Committing: " << local_entry;
183 return response;
184 }
185 if (CommitResponse::OVER_QUOTA == response) {
186 LOG(WARNING) << "Hit deprecated OVER_QUOTA Committing: " << local_entry;
187 return response;
188 }
189 if (!server_entry.has_id_string()) {
190 LOG(ERROR) << "Commit response has no id";
191 return CommitResponse::INVALID_MESSAGE;
192 }
193
194 // Implied by the IsValid call above, but here for clarity.
195 DCHECK_EQ(CommitResponse::SUCCESS, response) << response;
196 // Check to see if we've been given the ID of an existing entry. If so treat
197 // it as an error response and retry later.
198 const syncable::Id& server_entry_id =
199 SyncableIdFromProto(server_entry.id_string());
200 if (local_entry.GetId() != server_entry_id) {
201 Entry e(trans, GET_BY_ID, server_entry_id);
202 if (e.good()) {
203 LOG(ERROR)
204 << "Got duplicate id when commiting id: "
205 << local_entry.GetId()
206 << ". Treating as an error return";
207 return CommitResponse::INVALID_MESSAGE;
208 }
209 }
210
211 if (server_entry.version() == 0) {
212 LOG(WARNING) << "Server returned a zero version on a commit response.";
213 }
214
215 ProcessSuccessfulCommitResponse(commit_request_entry, server_entry,
216 local_entry.GetId(), &local_entry, syncing_was_set, deleted_folders);
217 return response;
218 }
219
220 const string& ProcessCommitResponseCommand::GetResultingPostCommitName(
221 const sync_pb::SyncEntity& committed_entry, 193 const sync_pb::SyncEntity& committed_entry,
222 const sync_pb::CommitResponse_EntryResponse& entry_response) { 194 const sync_pb::CommitResponse_EntryResponse& entry_response) {
223 const string& response_name = 195 const string& response_name =
224 SyncerProtoUtil::NameFromCommitEntryResponse(entry_response); 196 SyncerProtoUtil::NameFromCommitEntryResponse(entry_response);
225 if (!response_name.empty()) 197 if (!response_name.empty())
226 return response_name; 198 return response_name;
227 return SyncerProtoUtil::NameFromSyncEntity(committed_entry); 199 return SyncerProtoUtil::NameFromSyncEntity(committed_entry);
228 } 200 }
229 201
230 bool ProcessCommitResponseCommand::UpdateVersionAfterCommit( 202 bool UpdateVersionAfterCommit(
231 const sync_pb::SyncEntity& committed_entry, 203 const sync_pb::SyncEntity& committed_entry,
232 const sync_pb::CommitResponse_EntryResponse& entry_response, 204 const sync_pb::CommitResponse_EntryResponse& entry_response,
233 const syncable::Id& pre_commit_id, 205 const syncable::Id& pre_commit_id,
234 syncable::ModelNeutralMutableEntry* local_entry) { 206 syncable::ModelNeutralMutableEntry* local_entry) {
235 int64 old_version = local_entry->GetBaseVersion(); 207 int64 old_version = local_entry->GetBaseVersion();
236 int64 new_version = entry_response.version(); 208 int64 new_version = entry_response.version();
237 bool bad_commit_version = false; 209 bool bad_commit_version = false;
238 if (committed_entry.deleted() && 210 if (committed_entry.deleted() &&
239 !local_entry->GetUniqueClientTag().empty()) { 211 !local_entry->GetUniqueClientTag().empty()) {
240 // If the item was deleted, and it's undeletable (uses the client tag), 212 // If the item was deleted, and it's undeletable (uses the client tag),
(...skipping 16 matching lines...) Expand all
257 // Update the base version and server version. The base version must change 229 // Update the base version and server version. The base version must change
258 // here, even if syncing_was_set is false; that's because local changes were 230 // here, even if syncing_was_set is false; that's because local changes were
259 // on top of the successfully committed version. 231 // on top of the successfully committed version.
260 local_entry->PutBaseVersion(new_version); 232 local_entry->PutBaseVersion(new_version);
261 DVLOG(1) << "Commit is changing base version of " << local_entry->GetId() 233 DVLOG(1) << "Commit is changing base version of " << local_entry->GetId()
262 << " to: " << new_version; 234 << " to: " << new_version;
263 local_entry->PutServerVersion(new_version); 235 local_entry->PutServerVersion(new_version);
264 return true; 236 return true;
265 } 237 }
266 238
267 bool ProcessCommitResponseCommand::ChangeIdAfterCommit( 239 bool ChangeIdAfterCommit(
268 const sync_pb::CommitResponse_EntryResponse& entry_response, 240 const sync_pb::CommitResponse_EntryResponse& entry_response,
269 const syncable::Id& pre_commit_id, 241 const syncable::Id& pre_commit_id,
270 syncable::ModelNeutralMutableEntry* local_entry) { 242 syncable::ModelNeutralMutableEntry* local_entry) {
271 syncable::BaseWriteTransaction* trans = local_entry->base_write_transaction(); 243 syncable::BaseWriteTransaction* trans = local_entry->base_write_transaction();
272 const syncable::Id& entry_response_id = 244 const syncable::Id& entry_response_id =
273 SyncableIdFromProto(entry_response.id_string()); 245 SyncableIdFromProto(entry_response.id_string());
274 if (entry_response_id != pre_commit_id) { 246 if (entry_response_id != pre_commit_id) {
275 if (pre_commit_id.ServerKnows()) { 247 if (pre_commit_id.ServerKnows()) {
276 // The server can sometimes generate a new ID on commit; for example, 248 // The server can sometimes generate a new ID on commit; for example,
277 // when committing an undeletion. 249 // when committing an undeletion.
278 DVLOG(1) << " ID changed while committing an old entry. " 250 DVLOG(1) << " ID changed while committing an old entry. "
279 << pre_commit_id << " became " << entry_response_id << "."; 251 << pre_commit_id << " became " << entry_response_id << ".";
280 } 252 }
281 ModelNeutralMutableEntry same_id(trans, GET_BY_ID, entry_response_id); 253 syncable::ModelNeutralMutableEntry same_id(
254 trans,
255 syncable::GET_BY_ID,
256 entry_response_id);
282 // We should trap this before this function. 257 // We should trap this before this function.
283 if (same_id.good()) { 258 if (same_id.good()) {
284 LOG(ERROR) << "ID clash with id " << entry_response_id 259 LOG(ERROR) << "ID clash with id " << entry_response_id
285 << " during commit " << same_id; 260 << " during commit " << same_id;
286 return false; 261 return false;
287 } 262 }
288 ChangeEntryIDAndUpdateChildren(trans, local_entry, entry_response_id); 263 ChangeEntryIDAndUpdateChildren(trans, local_entry, entry_response_id);
289 DVLOG(1) << "Changing ID to " << entry_response_id; 264 DVLOG(1) << "Changing ID to " << entry_response_id;
290 } 265 }
291 return true; 266 return true;
292 } 267 }
293 268
294 void ProcessCommitResponseCommand::UpdateServerFieldsAfterCommit( 269 void UpdateServerFieldsAfterCommit(
295 const sync_pb::SyncEntity& committed_entry, 270 const sync_pb::SyncEntity& committed_entry,
296 const sync_pb::CommitResponse_EntryResponse& entry_response, 271 const sync_pb::CommitResponse_EntryResponse& entry_response,
297 syncable::ModelNeutralMutableEntry* local_entry) { 272 syncable::ModelNeutralMutableEntry* local_entry) {
298 273
299 // We just committed an entry successfully, and now we want to make our view 274 // We just committed an entry successfully, and now we want to make our view
300 // of the server state consistent with the server state. We must be careful; 275 // of the server state consistent with the server state. We must be careful;
301 // |entry_response| and |committed_entry| have some identically named 276 // |entry_response| and |committed_entry| have some identically named
302 // fields. We only want to consider fields from |committed_entry| when there 277 // fields. We only want to consider fields from |committed_entry| when there
303 // is not an overriding field in the |entry_response|. We do not want to 278 // is not an overriding field in the |entry_response|. We do not want to
304 // update the server data from the local data in the entry -- it's possible 279 // update the server data from the local data in the entry -- it's possible
(...skipping 30 matching lines...) Expand all
335 GetResultingPostCommitName(committed_entry, entry_response)); 310 GetResultingPostCommitName(committed_entry, entry_response));
336 311
337 if (local_entry->GetIsUnappliedUpdate()) { 312 if (local_entry->GetIsUnappliedUpdate()) {
338 // This shouldn't happen; an unapplied update shouldn't be committed, and 313 // This shouldn't happen; an unapplied update shouldn't be committed, and
339 // if it were, the commit should have failed. But if it does happen: we've 314 // if it were, the commit should have failed. But if it does happen: we've
340 // just overwritten the update info, so clear the flag. 315 // just overwritten the update info, so clear the flag.
341 local_entry->PutIsUnappliedUpdate(false); 316 local_entry->PutIsUnappliedUpdate(false);
342 } 317 }
343 } 318 }
344 319
345 void ProcessCommitResponseCommand::ProcessSuccessfulCommitResponse( 320 void ProcessSuccessfulCommitResponse(
346 const sync_pb::SyncEntity& committed_entry, 321 const sync_pb::SyncEntity& committed_entry,
347 const sync_pb::CommitResponse_EntryResponse& entry_response, 322 const sync_pb::CommitResponse_EntryResponse& entry_response,
348 const syncable::Id& pre_commit_id, 323 const syncable::Id& pre_commit_id,
349 syncable::ModelNeutralMutableEntry* local_entry, 324 syncable::ModelNeutralMutableEntry* local_entry,
350 bool syncing_was_set, set<syncable::Id>* deleted_folders) { 325 bool syncing_was_set, set<syncable::Id>* deleted_folders) {
351 DCHECK(local_entry->GetIsUnsynced()); 326 DCHECK(local_entry->GetIsUnsynced());
352 327
353 // Update SERVER_VERSION and BASE_VERSION. 328 // Update SERVER_VERSION and BASE_VERSION.
354 if (!UpdateVersionAfterCommit(committed_entry, entry_response, pre_commit_id, 329 if (!UpdateVersionAfterCommit(committed_entry, entry_response, pre_commit_id,
355 local_entry)) { 330 local_entry)) {
(...skipping 21 matching lines...) Expand all
377 // Make a note of any deleted folders, whose children would have 352 // Make a note of any deleted folders, whose children would have
378 // been recursively deleted. 353 // been recursively deleted.
379 // TODO(nick): Here, commit_message.deleted() would be more correct than 354 // TODO(nick): Here, commit_message.deleted() would be more correct than
380 // local_entry->GetIsDel(). For example, an item could be renamed, and then 355 // local_entry->GetIsDel(). For example, an item could be renamed, and then
381 // deleted during the commit of the rename. Unit test & fix. 356 // deleted during the commit of the rename. Unit test & fix.
382 if (local_entry->GetIsDir() && local_entry->GetIsDel()) { 357 if (local_entry->GetIsDir() && local_entry->GetIsDel()) {
383 deleted_folders->insert(local_entry->GetId()); 358 deleted_folders->insert(local_entry->GetId());
384 } 359 }
385 } 360 }
386 361
362 } // namespace
363
364 sync_pb::CommitResponse::ResponseType
365 ProcessSingleCommitResponse(
366 syncable::BaseWriteTransaction* trans,
367 const sync_pb::CommitResponse_EntryResponse& server_entry,
368 const sync_pb::SyncEntity& commit_request_entry,
369 int64 metahandle,
370 set<syncable::Id>* deleted_folders) {
371 syncable::ModelNeutralMutableEntry local_entry(
372 trans,
373 syncable::GET_BY_HANDLE,
374 metahandle);
375 CHECK(local_entry.good());
376 bool syncing_was_set = local_entry.GetSyncing();
377 local_entry.PutSyncing(false);
378
379 sync_pb::CommitResponse::ResponseType response = server_entry.response_type();
380 if (!sync_pb::CommitResponse::ResponseType_IsValid(response)) {
381 LOG(ERROR) << "Commit response has unknown response type! Possibly out "
382 "of date client?";
383 return sync_pb::CommitResponse::INVALID_MESSAGE;
384 }
385 if (sync_pb::CommitResponse::TRANSIENT_ERROR == response) {
386 DVLOG(1) << "Transient Error Committing: " << local_entry;
387 LogServerError(server_entry);
388 return sync_pb::CommitResponse::TRANSIENT_ERROR;
389 }
390 if (sync_pb::CommitResponse::INVALID_MESSAGE == response) {
391 LOG(ERROR) << "Error Commiting: " << local_entry;
392 LogServerError(server_entry);
393 return response;
394 }
395 if (sync_pb::CommitResponse::CONFLICT == response) {
396 DVLOG(1) << "Conflict Committing: " << local_entry;
397 return response;
398 }
399 if (sync_pb::CommitResponse::RETRY == response) {
400 DVLOG(1) << "Retry Committing: " << local_entry;
401 return response;
402 }
403 if (sync_pb::CommitResponse::OVER_QUOTA == response) {
404 LOG(WARNING) << "Hit deprecated OVER_QUOTA Committing: " << local_entry;
405 return response;
406 }
407 if (!server_entry.has_id_string()) {
408 LOG(ERROR) << "Commit response has no id";
409 return sync_pb::CommitResponse::INVALID_MESSAGE;
410 }
411
412 // Implied by the IsValid call above, but here for clarity.
413 DCHECK_EQ(sync_pb::CommitResponse::SUCCESS, response) << response;
414 // Check to see if we've been given the ID of an existing entry. If so treat
415 // it as an error response and retry later.
416 const syncable::Id& server_entry_id =
417 SyncableIdFromProto(server_entry.id_string());
418 if (local_entry.GetId() != server_entry_id) {
419 Entry e(trans, syncable::GET_BY_ID, server_entry_id);
420 if (e.good()) {
421 LOG(ERROR)
422 << "Got duplicate id when commiting id: "
423 << local_entry.GetId()
424 << ". Treating as an error return";
425 return sync_pb::CommitResponse::INVALID_MESSAGE;
426 }
427 }
428
429 if (server_entry.version() == 0) {
430 LOG(WARNING) << "Server returned a zero version on a commit response.";
431 }
432
433 ProcessSuccessfulCommitResponse(commit_request_entry, server_entry,
434 local_entry.GetId(), &local_entry, syncing_was_set, deleted_folders);
435 return response;
436 }
437
438 } // namespace commit_util
439
387 } // namespace syncer 440 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/engine/commit_util.h ('k') | sync/engine/get_commit_ids.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698