OLD | NEW |
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/process_commit_response_command.h" |
6 | 6 |
7 #include <cstddef> | 7 #include <cstddef> |
8 #include <set> | 8 #include <set> |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
(...skipping 12 matching lines...) Expand all Loading... |
23 #include "sync/syncable/syncable_util.h" | 23 #include "sync/syncable/syncable_util.h" |
24 #include "sync/util/time.h" | 24 #include "sync/util/time.h" |
25 | 25 |
26 using std::set; | 26 using std::set; |
27 using std::string; | 27 using std::string; |
28 using std::vector; | 28 using std::vector; |
29 using sync_pb::CommitResponse; | 29 using sync_pb::CommitResponse; |
30 | 30 |
31 namespace syncer { | 31 namespace syncer { |
32 | 32 |
33 using sessions::OrderedCommitSet; | |
34 using sessions::StatusController; | 33 using sessions::StatusController; |
35 using sessions::SyncSession; | 34 using sessions::SyncSession; |
36 using syncable::ModelNeutralWriteTransaction; | 35 using syncable::ModelNeutralWriteTransaction; |
37 using syncable::ModelNeutralMutableEntry; | 36 using syncable::ModelNeutralMutableEntry; |
38 using syncable::Entry; | 37 using syncable::Entry; |
39 using syncable::BASE_VERSION; | 38 using syncable::BASE_VERSION; |
40 using syncable::GET_BY_ID; | 39 using syncable::GET_BY_ID; |
41 using syncable::GET_BY_HANDLE; | 40 using syncable::GET_BY_HANDLE; |
42 using syncable::ID; | 41 using syncable::ID; |
43 using syncable::IS_DEL; | 42 using syncable::IS_DEL; |
44 using syncable::IS_DIR; | 43 using syncable::IS_DIR; |
45 using syncable::IS_UNAPPLIED_UPDATE; | 44 using syncable::IS_UNAPPLIED_UPDATE; |
46 using syncable::IS_UNSYNCED; | 45 using syncable::IS_UNSYNCED; |
47 using syncable::PARENT_ID; | 46 using syncable::PARENT_ID; |
48 using syncable::SERVER_IS_DEL; | 47 using syncable::SERVER_IS_DEL; |
49 using syncable::SERVER_PARENT_ID; | 48 using syncable::SERVER_PARENT_ID; |
50 using syncable::SERVER_VERSION; | 49 using syncable::SERVER_VERSION; |
51 using syncable::SYNCER; | 50 using syncable::SYNCER; |
52 using syncable::SYNCING; | 51 using syncable::SYNCING; |
53 | 52 |
54 ProcessCommitResponseCommand::ProcessCommitResponseCommand( | |
55 const sessions::OrderedCommitSet& commit_set, | |
56 const sync_pb::ClientToServerMessage& commit_message, | |
57 const sync_pb::ClientToServerResponse& commit_response) | |
58 : commit_set_(commit_set), | |
59 commit_message_(commit_message), | |
60 commit_response_(commit_response) { | |
61 } | |
62 | |
63 ProcessCommitResponseCommand::~ProcessCommitResponseCommand() {} | |
64 | |
65 SyncerError ProcessCommitResponseCommand::ExecuteImpl(SyncSession* session) { | |
66 syncable::Directory* dir = session->context()->directory(); | |
67 StatusController* status = session->mutable_status_controller(); | |
68 const CommitResponse& cr = commit_response_.commit(); | |
69 const sync_pb::CommitMessage& commit_message = commit_message_.commit(); | |
70 | |
71 int transient_error_commits = 0; | |
72 int conflicting_commits = 0; | |
73 int error_commits = 0; | |
74 int successes = 0; | |
75 | |
76 set<syncable::Id> deleted_folders; | |
77 | |
78 { // Scope for ModelNeutralWriteTransaction. | |
79 ModelNeutralWriteTransaction trans(FROM_HERE, SYNCER, dir); | |
80 for (size_t i = 0; i < commit_set_.Size(); i++) { | |
81 CommitResponse::ResponseType response_type = ProcessSingleCommitResponse( | |
82 &trans, | |
83 cr.entryresponse(i), | |
84 commit_message.entries(i), | |
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 | |
113 MarkDeletedChildrenSynced(dir, &trans, &deleted_folders); | |
114 } | |
115 | |
116 int commit_count = static_cast<int>(commit_set_.Size()); | |
117 if (commit_count == successes) { | |
118 return SYNCER_OK; | |
119 } else if (error_commits > 0) { | |
120 return SERVER_RETURN_UNKNOWN_ERROR; | |
121 } else if (transient_error_commits > 0) { | |
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 { | |
136 LOG(FATAL) << "Inconsistent counts when processing commit response"; | |
137 return SYNCER_OK; | |
138 } | |
139 } | |
140 | |
141 void LogServerError(const sync_pb::CommitResponse_EntryResponse& res) { | 53 void LogServerError(const sync_pb::CommitResponse_EntryResponse& res) { |
142 if (res.has_error_message()) | 54 if (res.has_error_message()) |
143 LOG(WARNING) << " " << res.error_message(); | 55 LOG(WARNING) << " " << res.error_message(); |
144 else | 56 else |
145 LOG(WARNING) << " No detailed error message returned from server"; | 57 LOG(WARNING) << " No detailed error message returned from server"; |
146 } | 58 } |
147 | 59 |
148 CommitResponse::ResponseType | 60 CommitResponse::ResponseType |
149 ProcessCommitResponseCommand::ProcessSingleCommitResponse( | 61 ProcessCommitResponseCommand::ProcessSingleCommitResponse( |
150 syncable::ModelNeutralWriteTransaction* trans, | 62 syncable::ModelNeutralWriteTransaction* trans, |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 // been recursively deleted. | 290 // been recursively deleted. |
379 // TODO(nick): Here, commit_message.deleted() would be more correct than | 291 // TODO(nick): Here, commit_message.deleted() would be more correct than |
380 // local_entry->GetIsDel(). For example, an item could be renamed, and then | 292 // local_entry->GetIsDel(). For example, an item could be renamed, and then |
381 // deleted during the commit of the rename. Unit test & fix. | 293 // deleted during the commit of the rename. Unit test & fix. |
382 if (local_entry->GetIsDir() && local_entry->GetIsDel()) { | 294 if (local_entry->GetIsDir() && local_entry->GetIsDel()) { |
383 deleted_folders->insert(local_entry->GetId()); | 295 deleted_folders->insert(local_entry->GetId()); |
384 } | 296 } |
385 } | 297 } |
386 | 298 |
387 } // namespace syncer | 299 } // namespace syncer |
OLD | NEW |