OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/test/fake_server/fake_server.h" | 5 #include "components/sync/test/fake_server/fake_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/guid.h" | 12 #include "base/guid.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/memory/ptr_util.h" | |
14 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
15 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
16 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
17 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
18 #include "base/synchronization/lock.h" | 19 #include "base/synchronization/lock.h" |
19 #include "components/sync/test/fake_server/bookmark_entity.h" | 20 #include "components/sync/test/fake_server/bookmark_entity.h" |
20 #include "components/sync/test/fake_server/permanent_entity.h" | 21 #include "components/sync/test/fake_server/permanent_entity.h" |
21 #include "components/sync/test/fake_server/tombstone_entity.h" | 22 #include "components/sync/test/fake_server/tombstone_entity.h" |
22 #include "components/sync/test/fake_server/unique_client_entity.h" | 23 #include "components/sync/test/fake_server/unique_client_entity.h" |
23 #include "net/base/net_errors.h" | 24 #include "net/base/net_errors.h" |
(...skipping 21 matching lines...) Expand all Loading... | |
45 | 46 |
46 // Properties of the other bookmarks permanent folder. | 47 // Properties of the other bookmarks permanent folder. |
47 static const char kOtherBookmarksFolderServerTag[] = "other_bookmarks"; | 48 static const char kOtherBookmarksFolderServerTag[] = "other_bookmarks"; |
48 static const char kOtherBookmarksFolderName[] = "Other Bookmarks"; | 49 static const char kOtherBookmarksFolderName[] = "Other Bookmarks"; |
49 | 50 |
50 // Properties of the synced bookmarks permanent folder. | 51 // Properties of the synced bookmarks permanent folder. |
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. | |
maxbogue
2016/12/09 21:10:15
the nit of all nits: s/,/;/
skym
2016/12/09 21:51:50
Done.
| |
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 (auto& kv : response_version_map_) { |
maxbogue
2016/12/09 21:10:15
const auto& perhaps?
skym
2016/12/09 21:51:50
Done.
| |
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 FakeServerEntity& entity) const { | 80 // side effect which will later be used to set response progress markers. |
81 bool ClientWantsItem(const FakeServerEntity& entity) { | |
87 int64_t version = entity.GetVersion(); | 82 int64_t version = entity.GetVersion(); |
88 if (version <= min_version_) { | 83 ModelType type = entity.model_type(); |
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.model_type()); | |
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 typedef std::map<ModelType, int64_t> ModelTypeToVersionMap; | 91 typedef std::map<ModelType, int64_t> ModelTypeToVersionMap; |
105 | 92 |
106 // Creates an UpdateSieve. | 93 static UpdateSieve::ModelTypeToVersionMap MessageToVersionMap( |
maxbogue
2016/12/09 21:10:15
you shouldn't need the UpdateSieve:: bit right?
skym
2016/12/09 21:51:50
Does not compile w/o it. I think it has to do with
| |
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 request_version_map[model_type] = version; |
maxbogue
2016/12/09 21:10:15
Consider adding a DCHECK above this that model_typ
skym
2016/12/09 21:51:50
Done.
| |
122 << "A GetUpdates request must have at least one progress marker."; | |
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 } | 114 } |
137 | 115 return request_version_map; |
138 ModelType model_type = | |
139 syncer::GetModelTypeFromSpecificsFieldNumber(marker.data_type_id()); | |
140 request_from_version[model_type] = version; | |
141 | |
142 if (version < min_version) | |
143 min_version = version; | |
144 } | 116 } |
145 | 117 |
146 return std::unique_ptr<UpdateSieve>( | 118 explicit UpdateSieve(const ModelTypeToVersionMap request_version_map) |
147 new UpdateSieve(request_from_version, min_version)); | 119 : request_version_map_(request_version_map), |
148 } | 120 response_version_map_(request_version_map) {} |
121 | |
122 // The largest versions the client has seen before this request, and is used | |
123 // to filter entities to send back to clients. The values in this map are not | |
124 // updated after being initially set. The presence of a type in this map is a | |
125 // proxy for the desire to receive results about this type. | |
126 const ModelTypeToVersionMap request_version_map_; | |
127 | |
128 // The largest versions seen between client and server, ultimately used to | |
129 // send progress markers back to the client. | |
130 ModelTypeToVersionMap response_version_map_; | |
131 }; | |
149 | 132 |
150 // Returns whether |entity| is deleted or permanent. | 133 // Returns whether |entity| is deleted or permanent. |
151 bool IsDeletedOrPermanent(const FakeServerEntity& entity) { | 134 bool IsDeletedOrPermanent(const FakeServerEntity& entity) { |
152 return entity.IsDeleted() || entity.IsPermanent(); | 135 return entity.IsDeleted() || entity.IsPermanent(); |
153 } | 136 } |
154 | 137 |
155 } // namespace | 138 } // namespace |
156 | 139 |
157 FakeServer::FakeServer() | 140 FakeServer::FakeServer() |
158 : version_(0), | 141 : version_(0), |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
331 return true; | 314 return true; |
332 } | 315 } |
333 | 316 |
334 bool FakeServer::HandleGetUpdatesRequest( | 317 bool FakeServer::HandleGetUpdatesRequest( |
335 const sync_pb::GetUpdatesMessage& get_updates, | 318 const sync_pb::GetUpdatesMessage& get_updates, |
336 sync_pb::GetUpdatesResponse* response) { | 319 sync_pb::GetUpdatesResponse* response) { |
337 // TODO(pvalenzuela): Implement batching instead of sending all information | 320 // TODO(pvalenzuela): Implement batching instead of sending all information |
338 // at once. | 321 // at once. |
339 response->set_changes_remaining(0); | 322 response->set_changes_remaining(0); |
340 | 323 |
341 std::unique_ptr<UpdateSieve> sieve = UpdateSieve::Create(get_updates); | 324 auto sieve = base::MakeUnique<UpdateSieve>(get_updates); |
342 | 325 |
343 // This folder is called "Synced Bookmarks" by sync and is renamed | 326 // This folder is called "Synced Bookmarks" by sync and is renamed |
344 // "Mobile Bookmarks" by the mobile client UIs. | 327 // "Mobile Bookmarks" by the mobile client UIs. |
345 if (get_updates.create_mobile_bookmarks_folder() && | 328 if (get_updates.create_mobile_bookmarks_folder() && |
346 !CreatePermanentBookmarkFolder(kSyncedBookmarksFolderServerTag, | 329 !CreatePermanentBookmarkFolder(kSyncedBookmarksFolderServerTag, |
347 kSyncedBookmarksFolderName)) { | 330 kSyncedBookmarksFolderName)) { |
348 return false; | 331 return false; |
349 } | 332 } |
350 | 333 |
351 bool send_encryption_keys_based_on_nigori = false; | 334 bool send_encryption_keys_based_on_nigori = false; |
352 int64_t max_response_version = 0; | |
353 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); | 335 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
354 ++it) { | 336 ++it) { |
355 const FakeServerEntity& entity = *it->second; | 337 const FakeServerEntity& entity = *it->second; |
356 if (sieve->ClientWantsItem(entity)) { | 338 if (sieve->ClientWantsItem(entity)) { |
357 sync_pb::SyncEntity* response_entity = response->add_entries(); | 339 sync_pb::SyncEntity* response_entity = response->add_entries(); |
358 entity.SerializeAsProto(response_entity); | 340 entity.SerializeAsProto(response_entity); |
359 | 341 |
360 max_response_version = | |
361 std::max(max_response_version, response_entity->version()); | |
362 | |
363 if (entity.model_type() == syncer::NIGORI) { | 342 if (entity.model_type() == syncer::NIGORI) { |
364 send_encryption_keys_based_on_nigori = | 343 send_encryption_keys_based_on_nigori = |
365 response_entity->specifics().nigori().passphrase_type() == | 344 response_entity->specifics().nigori().passphrase_type() == |
366 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE; | 345 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE; |
367 } | 346 } |
368 } | 347 } |
369 } | 348 } |
370 | 349 |
371 if (send_encryption_keys_based_on_nigori || | 350 if (send_encryption_keys_based_on_nigori || |
372 get_updates.need_encryption_key()) { | 351 get_updates.need_encryption_key()) { |
373 for (vector<string>::iterator it = keystore_keys_.begin(); | 352 for (vector<string>::iterator it = keystore_keys_.begin(); |
374 it != keystore_keys_.end(); ++it) { | 353 it != keystore_keys_.end(); ++it) { |
375 response->add_encryption_keys(*it); | 354 response->add_encryption_keys(*it); |
376 } | 355 } |
377 } | 356 } |
378 | 357 |
379 sieve->UpdateProgressMarkers(max_response_version, response); | 358 sieve->SetProgressMarkers(response); |
380 return true; | 359 return true; |
381 } | 360 } |
382 | 361 |
383 string FakeServer::CommitEntity( | 362 string FakeServer::CommitEntity( |
384 const sync_pb::SyncEntity& client_entity, | 363 const sync_pb::SyncEntity& client_entity, |
385 sync_pb::CommitResponse_EntryResponse* entry_response, | 364 sync_pb::CommitResponse_EntryResponse* entry_response, |
386 const string& client_guid, | 365 const string& client_guid, |
387 const string& parent_id) { | 366 const string& parent_id) { |
388 if (client_entity.version() == 0 && client_entity.deleted()) { | 367 if (client_entity.version() == 0 && client_entity.deleted()) { |
389 return string(); | 368 return string(); |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
720 DCHECK(thread_checker_.CalledOnValidThread()); | 699 DCHECK(thread_checker_.CalledOnValidThread()); |
721 return weak_ptr_factory_.GetWeakPtr(); | 700 return weak_ptr_factory_.GetWeakPtr(); |
722 } | 701 } |
723 | 702 |
724 std::string FakeServer::GetStoreBirthday() const { | 703 std::string FakeServer::GetStoreBirthday() const { |
725 DCHECK(thread_checker_.CalledOnValidThread()); | 704 DCHECK(thread_checker_.CalledOnValidThread()); |
726 return base::Int64ToString(store_birthday_); | 705 return base::Int64ToString(store_birthday_); |
727 } | 706 } |
728 | 707 |
729 } // namespace fake_server | 708 } // namespace fake_server |
OLD | NEW |