summaryrefslogtreecommitdiffstats
path: root/sync/internal_api/processor_entity_tracker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sync/internal_api/processor_entity_tracker.cc')
-rw-r--r--sync/internal_api/processor_entity_tracker.cc210
1 files changed, 210 insertions, 0 deletions
diff --git a/sync/internal_api/processor_entity_tracker.cc b/sync/internal_api/processor_entity_tracker.cc
new file mode 100644
index 0000000..87c400c
--- /dev/null
+++ b/sync/internal_api/processor_entity_tracker.cc
@@ -0,0 +1,210 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/internal_api/public/processor_entity_tracker.h"
+
+#include <stdint.h>
+
+#include "base/base64.h"
+#include "base/sha1.h"
+#include "base/time/time.h"
+#include "sync/internal_api/public/non_blocking_sync_common.h"
+#include "sync/syncable/syncable_util.h"
+#include "sync/util/time.h"
+
+namespace syncer_v2 {
+
+scoped_ptr<ProcessorEntityTracker> ProcessorEntityTracker::CreateNew(
+ const std::string& client_tag,
+ const std::string& client_tag_hash,
+ const std::string& id,
+ base::Time creation_time) {
+ // Initialize metadata
+ sync_pb::EntityMetadata metadata;
+ metadata.set_client_tag_hash(client_tag_hash);
+ if (!id.empty())
+ metadata.set_server_id(id);
+ metadata.set_sequence_number(0);
+ metadata.set_acked_sequence_number(0);
+ metadata.set_server_version(kUncommittedVersion);
+ metadata.set_creation_time(syncer::TimeToProtoTime(creation_time));
+
+ return scoped_ptr<ProcessorEntityTracker>(
+ new ProcessorEntityTracker(client_tag, &metadata));
+}
+
+scoped_ptr<ProcessorEntityTracker> ProcessorEntityTracker::CreateFromMetadata(
+ const std::string& client_tag,
+ sync_pb::EntityMetadata* metadata) {
+ return scoped_ptr<ProcessorEntityTracker>(
+ new ProcessorEntityTracker(client_tag, metadata));
+}
+
+ProcessorEntityTracker::ProcessorEntityTracker(
+ const std::string& client_tag,
+ sync_pb::EntityMetadata* metadata)
+ : client_tag_(client_tag),
+ commit_requested_sequence_number_(metadata->acked_sequence_number()) {
+ DCHECK(metadata->has_client_tag_hash());
+ DCHECK(metadata->has_creation_time());
+ metadata_.Swap(metadata);
+}
+
+ProcessorEntityTracker::~ProcessorEntityTracker() {}
+
+void ProcessorEntityTracker::CacheCommitData(EntityData* data) {
+ DCHECK(RequiresCommitRequest());
+ if (data->client_tag_hash.empty()) {
+ data->client_tag_hash = metadata_.client_tag_hash();
+ }
+ commit_data_ = data->PassToPtr();
+ DCHECK(HasCommitData());
+}
+
+bool ProcessorEntityTracker::HasCommitData() const {
+ return !commit_data_->client_tag_hash.empty();
+}
+
+bool ProcessorEntityTracker::IsUnsynced() const {
+ return metadata_.sequence_number() > metadata_.acked_sequence_number();
+}
+
+bool ProcessorEntityTracker::RequiresCommitRequest() const {
+ return metadata_.sequence_number() > commit_requested_sequence_number_;
+}
+
+bool ProcessorEntityTracker::RequiresCommitData() const {
+ return RequiresCommitRequest() && !HasCommitData() && !metadata_.is_deleted();
+}
+
+bool ProcessorEntityTracker::UpdateIsReflection(int64_t update_version) const {
+ return metadata_.server_version() >= update_version;
+}
+
+bool ProcessorEntityTracker::UpdateIsInConflict(int64_t update_version) const {
+ return IsUnsynced() && !UpdateIsReflection(update_version);
+}
+
+void ProcessorEntityTracker::ApplyUpdateFromServer(
+ const UpdateResponseData& response_data) {
+ DCHECK(metadata_.has_client_tag_hash());
+ DCHECK(!metadata_.client_tag_hash().empty());
+ DCHECK(metadata_.has_sequence_number());
+
+ // TODO(stanisc): crbug/561829: Filter out update if specifics hash hasn't
+ // changed.
+
+ // TODO(stanisc): crbug/521867: Understand and verify the conflict resolution
+ // logic here.
+ // There was a conflict and the server just won it.
+ // This implicitly acks all outstanding commits because a received update
+ // will clobber any pending commits on the sync thread.
+ metadata_.set_acked_sequence_number(metadata_.sequence_number());
+ commit_requested_sequence_number_ = metadata_.sequence_number();
+
+ metadata_.set_server_version(response_data.response_version);
+ metadata_.set_modification_time(
+ syncer::TimeToProtoTime(response_data.entity->modification_time));
+ UpdateSpecificsHash(response_data.entity->specifics);
+
+ encryption_key_name_ = response_data.encryption_key_name;
+}
+
+void ProcessorEntityTracker::MakeLocalChange(scoped_ptr<EntityData> data) {
+ DCHECK(!metadata_.client_tag_hash().empty());
+ DCHECK_EQ(metadata_.client_tag_hash(), data->client_tag_hash);
+ DCHECK(!data->modification_time.is_null());
+
+ metadata_.set_modification_time(
+ syncer::TimeToProtoTime(data->modification_time));
+ metadata_.set_is_deleted(false);
+ IncrementSequenceNumber();
+ UpdateSpecificsHash(data->specifics);
+
+ data->id = metadata_.server_id();
+ data->creation_time = syncer::ProtoTimeToTime(metadata_.creation_time());
+ CacheCommitData(data.get());
+}
+
+void ProcessorEntityTracker::UpdateDesiredEncryptionKey(
+ const std::string& name) {
+ if (encryption_key_name_ == name)
+ return;
+
+ DVLOG(2) << metadata_.server_id()
+ << ": Encryption triggered commit: " << encryption_key_name_
+ << " -> " << name;
+
+ // Schedule commit with the expectation that the worker will re-encrypt with
+ // the latest encryption key as it does.
+ IncrementSequenceNumber();
+}
+
+void ProcessorEntityTracker::Delete() {
+ IncrementSequenceNumber();
+ metadata_.set_is_deleted(true);
+ metadata_.clear_specifics_hash();
+ // Clear any cached pending commit data.
+ if (HasCommitData())
+ commit_data_.reset();
+}
+
+void ProcessorEntityTracker::InitializeCommitRequestData(
+ CommitRequestData* request) {
+ if (!metadata_.is_deleted()) {
+ DCHECK(HasCommitData());
+ DCHECK_EQ(commit_data_->client_tag_hash, metadata_.client_tag_hash());
+ request->entity = commit_data_;
+ } else {
+ // Make an EntityData with empty specifics to indicate deletion. This is
+ // done lazily here to simplify loading a pending deletion on startup.
+ EntityData data;
+ data.client_tag_hash = metadata_.client_tag_hash();
+ data.id = metadata_.server_id();
+ data.creation_time = syncer::ProtoTimeToTime(metadata_.creation_time());
+ request->entity = data.PassToPtr();
+ }
+
+ request->sequence_number = metadata_.sequence_number();
+ request->base_version = metadata_.server_version();
+ commit_requested_sequence_number_ = metadata_.sequence_number();
+}
+
+void ProcessorEntityTracker::ReceiveCommitResponse(
+ const std::string& id,
+ int64_t sequence_number,
+ int64_t response_version,
+ const std::string& encryption_key_name) {
+ // The server can assign us a new ID in a commit response.
+ metadata_.set_server_id(id);
+ metadata_.set_acked_sequence_number(sequence_number);
+ metadata_.set_server_version(response_version);
+ encryption_key_name_ = encryption_key_name;
+}
+
+void ProcessorEntityTracker::ClearTransientSyncState() {
+ // If we have any unacknowledged commit requests outstanding, they've been
+ // dropped and we should forget about them.
+ commit_requested_sequence_number_ = metadata_.acked_sequence_number();
+}
+
+void ProcessorEntityTracker::IncrementSequenceNumber() {
+ DCHECK(metadata_.has_sequence_number());
+ metadata_.set_sequence_number(metadata_.sequence_number() + 1);
+}
+
+// Update hash string for EntitySpecifics.
+void ProcessorEntityTracker::UpdateSpecificsHash(
+ const sync_pb::EntitySpecifics& specifics) {
+ if (specifics.ByteSize() > 0) {
+ std::string hash_input;
+ specifics.AppendToString(&hash_input);
+ base::Base64Encode(base::SHA1HashString(hash_input),
+ metadata_.mutable_specifics_hash());
+ } else {
+ metadata_.clear_specifics_hash();
+ }
+}
+
+} // namespace syncer_v2