• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "sync/engine/sync_thread_sync_entity.h"
6 
7 #include "base/logging.h"
8 #include "sync/engine/non_blocking_sync_common.h"
9 #include "sync/internal_api/public/base/model_type.h"
10 #include "sync/syncable/syncable_util.h"
11 #include "sync/util/time.h"
12 
13 namespace syncer {
14 
FromServerUpdate(const std::string & id_string,const std::string & client_tag_hash,int64 received_version)15 SyncThreadSyncEntity* SyncThreadSyncEntity::FromServerUpdate(
16     const std::string& id_string,
17     const std::string& client_tag_hash,
18     int64 received_version) {
19   return new SyncThreadSyncEntity(
20       id_string, client_tag_hash, 0, received_version);
21 }
22 
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)23 SyncThreadSyncEntity* SyncThreadSyncEntity::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 new SyncThreadSyncEntity(id_string,
34                                   client_tag_hash,
35                                   0,
36                                   0,
37                                   true,
38                                   sequence_number,
39                                   base_version,
40                                   ctime,
41                                   mtime,
42                                   non_unique_name,
43                                   deleted,
44                                   specifics);
45 }
46 
47 // Constructor that does not set any pending commit fields.
SyncThreadSyncEntity(const std::string & id,const std::string & client_tag_hash,int64 highest_commit_response_version,int64 highest_gu_response_version)48 SyncThreadSyncEntity::SyncThreadSyncEntity(
49     const std::string& id,
50     const std::string& client_tag_hash,
51     int64 highest_commit_response_version,
52     int64 highest_gu_response_version)
53     : id_(id),
54       client_tag_hash_(client_tag_hash),
55       highest_commit_response_version_(highest_commit_response_version),
56       highest_gu_response_version_(highest_gu_response_version),
57       is_commit_pending_(false),
58       sequence_number_(0),
59       base_version_(0),
60       deleted_(false) {
61 }
62 
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)63 SyncThreadSyncEntity::SyncThreadSyncEntity(
64     const std::string& id,
65     const std::string& client_tag_hash,
66     int64 highest_commit_response_version,
67     int64 highest_gu_response_version,
68     bool is_commit_pending,
69     int64 sequence_number,
70     int64 base_version,
71     base::Time ctime,
72     base::Time mtime,
73     const std::string& non_unique_name,
74     bool deleted,
75     const sync_pb::EntitySpecifics& specifics)
76     : id_(id),
77       client_tag_hash_(client_tag_hash),
78       highest_commit_response_version_(highest_commit_response_version),
79       highest_gu_response_version_(highest_gu_response_version),
80       is_commit_pending_(is_commit_pending),
81       sequence_number_(sequence_number),
82       base_version_(base_version),
83       ctime_(ctime),
84       mtime_(mtime),
85       non_unique_name_(non_unique_name),
86       deleted_(deleted),
87       specifics_(specifics) {
88 }
89 
~SyncThreadSyncEntity()90 SyncThreadSyncEntity::~SyncThreadSyncEntity() {
91 }
92 
IsCommitPending() const93 bool SyncThreadSyncEntity::IsCommitPending() const {
94   return is_commit_pending_;
95 }
96 
PrepareCommitProto(sync_pb::SyncEntity * commit_entity,int64 * sequence_number) const97 void SyncThreadSyncEntity::PrepareCommitProto(
98     sync_pb::SyncEntity* commit_entity,
99     int64* sequence_number) const {
100   // Set ID if we have a server-assigned ID.  Otherwise, it will be up to
101   // our caller to assign a client-unique initial ID.
102   if (base_version_ != kUncommittedVersion) {
103     commit_entity->set_id_string(id_);
104   }
105 
106   commit_entity->set_client_defined_unique_tag(client_tag_hash_);
107   commit_entity->set_version(base_version_);
108   commit_entity->set_deleted(deleted_);
109   commit_entity->set_folder(false);
110   commit_entity->set_name(non_unique_name_);
111   if (!deleted_) {
112     commit_entity->set_ctime(TimeToProtoTime(ctime_));
113     commit_entity->set_mtime(TimeToProtoTime(mtime_));
114     commit_entity->mutable_specifics()->CopyFrom(specifics_);
115   }
116 
117   *sequence_number = sequence_number_;
118 }
119 
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)120 void SyncThreadSyncEntity::RequestCommit(
121     const std::string& id,
122     const std::string& client_tag_hash,
123     int64 sequence_number,
124     int64 base_version,
125     base::Time ctime,
126     base::Time mtime,
127     const std::string& non_unique_name,
128     bool deleted,
129     const sync_pb::EntitySpecifics& specifics) {
130   DCHECK_GE(base_version, base_version_)
131       << "Base version should never decrease";
132 
133   DCHECK_GE(sequence_number, sequence_number_)
134       << "Sequence number should never decrease";
135 
136   // Update our book-keeping counters.
137   base_version_ = base_version;
138   sequence_number_ = sequence_number;
139 
140   // Do our counter values indicate a conflict?  If so, don't commit.
141   //
142   // There's no need to inform the model thread of the conflict.  The
143   // conflicting update has already been posted to its task runner; it will
144   // figure it out as soon as it runs that task.
145   is_commit_pending_ = true;
146   if (IsInConflict()) {
147     ClearPendingCommit();
148     return;
149   }
150 
151   // We don't commit deletions of server-unknown items.
152   if (deleted && !IsServerKnown()) {
153     ClearPendingCommit();
154     return;
155   }
156 
157   // Otherwise, we should store the data associated with this pending commit
158   // so we're ready to commit at the next possible opportunity.
159 
160   // We intentionally don't update the id_ here.  Good ID values come from the
161   // server and always pass through the sync thread first.  There's no way the
162   // model thread could have a better ID value than we do.
163 
164   // This entity is identified by its client tag.  That value can never change.
165   DCHECK_EQ(client_tag_hash_, client_tag_hash);
166 
167   // Set the fields for the pending commit.
168   ctime_ = ctime;
169   mtime_ = mtime;
170   non_unique_name_ = non_unique_name;
171   deleted_ = deleted;
172   specifics_ = specifics;
173 }
174 
ReceiveCommitResponse(const std::string & response_id,int64 response_version,int64 sequence_number)175 void SyncThreadSyncEntity::ReceiveCommitResponse(const std::string& response_id,
176                                                  int64 response_version,
177                                                  int64 sequence_number) {
178   // Commit responses, especially after the first commit, can update our ID.
179   id_ = response_id;
180 
181   DCHECK_GT(response_version, highest_commit_response_version_)
182       << "Had expected higher response version."
183       << " id: " << id_;
184 
185   // Commits are synchronous, so there's no reason why the sequence numbers
186   // wouldn't match.
187   DCHECK_EQ(sequence_number_, sequence_number)
188       << "Unexpected sequence number mismatch."
189       << " id: " << id_;
190 
191   highest_commit_response_version_ = response_version;
192 
193   // Because an in-progress commit blocks the sync thread, we can assume that
194   // the item we just committed successfully is exactly the one we have now.
195   // Nothing changed it while the commit was happening.  Since we're now in
196   // sync with the server, we can clear the pending commit.
197   ClearPendingCommit();
198 }
199 
ReceiveUpdate(int64 version)200 void SyncThreadSyncEntity::ReceiveUpdate(int64 version) {
201   highest_gu_response_version_ =
202       std::max(highest_gu_response_version_, version);
203 
204   if (IsInConflict()) {
205     // Incoming update clobbers the pending commit on the sync thread.
206     // The model thread can re-request this commit later if it wants to.
207     ClearPendingCommit();
208   }
209 }
210 
IsInConflict() const211 bool SyncThreadSyncEntity::IsInConflict() const {
212   if (!is_commit_pending_)
213     return false;
214 
215   if (highest_gu_response_version_ <= highest_commit_response_version_) {
216     // The most recent server state was created in a commit made by this
217     // client.  We're fully up to date, and therefore not in conflict.
218     return false;
219   } else {
220     // The most recent server state was written by someone else.
221     // Did the model thread have the most up to date version when it issued the
222     // commit request?
223     if (base_version_ >= highest_gu_response_version_) {
224       return false;  // Yes.
225     } else {
226       return true;  // No.
227     }
228   }
229 }
230 
IsServerKnown() const231 bool SyncThreadSyncEntity::IsServerKnown() const {
232   return base_version_ != kUncommittedVersion;
233 }
234 
ClearPendingCommit()235 void SyncThreadSyncEntity::ClearPendingCommit() {
236   is_commit_pending_ = false;
237 
238   // Clearing the specifics might free up some memory.  It can't hurt to try.
239   specifics_.Clear();
240 }
241 
242 }  // namespace syncer
243