Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: components/sync/engine_impl/loopback_server/loopback_server.cc

Issue 2887343002: wip 3 (Closed)
Patch Set: cleanup Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698