OLD | NEW |
---|---|
(Empty) | |
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 | |
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 | |
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. | |
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 | |
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 | |
90 SyncThreadSyncEntity::~SyncThreadSyncEntity() { | |
91 } | |
92 | |
93 bool SyncThreadSyncEntity::IsCommitPending() const { | |
94 return is_commit_pending_; | |
95 } | |
96 | |
97 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 | |
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 if (base_version < base_version_) { | |
131 NOTREACHED() << "Base version should never decrease"; | |
132 return; | |
133 } | |
134 | |
135 if (sequence_number < sequence_number_) { | |
136 NOTREACHED() << "Sequence number should never decrease"; | |
137 return; | |
138 } | |
139 | |
140 // Update our book-keeping counters. | |
141 base_version_ = base_version; | |
142 sequence_number_ = sequence_number; | |
143 | |
144 // Do our counter values indicate a conflict? If so, don't commit. | |
145 // | |
146 // There's no need to inform the model thread of the conflict. The | |
147 // conflicting update has already been posted to its task runner; it will | |
148 // figure it out as soon as it runs that task. | |
149 is_commit_pending_ = true; | |
150 if (IsInConflict()) { | |
151 ClearPendingCommit(); | |
152 return; | |
153 } | |
154 | |
155 // We don't commit deletions of server-unknown items. | |
156 if (deleted && !IsServerKnown()) { | |
157 ClearPendingCommit(); | |
158 return; | |
159 } | |
160 | |
161 // Otherwise, we should store the data associated with this pending commit | |
162 // so we're ready to commit at the next possible opportunity. | |
163 | |
164 // We intentionally don't update the id_ here. Good ID values come from the | |
165 // server and always pass through the sync thread first. There's no way the | |
166 // model thread could have a better ID value than we do. | |
167 | |
168 // This entity is identified by its client tag. That value can never change. | |
169 DCHECK_EQ(client_tag_hash_, client_tag_hash); | |
170 | |
171 // Set the fields for the pending commit. | |
172 ctime_ = ctime; | |
173 mtime_ = mtime; | |
174 non_unique_name_ = non_unique_name; | |
175 deleted_ = deleted; | |
176 specifics_ = specifics; | |
177 } | |
178 | |
179 void SyncThreadSyncEntity::ReceiveCommitResponse(const std::string& response_id, | |
180 int64 response_version, | |
181 int64 sequence_number) { | |
182 // Commit responses, especially after the first commit, can update our ID. | |
183 id_ = response_id; | |
184 | |
185 DCHECK_GT(response_version, highest_commit_response_version_) | |
186 << "Had expected higher response version." | |
187 << " id: " << id_; | |
188 | |
189 // Commits are synchronous, so there should there's no reason why the | |
Nicolas Zea
2014/05/28 23:56:16
nit: there should there's
rlarocque
2014/05/29 20:54:52
Done.
| |
190 // sequence numbers wouldn't match. | |
191 DCHECK_EQ(sequence_number_, sequence_number) | |
192 << "Unexpected sequence number mismatch." | |
193 << " id: " << id_; | |
194 | |
195 highest_commit_response_version_ = response_version; | |
196 | |
197 // Because an in-progress commit blocks the sync thread, we can assume that | |
198 // the item we just committed successfully is exactly the one we have now. | |
199 // Nothing changed it while the commit was happening. Since we're now in | |
200 // sync with the server, we can clear the pending commit. | |
201 ClearPendingCommit(); | |
202 } | |
203 | |
204 void SyncThreadSyncEntity::ReceiveUpdate(int64 version) { | |
205 highest_gu_response_version_ = | |
206 std::max(highest_gu_response_version_, version); | |
207 | |
208 if (IsInConflict()) { | |
209 // Incoming update clobbers the pending commit on the sync thread. | |
210 // The model thread can re-request this commit later if it wants to. | |
211 ClearPendingCommit(); | |
212 } | |
213 } | |
214 | |
215 bool SyncThreadSyncEntity::IsInConflict() const { | |
216 if (!is_commit_pending_) | |
217 return false; | |
218 | |
219 if (highest_gu_response_version_ <= highest_commit_response_version_) { | |
220 // The most recent server state was created in a commit made by this | |
221 // client. We're fully up to date, and therefore not in conflict. | |
222 return false; | |
223 } else { | |
224 // The most recent server state was written by someone else. | |
225 // Did the model thread have the most up to date version when it issued the | |
226 // commit request? | |
227 if (base_version_ >= highest_gu_response_version_) { | |
228 return false; // Yes. | |
229 } else { | |
230 return true; // No. | |
231 } | |
232 } | |
233 } | |
234 | |
235 bool SyncThreadSyncEntity::IsServerKnown() const { | |
236 return base_version_ != kUncommittedVersion; | |
237 } | |
238 | |
239 void SyncThreadSyncEntity::ClearPendingCommit() { | |
240 is_commit_pending_ = false; | |
241 specifics_.Clear(); | |
Nicolas Zea
2014/05/28 23:56:16
why clear the specific here?
rlarocque
2014/05/29 20:54:52
It's an optimization. At this point we've given u
Nicolas Zea
2014/06/02 20:27:17
Does the protobuf library actually free memory whe
rlarocque
2014/06/02 21:39:13
According to the documentation [1], protobufs can
| |
242 } | |
243 | |
244 } // namespace syncer | |
OLD | NEW |