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()); |
131 continue; | 134 DCHECK(handler_it != handler_map->end()); |
132 sync_pb::DataTypeProgressMarker* progress_marker = | 135 sync_pb::DataTypeProgressMarker* progress_marker = |
133 get_updates->add_from_progress_marker(); | 136 get_updates->add_from_progress_marker(); |
134 dir->GetDownloadProgress(it.Get(), progress_marker); | 137 handler_it->second->GetDownloadProgress(progress_marker); |
135 } | 138 } |
136 } | 139 } |
137 | 140 |
| 141 // Builds a map of ModelTypes to indices to progress markers in the given |
| 142 // |gu_response| message. The map is returned in the |index_map| parameter. |
| 143 void PartitionProgressMarkersByType( |
| 144 const sync_pb::GetUpdatesResponse& gu_response, |
| 145 ModelTypeSet request_types, |
| 146 TypeToIndexMap* index_map) { |
| 147 for (int i = 0; i < gu_response.new_progress_marker_size(); ++i) { |
| 148 int field_number = gu_response.new_progress_marker(i).data_type_id(); |
| 149 ModelType model_type = GetModelTypeFromSpecificsFieldNumber(field_number); |
| 150 if (!IsRealDataType(model_type)) { |
| 151 DLOG(WARNING) << "Unknown field number " << field_number; |
| 152 continue; |
| 153 } |
| 154 if (!request_types.Has(model_type)) { |
| 155 DLOG(WARNING) |
| 156 << "Skipping unexpected progress marker for non-enabled type " |
| 157 << ModelTypeToString(model_type); |
| 158 continue; |
| 159 } |
| 160 index_map->insert(std::make_pair(model_type, i)); |
| 161 } |
| 162 } |
| 163 |
| 164 // Examines the contents of the GetUpdates response message and forwards |
| 165 // relevant data to the UpdateHandlers for processing and persisting. |
| 166 bool ProcessUpdateResponseMessage( |
| 167 const sync_pb::GetUpdatesResponse& gu_response, |
| 168 ModelTypeSet proto_request_types, |
| 169 UpdateHandlerMap* handler_map, |
| 170 StatusController* status) { |
| 171 TypeSyncEntityMap updates_by_type; |
| 172 PartitionUpdatesByType(gu_response, proto_request_types, &updates_by_type); |
| 173 DCHECK_EQ(proto_request_types.Size(), updates_by_type.size()); |
| 174 |
| 175 TypeToIndexMap progress_index_by_type; |
| 176 PartitionProgressMarkersByType(gu_response, |
| 177 proto_request_types, |
| 178 &progress_index_by_type); |
| 179 if (proto_request_types.Size() != progress_index_by_type.size()) { |
| 180 NOTREACHED() << "Missing progress markers in GetUpdates response."; |
| 181 return false; |
| 182 } |
| 183 |
| 184 // Iterate over these maps in parallel, processing updates for each type. |
| 185 TypeToIndexMap::iterator progress_marker_iter = |
| 186 progress_index_by_type.begin(); |
| 187 TypeSyncEntityMap::iterator updates_iter = updates_by_type.begin(); |
| 188 for ( ; (progress_marker_iter != progress_index_by_type.end() |
| 189 && updates_iter != updates_by_type.end()); |
| 190 ++progress_marker_iter, ++updates_iter) { |
| 191 DCHECK_EQ(progress_marker_iter->first, updates_iter->first); |
| 192 ModelType type = progress_marker_iter->first; |
| 193 |
| 194 UpdateHandlerMap::iterator update_handler_iter = handler_map->find(type); |
| 195 |
| 196 if (update_handler_iter != handler_map->end()) { |
| 197 update_handler_iter->second->ProcessGetUpdatesResponse( |
| 198 gu_response.new_progress_marker(progress_marker_iter->second), |
| 199 updates_iter->second, |
| 200 status); |
| 201 } else { |
| 202 DLOG(WARNING) |
| 203 << "Ignoring received updates of a type we can't handle. " |
| 204 << "Type is: " << ModelTypeToString(type); |
| 205 continue; |
| 206 } |
| 207 } |
| 208 DCHECK(progress_marker_iter == progress_index_by_type.end() |
| 209 && updates_iter == updates_by_type.end()); |
| 210 |
| 211 return true; |
| 212 } |
| 213 |
138 } // namespace | 214 } // namespace |
139 | 215 |
140 void BuildNormalDownloadUpdates( | 216 void BuildNormalDownloadUpdates( |
141 SyncSession* session, | 217 SyncSession* session, |
142 bool create_mobile_bookmarks_folder, | 218 bool create_mobile_bookmarks_folder, |
143 ModelTypeSet request_types, | 219 ModelTypeSet request_types, |
144 const sessions::NudgeTracker& nudge_tracker, | 220 const sessions::NudgeTracker& nudge_tracker, |
145 sync_pb::ClientToServerMessage* client_to_server_message) { | 221 sync_pb::ClientToServerMessage* client_to_server_message) { |
146 InitDownloadUpdatesRequest( | 222 InitDownloadUpdatesRequest( |
147 session, | 223 session, |
148 create_mobile_bookmarks_folder, | 224 create_mobile_bookmarks_folder, |
149 client_to_server_message, | 225 client_to_server_message, |
150 request_types); | 226 Intersection(request_types, ProtocolTypes())); |
151 sync_pb::GetUpdatesMessage* get_updates = | 227 sync_pb::GetUpdatesMessage* get_updates = |
152 client_to_server_message->mutable_get_updates(); | 228 client_to_server_message->mutable_get_updates(); |
153 | 229 |
154 // Request updates for all requested types. | 230 // Request updates for all requested types. |
155 DVLOG(1) << "Getting updates for types " | 231 DVLOG(1) << "Getting updates for types " |
156 << ModelTypeSetToString(request_types); | 232 << ModelTypeSetToString(request_types); |
157 DCHECK(!request_types.Empty()); | 233 DCHECK(!request_types.Empty()); |
158 | 234 |
159 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. | 235 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. |
160 get_updates->mutable_caller_info()->set_source( | 236 get_updates->mutable_caller_info()->set_source( |
(...skipping 22 matching lines...) Expand all Loading... |
183 void BuildDownloadUpdatesForConfigure( | 259 void BuildDownloadUpdatesForConfigure( |
184 SyncSession* session, | 260 SyncSession* session, |
185 bool create_mobile_bookmarks_folder, | 261 bool create_mobile_bookmarks_folder, |
186 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source, | 262 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source, |
187 ModelTypeSet request_types, | 263 ModelTypeSet request_types, |
188 sync_pb::ClientToServerMessage* client_to_server_message) { | 264 sync_pb::ClientToServerMessage* client_to_server_message) { |
189 InitDownloadUpdatesRequest( | 265 InitDownloadUpdatesRequest( |
190 session, | 266 session, |
191 create_mobile_bookmarks_folder, | 267 create_mobile_bookmarks_folder, |
192 client_to_server_message, | 268 client_to_server_message, |
193 request_types); | 269 Intersection(request_types, ProtocolTypes())); |
194 sync_pb::GetUpdatesMessage* get_updates = | 270 sync_pb::GetUpdatesMessage* get_updates = |
195 client_to_server_message->mutable_get_updates(); | 271 client_to_server_message->mutable_get_updates(); |
196 | 272 |
197 // Request updates for all enabled types. | 273 // Request updates for all enabled types. |
198 DVLOG(1) << "Initial download for types " | 274 DVLOG(1) << "Initial download for types " |
199 << ModelTypeSetToString(request_types); | 275 << ModelTypeSetToString(request_types); |
200 DCHECK(!request_types.Empty()); | 276 DCHECK(!request_types.Empty()); |
201 | 277 |
202 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. | 278 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. |
203 get_updates->mutable_caller_info()->set_source(source); | 279 get_updates->mutable_caller_info()->set_source(source); |
204 | 280 |
205 // Set the new and improved version of source, too. | 281 // Set the new and improved version of source, too. |
206 sync_pb::SyncEnums::GetUpdatesOrigin origin = | 282 sync_pb::SyncEnums::GetUpdatesOrigin origin = |
207 ConvertConfigureSourceToOrigin(source); | 283 ConvertConfigureSourceToOrigin(source); |
208 get_updates->set_get_updates_origin(origin); | 284 get_updates->set_get_updates_origin(origin); |
209 } | 285 } |
210 | 286 |
211 void BuildDownloadUpdatesForPoll( | 287 void BuildDownloadUpdatesForPoll( |
212 SyncSession* session, | 288 SyncSession* session, |
213 bool create_mobile_bookmarks_folder, | 289 bool create_mobile_bookmarks_folder, |
214 ModelTypeSet request_types, | 290 ModelTypeSet request_types, |
215 sync_pb::ClientToServerMessage* client_to_server_message) { | 291 sync_pb::ClientToServerMessage* client_to_server_message) { |
216 InitDownloadUpdatesRequest( | 292 InitDownloadUpdatesRequest( |
217 session, | 293 session, |
218 create_mobile_bookmarks_folder, | 294 create_mobile_bookmarks_folder, |
219 client_to_server_message, | 295 client_to_server_message, |
220 request_types); | 296 Intersection(request_types, ProtocolTypes())); |
221 sync_pb::GetUpdatesMessage* get_updates = | 297 sync_pb::GetUpdatesMessage* get_updates = |
222 client_to_server_message->mutable_get_updates(); | 298 client_to_server_message->mutable_get_updates(); |
223 | 299 |
224 DVLOG(1) << "Polling for types " | 300 DVLOG(1) << "Polling for types " |
225 << ModelTypeSetToString(request_types); | 301 << ModelTypeSetToString(request_types); |
226 DCHECK(!request_types.Empty()); | 302 DCHECK(!request_types.Empty()); |
227 | 303 |
228 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. | 304 // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information. |
229 get_updates->mutable_caller_info()->set_source( | 305 get_updates->mutable_caller_info()->set_source( |
230 sync_pb::GetUpdatesCallerInfo::PERIODIC); | 306 sync_pb::GetUpdatesCallerInfo::PERIODIC); |
231 | 307 |
232 // Set the new and improved version of source, too. | 308 // Set the new and improved version of source, too. |
233 get_updates->set_get_updates_origin(sync_pb::SyncEnums::PERIODIC); | 309 get_updates->set_get_updates_origin(sync_pb::SyncEnums::PERIODIC); |
234 } | 310 } |
235 | 311 |
236 SyncerError ExecuteDownloadUpdates( | 312 SyncerError ExecuteDownloadUpdates( |
| 313 ModelTypeSet request_types, |
237 SyncSession* session, | 314 SyncSession* session, |
238 sync_pb::ClientToServerMessage* msg) { | 315 sync_pb::ClientToServerMessage* msg) { |
239 sync_pb::ClientToServerResponse update_response; | 316 sync_pb::ClientToServerResponse update_response; |
240 StatusController* status = session->mutable_status_controller(); | 317 StatusController* status = session->mutable_status_controller(); |
241 bool need_encryption_key = ShouldRequestEncryptionKey(session->context()); | 318 bool need_encryption_key = ShouldRequestEncryptionKey(session->context()); |
242 | 319 |
243 SyncerError result = SyncerProtoUtil::PostClientToServerMessage( | 320 SyncerError result = SyncerProtoUtil::PostClientToServerMessage( |
244 msg, | 321 msg, |
245 &update_response, | 322 &update_response, |
246 session); | 323 session); |
247 | 324 |
248 DVLOG(2) << SyncerProtoUtil::ClientToServerResponseDebugString( | 325 DVLOG(2) << SyncerProtoUtil::ClientToServerResponseDebugString( |
249 update_response); | 326 update_response); |
250 | 327 |
251 if (result != SYNCER_OK) { | 328 if (result != SYNCER_OK) { |
252 status->mutable_updates_response()->Clear(); | 329 status->mutable_updates_response()->Clear(); |
253 LOG(ERROR) << "PostClientToServerMessage() failed during GetUpdates"; | 330 LOG(ERROR) << "PostClientToServerMessage() failed during GetUpdates"; |
254 } else { | 331 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 } | 332 } |
270 | 333 |
271 ProcessUpdatesCommand process_updates; | 334 status->mutable_updates_response()->CopyFrom(update_response); |
272 process_updates.Execute(session); | |
273 | 335 |
274 StoreTimestampsCommand store_timestamps; | 336 DVLOG(1) << "GetUpdates " |
275 store_timestamps.Execute(session); | 337 << " returned " << update_response.get_updates().entries_size() |
| 338 << " updates and indicated " |
| 339 << update_response.get_updates().changes_remaining() |
| 340 << " updates left on server."; |
276 | 341 |
277 return result; | 342 if (need_encryption_key || |
| 343 update_response.get_updates().encryption_keys_size() > 0) { |
| 344 syncable::Directory* dir = session->context()->directory(); |
| 345 status->set_last_get_key_result( |
| 346 HandleGetEncryptionKeyResponse(update_response, dir)); |
| 347 } |
| 348 |
| 349 const sync_pb::GetUpdatesResponse& gu_response = |
| 350 update_response.get_updates(); |
| 351 status->increment_num_updates_downloaded_by(gu_response.entries_size()); |
| 352 DCHECK(gu_response.has_changes_remaining()); |
| 353 status->set_num_server_changes_remaining(gu_response.changes_remaining()); |
| 354 |
| 355 const ModelTypeSet proto_request_types = |
| 356 Intersection(request_types, ProtocolTypes()); |
| 357 |
| 358 if (!ProcessUpdateResponseMessage(gu_response, |
| 359 proto_request_types, |
| 360 session->context()->update_handler_map(), |
| 361 status)) { |
| 362 return SERVER_RESPONSE_VALIDATION_FAILED; |
| 363 } else { |
| 364 return result; |
| 365 } |
278 } | 366 } |
279 | 367 |
280 } // namespace syncer | 368 } // namespace syncer |
OLD | NEW |