OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/download.h" | 5 #include "sync/engine/download.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "sync/engine/process_updates_command.h" | 10 #include "sync/engine/process_updates_util.h" |
11 #include "sync/engine/store_timestamps_command.h" | 11 #include "sync/engine/sync_directory_update_handler.h" |
12 #include "sync/engine/syncer.h" | 12 #include "sync/engine/syncer.h" |
13 #include "sync/engine/syncer_proto_util.h" | 13 #include "sync/engine/syncer_proto_util.h" |
14 #include "sync/sessions/nudge_tracker.h" | 14 #include "sync/sessions/nudge_tracker.h" |
15 #include "sync/syncable/directory.h" | 15 #include "sync/syncable/directory.h" |
16 #include "sync/syncable/nigori_handler.h" | 16 #include "sync/syncable/nigori_handler.h" |
17 #include "sync/syncable/syncable_read_transaction.h" | 17 #include "sync/syncable/syncable_read_transaction.h" |
18 | 18 |
19 using sync_pb::DebugInfo; | 19 using sync_pb::DebugInfo; |
20 | 20 |
21 namespace syncer { | 21 namespace syncer { |
22 | 22 |
23 using sessions::StatusController; | 23 using sessions::StatusController; |
24 using sessions::SyncSession; | 24 using sessions::SyncSession; |
25 using sessions::SyncSessionContext; | 25 using sessions::SyncSessionContext; |
26 using std::string; | 26 using std::string; |
27 | 27 |
28 namespace { | 28 namespace { |
29 | 29 |
30 typedef std::map<ModelType, size_t> TypeToIndexMap; | |
31 | |
30 SyncerError HandleGetEncryptionKeyResponse( | 32 SyncerError HandleGetEncryptionKeyResponse( |
31 const sync_pb::ClientToServerResponse& update_response, | 33 const sync_pb::ClientToServerResponse& update_response, |
32 syncable::Directory* dir) { | 34 syncable::Directory* dir) { |
33 bool success = false; | 35 bool success = false; |
34 if (update_response.get_updates().encryption_keys_size() == 0) { | 36 if (update_response.get_updates().encryption_keys_size() == 0) { |
35 LOG(ERROR) << "Failed to receive encryption key from server."; | 37 LOG(ERROR) << "Failed to receive encryption key from server."; |
36 return SERVER_RESPONSE_VALIDATION_FAILED; | 38 return SERVER_RESPONSE_VALIDATION_FAILED; |
37 } | 39 } |
38 syncable::ReadTransaction trans(FROM_HERE, dir); | 40 syncable::ReadTransaction trans(FROM_HERE, dir); |
39 syncable::NigoriHandler* nigori_handler = dir->GetNigoriHandler(); | 41 syncable::NigoriHandler* nigori_handler = dir->GetNigoriHandler(); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
91 debug_info); | 93 debug_info); |
92 } | 94 } |
93 session->mutable_status_controller()->set_debug_info_sent(); | 95 session->mutable_status_controller()->set_debug_info_sent(); |
94 } | 96 } |
95 } | 97 } |
96 | 98 |
97 void InitDownloadUpdatesRequest( | 99 void InitDownloadUpdatesRequest( |
98 SyncSession* session, | 100 SyncSession* session, |
99 bool create_mobile_bookmarks_folder, | 101 bool create_mobile_bookmarks_folder, |
100 sync_pb::ClientToServerMessage* message, | 102 sync_pb::ClientToServerMessage* message, |
101 ModelTypeSet request_types) { | 103 ModelTypeSet proto_request_types) { |
102 message->set_share(session->context()->account_name()); | 104 message->set_share(session->context()->account_name()); |
103 message->set_message_contents(sync_pb::ClientToServerMessage::GET_UPDATES); | 105 message->set_message_contents(sync_pb::ClientToServerMessage::GET_UPDATES); |
104 | 106 |
105 sync_pb::GetUpdatesMessage* get_updates = message->mutable_get_updates(); | 107 sync_pb::GetUpdatesMessage* get_updates = message->mutable_get_updates(); |
106 | 108 |
107 // We want folders for our associated types, always. If we were to set | 109 // We want folders for our associated types, always. If we were to set |
108 // this to false, the server would send just the non-container items | 110 // this to false, the server would send just the non-container items |
109 // (e.g. Bookmark URLs but not their containing folders). | 111 // (e.g. Bookmark URLs but not their containing folders). |
110 get_updates->set_fetch_folders(true); | 112 get_updates->set_fetch_folders(true); |
111 | 113 |
112 DebugInfo* debug_info = message->mutable_debug_info(); | 114 DebugInfo* debug_info = message->mutable_debug_info(); |
113 AppendClientDebugInfoIfNeeded(session, debug_info); | 115 AppendClientDebugInfoIfNeeded(session, debug_info); |
114 | 116 |
115 get_updates->set_create_mobile_bookmarks_folder( | 117 get_updates->set_create_mobile_bookmarks_folder( |
116 create_mobile_bookmarks_folder); | 118 create_mobile_bookmarks_folder); |
117 bool need_encryption_key = ShouldRequestEncryptionKey(session->context()); | 119 bool need_encryption_key = ShouldRequestEncryptionKey(session->context()); |
118 get_updates->set_need_encryption_key(need_encryption_key); | 120 get_updates->set_need_encryption_key(need_encryption_key); |
119 | 121 |
120 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. | 122 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. |
121 get_updates->mutable_caller_info()->set_notifications_enabled( | 123 get_updates->mutable_caller_info()->set_notifications_enabled( |
122 session->context()->notifications_enabled()); | 124 session->context()->notifications_enabled()); |
123 | 125 |
124 StatusController* status = session->mutable_status_controller(); | 126 StatusController* status = session->mutable_status_controller(); |
125 status->set_updates_request_types(request_types); | 127 status->set_updates_request_types(proto_request_types); |
126 | 128 |
127 syncable::Directory* dir = session->context()->directory(); | 129 UpdateHandlerMap* handler_map = session->context()->update_handler_map(); |
128 for (ModelTypeSet::Iterator it = request_types.First(); | 130 |
131 for (ModelTypeSet::Iterator it = proto_request_types.First(); | |
129 it.Good(); it.Inc()) { | 132 it.Good(); it.Inc()) { |
130 if (ProxyTypes().Has(it.Get())) | 133 UpdateHandlerMap::iterator handler_it = handler_map->find(it.Get()); |
Nicolas Zea
2013/10/29 22:50:18
DCHECK that handler_it != handler_map->end()?
rlarocque
2013/10/30 00:32:22
Done.
| |
131 continue; | |
132 sync_pb::DataTypeProgressMarker* progress_marker = | 134 sync_pb::DataTypeProgressMarker* progress_marker = |
133 get_updates->add_from_progress_marker(); | 135 get_updates->add_from_progress_marker(); |
134 dir->GetDownloadProgress(it.Get(), progress_marker); | 136 handler_it->second->GetDownloadProgress(progress_marker); |
135 } | 137 } |
136 } | 138 } |
137 | 139 |
140 // Builds a map of ModelTypes to indices to progress markers in the given | |
141 // |gu_response| message. The map is returned in the |index_map| parameter. | |
142 void PartitionProgressMarkersByType( | |
143 const sync_pb::GetUpdatesResponse& gu_response, | |
144 ModelTypeSet request_types, | |
145 TypeToIndexMap* index_map) { | |
146 for (int i = 0; i < gu_response.new_progress_marker_size(); ++i) { | |
147 int field_number = gu_response.new_progress_marker(i).data_type_id(); | |
148 ModelType model_type = GetModelTypeFromSpecificsFieldNumber(field_number); | |
149 if (!IsRealDataType(model_type)) { | |
150 DLOG(WARNING) << "Unknown field number " << field_number; | |
151 continue; | |
152 } | |
153 if (!request_types.Has(model_type)) { | |
154 DLOG(WARNING) | |
155 << "Skipping unexpected progress marker for non-enabled type " | |
156 << ModelTypeToString(model_type); | |
157 continue; | |
158 } | |
159 index_map->insert(std::make_pair(model_type, i)); | |
160 } | |
161 } | |
162 | |
163 // Examines the contents of the GetUpdates response message and forwards | |
164 // relevant data to the UpdateHandlers for processing and persisting. | |
165 bool ProcessUpdateResponseMessage( | |
166 const sync_pb::GetUpdatesResponse& gu_response, | |
167 ModelTypeSet proto_request_types, | |
168 UpdateHandlerMap* handler_map, | |
169 StatusController* status) { | |
170 TypeSyncEntityMap updates_by_type; | |
171 PartitionUpdatesByType(gu_response, proto_request_types, &updates_by_type); | |
172 DCHECK_EQ(proto_request_types.Size(), updates_by_type.size()); | |
173 | |
174 TypeToIndexMap progress_index_by_type; | |
175 PartitionProgressMarkersByType(gu_response, | |
176 proto_request_types, | |
177 &progress_index_by_type); | |
178 if (proto_request_types.Size() != progress_index_by_type.size()) { | |
179 NOTREACHED() << "Missing progress markers in GetUpdates response."; | |
180 return false; | |
181 } | |
182 | |
183 // Iterate over these maps in parallel, processing updates for each type. | |
184 TypeToIndexMap::iterator progress_marker_iter = | |
185 progress_index_by_type.begin(); | |
186 TypeSyncEntityMap::iterator updates_iter = updates_by_type.begin(); | |
187 for ( ; (progress_marker_iter != progress_index_by_type.end() | |
188 && updates_iter != updates_by_type.end()); | |
189 ++progress_marker_iter, ++updates_iter) { | |
190 DCHECK_EQ(progress_marker_iter->first, updates_iter->first); | |
191 ModelType type = progress_marker_iter->first; | |
192 | |
193 UpdateHandlerMap::iterator update_handler_iter = handler_map->find(type); | |
194 | |
195 if (update_handler_iter != handler_map->end()) { | |
196 update_handler_iter->second->ProcessGetUpdatesResponse( | |
197 gu_response.new_progress_marker(progress_marker_iter->second), | |
198 updates_iter->second, | |
199 status); | |
200 } else { | |
201 DLOG(WARNING) | |
202 << "Ignoring received updates of a type we can't handle. " | |
203 << "Type is: " << ModelTypeToString(type); | |
204 continue; | |
205 } | |
206 } | |
207 DCHECK(progress_marker_iter == progress_index_by_type.end() | |
208 && updates_iter == updates_by_type.end()); | |
209 | |
210 return true; | |
211 } | |
212 | |
138 } // namespace | 213 } // namespace |
139 | 214 |
140 void BuildNormalDownloadUpdates( | 215 void BuildNormalDownloadUpdates( |
141 SyncSession* session, | 216 SyncSession* session, |
142 bool create_mobile_bookmarks_folder, | 217 bool create_mobile_bookmarks_folder, |
143 ModelTypeSet request_types, | 218 ModelTypeSet request_types, |
144 const sessions::NudgeTracker& nudge_tracker, | 219 const sessions::NudgeTracker& nudge_tracker, |
145 sync_pb::ClientToServerMessage* client_to_server_message) { | 220 sync_pb::ClientToServerMessage* client_to_server_message) { |
146 InitDownloadUpdatesRequest( | 221 InitDownloadUpdatesRequest( |
147 session, | 222 session, |
148 create_mobile_bookmarks_folder, | 223 create_mobile_bookmarks_folder, |
149 client_to_server_message, | 224 client_to_server_message, |
150 request_types); | 225 Intersection(request_types, ProtocolTypes())); |
151 sync_pb::GetUpdatesMessage* get_updates = | 226 sync_pb::GetUpdatesMessage* get_updates = |
152 client_to_server_message->mutable_get_updates(); | 227 client_to_server_message->mutable_get_updates(); |
153 | 228 |
154 // Request updates for all requested types. | 229 // Request updates for all requested types. |
155 DVLOG(1) << "Getting updates for types " | 230 DVLOG(1) << "Getting updates for types " |
156 << ModelTypeSetToString(request_types); | 231 << ModelTypeSetToString(request_types); |
157 DCHECK(!request_types.Empty()); | 232 DCHECK(!request_types.Empty()); |
158 | 233 |
159 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. | 234 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. |
160 get_updates->mutable_caller_info()->set_source( | 235 get_updates->mutable_caller_info()->set_source( |
(...skipping 22 matching lines...) Expand all Loading... | |
183 void BuildDownloadUpdatesForConfigure( | 258 void BuildDownloadUpdatesForConfigure( |
184 SyncSession* session, | 259 SyncSession* session, |
185 bool create_mobile_bookmarks_folder, | 260 bool create_mobile_bookmarks_folder, |
186 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source, | 261 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source, |
187 ModelTypeSet request_types, | 262 ModelTypeSet request_types, |
188 sync_pb::ClientToServerMessage* client_to_server_message) { | 263 sync_pb::ClientToServerMessage* client_to_server_message) { |
189 InitDownloadUpdatesRequest( | 264 InitDownloadUpdatesRequest( |
190 session, | 265 session, |
191 create_mobile_bookmarks_folder, | 266 create_mobile_bookmarks_folder, |
192 client_to_server_message, | 267 client_to_server_message, |
193 request_types); | 268 Intersection(request_types, ProtocolTypes())); |
194 sync_pb::GetUpdatesMessage* get_updates = | 269 sync_pb::GetUpdatesMessage* get_updates = |
195 client_to_server_message->mutable_get_updates(); | 270 client_to_server_message->mutable_get_updates(); |
196 | 271 |
197 // Request updates for all enabled types. | 272 // Request updates for all enabled types. |
198 DVLOG(1) << "Initial download for types " | 273 DVLOG(1) << "Initial download for types " |
199 << ModelTypeSetToString(request_types); | 274 << ModelTypeSetToString(request_types); |
200 DCHECK(!request_types.Empty()); | 275 DCHECK(!request_types.Empty()); |
201 | 276 |
202 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. | 277 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. |
203 get_updates->mutable_caller_info()->set_source(source); | 278 get_updates->mutable_caller_info()->set_source(source); |
204 | 279 |
205 // Set the new and improved version of source, too. | 280 // Set the new and improved version of source, too. |
206 sync_pb::SyncEnums::GetUpdatesOrigin origin = | 281 sync_pb::SyncEnums::GetUpdatesOrigin origin = |
207 ConvertConfigureSourceToOrigin(source); | 282 ConvertConfigureSourceToOrigin(source); |
208 get_updates->set_get_updates_origin(origin); | 283 get_updates->set_get_updates_origin(origin); |
209 } | 284 } |
210 | 285 |
211 void BuildDownloadUpdatesForPoll( | 286 void BuildDownloadUpdatesForPoll( |
212 SyncSession* session, | 287 SyncSession* session, |
213 bool create_mobile_bookmarks_folder, | 288 bool create_mobile_bookmarks_folder, |
214 ModelTypeSet request_types, | 289 ModelTypeSet request_types, |
215 sync_pb::ClientToServerMessage* client_to_server_message) { | 290 sync_pb::ClientToServerMessage* client_to_server_message) { |
216 InitDownloadUpdatesRequest( | 291 InitDownloadUpdatesRequest( |
217 session, | 292 session, |
218 create_mobile_bookmarks_folder, | 293 create_mobile_bookmarks_folder, |
219 client_to_server_message, | 294 client_to_server_message, |
220 request_types); | 295 Intersection(request_types, ProtocolTypes())); |
221 sync_pb::GetUpdatesMessage* get_updates = | 296 sync_pb::GetUpdatesMessage* get_updates = |
222 client_to_server_message->mutable_get_updates(); | 297 client_to_server_message->mutable_get_updates(); |
223 | 298 |
224 DVLOG(1) << "Polling for types " | 299 DVLOG(1) << "Polling for types " |
225 << ModelTypeSetToString(request_types); | 300 << ModelTypeSetToString(request_types); |
226 DCHECK(!request_types.Empty()); | 301 DCHECK(!request_types.Empty()); |
227 | 302 |
228 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. | 303 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. |
229 get_updates->mutable_caller_info()->set_source( | 304 get_updates->mutable_caller_info()->set_source( |
230 sync_pb::GetUpdatesCallerInfo::PERIODIC); | 305 sync_pb::GetUpdatesCallerInfo::PERIODIC); |
231 | 306 |
232 // Set the new and improved version of source, too. | 307 // Set the new and improved version of source, too. |
233 get_updates->set_get_updates_origin(sync_pb::SyncEnums::PERIODIC); | 308 get_updates->set_get_updates_origin(sync_pb::SyncEnums::PERIODIC); |
234 } | 309 } |
235 | 310 |
236 SyncerError ExecuteDownloadUpdates( | 311 SyncerError ExecuteDownloadUpdates( |
312 ModelTypeSet request_types, | |
237 SyncSession* session, | 313 SyncSession* session, |
238 sync_pb::ClientToServerMessage* msg) { | 314 sync_pb::ClientToServerMessage* msg) { |
239 sync_pb::ClientToServerResponse update_response; | 315 sync_pb::ClientToServerResponse update_response; |
240 StatusController* status = session->mutable_status_controller(); | 316 StatusController* status = session->mutable_status_controller(); |
241 bool need_encryption_key = ShouldRequestEncryptionKey(session->context()); | 317 bool need_encryption_key = ShouldRequestEncryptionKey(session->context()); |
242 | 318 |
243 SyncerError result = SyncerProtoUtil::PostClientToServerMessage( | 319 SyncerError result = SyncerProtoUtil::PostClientToServerMessage( |
244 msg, | 320 msg, |
245 &update_response, | 321 &update_response, |
246 session); | 322 session); |
247 | 323 |
248 DVLOG(2) << SyncerProtoUtil::ClientToServerResponseDebugString( | 324 DVLOG(2) << SyncerProtoUtil::ClientToServerResponseDebugString( |
249 update_response); | 325 update_response); |
250 | 326 |
251 if (result != SYNCER_OK) { | 327 if (result != SYNCER_OK) { |
252 status->mutable_updates_response()->Clear(); | 328 status->mutable_updates_response()->Clear(); |
253 LOG(ERROR) << "PostClientToServerMessage() failed during GetUpdates"; | 329 LOG(ERROR) << "PostClientToServerMessage() failed during GetUpdates"; |
254 } else { | 330 return result; |
255 status->mutable_updates_response()->CopyFrom(update_response); | |
256 | |
257 DVLOG(1) << "GetUpdates " | |
258 << " returned " << update_response.get_updates().entries_size() | |
259 << " updates and indicated " | |
260 << update_response.get_updates().changes_remaining() | |
261 << " updates left on server."; | |
262 | |
263 if (need_encryption_key || | |
264 update_response.get_updates().encryption_keys_size() > 0) { | |
265 syncable::Directory* dir = session->context()->directory(); | |
266 status->set_last_get_key_result( | |
267 HandleGetEncryptionKeyResponse(update_response, dir)); | |
268 } | |
269 } | 331 } |
270 | 332 |
271 ProcessUpdatesCommand process_updates; | 333 status->mutable_updates_response()->CopyFrom(update_response); |
272 process_updates.Execute(session); | |
273 | 334 |
274 StoreTimestampsCommand store_timestamps; | 335 DVLOG(1) << "GetUpdates " |
275 store_timestamps.Execute(session); | 336 << " returned " << update_response.get_updates().entries_size() |
337 << " updates and indicated " | |
338 << update_response.get_updates().changes_remaining() | |
339 << " updates left on server."; | |
276 | 340 |
277 return result; | 341 if (need_encryption_key || |
342 update_response.get_updates().encryption_keys_size() > 0) { | |
343 syncable::Directory* dir = session->context()->directory(); | |
344 status->set_last_get_key_result( | |
345 HandleGetEncryptionKeyResponse(update_response, dir)); | |
346 } | |
347 | |
348 const sync_pb::GetUpdatesResponse& gu_response = | |
349 update_response.get_updates(); | |
350 status->increment_num_updates_downloaded_by(gu_response.entries_size()); | |
351 DCHECK(gu_response.has_changes_remaining()); | |
352 status->set_num_server_changes_remaining(gu_response.changes_remaining()); | |
353 | |
354 const ModelTypeSet proto_request_types = | |
355 Intersection(request_types, ProtocolTypes()); | |
356 | |
357 if (!ProcessUpdateResponseMessage(gu_response, | |
358 proto_request_types, | |
359 session->context()->update_handler_map(), | |
360 status)) { | |
361 return SERVER_RESPONSE_VALIDATION_FAILED; | |
362 } else { | |
363 return result; | |
364 } | |
278 } | 365 } |
279 | 366 |
280 } // namespace syncer | 367 } // namespace syncer |
OLD | NEW |