Chromium Code Reviews| 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 |