blob: 3bcf7106fc2da2882c580485cfe3fc4033688dfa [file] [log] [blame]
[email protected]f233b142014-06-05 18:05:331// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
maxbogue47762742016-03-01 00:56:185#include "sync/engine/worker_entity_tracker.h"
[email protected]f233b142014-06-05 18:05:336
avi4856ced02015-12-22 03:14:107#include <stdint.h>
8
[email protected]f233b142014-06-05 18:05:339#include "base/logging.h"
[email protected]f233b142014-06-05 18:05:3310#include "sync/internal_api/public/base/model_type.h"
[email protected]3e6597742014-07-28 21:59:5411#include "sync/internal_api/public/non_blocking_sync_common.h"
[email protected]f233b142014-06-05 18:05:3312#include "sync/syncable/syncable_util.h"
13#include "sync/util/time.h"
14
stanisc96665bd2015-08-14 18:59:1415namespace syncer_v2 {
[email protected]f233b142014-06-05 18:05:3316
maxbogue4b212e62016-03-21 22:09:0817WorkerEntityTracker::WorkerEntityTracker(const std::string& id,
18 const std::string& client_tag_hash)
[email protected]f233b142014-06-05 18:05:3319 : id_(id),
20 client_tag_hash_(client_tag_hash),
maxbogue4b212e62016-03-21 22:09:0821 highest_commit_response_version_(0),
22 highest_gu_response_version_(0),
[email protected]f233b142014-06-05 18:05:3323 sequence_number_(0),
maxbogue4b212e62016-03-21 22:09:0824 base_version_(kUncommittedVersion) {
25 DCHECK(!client_tag_hash_.empty());
26}
[email protected]f233b142014-06-05 18:05:3327
maxbogue47762742016-03-01 00:56:1828WorkerEntityTracker::~WorkerEntityTracker() {}
[email protected]f233b142014-06-05 18:05:3329
maxbogue47762742016-03-01 00:56:1830bool WorkerEntityTracker::HasPendingCommit() const {
maxbogue21e465ee32015-09-16 20:50:3331 return !!pending_commit_;
[email protected]f233b142014-06-05 18:05:3332}
33
pavely4c454e22016-04-18 18:58:3234void WorkerEntityTracker::PopulateCommitProto(
35 sync_pb::SyncEntity* commit_entity,
36 int64_t* sequence_number) const {
maxbogue21e465ee32015-09-16 20:50:3337 DCHECK(HasPendingCommit());
staniscf3e705f2015-11-18 02:18:5838 DCHECK(!client_tag_hash_.empty());
maxbogue21e465ee32015-09-16 20:50:3339
staniscf3e705f2015-11-18 02:18:5840 if (!id_.empty()) {
[email protected]f233b142014-06-05 18:05:3341 commit_entity->set_id_string(id_);
42 }
43
staniscf3e705f2015-11-18 02:18:5844 const EntityData& entity = pending_commit_->entity.value();
45 DCHECK_EQ(client_tag_hash_, entity.client_tag_hash);
46
[email protected]f233b142014-06-05 18:05:3347 commit_entity->set_client_defined_unique_tag(client_tag_hash_);
48 commit_entity->set_version(base_version_);
staniscf3e705f2015-11-18 02:18:5849 commit_entity->set_deleted(entity.is_deleted());
50
51 // TODO(stanisc): This doesn't support bookmarks yet.
52 DCHECK(entity.parent_id.empty());
[email protected]f233b142014-06-05 18:05:3353 commit_entity->set_folder(false);
staniscf3e705f2015-11-18 02:18:5854
55 commit_entity->set_name(entity.non_unique_name);
56 if (!entity.is_deleted()) {
57 commit_entity->set_ctime(syncer::TimeToProtoTime(entity.creation_time));
58 commit_entity->set_mtime(syncer::TimeToProtoTime(entity.modification_time));
59 commit_entity->mutable_specifics()->CopyFrom(entity.specifics);
[email protected]f233b142014-06-05 18:05:3360 }
61
62 *sequence_number = sequence_number_;
63}
64
maxbogue47762742016-03-01 00:56:1865void WorkerEntityTracker::RequestCommit(const CommitRequestData& data) {
maxbogue21e465ee32015-09-16 20:50:3366 DCHECK_GE(data.base_version, base_version_)
[email protected]f233b142014-06-05 18:05:3367 << "Base version should never decrease";
68
maxbogue21e465ee32015-09-16 20:50:3369 DCHECK_GE(data.sequence_number, sequence_number_)
[email protected]f233b142014-06-05 18:05:3370 << "Sequence number should never decrease";
71
72 // Update our book-keeping counters.
maxbogue21e465ee32015-09-16 20:50:3373 base_version_ = data.base_version;
74 sequence_number_ = data.sequence_number;
[email protected]f233b142014-06-05 18:05:3375
maxbogue21e465ee32015-09-16 20:50:3376 // Don't commit deletions of server-unknown items.
staniscf3e705f2015-11-18 02:18:5877 if (data.entity->is_deleted() && !IsServerKnown()) {
[email protected]f233b142014-06-05 18:05:3378 ClearPendingCommit();
79 return;
80 }
81
[email protected]f233b142014-06-05 18:05:3382 // We intentionally don't update the id_ here. Good ID values come from the
83 // server and always pass through the sync thread first. There's no way the
84 // model thread could have a better ID value than we do.
85
86 // This entity is identified by its client tag. That value can never change.
staniscf3e705f2015-11-18 02:18:5887 DCHECK_EQ(client_tag_hash_, data.entity->client_tag_hash);
stanisc29a90292015-12-01 19:29:0088 // TODO(stanisc): consider simply copying CommitRequestData instead of
89 // allocating one dynamically.
maxbogue21e465ee32015-09-16 20:50:3390 pending_commit_.reset(new CommitRequestData(data));
[email protected]f233b142014-06-05 18:05:3391
maxbogue21e465ee32015-09-16 20:50:3392 // Do our counter values indicate a conflict? If so, don't commit.
93 //
94 // There's no need to inform the model thread of the conflict. The
95 // conflicting update has already been posted to its task runner; it will
96 // figure it out as soon as it runs that task.
97 //
98 // Note that this check must be after pending_commit_ is set.
99 if (IsInConflict()) {
100 ClearPendingCommit();
101 return;
102 }
103
104 // Otherwise, keep the data associated with this pending commit
105 // so it can be committed at the next possible opportunity.
[email protected]f233b142014-06-05 18:05:33106}
107
maxbogue47762742016-03-01 00:56:18108void WorkerEntityTracker::ReceiveCommitResponse(const std::string& response_id,
109 int64_t response_version,
110 int64_t sequence_number) {
[email protected]f233b142014-06-05 18:05:33111 // Commit responses, especially after the first commit, can update our ID.
112 id_ = response_id;
113
114 DCHECK_GT(response_version, highest_commit_response_version_)
115 << "Had expected higher response version."
116 << " id: " << id_;
117
118 // Commits are synchronous, so there's no reason why the sequence numbers
119 // wouldn't match.
120 DCHECK_EQ(sequence_number_, sequence_number)
121 << "Unexpected sequence number mismatch."
122 << " id: " << id_;
123
124 highest_commit_response_version_ = response_version;
125
126 // Because an in-progress commit blocks the sync thread, we can assume that
127 // the item we just committed successfully is exactly the one we have now.
128 // Nothing changed it while the commit was happening. Since we're now in
129 // sync with the server, we can clear the pending commit.
130 ClearPendingCommit();
131}
132
maxbogue47762742016-03-01 00:56:18133void WorkerEntityTracker::ReceiveUpdate(int64_t version) {
[email protected]4237bc172014-08-06 20:46:11134 if (version <= highest_gu_response_version_)
135 return;
136
137 highest_gu_response_version_ = version;
138
139 // Got an applicable update newer than any pending updates. It must be safe
maxbogue8cd3afc2016-03-24 00:45:47140 // to discard the old encrypted update, if there was one.
141 ClearEncryptedUpdate();
[email protected]f233b142014-06-05 18:05:33142
143 if (IsInConflict()) {
144 // Incoming update clobbers the pending commit on the sync thread.
145 // The model thread can re-request this commit later if it wants to.
146 ClearPendingCommit();
147 }
148}
149
maxbogue8cd3afc2016-03-24 00:45:47150bool WorkerEntityTracker::ReceiveEncryptedUpdate(
151 const UpdateResponseData& data) {
[email protected]4237bc172014-08-06 20:46:11152 if (data.response_version < highest_gu_response_version_)
153 return false;
154
155 highest_gu_response_version_ = data.response_version;
maxbogue8cd3afc2016-03-24 00:45:47156 encrypted_update_.reset(new UpdateResponseData(data));
[email protected]4237bc172014-08-06 20:46:11157 ClearPendingCommit();
158 return true;
159}
160
maxbogue8cd3afc2016-03-24 00:45:47161bool WorkerEntityTracker::HasEncryptedUpdate() const {
162 return !!encrypted_update_;
[email protected]4237bc172014-08-06 20:46:11163}
164
maxbogue8cd3afc2016-03-24 00:45:47165UpdateResponseData WorkerEntityTracker::GetEncryptedUpdate() const {
166 return *encrypted_update_;
[email protected]4237bc172014-08-06 20:46:11167}
168
maxbogue8cd3afc2016-03-24 00:45:47169void WorkerEntityTracker::ClearEncryptedUpdate() {
170 encrypted_update_.reset();
[email protected]4237bc172014-08-06 20:46:11171}
172
maxbogue47762742016-03-01 00:56:18173bool WorkerEntityTracker::IsInConflict() const {
maxbogue21e465ee32015-09-16 20:50:33174 if (!HasPendingCommit())
[email protected]f233b142014-06-05 18:05:33175 return false;
176
maxbogue8cd3afc2016-03-24 00:45:47177 if (HasEncryptedUpdate())
[email protected]4237bc172014-08-06 20:46:11178 return true;
179
[email protected]f233b142014-06-05 18:05:33180 if (highest_gu_response_version_ <= highest_commit_response_version_) {
181 // The most recent server state was created in a commit made by this
182 // client. We're fully up to date, and therefore not in conflict.
183 return false;
184 } else {
185 // The most recent server state was written by someone else.
186 // Did the model thread have the most up to date version when it issued the
187 // commit request?
188 if (base_version_ >= highest_gu_response_version_) {
189 return false; // Yes.
190 } else {
191 return true; // No.
192 }
193 }
194}
195
maxbogue47762742016-03-01 00:56:18196bool WorkerEntityTracker::IsServerKnown() const {
stanisc96665bd2015-08-14 18:59:14197 return base_version_ != kUncommittedVersion;
[email protected]f233b142014-06-05 18:05:33198}
199
maxbogue47762742016-03-01 00:56:18200void WorkerEntityTracker::ClearPendingCommit() {
maxbogue21e465ee32015-09-16 20:50:33201 pending_commit_.reset();
[email protected]f233b142014-06-05 18:05:33202}
203
stanisc29a90292015-12-01 19:29:00204} // namespace syncer_v2