| Index: sync/engine/sync_thread_sync_entity.cc
|
| diff --git a/sync/engine/sync_thread_sync_entity.cc b/sync/engine/sync_thread_sync_entity.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8b689b3af36c4f8f31d1aa177cb343e2986bd1f0
|
| --- /dev/null
|
| +++ b/sync/engine/sync_thread_sync_entity.cc
|
| @@ -0,0 +1,229 @@
|
| +// 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/engine/sync_thread_sync_entity.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "sync/internal_api/public/base/model_type.h"
|
| +#include "sync/syncable/syncable_util.h"
|
| +#include "sync/util/time.h"
|
| +
|
| +namespace syncer {
|
| +
|
| +SyncThreadSyncEntity* SyncThreadSyncEntity::FromServerUpdate(
|
| + const std::string& id_string,
|
| + const std::string& client_tag_hash,
|
| + int64 received_version) {
|
| + return new SyncThreadSyncEntity(
|
| + id_string, client_tag_hash, 0, received_version);
|
| +}
|
| +
|
| +SyncThreadSyncEntity* SyncThreadSyncEntity::FromCommitRequest(
|
| + const std::string& id_string,
|
| + const std::string& client_tag_hash,
|
| + int64 sequence_number,
|
| + int64 base_version,
|
| + base::Time ctime,
|
| + base::Time mtime,
|
| + const std::string& non_unique_name,
|
| + bool deleted,
|
| + const sync_pb::EntitySpecifics& specifics) {
|
| + return new SyncThreadSyncEntity(id_string,
|
| + client_tag_hash,
|
| + 0,
|
| + 0,
|
| + true,
|
| + sequence_number,
|
| + base_version,
|
| + ctime,
|
| + mtime,
|
| + non_unique_name,
|
| + deleted,
|
| + specifics);
|
| +}
|
| +
|
| +// Constructor that does not set any pending commit fields.
|
| +SyncThreadSyncEntity::SyncThreadSyncEntity(
|
| + const std::string& id,
|
| + const std::string& client_tag_hash,
|
| + int64 highest_commit_response_version,
|
| + int64 highest_gu_response_version)
|
| + : id_(id),
|
| + client_tag_hash_(client_tag_hash),
|
| + highest_commit_response_version_(highest_commit_response_version),
|
| + highest_gu_response_version_(highest_gu_response_version),
|
| + is_commit_pending_(false),
|
| + sequence_number_(0),
|
| + base_version_(0),
|
| + deleted_(false) {
|
| +}
|
| +
|
| +SyncThreadSyncEntity::SyncThreadSyncEntity(
|
| + const std::string& id,
|
| + const std::string& client_tag_hash,
|
| + int64 highest_commit_response_version,
|
| + int64 highest_gu_response_version,
|
| + bool is_commit_pending,
|
| + int64 sequence_number,
|
| + int64 base_version,
|
| + base::Time ctime,
|
| + base::Time mtime,
|
| + const std::string& non_unique_name,
|
| + bool deleted,
|
| + const sync_pb::EntitySpecifics& specifics)
|
| + : id_(id),
|
| + client_tag_hash_(client_tag_hash),
|
| + highest_commit_response_version_(highest_commit_response_version),
|
| + highest_gu_response_version_(highest_gu_response_version),
|
| + is_commit_pending_(is_commit_pending),
|
| + sequence_number_(sequence_number),
|
| + base_version_(base_version),
|
| + ctime_(ctime),
|
| + mtime_(mtime),
|
| + non_unique_name_(non_unique_name),
|
| + deleted_(deleted),
|
| + specifics_(specifics) {
|
| +}
|
| +
|
| +SyncThreadSyncEntity::~SyncThreadSyncEntity() {
|
| +}
|
| +
|
| +bool SyncThreadSyncEntity::IsCommitPending() const {
|
| + return is_commit_pending_;
|
| +}
|
| +
|
| +void SyncThreadSyncEntity::PrepareCommitProto(
|
| + sync_pb::SyncEntity* commit_entity,
|
| + int64* sequence_number) const {
|
| + // Set ID if we have a server-assigned ID. Otherwise, it will be up to
|
| + // our caller to assign a client-unique initial ID.
|
| + if (base_version_ != 0) {
|
| + commit_entity->set_id_string(id_);
|
| + }
|
| +
|
| + commit_entity->set_version(base_version_);
|
| + commit_entity->set_ctime(TimeToProtoTime(ctime_));
|
| + commit_entity->set_mtime(TimeToProtoTime(mtime_));
|
| + commit_entity->set_name(non_unique_name_);
|
| + commit_entity->set_deleted(deleted_);
|
| + commit_entity->mutable_specifics()->CopyFrom(specifics_);
|
| + commit_entity->set_folder(false);
|
| + commit_entity->set_client_defined_unique_tag(client_tag_hash_);
|
| +
|
| + *sequence_number = sequence_number_;
|
| +}
|
| +
|
| +void SyncThreadSyncEntity::RequestCommit(
|
| + const std::string& id,
|
| + const std::string& client_tag_hash,
|
| + int64 sequence_number,
|
| + int64 base_version,
|
| + base::Time ctime,
|
| + base::Time mtime,
|
| + const std::string& non_unique_name,
|
| + bool deleted,
|
| + const sync_pb::EntitySpecifics& specifics) {
|
| + if (base_version < base_version_) {
|
| + NOTREACHED() << "Base version should never decrease";
|
| + return;
|
| + }
|
| +
|
| + if (sequence_number < sequence_number_) {
|
| + NOTREACHED() << "Sequence number should never decrease";
|
| + return;
|
| + }
|
| +
|
| + // Update our book-keeping counters.
|
| + base_version_ = base_version;
|
| + sequence_number_ = sequence_number;
|
| +
|
| + // Do our counter values indicate a conflict? If so, don't commit.
|
| + //
|
| + // There's no need to inform the model thread of the conflict. The
|
| + // conflicting update has already been posted to its task runner; it will
|
| + // figure it out as soon as it runs that task.
|
| + is_commit_pending_ = true;
|
| + if (IsInConflict()) {
|
| + ClearPendingCommit();
|
| + return;
|
| + }
|
| +
|
| + // Otherwise, we should store the data associated with this pending commit
|
| + // so we're ready to commit at the next possible opportunity.
|
| +
|
| + // We intentionally don't update the id_ here. Good ID values come from the
|
| + // server and always pass through the sync thread first. There's no way the
|
| + // model thread could have a better ID value than we do.
|
| +
|
| + // This entity is identified by its client tag. That value can never change.
|
| + DCHECK_EQ(client_tag_hash_, client_tag_hash);
|
| +
|
| + // Set the fields for the pending commit.
|
| + ctime_ = ctime;
|
| + mtime_ = mtime;
|
| + non_unique_name_ = non_unique_name;
|
| + deleted_ = deleted;
|
| + specifics_ = specifics;
|
| +
|
| + specifics_.CopyFrom(specifics);
|
| +}
|
| +
|
| +void SyncThreadSyncEntity::ReceiveCommitResponse(int64 response_version,
|
| + int64 sequence_number) {
|
| + DCHECK_GT(response_version, highest_commit_response_version_)
|
| + << "Had expected higher response version."
|
| + << " id: " << id_;
|
| +
|
| + // Commits are synchronous, so there should there's no reason why the
|
| + // sequence numbers wouldn't match.
|
| + DCHECK_EQ(sequence_number_, sequence_number)
|
| + << "Unexpected sequence number mismatch."
|
| + << " id: " << id_;
|
| +
|
| + highest_commit_response_version_ = response_version;
|
| +
|
| + // Because an in-progress commit blocks the sync thread, we can assume that
|
| + // the item we just committed successfully is exactly the one we have now.
|
| + // Nothing changed it while the commit was happening. Since we're now in
|
| + // sync with the server, we can clear the pending commit.
|
| + ClearPendingCommit();
|
| +}
|
| +
|
| +void SyncThreadSyncEntity::ReceiveUpdate(int64 version) {
|
| + highest_gu_response_version_ =
|
| + std::max(highest_gu_response_version_, version);
|
| +
|
| + if (IsInConflict()) {
|
| + // Incoming update clobbers the pending commit on the sync thread.
|
| + // The model thread can re-request this commit later if it wants to.
|
| + ClearPendingCommit();
|
| + }
|
| +}
|
| +
|
| +bool SyncThreadSyncEntity::IsInConflict() const {
|
| + if (!is_commit_pending_)
|
| + return false;
|
| +
|
| + if (highest_gu_response_version_ <= highest_commit_response_version_) {
|
| + // The most recent server state was created in a commit made by this
|
| + // client. We're fully up to date, and therefore not in conflict.
|
| + return false;
|
| + } else {
|
| + // The most recent server state was written by someone else.
|
| + // Did the model thread have the most up to date version when it issued the
|
| + // commit request?
|
| + if (base_version_ >= highest_gu_response_version_) {
|
| + return false; // Yes.
|
| + } else {
|
| + return true; // No.
|
| + }
|
| + }
|
| +}
|
| +
|
| +void SyncThreadSyncEntity::ClearPendingCommit() {
|
| + is_commit_pending_ = false;
|
| + specifics_.Clear();
|
| +}
|
| +
|
| +} // namespace syncer
|
|
|