Roll WebRTC 9846:9854, Libjingle 9845:9853
[chromium-blink-merge.git] / sync / engine / entity_tracker.cc
blob49228ac3bbc9945e36e276acb7f5ae81accae8cc
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
3 // found in the LICENSE file.
5 #include "sync/engine/entity_tracker.h"
7 #include "base/logging.h"
8 #include "sync/internal_api/public/base/model_type.h"
9 #include "sync/internal_api/public/non_blocking_sync_common.h"
10 #include "sync/syncable/syncable_util.h"
11 #include "sync/util/time.h"
13 namespace syncer_v2 {
15 scoped_ptr<EntityTracker> EntityTracker::FromServerUpdate(
16 const std::string& id_string,
17 const std::string& client_tag_hash,
18 int64 received_version) {
19 return make_scoped_ptr(
20 new EntityTracker(id_string, client_tag_hash, 0, received_version));
23 scoped_ptr<EntityTracker> EntityTracker::FromCommitRequest(
24 const std::string& id_string,
25 const std::string& client_tag_hash,
26 int64 sequence_number,
27 int64 base_version,
28 base::Time ctime,
29 base::Time mtime,
30 const std::string& non_unique_name,
31 bool deleted,
32 const sync_pb::EntitySpecifics& specifics) {
33 return make_scoped_ptr(new EntityTracker(
34 id_string, client_tag_hash, 0, 0, true, sequence_number, base_version,
35 ctime, mtime, non_unique_name, deleted, specifics));
38 // Constructor that does not set any pending commit fields.
39 EntityTracker::EntityTracker(const std::string& id,
40 const std::string& client_tag_hash,
41 int64 highest_commit_response_version,
42 int64 highest_gu_response_version)
43 : id_(id),
44 client_tag_hash_(client_tag_hash),
45 highest_commit_response_version_(highest_commit_response_version),
46 highest_gu_response_version_(highest_gu_response_version),
47 is_commit_pending_(false),
48 sequence_number_(0),
49 base_version_(0),
50 deleted_(false) {
53 EntityTracker::EntityTracker(const std::string& id,
54 const std::string& client_tag_hash,
55 int64 highest_commit_response_version,
56 int64 highest_gu_response_version,
57 bool is_commit_pending,
58 int64 sequence_number,
59 int64 base_version,
60 base::Time ctime,
61 base::Time mtime,
62 const std::string& non_unique_name,
63 bool deleted,
64 const sync_pb::EntitySpecifics& specifics)
65 : id_(id),
66 client_tag_hash_(client_tag_hash),
67 highest_commit_response_version_(highest_commit_response_version),
68 highest_gu_response_version_(highest_gu_response_version),
69 is_commit_pending_(is_commit_pending),
70 sequence_number_(sequence_number),
71 base_version_(base_version),
72 ctime_(ctime),
73 mtime_(mtime),
74 non_unique_name_(non_unique_name),
75 deleted_(deleted),
76 specifics_(specifics) {
79 EntityTracker::~EntityTracker() {
82 bool EntityTracker::IsCommitPending() const {
83 return is_commit_pending_;
86 void EntityTracker::PrepareCommitProto(sync_pb::SyncEntity* commit_entity,
87 int64* sequence_number) const {
88 // Set ID if we have a server-assigned ID. Otherwise, it will be up to
89 // our caller to assign a client-unique initial ID.
90 if (base_version_ != kUncommittedVersion) {
91 commit_entity->set_id_string(id_);
94 commit_entity->set_client_defined_unique_tag(client_tag_hash_);
95 commit_entity->set_version(base_version_);
96 commit_entity->set_deleted(deleted_);
97 commit_entity->set_folder(false);
98 commit_entity->set_name(non_unique_name_);
99 if (!deleted_) {
100 commit_entity->set_ctime(syncer::TimeToProtoTime(ctime_));
101 commit_entity->set_mtime(syncer::TimeToProtoTime(mtime_));
102 commit_entity->mutable_specifics()->CopyFrom(specifics_);
105 *sequence_number = sequence_number_;
108 void EntityTracker::RequestCommit(const std::string& id,
109 const std::string& client_tag_hash,
110 int64 sequence_number,
111 int64 base_version,
112 base::Time ctime,
113 base::Time mtime,
114 const std::string& non_unique_name,
115 bool deleted,
116 const sync_pb::EntitySpecifics& specifics) {
117 DCHECK_GE(base_version, base_version_)
118 << "Base version should never decrease";
120 DCHECK_GE(sequence_number, sequence_number_)
121 << "Sequence number should never decrease";
123 // Update our book-keeping counters.
124 base_version_ = base_version;
125 sequence_number_ = sequence_number;
127 // Do our counter values indicate a conflict? If so, don't commit.
129 // There's no need to inform the model thread of the conflict. The
130 // conflicting update has already been posted to its task runner; it will
131 // figure it out as soon as it runs that task.
132 is_commit_pending_ = true;
133 if (IsInConflict()) {
134 ClearPendingCommit();
135 return;
138 // We don't commit deletions of server-unknown items.
139 if (deleted && !IsServerKnown()) {
140 ClearPendingCommit();
141 return;
144 // Otherwise, we should store the data associated with this pending commit
145 // so we're ready to commit at the next possible opportunity.
147 // We intentionally don't update the id_ here. Good ID values come from the
148 // server and always pass through the sync thread first. There's no way the
149 // model thread could have a better ID value than we do.
151 // This entity is identified by its client tag. That value can never change.
152 DCHECK_EQ(client_tag_hash_, client_tag_hash);
154 // Set the fields for the pending commit.
155 ctime_ = ctime;
156 mtime_ = mtime;
157 non_unique_name_ = non_unique_name;
158 deleted_ = deleted;
159 specifics_ = specifics;
162 void EntityTracker::ReceiveCommitResponse(const std::string& response_id,
163 int64 response_version,
164 int64 sequence_number) {
165 // Commit responses, especially after the first commit, can update our ID.
166 id_ = response_id;
168 DCHECK_GT(response_version, highest_commit_response_version_)
169 << "Had expected higher response version."
170 << " id: " << id_;
172 // Commits are synchronous, so there's no reason why the sequence numbers
173 // wouldn't match.
174 DCHECK_EQ(sequence_number_, sequence_number)
175 << "Unexpected sequence number mismatch."
176 << " id: " << id_;
178 highest_commit_response_version_ = response_version;
180 // Because an in-progress commit blocks the sync thread, we can assume that
181 // the item we just committed successfully is exactly the one we have now.
182 // Nothing changed it while the commit was happening. Since we're now in
183 // sync with the server, we can clear the pending commit.
184 ClearPendingCommit();
187 void EntityTracker::ReceiveUpdate(int64 version) {
188 if (version <= highest_gu_response_version_)
189 return;
191 highest_gu_response_version_ = version;
193 // Got an applicable update newer than any pending updates. It must be safe
194 // to discard the old pending update, if there was one.
195 ClearPendingUpdate();
197 if (IsInConflict()) {
198 // Incoming update clobbers the pending commit on the sync thread.
199 // The model thread can re-request this commit later if it wants to.
200 ClearPendingCommit();
204 bool EntityTracker::ReceivePendingUpdate(const UpdateResponseData& data) {
205 if (data.response_version < highest_gu_response_version_)
206 return false;
208 highest_gu_response_version_ = data.response_version;
209 pending_update_.reset(new UpdateResponseData(data));
210 ClearPendingCommit();
211 return true;
214 bool EntityTracker::HasPendingUpdate() const {
215 return !!pending_update_;
218 UpdateResponseData EntityTracker::GetPendingUpdate() const {
219 return *pending_update_;
222 void EntityTracker::ClearPendingUpdate() {
223 pending_update_.reset();
226 bool EntityTracker::IsInConflict() const {
227 if (!is_commit_pending_)
228 return false;
230 if (HasPendingUpdate())
231 return true;
233 if (highest_gu_response_version_ <= highest_commit_response_version_) {
234 // The most recent server state was created in a commit made by this
235 // client. We're fully up to date, and therefore not in conflict.
236 return false;
237 } else {
238 // The most recent server state was written by someone else.
239 // Did the model thread have the most up to date version when it issued the
240 // commit request?
241 if (base_version_ >= highest_gu_response_version_) {
242 return false; // Yes.
243 } else {
244 return true; // No.
249 bool EntityTracker::IsServerKnown() const {
250 return base_version_ != kUncommittedVersion;
253 void EntityTracker::ClearPendingCommit() {
254 is_commit_pending_ = false;
256 // Clearing the specifics might free up some memory. It can't hurt to try.
257 specifics_.Clear();
260 } // namespace syncer