OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sync/engine/model_type_sync_proxy_impl.h" | 5 #include "sync/engine/model_type_sync_proxy_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/location.h" | 8 #include "base/location.h" |
9 #include "sync/engine/model_type_entity.h" | 9 #include "sync/engine/model_type_entity.h" |
10 #include "sync/engine/model_type_sync_worker.h" | 10 #include "sync/engine/model_type_sync_worker.h" |
11 #include "sync/internal_api/public/sync_context_proxy.h" | 11 #include "sync/internal_api/public/sync_context_proxy.h" |
12 #include "sync/syncable/syncable_util.h" | 12 #include "sync/syncable/syncable_util.h" |
13 | 13 |
14 namespace syncer { | 14 namespace syncer { |
15 | 15 |
16 ModelTypeSyncProxyImpl::ModelTypeSyncProxyImpl(ModelType type) | 16 ModelTypeSyncProxyImpl::ModelTypeSyncProxyImpl(ModelType type) |
17 : type_(type), | 17 : type_(type), |
18 is_preferred_(false), | 18 is_preferred_(false), |
19 is_connected_(false), | 19 is_connected_(false), |
20 entities_deleter_(&entities_), | |
21 pending_updates_map_deleter_(&pending_updates_map_), | |
22 weak_ptr_factory_for_ui_(this), | 20 weak_ptr_factory_for_ui_(this), |
23 weak_ptr_factory_for_sync_(this) { | 21 weak_ptr_factory_for_sync_(this) { |
24 } | 22 } |
25 | 23 |
26 ModelTypeSyncProxyImpl::~ModelTypeSyncProxyImpl() { | 24 ModelTypeSyncProxyImpl::~ModelTypeSyncProxyImpl() { |
27 } | 25 } |
28 | 26 |
29 bool ModelTypeSyncProxyImpl::IsPreferred() const { | 27 bool ModelTypeSyncProxyImpl::IsPreferred() const { |
30 DCHECK(CalledOnValidThread()); | 28 DCHECK(CalledOnValidThread()); |
31 return is_preferred_; | 29 return is_preferred_; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 FlushPendingCommitRequests(); | 98 FlushPendingCommitRequests(); |
101 } | 99 } |
102 | 100 |
103 void ModelTypeSyncProxyImpl::Put(const std::string& client_tag, | 101 void ModelTypeSyncProxyImpl::Put(const std::string& client_tag, |
104 const sync_pb::EntitySpecifics& specifics) { | 102 const sync_pb::EntitySpecifics& specifics) { |
105 DCHECK_EQ(type_, GetModelTypeFromSpecifics(specifics)); | 103 DCHECK_EQ(type_, GetModelTypeFromSpecifics(specifics)); |
106 | 104 |
107 const std::string client_tag_hash( | 105 const std::string client_tag_hash( |
108 syncable::GenerateSyncableHash(type_, client_tag)); | 106 syncable::GenerateSyncableHash(type_, client_tag)); |
109 | 107 |
110 EntityMap::iterator it = entities_.find(client_tag_hash); | 108 EntityMap::const_iterator it = entities_.find(client_tag_hash); |
111 if (it == entities_.end()) { | 109 if (it == entities_.end()) { |
112 scoped_ptr<ModelTypeEntity> entity(ModelTypeEntity::NewLocalItem( | 110 scoped_ptr<ModelTypeEntity> entity(ModelTypeEntity::NewLocalItem( |
113 client_tag, specifics, base::Time::Now())); | 111 client_tag, specifics, base::Time::Now())); |
114 entities_.insert(std::make_pair(client_tag_hash, entity.release())); | 112 entities_.insert(client_tag_hash, entity.Pass()); |
115 } else { | 113 } else { |
116 ModelTypeEntity* entity = it->second; | 114 ModelTypeEntity* entity = it->second; |
117 entity->MakeLocalChange(specifics); | 115 entity->MakeLocalChange(specifics); |
118 } | 116 } |
119 | 117 |
120 FlushPendingCommitRequests(); | 118 FlushPendingCommitRequests(); |
121 } | 119 } |
122 | 120 |
123 void ModelTypeSyncProxyImpl::Delete(const std::string& client_tag) { | 121 void ModelTypeSyncProxyImpl::Delete(const std::string& client_tag) { |
124 const std::string client_tag_hash( | 122 const std::string client_tag_hash( |
125 syncable::GenerateSyncableHash(type_, client_tag)); | 123 syncable::GenerateSyncableHash(type_, client_tag)); |
126 | 124 |
127 EntityMap::iterator it = entities_.find(client_tag_hash); | 125 EntityMap::const_iterator it = entities_.find(client_tag_hash); |
128 if (it == entities_.end()) { | 126 if (it == entities_.end()) { |
129 // That's unusual, but not necessarily a bad thing. | 127 // That's unusual, but not necessarily a bad thing. |
130 // Missing is as good as deleted as far as the model is concerned. | 128 // Missing is as good as deleted as far as the model is concerned. |
131 DLOG(WARNING) << "Attempted to delete missing item." | 129 DLOG(WARNING) << "Attempted to delete missing item." |
132 << " client tag: " << client_tag; | 130 << " client tag: " << client_tag; |
133 } else { | 131 } else { |
134 ModelTypeEntity* entity = it->second; | 132 ModelTypeEntity* entity = it->second; |
135 entity->Delete(); | 133 entity->Delete(); |
136 } | 134 } |
137 | 135 |
138 FlushPendingCommitRequests(); | 136 FlushPendingCommitRequests(); |
139 } | 137 } |
140 | 138 |
141 void ModelTypeSyncProxyImpl::FlushPendingCommitRequests() { | 139 void ModelTypeSyncProxyImpl::FlushPendingCommitRequests() { |
142 CommitRequestDataList commit_requests; | 140 CommitRequestDataList commit_requests; |
143 | 141 |
144 // Don't bother sending anything if there's no one to send to. | 142 // Don't bother sending anything if there's no one to send to. |
145 if (!IsConnected()) | 143 if (!IsConnected()) |
146 return; | 144 return; |
147 | 145 |
148 // Don't send anything if the type is not ready to handle commits. | 146 // Don't send anything if the type is not ready to handle commits. |
149 if (!data_type_state_.initial_sync_done) | 147 if (!data_type_state_.initial_sync_done) |
150 return; | 148 return; |
151 | 149 |
152 // TODO(rlarocque): Do something smarter than iterate here. | 150 // TODO(rlarocque): Do something smarter than iterate here. |
153 for (EntityMap::iterator it = entities_.begin(); it != entities_.end(); | 151 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
154 ++it) { | 152 ++it) { |
155 if (it->second->RequiresCommitRequest()) { | 153 if (it->second->RequiresCommitRequest()) { |
156 CommitRequestData request; | 154 CommitRequestData request; |
157 it->second->InitializeCommitRequestData(&request); | 155 it->second->InitializeCommitRequestData(&request); |
158 commit_requests.push_back(request); | 156 commit_requests.push_back(request); |
159 it->second->SetCommitRequestInProgress(); | 157 it->second->SetCommitRequestInProgress(); |
160 } | 158 } |
161 } | 159 } |
162 | 160 |
163 if (!commit_requests.empty()) | 161 if (!commit_requests.empty()) |
164 worker_->EnqueueForCommit(commit_requests); | 162 worker_->EnqueueForCommit(commit_requests); |
165 } | 163 } |
166 | 164 |
167 void ModelTypeSyncProxyImpl::OnCommitCompleted( | 165 void ModelTypeSyncProxyImpl::OnCommitCompleted( |
168 const DataTypeState& type_state, | 166 const DataTypeState& type_state, |
169 const CommitResponseDataList& response_list) { | 167 const CommitResponseDataList& response_list) { |
170 data_type_state_ = type_state; | 168 data_type_state_ = type_state; |
171 | 169 |
172 for (CommitResponseDataList::const_iterator list_it = response_list.begin(); | 170 for (CommitResponseDataList::const_iterator list_it = response_list.begin(); |
173 list_it != response_list.end(); | 171 list_it != response_list.end(); |
174 ++list_it) { | 172 ++list_it) { |
175 const CommitResponseData& response_data = *list_it; | 173 const CommitResponseData& response_data = *list_it; |
176 const std::string& client_tag_hash = response_data.client_tag_hash; | 174 const std::string& client_tag_hash = response_data.client_tag_hash; |
177 | 175 |
178 EntityMap::iterator it = entities_.find(client_tag_hash); | 176 EntityMap::const_iterator it = entities_.find(client_tag_hash); |
179 if (it == entities_.end()) { | 177 if (it == entities_.end()) { |
180 NOTREACHED() << "Received commit response for missing item." | 178 NOTREACHED() << "Received commit response for missing item." |
181 << " type: " << type_ << " client_tag: " << client_tag_hash; | 179 << " type: " << type_ << " client_tag: " << client_tag_hash; |
182 return; | 180 return; |
183 } else { | 181 } else { |
184 it->second->ReceiveCommitResponse(response_data.id, | 182 it->second->ReceiveCommitResponse(response_data.id, |
185 response_data.sequence_number, | 183 response_data.sequence_number, |
186 response_data.response_version, | 184 response_data.response_version, |
187 data_type_state_.encryption_key_name); | 185 data_type_state_.encryption_key_name); |
188 } | 186 } |
189 } | 187 } |
190 } | 188 } |
191 | 189 |
192 void ModelTypeSyncProxyImpl::OnUpdateReceived( | 190 void ModelTypeSyncProxyImpl::OnUpdateReceived( |
193 const DataTypeState& data_type_state, | 191 const DataTypeState& data_type_state, |
194 const UpdateResponseDataList& response_list, | 192 const UpdateResponseDataList& response_list, |
195 const UpdateResponseDataList& pending_updates) { | 193 const UpdateResponseDataList& pending_updates) { |
196 bool got_new_encryption_requirements = data_type_state_.encryption_key_name != | 194 bool got_new_encryption_requirements = data_type_state_.encryption_key_name != |
197 data_type_state.encryption_key_name; | 195 data_type_state.encryption_key_name; |
198 | 196 |
199 data_type_state_ = data_type_state; | 197 data_type_state_ = data_type_state; |
200 | 198 |
201 for (UpdateResponseDataList::const_iterator list_it = response_list.begin(); | 199 for (UpdateResponseDataList::const_iterator list_it = response_list.begin(); |
202 list_it != response_list.end(); | 200 list_it != response_list.end(); |
203 ++list_it) { | 201 ++list_it) { |
204 const UpdateResponseData& response_data = *list_it; | 202 const UpdateResponseData& response_data = *list_it; |
205 const std::string& client_tag_hash = response_data.client_tag_hash; | 203 const std::string& client_tag_hash = response_data.client_tag_hash; |
206 | 204 |
207 UpdateMap::iterator old_it = pending_updates_map_.find(client_tag_hash); | 205 // If we're being asked to apply an update to this entity, this overrides |
208 if (old_it != pending_updates_map_.end()) { | 206 // the previous pending updates. |
209 // If we're being asked to apply an update to this entity, this overrides | 207 pending_updates_map_.erase(client_tag_hash); |
210 // the previous pending updates. | |
211 delete old_it->second; | |
212 pending_updates_map_.erase(old_it); | |
213 } | |
214 | 208 |
215 EntityMap::iterator it = entities_.find(client_tag_hash); | 209 EntityMap::const_iterator it = entities_.find(client_tag_hash); |
216 if (it == entities_.end()) { | 210 if (it == entities_.end()) { |
217 scoped_ptr<ModelTypeEntity> entity = | 211 scoped_ptr<ModelTypeEntity> entity = |
218 ModelTypeEntity::FromServerUpdate(response_data.id, | 212 ModelTypeEntity::FromServerUpdate(response_data.id, |
219 response_data.client_tag_hash, | 213 response_data.client_tag_hash, |
220 response_data.non_unique_name, | 214 response_data.non_unique_name, |
221 response_data.response_version, | 215 response_data.response_version, |
222 response_data.specifics, | 216 response_data.specifics, |
223 response_data.deleted, | 217 response_data.deleted, |
224 response_data.ctime, | 218 response_data.ctime, |
225 response_data.mtime, | 219 response_data.mtime, |
226 response_data.encryption_key_name); | 220 response_data.encryption_key_name); |
227 entities_.insert(std::make_pair(client_tag_hash, entity.release())); | 221 entities_.insert(client_tag_hash, entity.Pass()); |
228 } else { | 222 } else { |
229 ModelTypeEntity* entity = it->second; | 223 ModelTypeEntity* entity = it->second; |
230 entity->ApplyUpdateFromServer(response_data.response_version, | 224 entity->ApplyUpdateFromServer(response_data.response_version, |
231 response_data.deleted, | 225 response_data.deleted, |
232 response_data.specifics, | 226 response_data.specifics, |
233 response_data.mtime, | 227 response_data.mtime, |
234 response_data.encryption_key_name); | 228 response_data.encryption_key_name); |
235 | 229 |
236 // TODO: Do something special when conflicts are detected. | 230 // TODO: Do something special when conflicts are detected. |
237 } | 231 } |
238 | 232 |
239 // If the received entity has out of date encryption, we schedule another | 233 // If the received entity has out of date encryption, we schedule another |
240 // commit to fix it. | 234 // commit to fix it. |
241 if (data_type_state_.encryption_key_name != | 235 if (data_type_state_.encryption_key_name != |
242 response_data.encryption_key_name) { | 236 response_data.encryption_key_name) { |
243 DVLOG(2) << ModelTypeToString(type_) << ": Requesting re-encrypt commit " | 237 DVLOG(2) << ModelTypeToString(type_) << ": Requesting re-encrypt commit " |
244 << response_data.encryption_key_name << " -> " | 238 << response_data.encryption_key_name << " -> " |
245 << data_type_state_.encryption_key_name; | 239 << data_type_state_.encryption_key_name; |
246 EntityMap::iterator it2 = entities_.find(client_tag_hash); | 240 EntityMap::const_iterator it2 = entities_.find(client_tag_hash); |
247 it2->second->UpdateDesiredEncryptionKey( | 241 it2->second->UpdateDesiredEncryptionKey( |
248 data_type_state_.encryption_key_name); | 242 data_type_state_.encryption_key_name); |
249 } | 243 } |
250 } | 244 } |
251 | 245 |
252 // Save pending updates in the appropriate data structure. | 246 // Save pending updates in the appropriate data structure. |
253 for (UpdateResponseDataList::const_iterator list_it = pending_updates.begin(); | 247 for (UpdateResponseDataList::const_iterator list_it = pending_updates.begin(); |
254 list_it != pending_updates.end(); | 248 list_it != pending_updates.end(); |
255 ++list_it) { | 249 ++list_it) { |
256 const UpdateResponseData& update = *list_it; | 250 const UpdateResponseData& update = *list_it; |
257 const std::string& client_tag_hash = update.client_tag_hash; | 251 const std::string& client_tag_hash = update.client_tag_hash; |
258 | 252 |
259 UpdateMap::iterator lookup_it = pending_updates_map_.find(client_tag_hash); | 253 UpdateMap::const_iterator lookup_it = |
| 254 pending_updates_map_.find(client_tag_hash); |
260 if (lookup_it == pending_updates_map_.end()) { | 255 if (lookup_it == pending_updates_map_.end()) { |
261 pending_updates_map_.insert( | 256 pending_updates_map_.insert( |
262 std::make_pair(client_tag_hash, new UpdateResponseData(update))); | 257 client_tag_hash, make_scoped_ptr(new UpdateResponseData(update))); |
263 } else if (lookup_it->second->response_version <= update.response_version) { | 258 } else if (lookup_it->second->response_version <= update.response_version) { |
264 delete lookup_it->second; | |
265 pending_updates_map_.erase(lookup_it); | 259 pending_updates_map_.erase(lookup_it); |
266 pending_updates_map_.insert( | 260 pending_updates_map_.insert( |
267 std::make_pair(client_tag_hash, new UpdateResponseData(update))); | 261 client_tag_hash, make_scoped_ptr(new UpdateResponseData(update))); |
268 } else { | 262 } else { |
269 // Received update is stale, do not overwrite existing. | 263 // Received update is stale, do not overwrite existing. |
270 } | 264 } |
271 } | 265 } |
272 | 266 |
273 if (got_new_encryption_requirements) { | 267 if (got_new_encryption_requirements) { |
274 for (EntityMap::iterator it = entities_.begin(); it != entities_.end(); | 268 for (EntityMap::const_iterator it = entities_.begin(); |
275 ++it) { | 269 it != entities_.end(); ++it) { |
276 it->second->UpdateDesiredEncryptionKey( | 270 it->second->UpdateDesiredEncryptionKey( |
277 data_type_state_.encryption_key_name); | 271 data_type_state_.encryption_key_name); |
278 } | 272 } |
279 } | 273 } |
280 | 274 |
281 // We may have new reasons to commit by the time this function is done. | 275 // We may have new reasons to commit by the time this function is done. |
282 FlushPendingCommitRequests(); | 276 FlushPendingCommitRequests(); |
283 | 277 |
284 // TODO: Inform the model of the new or updated data. | 278 // TODO: Inform the model of the new or updated data. |
285 // TODO: Persist the new data on disk. | 279 // TODO: Persist the new data on disk. |
286 } | 280 } |
287 | 281 |
288 UpdateResponseDataList ModelTypeSyncProxyImpl::GetPendingUpdates() { | 282 UpdateResponseDataList ModelTypeSyncProxyImpl::GetPendingUpdates() { |
289 UpdateResponseDataList pending_updates_list; | 283 UpdateResponseDataList pending_updates_list; |
290 for (UpdateMap::const_iterator it = pending_updates_map_.begin(); | 284 for (UpdateMap::const_iterator it = pending_updates_map_.begin(); |
291 it != pending_updates_map_.end(); | 285 it != pending_updates_map_.end(); |
292 ++it) { | 286 ++it) { |
293 pending_updates_list.push_back(*it->second); | 287 pending_updates_list.push_back(*it->second); |
294 } | 288 } |
295 return pending_updates_list; | 289 return pending_updates_list; |
296 } | 290 } |
297 | 291 |
298 void ModelTypeSyncProxyImpl::ClearTransientSyncState() { | 292 void ModelTypeSyncProxyImpl::ClearTransientSyncState() { |
299 for (EntityMap::iterator it = entities_.begin(); it != entities_.end(); | 293 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
300 ++it) { | 294 ++it) { |
301 it->second->ClearTransientSyncState(); | 295 it->second->ClearTransientSyncState(); |
302 } | 296 } |
303 } | 297 } |
304 | 298 |
305 void ModelTypeSyncProxyImpl::ClearSyncState() { | 299 void ModelTypeSyncProxyImpl::ClearSyncState() { |
306 for (EntityMap::iterator it = entities_.begin(); it != entities_.end(); | 300 for (EntityMap::const_iterator it = entities_.begin(); it != entities_.end(); |
307 ++it) { | 301 ++it) { |
308 it->second->ClearSyncState(); | 302 it->second->ClearSyncState(); |
309 } | 303 } |
310 STLDeleteValues(&pending_updates_map_); | 304 pending_updates_map_.clear(); |
311 data_type_state_ = DataTypeState(); | 305 data_type_state_ = DataTypeState(); |
312 } | 306 } |
313 | 307 |
314 } // namespace syncer | 308 } // namespace syncer |
OLD | NEW |