Index: components/sync/engine_impl/loopback_server/loopback_server.cc |
diff --git a/components/sync/engine_impl/loopback_server/loopback_server.cc b/components/sync/engine_impl/loopback_server/loopback_server.cc |
index 55ea0cd369c09a738f9bacd1b9797bc6cb50b821..b09b01f71942a8160a1389bb6e9ec25a69931216 100644 |
--- a/components/sync/engine_impl/loopback_server/loopback_server.cc |
+++ b/components/sync/engine_impl/loopback_server/loopback_server.cc |
@@ -12,6 +12,7 @@ |
#include "base/files/file_util.h" |
#include "base/guid.h" |
#include "base/logging.h" |
+#include "base/memory/ptr_util.h" |
#include "base/metrics/histogram_macros.h" |
#include "base/rand_util.h" |
#include "base/stl_util.h" |
@@ -52,104 +53,91 @@ static const char kSyncedBookmarksFolderServerTag[] = "synced_bookmarks"; |
static const char kSyncedBookmarksFolderName[] = "Synced Bookmarks"; |
// A filter used during GetUpdates calls to determine what information to |
-// send back to the client. There is a 1:1 correspondence between any given |
-// GetUpdates call and an UpdateSieve instance. |
+// send back to the client; filtering out old entities and tracking versions to |
+// use in response progress markers. Note that only the GetUpdatesMessage's |
+// from_progress_marker is used to determine this; legacy fields are ignored. |
class UpdateSieve { |
public: |
+ explicit UpdateSieve(const sync_pb::GetUpdatesMessage& message) |
+ : UpdateSieve(MessageToVersionMap(message)) {} |
~UpdateSieve() {} |
- // Factory method for creating an UpdateSieve. |
- static std::unique_ptr<UpdateSieve> Create( |
- const sync_pb::GetUpdatesMessage& get_updates_message); |
- |
- // Sets the progress markers in |get_updates_response| given the progress |
- // markers from the original GetUpdatesMessage and |new_version| (the latest |
- // version in the entries sent back). |
- void UpdateProgressMarkers( |
- int64_t new_version, |
+ // Sets the progress markers in |get_updates_response| based on the highest |
+ // version between request progress markers and response entities. |
+ void SetProgressMarkers( |
sync_pb::GetUpdatesResponse* get_updates_response) const { |
- ModelTypeToVersionMap::const_iterator it; |
- for (it = request_from_version_.begin(); it != request_from_version_.end(); |
- ++it) { |
+ for (const auto& kv : response_version_map_) { |
sync_pb::DataTypeProgressMarker* new_marker = |
get_updates_response->add_new_progress_marker(); |
new_marker->set_data_type_id( |
- GetSpecificsFieldNumberFromModelType(it->first)); |
- |
- int64_t version = std::max(new_version, it->second); |
- new_marker->set_token(base::Int64ToString(version)); |
+ GetSpecificsFieldNumberFromModelType(kv.first)); |
+ new_marker->set_token(base::Int64ToString(kv.second)); |
} |
} |
// Determines whether the server should send an |entity| to the client as |
- // part of a GetUpdatesResponse. |
- bool ClientWantsItem(const LoopbackServerEntity& entity) const { |
+ // part of a GetUpdatesResponse. Update internal tracking of max versions as a |
+ // side effect which will later be used to set response progress markers. |
+ bool ClientWantsItem(const LoopbackServerEntity& entity) { |
int64_t version = entity.GetVersion(); |
- if (version <= min_version_) { |
- return false; |
- } else if (entity.IsDeleted()) { |
- return true; |
- } |
- |
- ModelTypeToVersionMap::const_iterator it = |
- request_from_version_.find(entity.GetModelType()); |
- |
- return it == request_from_version_.end() ? false : it->second < version; |
+ ModelType type = entity.GetModelType(); |
+ response_version_map_[type] = |
+ std::max(response_version_map_[type], version); |
+ auto it = request_version_map_.find(type); |
+ return it == request_version_map_.end() ? false : it->second < version; |
} |
- // Returns the minimum version seen across all types. |
- int64_t GetMinVersion() const { return min_version_; } |
- |
private: |
using ModelTypeToVersionMap = std::map<ModelType, int64_t>; |
- // Creates an UpdateSieve. |
- UpdateSieve(const ModelTypeToVersionMap request_from_version, |
- const int64_t min_version) |
- : request_from_version_(request_from_version), |
- min_version_(min_version) {} |
- |
- // Maps data type IDs to the latest version seen for that type. |
- const ModelTypeToVersionMap request_from_version_; |
- |
- // The minimum version seen among all data types. |
- const int min_version_; |
-}; |
+ static UpdateSieve::ModelTypeToVersionMap MessageToVersionMap( |
+ const sync_pb::GetUpdatesMessage& get_updates_message) { |
+ CHECK_GT(get_updates_message.from_progress_marker_size(), 0) |
+ << "A GetUpdates request must have at least one progress marker."; |
+ ModelTypeToVersionMap request_version_map; |
+ |
+ for (int i = 0; i < get_updates_message.from_progress_marker_size(); i++) { |
+ sync_pb::DataTypeProgressMarker marker = |
+ get_updates_message.from_progress_marker(i); |
+ |
+ int64_t version = 0; |
+ // Let the version remain zero if there is no token or an empty token (the |
+ // first request for this type). |
+ if (marker.has_token() && !marker.token().empty()) { |
+ bool parsed = base::StringToInt64(marker.token(), &version); |
+ CHECK(parsed) << "Unable to parse progress marker token."; |
+ } |
-std::unique_ptr<UpdateSieve> UpdateSieve::Create( |
- const sync_pb::GetUpdatesMessage& get_updates_message) { |
- CHECK_GT(get_updates_message.from_progress_marker_size(), 0) |
- << "A GetUpdates request must have at least one progress marker."; |
- |
- UpdateSieve::ModelTypeToVersionMap request_from_version; |
- int64_t min_version = std::numeric_limits<int64_t>::max(); |
- for (int i = 0; i < get_updates_message.from_progress_marker_size(); i++) { |
- sync_pb::DataTypeProgressMarker marker = |
- get_updates_message.from_progress_marker(i); |
- |
- int64_t version = 0; |
- // Let the version remain zero if there is no token or an empty token (the |
- // first request for this type). |
- if (marker.has_token() && !marker.token().empty()) { |
- bool parsed = base::StringToInt64(marker.token(), &version); |
- CHECK(parsed) << "Unable to parse progress marker token."; |
+ ModelType model_type = |
+ syncer::GetModelTypeFromSpecificsFieldNumber(marker.data_type_id()); |
+ DCHECK(request_version_map.find(model_type) == request_version_map.end()); |
+ request_version_map[model_type] = version; |
} |
- ModelType model_type = |
- syncer::GetModelTypeFromSpecificsFieldNumber(marker.data_type_id()); |
- request_from_version[model_type] = version; |
- |
- if (version < min_version) |
- min_version = version; |
+ return request_version_map; |
} |
- return std::unique_ptr<UpdateSieve>( |
- new UpdateSieve(request_from_version, min_version)); |
-} |
+ explicit UpdateSieve(const ModelTypeToVersionMap request_version_map) |
+ : request_version_map_(request_version_map), |
+ response_version_map_(request_version_map) {} |
+ |
+ // The largest versions the client has seen before this request, and is used |
+ // to filter entities to send back to clients. The values in this map are not |
+ // updated after being initially set. The presence of a type in this map is a |
+ // proxy for the desire to receive results about this type. |
+ const ModelTypeToVersionMap request_version_map_; |
+ |
+ // The largest versions seen between client and server, ultimately used to |
+ // send progress markers back to the client. |
+ ModelTypeToVersionMap response_version_map_; |
+}; |
} // namespace |
LoopbackServer::LoopbackServer(const base::FilePath& persistent_file) |
- : version_(0), store_birthday_(0), persistent_file_(persistent_file) { |
+ : version_(0), |
+ store_birthday_(0), |
+ persistent_file_(persistent_file), |
+ observer_for_tests_(NULL) { |
Init(); |
} |
@@ -290,7 +278,7 @@ bool LoopbackServer::HandleGetUpdatesRequest( |
// at once. |
response->set_changes_remaining(0); |
- std::unique_ptr<UpdateSieve> sieve = UpdateSieve::Create(get_updates); |
+ auto sieve = base::MakeUnique<UpdateSieve>(get_updates); |
// This folder is called "Synced Bookmarks" by sync and is renamed |
// "Mobile Bookmarks" by the mobile client UIs. |
@@ -301,7 +289,6 @@ bool LoopbackServer::HandleGetUpdatesRequest( |
} |
bool send_encryption_keys_based_on_nigori = false; |
- int64_t max_response_version = 0; |
for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
++it) { |
const LoopbackServerEntity& entity = *it->second; |
@@ -309,9 +296,6 @@ bool LoopbackServer::HandleGetUpdatesRequest( |
sync_pb::SyncEntity* response_entity = response->add_entries(); |
entity.SerializeAsProto(response_entity); |
- max_response_version = |
- std::max(max_response_version, response_entity->version()); |
- |
if (entity.GetModelType() == syncer::NIGORI) { |
send_encryption_keys_based_on_nigori = |
response_entity->specifics().nigori().passphrase_type() == |
@@ -328,7 +312,7 @@ bool LoopbackServer::HandleGetUpdatesRequest( |
} |
} |
- sieve->UpdateProgressMarkers(max_response_version, response); |
+ sieve->SetProgressMarkers(response); |
return true; |
} |
@@ -465,6 +449,9 @@ bool LoopbackServer::HandleCommitRequest( |
committed_model_types.Put(iter->second->GetModelType()); |
} |
+ if (observer_for_tests_) |
+ observer_for_tests_->OnCommit(invalidator_client_id, committed_model_types); |
+ |
return true; |
} |
@@ -473,6 +460,7 @@ void LoopbackServer::ClearServerData() { |
entities_.clear(); |
keystore_keys_.clear(); |
++store_birthday_; |
+ base::DeleteFile(persistent_file_, false); |
Init(); |
} |
@@ -481,6 +469,74 @@ std::string LoopbackServer::GetStoreBirthday() const { |
return base::Int64ToString(store_birthday_); |
} |
+std::vector<sync_pb::SyncEntity> LoopbackServer::GetSyncEntitiesByModelType( |
+ ModelType model_type) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ std::vector<sync_pb::SyncEntity> sync_entities; |
+ for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
+ ++it) { |
+ const LoopbackServerEntity& entity = *it->second; |
+ if (!(entity.IsDeleted() || entity.IsPermanent()) && |
+ entity.GetModelType() == model_type) { |
+ sync_pb::SyncEntity sync_entity; |
+ entity.SerializeAsProto(&sync_entity); |
+ sync_entities.push_back(sync_entity); |
+ } |
+ } |
+ return sync_entities; |
+} |
+ |
+std::unique_ptr<base::DictionaryValue> |
+LoopbackServer::GetEntitiesAsDictionaryValue() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ std::unique_ptr<base::DictionaryValue> dictionary( |
+ new base::DictionaryValue()); |
+ |
+ // Initialize an empty ListValue for all ModelTypes. |
+ ModelTypeSet all_types = ModelTypeSet::All(); |
+ for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) { |
+ dictionary->Set(ModelTypeToString(it.Get()), new base::ListValue()); |
+ } |
+ |
+ for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
+ ++it) { |
+ const LoopbackServerEntity& entity = *it->second; |
+ if (entity.IsDeleted() || entity.IsPermanent()) { |
+ // Tombstones are ignored as they don't represent current data. Folders |
+ // are also ignored as current verification infrastructure does not |
+ // consider them. |
+ continue; |
+ } |
+ base::ListValue* list_value; |
+ if (!dictionary->GetList(ModelTypeToString(entity.GetModelType()), |
+ &list_value)) { |
+ return std::unique_ptr<base::DictionaryValue>(); |
+ } |
+ // TODO(pvalenzuela): Store more data for each entity so additional |
+ // verification can be performed. One example of additional verification |
+ // is checking the correctness of the bookmark hierarchy. |
+ list_value->AppendString(entity.GetName()); |
+ } |
+ |
+ return dictionary; |
+} |
+ |
+bool LoopbackServer::ModifyEntitySpecifics( |
+ const std::string& id, |
+ const sync_pb::EntitySpecifics& updated_specifics) { |
+ EntityMap::const_iterator iter = entities_.find(id); |
+ if (iter == entities_.end() || |
+ iter->second->GetModelType() != |
+ GetModelTypeFromSpecifics(updated_specifics)) { |
+ return false; |
+ } |
+ |
+ LoopbackServerEntity* entity = iter->second.get(); |
+ entity->SetSpecifics(updated_specifics); |
+ UpdateEntityVersion(entity); |
+ return true; |
+} |
+ |
void LoopbackServer::SerializeState(sync_pb::LoopbackServerProto* proto) const { |
DCHECK(thread_checker_.CalledOnValidThread()); |