| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "components/sync/engine_impl/loopback_server/loopback_server.h" | 5 #include "components/sync/engine_impl/loopback_server/loopback_server.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
| 13 #include "base/guid.h" | 13 #include "base/guid.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/memory/ptr_util.h" |
| 15 #include "base/metrics/histogram_macros.h" | 16 #include "base/metrics/histogram_macros.h" |
| 16 #include "base/rand_util.h" | 17 #include "base/rand_util.h" |
| 17 #include "base/stl_util.h" | 18 #include "base/stl_util.h" |
| 18 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
| 19 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
| 20 #include "base/strings/stringprintf.h" | 21 #include "base/strings/stringprintf.h" |
| 21 #include "base/synchronization/lock.h" | 22 #include "base/synchronization/lock.h" |
| 22 #include "components/sync/engine_impl/loopback_server/persistent_bookmark_entity
.h" | 23 #include "components/sync/engine_impl/loopback_server/persistent_bookmark_entity
.h" |
| 23 #include "components/sync/engine_impl/loopback_server/persistent_permanent_entit
y.h" | 24 #include "components/sync/engine_impl/loopback_server/persistent_permanent_entit
y.h" |
| 24 #include "components/sync/engine_impl/loopback_server/persistent_tombstone_entit
y.h" | 25 #include "components/sync/engine_impl/loopback_server/persistent_tombstone_entit
y.h" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 45 | 46 |
| 46 // Properties of the bookmark bar permanent folders. | 47 // Properties of the bookmark bar permanent folders. |
| 47 static const char kBookmarkBarFolderServerTag[] = "bookmark_bar"; | 48 static const char kBookmarkBarFolderServerTag[] = "bookmark_bar"; |
| 48 static const char kBookmarkBarFolderName[] = "Bookmark Bar"; | 49 static const char kBookmarkBarFolderName[] = "Bookmark Bar"; |
| 49 static const char kOtherBookmarksFolderServerTag[] = "other_bookmarks"; | 50 static const char kOtherBookmarksFolderServerTag[] = "other_bookmarks"; |
| 50 static const char kOtherBookmarksFolderName[] = "Other Bookmarks"; | 51 static const char kOtherBookmarksFolderName[] = "Other Bookmarks"; |
| 51 static const char kSyncedBookmarksFolderServerTag[] = "synced_bookmarks"; | 52 static const char kSyncedBookmarksFolderServerTag[] = "synced_bookmarks"; |
| 52 static const char kSyncedBookmarksFolderName[] = "Synced Bookmarks"; | 53 static const char kSyncedBookmarksFolderName[] = "Synced Bookmarks"; |
| 53 | 54 |
| 54 // A filter used during GetUpdates calls to determine what information to | 55 // A filter used during GetUpdates calls to determine what information to |
| 55 // send back to the client. There is a 1:1 correspondence between any given | 56 // send back to the client; filtering out old entities and tracking versions to |
| 56 // GetUpdates call and an UpdateSieve instance. | 57 // use in response progress markers. Note that only the GetUpdatesMessage's |
| 58 // from_progress_marker is used to determine this; legacy fields are ignored. |
| 57 class UpdateSieve { | 59 class UpdateSieve { |
| 58 public: | 60 public: |
| 61 explicit UpdateSieve(const sync_pb::GetUpdatesMessage& message) |
| 62 : UpdateSieve(MessageToVersionMap(message)) {} |
| 59 ~UpdateSieve() {} | 63 ~UpdateSieve() {} |
| 60 | 64 |
| 61 // Factory method for creating an UpdateSieve. | 65 // Sets the progress markers in |get_updates_response| based on the highest |
| 62 static std::unique_ptr<UpdateSieve> Create( | 66 // version between request progress markers and response entities. |
| 63 const sync_pb::GetUpdatesMessage& get_updates_message); | 67 void SetProgressMarkers( |
| 64 | |
| 65 // Sets the progress markers in |get_updates_response| given the progress | |
| 66 // markers from the original GetUpdatesMessage and |new_version| (the latest | |
| 67 // version in the entries sent back). | |
| 68 void UpdateProgressMarkers( | |
| 69 int64_t new_version, | |
| 70 sync_pb::GetUpdatesResponse* get_updates_response) const { | 68 sync_pb::GetUpdatesResponse* get_updates_response) const { |
| 71 ModelTypeToVersionMap::const_iterator it; | 69 for (const auto& kv : response_version_map_) { |
| 72 for (it = request_from_version_.begin(); it != request_from_version_.end(); | |
| 73 ++it) { | |
| 74 sync_pb::DataTypeProgressMarker* new_marker = | 70 sync_pb::DataTypeProgressMarker* new_marker = |
| 75 get_updates_response->add_new_progress_marker(); | 71 get_updates_response->add_new_progress_marker(); |
| 76 new_marker->set_data_type_id( | 72 new_marker->set_data_type_id( |
| 77 GetSpecificsFieldNumberFromModelType(it->first)); | 73 GetSpecificsFieldNumberFromModelType(kv.first)); |
| 78 | 74 new_marker->set_token(base::Int64ToString(kv.second)); |
| 79 int64_t version = std::max(new_version, it->second); | |
| 80 new_marker->set_token(base::Int64ToString(version)); | |
| 81 } | 75 } |
| 82 } | 76 } |
| 83 | 77 |
| 84 // Determines whether the server should send an |entity| to the client as | 78 // Determines whether the server should send an |entity| to the client as |
| 85 // part of a GetUpdatesResponse. | 79 // part of a GetUpdatesResponse. Update internal tracking of max versions as a |
| 86 bool ClientWantsItem(const LoopbackServerEntity& entity) const { | 80 // side effect which will later be used to set response progress markers. |
| 81 bool ClientWantsItem(const LoopbackServerEntity& entity) { |
| 87 int64_t version = entity.GetVersion(); | 82 int64_t version = entity.GetVersion(); |
| 88 if (version <= min_version_) { | 83 ModelType type = entity.GetModelType(); |
| 89 return false; | 84 response_version_map_[type] = |
| 90 } else if (entity.IsDeleted()) { | 85 std::max(response_version_map_[type], version); |
| 91 return true; | 86 auto it = request_version_map_.find(type); |
| 92 } | 87 return it == request_version_map_.end() ? false : it->second < version; |
| 93 | |
| 94 ModelTypeToVersionMap::const_iterator it = | |
| 95 request_from_version_.find(entity.GetModelType()); | |
| 96 | |
| 97 return it == request_from_version_.end() ? false : it->second < version; | |
| 98 } | 88 } |
| 99 | 89 |
| 100 // Returns the minimum version seen across all types. | |
| 101 int64_t GetMinVersion() const { return min_version_; } | |
| 102 | |
| 103 private: | 90 private: |
| 104 using ModelTypeToVersionMap = std::map<ModelType, int64_t>; | 91 using ModelTypeToVersionMap = std::map<ModelType, int64_t>; |
| 105 | 92 |
| 106 // Creates an UpdateSieve. | 93 static UpdateSieve::ModelTypeToVersionMap MessageToVersionMap( |
| 107 UpdateSieve(const ModelTypeToVersionMap request_from_version, | 94 const sync_pb::GetUpdatesMessage& get_updates_message) { |
| 108 const int64_t min_version) | 95 CHECK_GT(get_updates_message.from_progress_marker_size(), 0) |
| 109 : request_from_version_(request_from_version), | 96 << "A GetUpdates request must have at least one progress marker."; |
| 110 min_version_(min_version) {} | 97 ModelTypeToVersionMap request_version_map; |
| 111 | 98 |
| 112 // Maps data type IDs to the latest version seen for that type. | 99 for (int i = 0; i < get_updates_message.from_progress_marker_size(); i++) { |
| 113 const ModelTypeToVersionMap request_from_version_; | 100 sync_pb::DataTypeProgressMarker marker = |
| 101 get_updates_message.from_progress_marker(i); |
| 114 | 102 |
| 115 // The minimum version seen among all data types. | 103 int64_t version = 0; |
| 116 const int min_version_; | 104 // Let the version remain zero if there is no token or an empty token (the |
| 117 }; | 105 // first request for this type). |
| 106 if (marker.has_token() && !marker.token().empty()) { |
| 107 bool parsed = base::StringToInt64(marker.token(), &version); |
| 108 CHECK(parsed) << "Unable to parse progress marker token."; |
| 109 } |
| 118 | 110 |
| 119 std::unique_ptr<UpdateSieve> UpdateSieve::Create( | 111 ModelType model_type = |
| 120 const sync_pb::GetUpdatesMessage& get_updates_message) { | 112 syncer::GetModelTypeFromSpecificsFieldNumber(marker.data_type_id()); |
| 121 CHECK_GT(get_updates_message.from_progress_marker_size(), 0) | 113 DCHECK(request_version_map.find(model_type) == request_version_map.end()); |
| 122 << "A GetUpdates request must have at least one progress marker."; | 114 request_version_map[model_type] = version; |
| 123 | |
| 124 UpdateSieve::ModelTypeToVersionMap request_from_version; | |
| 125 int64_t min_version = std::numeric_limits<int64_t>::max(); | |
| 126 for (int i = 0; i < get_updates_message.from_progress_marker_size(); i++) { | |
| 127 sync_pb::DataTypeProgressMarker marker = | |
| 128 get_updates_message.from_progress_marker(i); | |
| 129 | |
| 130 int64_t version = 0; | |
| 131 // Let the version remain zero if there is no token or an empty token (the | |
| 132 // first request for this type). | |
| 133 if (marker.has_token() && !marker.token().empty()) { | |
| 134 bool parsed = base::StringToInt64(marker.token(), &version); | |
| 135 CHECK(parsed) << "Unable to parse progress marker token."; | |
| 136 } | 115 } |
| 137 ModelType model_type = | 116 return request_version_map; |
| 138 syncer::GetModelTypeFromSpecificsFieldNumber(marker.data_type_id()); | |
| 139 request_from_version[model_type] = version; | |
| 140 | |
| 141 if (version < min_version) | |
| 142 min_version = version; | |
| 143 } | 117 } |
| 144 | 118 |
| 145 return std::unique_ptr<UpdateSieve>( | 119 explicit UpdateSieve(const ModelTypeToVersionMap request_version_map) |
| 146 new UpdateSieve(request_from_version, min_version)); | 120 : request_version_map_(request_version_map), |
| 147 } | 121 response_version_map_(request_version_map) {} |
| 122 |
| 123 // The largest versions the client has seen before this request, and is used |
| 124 // to filter entities to send back to clients. The values in this map are not |
| 125 // updated after being initially set. The presence of a type in this map is a |
| 126 // proxy for the desire to receive results about this type. |
| 127 const ModelTypeToVersionMap request_version_map_; |
| 128 |
| 129 // The largest versions seen between client and server, ultimately used to |
| 130 // send progress markers back to the client. |
| 131 ModelTypeToVersionMap response_version_map_; |
| 132 }; |
| 148 | 133 |
| 149 } // namespace | 134 } // namespace |
| 150 | 135 |
| 151 LoopbackServer::LoopbackServer(const base::FilePath& persistent_file) | 136 LoopbackServer::LoopbackServer(const base::FilePath& persistent_file) |
| 152 : version_(0), store_birthday_(0), persistent_file_(persistent_file) { | 137 : version_(0), |
| 138 store_birthday_(0), |
| 139 persistent_file_(persistent_file), |
| 140 observer_for_tests_(NULL) { |
| 153 Init(); | 141 Init(); |
| 154 } | 142 } |
| 155 | 143 |
| 156 LoopbackServer::~LoopbackServer() {} | 144 LoopbackServer::~LoopbackServer() {} |
| 157 | 145 |
| 158 void LoopbackServer::Init() { | 146 void LoopbackServer::Init() { |
| 159 if (LoadStateFromFile(persistent_file_)) | 147 if (LoadStateFromFile(persistent_file_)) |
| 160 return; | 148 return; |
| 161 | 149 |
| 162 keystore_keys_.push_back(GenerateNewKeystoreKey()); | 150 keystore_keys_.push_back(GenerateNewKeystoreKey()); |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 SaveStateToFile(persistent_file_); | 271 SaveStateToFile(persistent_file_); |
| 284 } | 272 } |
| 285 | 273 |
| 286 bool LoopbackServer::HandleGetUpdatesRequest( | 274 bool LoopbackServer::HandleGetUpdatesRequest( |
| 287 const sync_pb::GetUpdatesMessage& get_updates, | 275 const sync_pb::GetUpdatesMessage& get_updates, |
| 288 sync_pb::GetUpdatesResponse* response) { | 276 sync_pb::GetUpdatesResponse* response) { |
| 289 // TODO(pvalenzuela): Implement batching instead of sending all information | 277 // TODO(pvalenzuela): Implement batching instead of sending all information |
| 290 // at once. | 278 // at once. |
| 291 response->set_changes_remaining(0); | 279 response->set_changes_remaining(0); |
| 292 | 280 |
| 293 std::unique_ptr<UpdateSieve> sieve = UpdateSieve::Create(get_updates); | 281 auto sieve = base::MakeUnique<UpdateSieve>(get_updates); |
| 294 | 282 |
| 295 // This folder is called "Synced Bookmarks" by sync and is renamed | 283 // This folder is called "Synced Bookmarks" by sync and is renamed |
| 296 // "Mobile Bookmarks" by the mobile client UIs. | 284 // "Mobile Bookmarks" by the mobile client UIs. |
| 297 if (get_updates.create_mobile_bookmarks_folder() && | 285 if (get_updates.create_mobile_bookmarks_folder() && |
| 298 !CreatePermanentBookmarkFolder(kSyncedBookmarksFolderServerTag, | 286 !CreatePermanentBookmarkFolder(kSyncedBookmarksFolderServerTag, |
| 299 kSyncedBookmarksFolderName)) { | 287 kSyncedBookmarksFolderName)) { |
| 300 return false; | 288 return false; |
| 301 } | 289 } |
| 302 | 290 |
| 303 bool send_encryption_keys_based_on_nigori = false; | 291 bool send_encryption_keys_based_on_nigori = false; |
| 304 int64_t max_response_version = 0; | |
| 305 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); | 292 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
| 306 ++it) { | 293 ++it) { |
| 307 const LoopbackServerEntity& entity = *it->second; | 294 const LoopbackServerEntity& entity = *it->second; |
| 308 if (sieve->ClientWantsItem(entity)) { | 295 if (sieve->ClientWantsItem(entity)) { |
| 309 sync_pb::SyncEntity* response_entity = response->add_entries(); | 296 sync_pb::SyncEntity* response_entity = response->add_entries(); |
| 310 entity.SerializeAsProto(response_entity); | 297 entity.SerializeAsProto(response_entity); |
| 311 | 298 |
| 312 max_response_version = | |
| 313 std::max(max_response_version, response_entity->version()); | |
| 314 | |
| 315 if (entity.GetModelType() == syncer::NIGORI) { | 299 if (entity.GetModelType() == syncer::NIGORI) { |
| 316 send_encryption_keys_based_on_nigori = | 300 send_encryption_keys_based_on_nigori = |
| 317 response_entity->specifics().nigori().passphrase_type() == | 301 response_entity->specifics().nigori().passphrase_type() == |
| 318 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE; | 302 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE; |
| 319 } | 303 } |
| 320 } | 304 } |
| 321 } | 305 } |
| 322 | 306 |
| 323 if (send_encryption_keys_based_on_nigori || | 307 if (send_encryption_keys_based_on_nigori || |
| 324 get_updates.need_encryption_key()) { | 308 get_updates.need_encryption_key()) { |
| 325 for (vector<string>::iterator it = keystore_keys_.begin(); | 309 for (vector<string>::iterator it = keystore_keys_.begin(); |
| 326 it != keystore_keys_.end(); ++it) { | 310 it != keystore_keys_.end(); ++it) { |
| 327 response->add_encryption_keys(*it); | 311 response->add_encryption_keys(*it); |
| 328 } | 312 } |
| 329 } | 313 } |
| 330 | 314 |
| 331 sieve->UpdateProgressMarkers(max_response_version, response); | 315 sieve->SetProgressMarkers(response); |
| 332 return true; | 316 return true; |
| 333 } | 317 } |
| 334 | 318 |
| 335 string LoopbackServer::CommitEntity( | 319 string LoopbackServer::CommitEntity( |
| 336 const sync_pb::SyncEntity& client_entity, | 320 const sync_pb::SyncEntity& client_entity, |
| 337 sync_pb::CommitResponse_EntryResponse* entry_response, | 321 sync_pb::CommitResponse_EntryResponse* entry_response, |
| 338 const string& client_guid, | 322 const string& client_guid, |
| 339 const string& parent_id) { | 323 const string& parent_id) { |
| 340 if (client_entity.version() == 0 && client_entity.deleted()) { | 324 if (client_entity.version() == 0 && client_entity.deleted()) { |
| 341 return string(); | 325 return string(); |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 // Record the ID if it was renamed. | 442 // Record the ID if it was renamed. |
| 459 if (entity_id != client_entity.id_string()) { | 443 if (entity_id != client_entity.id_string()) { |
| 460 client_to_server_ids[client_entity.id_string()] = entity_id; | 444 client_to_server_ids[client_entity.id_string()] = entity_id; |
| 461 } | 445 } |
| 462 | 446 |
| 463 EntityMap::const_iterator iter = entities_.find(entity_id); | 447 EntityMap::const_iterator iter = entities_.find(entity_id); |
| 464 CHECK(iter != entities_.end()); | 448 CHECK(iter != entities_.end()); |
| 465 committed_model_types.Put(iter->second->GetModelType()); | 449 committed_model_types.Put(iter->second->GetModelType()); |
| 466 } | 450 } |
| 467 | 451 |
| 452 if (observer_for_tests_) |
| 453 observer_for_tests_->OnCommit(invalidator_client_id, committed_model_types); |
| 454 |
| 468 return true; | 455 return true; |
| 469 } | 456 } |
| 470 | 457 |
| 471 void LoopbackServer::ClearServerData() { | 458 void LoopbackServer::ClearServerData() { |
| 472 DCHECK(thread_checker_.CalledOnValidThread()); | 459 DCHECK(thread_checker_.CalledOnValidThread()); |
| 473 entities_.clear(); | 460 entities_.clear(); |
| 474 keystore_keys_.clear(); | 461 keystore_keys_.clear(); |
| 475 ++store_birthday_; | 462 ++store_birthday_; |
| 463 base::DeleteFile(persistent_file_, false); |
| 476 Init(); | 464 Init(); |
| 477 } | 465 } |
| 478 | 466 |
| 479 std::string LoopbackServer::GetStoreBirthday() const { | 467 std::string LoopbackServer::GetStoreBirthday() const { |
| 480 DCHECK(thread_checker_.CalledOnValidThread()); | 468 DCHECK(thread_checker_.CalledOnValidThread()); |
| 481 return base::Int64ToString(store_birthday_); | 469 return base::Int64ToString(store_birthday_); |
| 482 } | 470 } |
| 483 | 471 |
| 472 std::vector<sync_pb::SyncEntity> LoopbackServer::GetSyncEntitiesByModelType( |
| 473 ModelType model_type) { |
| 474 DCHECK(thread_checker_.CalledOnValidThread()); |
| 475 std::vector<sync_pb::SyncEntity> sync_entities; |
| 476 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
| 477 ++it) { |
| 478 const LoopbackServerEntity& entity = *it->second; |
| 479 if (!(entity.IsDeleted() || entity.IsPermanent()) && |
| 480 entity.GetModelType() == model_type) { |
| 481 sync_pb::SyncEntity sync_entity; |
| 482 entity.SerializeAsProto(&sync_entity); |
| 483 sync_entities.push_back(sync_entity); |
| 484 } |
| 485 } |
| 486 return sync_entities; |
| 487 } |
| 488 |
| 489 std::unique_ptr<base::DictionaryValue> |
| 490 LoopbackServer::GetEntitiesAsDictionaryValue() { |
| 491 DCHECK(thread_checker_.CalledOnValidThread()); |
| 492 std::unique_ptr<base::DictionaryValue> dictionary( |
| 493 new base::DictionaryValue()); |
| 494 |
| 495 // Initialize an empty ListValue for all ModelTypes. |
| 496 ModelTypeSet all_types = ModelTypeSet::All(); |
| 497 for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) { |
| 498 dictionary->Set(ModelTypeToString(it.Get()), new base::ListValue()); |
| 499 } |
| 500 |
| 501 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
| 502 ++it) { |
| 503 const LoopbackServerEntity& entity = *it->second; |
| 504 if (entity.IsDeleted() || entity.IsPermanent()) { |
| 505 // Tombstones are ignored as they don't represent current data. Folders |
| 506 // are also ignored as current verification infrastructure does not |
| 507 // consider them. |
| 508 continue; |
| 509 } |
| 510 base::ListValue* list_value; |
| 511 if (!dictionary->GetList(ModelTypeToString(entity.GetModelType()), |
| 512 &list_value)) { |
| 513 return std::unique_ptr<base::DictionaryValue>(); |
| 514 } |
| 515 // TODO(pvalenzuela): Store more data for each entity so additional |
| 516 // verification can be performed. One example of additional verification |
| 517 // is checking the correctness of the bookmark hierarchy. |
| 518 list_value->AppendString(entity.GetName()); |
| 519 } |
| 520 |
| 521 return dictionary; |
| 522 } |
| 523 |
| 524 bool LoopbackServer::ModifyEntitySpecifics( |
| 525 const std::string& id, |
| 526 const sync_pb::EntitySpecifics& updated_specifics) { |
| 527 EntityMap::const_iterator iter = entities_.find(id); |
| 528 if (iter == entities_.end() || |
| 529 iter->second->GetModelType() != |
| 530 GetModelTypeFromSpecifics(updated_specifics)) { |
| 531 return false; |
| 532 } |
| 533 |
| 534 LoopbackServerEntity* entity = iter->second.get(); |
| 535 entity->SetSpecifics(updated_specifics); |
| 536 UpdateEntityVersion(entity); |
| 537 return true; |
| 538 } |
| 539 |
| 484 void LoopbackServer::SerializeState(sync_pb::LoopbackServerProto* proto) const { | 540 void LoopbackServer::SerializeState(sync_pb::LoopbackServerProto* proto) const { |
| 485 DCHECK(thread_checker_.CalledOnValidThread()); | 541 DCHECK(thread_checker_.CalledOnValidThread()); |
| 486 | 542 |
| 487 proto->set_version(kCurrentLoopbackServerProtoVersion); | 543 proto->set_version(kCurrentLoopbackServerProtoVersion); |
| 488 proto->set_store_birthday(store_birthday_); | 544 proto->set_store_birthday(store_birthday_); |
| 489 proto->set_last_version_assigned(version_); | 545 proto->set_last_version_assigned(version_); |
| 490 for (const auto& key : keystore_keys_) | 546 for (const auto& key : keystore_keys_) |
| 491 proto->add_keystore_keys(key); | 547 proto->add_keystore_keys(key); |
| 492 for (const auto& entity : entities_) { | 548 for (const auto& entity : entities_) { |
| 493 auto* new_entity = proto->mutable_entities()->Add(); | 549 auto* new_entity = proto->mutable_entities()->Add(); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 547 // write. | 603 // write. |
| 548 LOG(ERROR) << "Loopback sync can not read the persistent state file."; | 604 LOG(ERROR) << "Loopback sync can not read the persistent state file."; |
| 549 return false; | 605 return false; |
| 550 } | 606 } |
| 551 } | 607 } |
| 552 LOG(WARNING) << "Loopback sync persistent state file does not exist."; | 608 LOG(WARNING) << "Loopback sync persistent state file does not exist."; |
| 553 return false; | 609 return false; |
| 554 } | 610 } |
| 555 | 611 |
| 556 } // namespace syncer | 612 } // namespace syncer |
| OLD | NEW |