OLD | NEW |
---|---|
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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/get_commit_ids_command.h" | 5 #include "sync/engine/get_commit_ids.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <utility> | |
9 #include <vector> | 8 #include <vector> |
10 | 9 |
10 #include "base/basictypes.h" | |
11 #include "sync/engine/syncer_util.h" | 11 #include "sync/engine/syncer_util.h" |
12 #include "sync/sessions/nudge_tracker.h" | 12 #include "sync/syncable/directory.h" |
13 #include "sync/syncable/entry.h" | 13 #include "sync/syncable/entry.h" |
14 #include "sync/syncable/nigori_handler.h" | 14 #include "sync/syncable/nigori_handler.h" |
15 #include "sync/syncable/nigori_util.h" | 15 #include "sync/syncable/nigori_util.h" |
16 #include "sync/syncable/syncable_base_transaction.h" | 16 #include "sync/syncable/syncable_base_transaction.h" |
17 #include "sync/syncable/syncable_util.h" | 17 #include "sync/syncable/syncable_util.h" |
18 #include "sync/util/cryptographer.h" | 18 #include "sync/util/cryptographer.h" |
19 | 19 |
20 using std::set; | 20 using std::set; |
21 using std::vector; | 21 using std::vector; |
22 | 22 |
23 namespace syncer { | 23 namespace syncer { |
24 | 24 |
25 using sessions::OrderedCommitSet; | 25 namespace { |
26 using sessions::SyncSession; | |
27 using sessions::StatusController; | |
28 | 26 |
29 GetCommitIdsCommand::GetCommitIdsCommand( | 27 // Forward-declare some helper functions. This gives us more options for |
28 // ordering the function defintions within this file. | |
29 | |
30 void FilterUnreadyEntries( | |
Nicolas Zea
2013/09/09 17:58:15
I think it's useful to keep the function descripti
rlarocque
2013/09/09 18:36:25
Done.
| |
30 syncable::BaseTransaction* trans, | 31 syncable::BaseTransaction* trans, |
31 ModelTypeSet requested_types, | 32 ModelTypeSet requested_types, |
32 const size_t commit_batch_size, | 33 ModelTypeSet encrypted_types, |
33 sessions::OrderedCommitSet* commit_set) | 34 bool passphrase_missing, |
34 : trans_(trans), | 35 const syncable::Directory::Metahandles& unsynced_handles, |
35 requested_types_(requested_types), | 36 std::set<int64>* ready_unsynced_set); |
36 requested_commit_batch_size_(commit_batch_size), | |
37 commit_set_(commit_set) { | |
38 } | |
39 | 37 |
40 GetCommitIdsCommand::~GetCommitIdsCommand() {} | 38 SYNC_EXPORT_PRIVATE void OrderCommitIds( |
39 syncable::BaseTransaction* trans, | |
40 size_t max_entries, | |
41 const std::set<int64>& ready_unsynced_set, | |
42 std::vector<int64>* out); | |
41 | 43 |
42 SyncerError GetCommitIdsCommand::ExecuteImpl(SyncSession* session) { | 44 } // namespace |
45 | |
46 void GetCommitIdsForType( | |
47 syncable::BaseTransaction* trans, | |
48 ModelType type, | |
49 size_t max_entries, | |
50 syncable::Directory::Metahandles* out) { | |
51 syncable::Directory* dir = trans->directory(); | |
52 | |
43 // Gather the full set of unsynced items and store it in the session. They | 53 // Gather the full set of unsynced items and store it in the session. They |
44 // are not in the correct order for commit. | 54 // are not in the correct order for commit. |
45 std::set<int64> ready_unsynced_set; | 55 std::set<int64> ready_unsynced_set; |
46 syncable::Directory::Metahandles all_unsynced_handles; | 56 syncable::Directory::Metahandles all_unsynced_handles; |
47 GetUnsyncedEntries(trans_, | 57 GetUnsyncedEntries(trans, &all_unsynced_handles); |
48 &all_unsynced_handles); | |
49 | 58 |
50 ModelTypeSet encrypted_types; | 59 ModelTypeSet encrypted_types; |
51 bool passphrase_missing = false; | 60 bool passphrase_missing = false; |
52 Cryptographer* cryptographer = | 61 Cryptographer* cryptographer = dir->GetCryptographer(trans); |
53 session->context()-> | |
54 directory()->GetCryptographer(trans_); | |
55 if (cryptographer) { | 62 if (cryptographer) { |
56 encrypted_types = session->context()->directory()->GetNigoriHandler()-> | 63 encrypted_types = dir->GetNigoriHandler()->GetEncryptedTypes(trans); |
57 GetEncryptedTypes(trans_); | |
58 passphrase_missing = cryptographer->has_pending_keys(); | 64 passphrase_missing = cryptographer->has_pending_keys(); |
59 }; | 65 }; |
60 | 66 |
61 // We filter out all unready entries from the set of unsynced handles. This | 67 // We filter out all unready entries from the set of unsynced handles. This |
62 // new set of ready and unsynced items is then what we use to determine what | 68 // new set of ready and unsynced items is then what we use to determine what |
63 // is a candidate for commit. The caller of this SyncerCommand is responsible | 69 // is a candidate for commit. The caller of this SyncerCommand is responsible |
64 // for ensuring that no throttled types are included among the | 70 // for ensuring that no throttled types are included among the |
65 // requested_types. | 71 // requested_types. |
66 FilterUnreadyEntries(trans_, | 72 FilterUnreadyEntries(trans, |
67 requested_types_, | 73 ModelTypeSet(type), |
68 encrypted_types, | 74 encrypted_types, |
69 passphrase_missing, | 75 passphrase_missing, |
70 all_unsynced_handles, | 76 all_unsynced_handles, |
71 &ready_unsynced_set); | 77 &ready_unsynced_set); |
72 | 78 |
73 BuildCommitIds(trans_, | 79 OrderCommitIds(trans, max_entries, ready_unsynced_set, out); |
74 session->context()->routing_info(), | |
75 ready_unsynced_set); | |
76 | 80 |
77 return SYNCER_OK; | 81 for (size_t i = 0; i < out->size(); i++) { |
Nicolas Zea
2013/09/09 17:58:15
put this entire thing in an if (DVLOG_IS_ON(1))?
rlarocque
2013/09/09 18:36:25
I trust the compiler will recognize this is a no-o
| |
82 DVLOG(1) << "Debug commit batch result:" << (*out)[i]; | |
83 } | |
78 } | 84 } |
79 | 85 |
80 namespace { | 86 namespace { |
81 | 87 |
82 bool IsEntryInConflict(const syncable::Entry& entry) { | 88 bool IsEntryInConflict(const syncable::Entry& entry) { |
83 if (entry.Get(syncable::IS_UNSYNCED) && | 89 if (entry.Get(syncable::IS_UNSYNCED) && |
84 entry.Get(syncable::SERVER_VERSION) > 0 && | 90 entry.Get(syncable::SERVER_VERSION) > 0 && |
85 (entry.Get(syncable::SERVER_VERSION) > | 91 (entry.Get(syncable::SERVER_VERSION) > |
86 entry.Get(syncable::BASE_VERSION))) { | 92 entry.Get(syncable::BASE_VERSION))) { |
87 // The local and server versions don't match. The item must be in | 93 // The local and server versions don't match. The item must be in |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
147 | 153 |
148 if (entry.IsRoot()) { | 154 if (entry.IsRoot()) { |
149 NOTREACHED() << "Permanent item became unsynced " << entry; | 155 NOTREACHED() << "Permanent item became unsynced " << entry; |
150 return false; | 156 return false; |
151 } | 157 } |
152 | 158 |
153 DVLOG(2) << "Entry is ready for commit: " << entry; | 159 DVLOG(2) << "Entry is ready for commit: " << entry; |
154 return true; | 160 return true; |
155 } | 161 } |
156 | 162 |
157 } // namespace | 163 // Filters |unsynced_handles| to remove all entries that do not belong to the |
158 | 164 // specified |requested_types|, or are not eligible for a commit at this time. |
159 void GetCommitIdsCommand::FilterUnreadyEntries( | 165 void FilterUnreadyEntries( |
160 syncable::BaseTransaction* trans, | 166 syncable::BaseTransaction* trans, |
161 ModelTypeSet requested_types, | 167 ModelTypeSet requested_types, |
162 ModelTypeSet encrypted_types, | 168 ModelTypeSet encrypted_types, |
163 bool passphrase_missing, | 169 bool passphrase_missing, |
164 const syncable::Directory::Metahandles& unsynced_handles, | 170 const syncable::Directory::Metahandles& unsynced_handles, |
165 std::set<int64>* ready_unsynced_set) { | 171 std::set<int64>* ready_unsynced_set) { |
166 for (syncable::Directory::Metahandles::const_iterator iter = | 172 for (syncable::Directory::Metahandles::const_iterator iter = |
167 unsynced_handles.begin(); iter != unsynced_handles.end(); ++iter) { | 173 unsynced_handles.begin(); iter != unsynced_handles.end(); ++iter) { |
168 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); | 174 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); |
169 if (IsEntryReadyForCommit(requested_types, | 175 if (IsEntryReadyForCommit(requested_types, |
170 encrypted_types, | 176 encrypted_types, |
171 passphrase_missing, | 177 passphrase_missing, |
172 entry)) { | 178 entry)) { |
173 ready_unsynced_set->insert(*iter); | 179 ready_unsynced_set->insert(*iter); |
174 } | 180 } |
175 } | 181 } |
176 } | 182 } |
177 | 183 |
178 bool GetCommitIdsCommand::AddUncommittedParentsAndTheirPredecessors( | 184 // This class helps to implement OrderCommitIds(). Its members track the |
185 // progress of a traversal while its methods extend it. It can return early if | |
186 // the traversal reaches the desired size before the full traversal is complete. | |
187 class Traversal { | |
188 public: | |
189 Traversal( | |
179 syncable::BaseTransaction* trans, | 190 syncable::BaseTransaction* trans, |
180 const ModelSafeRoutingInfo& routes, | 191 int64 max_entries, |
192 syncable::Directory::Metahandles* out); | |
193 ~Traversal(); | |
194 | |
195 // First step of traversal building. Adds non-deleted items in order. | |
196 void AddCreatesAndMoves(const std::set<int64>& ready_unsynced_set); | |
197 | |
198 // Second step of traverals building. Appends deleted items. | |
199 void AddDeletes(const std::set<int64>& ready_unsynced_set); | |
200 | |
201 private: | |
202 // The following functions do not modify the traversal directly. They return | |
203 // their results in the |result| vector instead. | |
204 bool AddUncommittedParentsAndTheirPredecessors( | |
205 const std::set<int64>& ready_unsynced_set, | |
206 const syncable::Entry& item, | |
207 syncable::Directory::Metahandles* result) const; | |
208 | |
209 void TryAddItem(const std::set<int64>& ready_unsynced_set, | |
210 const syncable::Entry& item, | |
211 syncable::Directory::Metahandles* result) const; | |
212 | |
213 void AddItemThenPredecessors( | |
214 const std::set<int64>& ready_unsynced_set, | |
215 const syncable::Entry& item, | |
216 syncable::Directory::Metahandles* result) const; | |
217 | |
218 void AddPredecessorsThenItem( | |
219 const std::set<int64>& ready_unsynced_set, | |
220 const syncable::Entry& item, | |
221 syncable::Directory::Metahandles* result) const; | |
222 | |
223 // Returns true if we've collected enough items. | |
224 bool IsFull() const; | |
225 | |
226 // Returns true if the specified handle is already in the traversal. | |
227 bool HaveItem(int64 handle) const; | |
228 | |
229 // Adds the specified handles to the traversal. | |
230 void AppendManyToTraversal(const syncable::Directory::Metahandles& handles); | |
231 | |
232 // Adds the specifed handle to the traversal. | |
233 void AppendToTraversal(int64 handle); | |
234 | |
235 syncable::Directory::Metahandles* out_; | |
236 std::set<int64> added_handles_; | |
237 const size_t max_entries_; | |
238 syncable::BaseTransaction* trans_; | |
239 | |
240 DISALLOW_COPY_AND_ASSIGN(Traversal); | |
241 }; | |
242 | |
243 Traversal::Traversal( | |
244 syncable::BaseTransaction* trans, | |
245 int64 max_entries, | |
246 syncable::Directory::Metahandles* out) | |
247 : out_(out), | |
248 max_entries_(max_entries), | |
249 trans_(trans) { } | |
250 | |
251 Traversal::~Traversal() {} | |
252 | |
253 bool Traversal::AddUncommittedParentsAndTheirPredecessors( | |
181 const std::set<int64>& ready_unsynced_set, | 254 const std::set<int64>& ready_unsynced_set, |
182 const syncable::Entry& item, | 255 const syncable::Entry& item, |
183 sessions::OrderedCommitSet* result) const { | 256 syncable::Directory::Metahandles* result) const { |
184 OrderedCommitSet item_dependencies(routes); | 257 syncable::Directory::Metahandles dependencies; |
185 syncable::Id parent_id = item.Get(syncable::PARENT_ID); | 258 syncable::Id parent_id = item.Get(syncable::PARENT_ID); |
186 | 259 |
187 // Climb the tree adding entries leaf -> root. | 260 // Climb the tree adding entries leaf -> root. |
188 while (!parent_id.ServerKnows()) { | 261 while (!parent_id.ServerKnows()) { |
189 syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id); | 262 syncable::Entry parent(trans_, syncable::GET_BY_ID, parent_id); |
190 CHECK(parent.good()) << "Bad user-only parent in item path."; | 263 CHECK(parent.good()) << "Bad user-only parent in item path."; |
191 int64 handle = parent.Get(syncable::META_HANDLE); | 264 int64 handle = parent.Get(syncable::META_HANDLE); |
192 if (commit_set_->HaveCommitItem(handle)) { | 265 if (HaveItem(handle)) { |
193 // We've already added this parent (and therefore all of its parents). | 266 // We've already added this parent (and therefore all of its parents). |
194 // We can return early. | 267 // We can return early. |
195 break; | 268 break; |
196 } | 269 } |
197 if (IsEntryInConflict(parent)) { | 270 if (IsEntryInConflict(parent)) { |
198 // We ignore all entries that are children of a conflicing item. Return | 271 // We ignore all entries that are children of a conflicing item. Return |
199 // false immediately to forget the traversal we've built up so far. | 272 // false immediately to forget the traversal we've built up so far. |
200 DVLOG(1) << "Parent was in conflict, omitting " << item; | 273 DVLOG(1) << "Parent was in conflict, omitting " << item; |
201 return false; | 274 return false; |
202 } | 275 } |
203 AddItemThenPredecessors(trans, | 276 AddItemThenPredecessors(ready_unsynced_set, |
204 ready_unsynced_set, | |
205 parent, | 277 parent, |
206 &item_dependencies); | 278 &dependencies); |
207 parent_id = parent.Get(syncable::PARENT_ID); | 279 parent_id = parent.Get(syncable::PARENT_ID); |
208 } | 280 } |
209 | 281 |
210 // Reverse what we added to get the correct order. | 282 // Reverse what we added to get the correct order. |
211 result->AppendReverse(item_dependencies); | 283 result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); |
212 return true; | 284 return true; |
213 } | 285 } |
214 | 286 |
215 // Adds the given item to the list if it is unsynced and ready for commit. | 287 // Adds the given item to the list if it is unsynced and ready for commit. |
216 void GetCommitIdsCommand::TryAddItem(const std::set<int64>& ready_unsynced_set, | 288 void Traversal::TryAddItem(const std::set<int64>& ready_unsynced_set, |
217 const syncable::Entry& item, | 289 const syncable::Entry& item, |
218 OrderedCommitSet* result) const { | 290 syncable::Directory::Metahandles* result) const { |
219 DCHECK(item.Get(syncable::IS_UNSYNCED)); | 291 DCHECK(item.Get(syncable::IS_UNSYNCED)); |
220 int64 item_handle = item.Get(syncable::META_HANDLE); | 292 int64 item_handle = item.Get(syncable::META_HANDLE); |
221 if (ready_unsynced_set.count(item_handle) != 0) { | 293 if (ready_unsynced_set.count(item_handle) != 0) { |
222 result->AddCommitItem(item_handle, item.GetModelType()); | 294 result->push_back(item_handle); |
223 } | 295 } |
224 } | 296 } |
225 | 297 |
226 // Adds the given item, and all its unsynced predecessors. The traversal will | 298 // Adds the given item, and all its unsynced predecessors. The traversal will |
227 // be cut short if any item along the traversal is not IS_UNSYNCED, or if we | 299 // be cut short if any item along the traversal is not IS_UNSYNCED, or if we |
228 // detect that this area of the tree has already been traversed. Items that are | 300 // detect that this area of the tree has already been traversed. Items that are |
229 // not 'ready' for commit (see IsEntryReadyForCommit()) will not be added to the | 301 // not 'ready' for commit (see IsEntryReadyForCommit()) will not be added to the |
230 // list, though they will not stop the traversal. | 302 // list, though they will not stop the traversal. |
231 void GetCommitIdsCommand::AddItemThenPredecessors( | 303 void Traversal::AddItemThenPredecessors( |
232 syncable::BaseTransaction* trans, | |
233 const std::set<int64>& ready_unsynced_set, | 304 const std::set<int64>& ready_unsynced_set, |
234 const syncable::Entry& item, | 305 const syncable::Entry& item, |
235 OrderedCommitSet* result) const { | 306 syncable::Directory::Metahandles* result) const { |
236 int64 item_handle = item.Get(syncable::META_HANDLE); | 307 int64 item_handle = item.Get(syncable::META_HANDLE); |
237 if (commit_set_->HaveCommitItem(item_handle)) { | 308 if (HaveItem(item_handle)) { |
238 // We've already added this item to the commit set, and so must have | 309 // We've already added this item to the commit set, and so must have |
239 // already added the predecessors as well. | 310 // already added the predecessors as well. |
240 return; | 311 return; |
241 } | 312 } |
242 TryAddItem(ready_unsynced_set, item, result); | 313 TryAddItem(ready_unsynced_set, item, result); |
243 if (item.Get(syncable::IS_DEL)) | 314 if (item.Get(syncable::IS_DEL)) |
244 return; // Deleted items have no predecessors. | 315 return; // Deleted items have no predecessors. |
245 | 316 |
246 syncable::Id prev_id = item.GetPredecessorId(); | 317 syncable::Id prev_id = item.GetPredecessorId(); |
247 while (!prev_id.IsRoot()) { | 318 while (!prev_id.IsRoot()) { |
248 syncable::Entry prev(trans, syncable::GET_BY_ID, prev_id); | 319 syncable::Entry prev(trans_, syncable::GET_BY_ID, prev_id); |
249 CHECK(prev.good()) << "Bad id when walking predecessors."; | 320 CHECK(prev.good()) << "Bad id when walking predecessors."; |
250 if (!prev.Get(syncable::IS_UNSYNCED)) { | 321 if (!prev.Get(syncable::IS_UNSYNCED)) { |
251 // We're interested in "runs" of unsynced items. This item breaks | 322 // We're interested in "runs" of unsynced items. This item breaks |
252 // the streak, so we stop traversing. | 323 // the streak, so we stop traversing. |
253 return; | 324 return; |
254 } | 325 } |
255 int64 handle = prev.Get(syncable::META_HANDLE); | 326 int64 handle = prev.Get(syncable::META_HANDLE); |
256 if (commit_set_->HaveCommitItem(handle)) { | 327 if (HaveItem(handle)) { |
257 // We've already added this item to the commit set, and so must have | 328 // We've already added this item to the commit set, and so must have |
258 // already added the predecessors as well. | 329 // already added the predecessors as well. |
259 return; | 330 return; |
260 } | 331 } |
261 TryAddItem(ready_unsynced_set, prev, result); | 332 TryAddItem(ready_unsynced_set, prev, result); |
262 prev_id = prev.GetPredecessorId(); | 333 prev_id = prev.GetPredecessorId(); |
263 } | 334 } |
264 } | 335 } |
265 | 336 |
266 // Same as AddItemThenPredecessor, but the traversal order will be reversed. | 337 // Same as AddItemThenPredecessor, but the traversal order will be reversed. |
267 void GetCommitIdsCommand::AddPredecessorsThenItem( | 338 void Traversal::AddPredecessorsThenItem( |
268 syncable::BaseTransaction* trans, | |
269 const ModelSafeRoutingInfo& routes, | |
270 const std::set<int64>& ready_unsynced_set, | 339 const std::set<int64>& ready_unsynced_set, |
271 const syncable::Entry& item, | 340 const syncable::Entry& item, |
272 OrderedCommitSet* result) const { | 341 syncable::Directory::Metahandles* result) const { |
273 OrderedCommitSet item_dependencies(routes); | 342 syncable::Directory::Metahandles dependencies; |
274 AddItemThenPredecessors(trans, ready_unsynced_set, item, &item_dependencies); | 343 AddItemThenPredecessors(ready_unsynced_set, item, &dependencies); |
275 | 344 |
276 // Reverse what we added to get the correct order. | 345 // Reverse what we added to get the correct order. |
277 result->AppendReverse(item_dependencies); | 346 result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); |
278 } | 347 } |
279 | 348 |
280 bool GetCommitIdsCommand::IsCommitBatchFull() const { | 349 bool Traversal::IsFull() const { |
281 return commit_set_->Size() >= requested_commit_batch_size_; | 350 return out_->size() >= max_entries_; |
282 } | 351 } |
283 | 352 |
284 void GetCommitIdsCommand::AddCreatesAndMoves( | 353 bool Traversal::HaveItem(int64 handle) const { |
285 syncable::BaseTransaction* trans, | 354 return added_handles_.find(handle) != added_handles_.end(); |
286 const ModelSafeRoutingInfo& routes, | 355 } |
356 | |
357 void Traversal::AppendManyToTraversal( | |
358 const syncable::Directory::Metahandles& handles) { | |
359 out_->insert(out_->end(), handles.begin(), handles.end()); | |
360 added_handles_.insert(handles.begin(), handles.end()); | |
361 } | |
362 | |
363 void Traversal::AppendToTraversal(int64 metahandle) { | |
364 out_->push_back(metahandle); | |
365 added_handles_.insert(metahandle); | |
366 } | |
367 | |
368 void Traversal::AddCreatesAndMoves( | |
287 const std::set<int64>& ready_unsynced_set) { | 369 const std::set<int64>& ready_unsynced_set) { |
288 // Add moves and creates, and prepend their uncommitted parents. | 370 // Add moves and creates, and prepend their uncommitted parents. |
289 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); | 371 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); |
290 !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) { | 372 !IsFull() && iter != ready_unsynced_set.end(); ++iter) { |
291 int64 metahandle = *iter; | 373 int64 metahandle = *iter; |
292 if (commit_set_->HaveCommitItem(metahandle)) | 374 if (HaveItem(metahandle)) |
293 continue; | 375 continue; |
294 | 376 |
295 syncable::Entry entry(trans, | 377 syncable::Entry entry(trans_, |
296 syncable::GET_BY_HANDLE, | 378 syncable::GET_BY_HANDLE, |
297 metahandle); | 379 metahandle); |
298 if (!entry.Get(syncable::IS_DEL)) { | 380 if (!entry.Get(syncable::IS_DEL)) { |
299 // We only commit an item + its dependencies if it and all its | 381 // We only commit an item + its dependencies if it and all its |
300 // dependencies are not in conflict. | 382 // dependencies are not in conflict. |
301 OrderedCommitSet item_dependencies(routes); | 383 syncable::Directory::Metahandles item_dependencies; |
302 if (AddUncommittedParentsAndTheirPredecessors( | 384 if (AddUncommittedParentsAndTheirPredecessors( |
303 trans, | |
304 routes, | |
305 ready_unsynced_set, | 385 ready_unsynced_set, |
306 entry, | 386 entry, |
307 &item_dependencies)) { | 387 &item_dependencies)) { |
308 AddPredecessorsThenItem(trans, | 388 AddPredecessorsThenItem(ready_unsynced_set, |
309 routes, | |
310 ready_unsynced_set, | |
311 entry, | 389 entry, |
312 &item_dependencies); | 390 &item_dependencies); |
313 commit_set_->Append(item_dependencies); | 391 AppendManyToTraversal(item_dependencies); |
314 } | 392 } |
315 } | 393 } |
316 } | 394 } |
317 | 395 |
318 // It's possible that we overcommitted while trying to expand dependent | 396 // It's possible that we overcommitted while trying to expand dependent |
319 // items. If so, truncate the set down to the allowed size. | 397 // items. If so, truncate the set down to the allowed size. |
320 commit_set_->Truncate(requested_commit_batch_size_); | 398 if (out_->size() > max_entries_) { |
Nicolas Zea
2013/09/09 17:58:15
nit: remove curly braces
rlarocque
2013/09/09 18:36:25
Done.
| |
399 out_->resize(max_entries_); | |
400 } | |
321 } | 401 } |
322 | 402 |
323 void GetCommitIdsCommand::AddDeletes( | 403 void Traversal::AddDeletes( |
324 syncable::BaseTransaction* trans, | |
325 const std::set<int64>& ready_unsynced_set) { | 404 const std::set<int64>& ready_unsynced_set) { |
326 set<syncable::Id> legal_delete_parents; | 405 set<syncable::Id> legal_delete_parents; |
327 | 406 |
328 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); | 407 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); |
329 !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) { | 408 !IsFull() && iter != ready_unsynced_set.end(); ++iter) { |
330 int64 metahandle = *iter; | 409 int64 metahandle = *iter; |
331 if (commit_set_->HaveCommitItem(metahandle)) | 410 if (HaveItem(metahandle)) |
332 continue; | 411 continue; |
333 | 412 |
334 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, | 413 syncable::Entry entry(trans_, syncable::GET_BY_HANDLE, |
335 metahandle); | 414 metahandle); |
336 | 415 |
337 if (entry.Get(syncable::IS_DEL)) { | 416 if (entry.Get(syncable::IS_DEL)) { |
338 syncable::Entry parent(trans, syncable::GET_BY_ID, | 417 syncable::Entry parent(trans_, syncable::GET_BY_ID, |
339 entry.Get(syncable::PARENT_ID)); | 418 entry.Get(syncable::PARENT_ID)); |
340 // If the parent is deleted and unsynced, then any children of that | 419 // If the parent is deleted and unsynced, then any children of that |
341 // parent don't need to be added to the delete queue. | 420 // parent don't need to be added to the delete queue. |
342 // | 421 // |
343 // Note: the parent could be synced if there was an update deleting a | 422 // Note: the parent could be synced if there was an update deleting a |
344 // folder when we had a deleted all items in it. | 423 // folder when we had a deleted all items in it. |
345 // We may get more updates, or we may want to delete the entry. | 424 // We may get more updates, or we may want to delete the entry. |
346 if (parent.good() && | 425 if (parent.good() && |
347 parent.Get(syncable::IS_DEL) && | 426 parent.Get(syncable::IS_DEL) && |
348 parent.Get(syncable::IS_UNSYNCED)) { | 427 parent.Get(syncable::IS_UNSYNCED)) { |
349 // However, if an entry is moved, these rules can apply differently. | 428 // However, if an entry is moved, these rules can apply differently. |
350 // | 429 // |
351 // If the entry was moved, then the destination parent was deleted, | 430 // If the entry was moved, then the destination parent was deleted, |
352 // then we'll miss it in the roll up. We have to add it in manually. | 431 // then we'll miss it in the roll up. We have to add it in manually. |
353 // TODO(chron): Unit test for move / delete cases: | 432 // TODO(chron): Unit test for move / delete cases: |
354 // Case 1: Locally moved, then parent deleted | 433 // Case 1: Locally moved, then parent deleted |
355 // Case 2: Server moved, then locally issue recursive delete. | 434 // Case 2: Server moved, then locally issue recursive delete. |
356 if (entry.Get(syncable::ID).ServerKnows() && | 435 if (entry.Get(syncable::ID).ServerKnows() && |
357 entry.Get(syncable::PARENT_ID) != | 436 entry.Get(syncable::PARENT_ID) != |
358 entry.Get(syncable::SERVER_PARENT_ID)) { | 437 entry.Get(syncable::SERVER_PARENT_ID)) { |
359 DVLOG(1) << "Inserting moved and deleted entry, will be missed by " | 438 DVLOG(1) << "Inserting moved and deleted entry, will be missed by " |
360 << "delete roll." << entry.Get(syncable::ID); | 439 << "delete roll." << entry.Get(syncable::ID); |
361 | 440 |
362 commit_set_->AddCommitItem(metahandle, entry.GetModelType()); | 441 AppendToTraversal(metahandle); |
363 } | 442 } |
364 | 443 |
365 // Skip this entry since it's a child of a parent that will be | 444 // Skip this entry since it's a child of a parent that will be |
366 // deleted. The server will unroll the delete and delete the | 445 // deleted. The server will unroll the delete and delete the |
367 // child as well. | 446 // child as well. |
368 continue; | 447 continue; |
369 } | 448 } |
370 | 449 |
371 legal_delete_parents.insert(entry.Get(syncable::PARENT_ID)); | 450 legal_delete_parents.insert(entry.Get(syncable::PARENT_ID)); |
372 } | 451 } |
373 } | 452 } |
374 | 453 |
375 // We could store all the potential entries with a particular parent during | 454 // We could store all the potential entries with a particular parent during |
376 // the above scan, but instead we rescan here. This is less efficient, but | 455 // the above scan, but instead we rescan here. This is less efficient, but |
377 // we're dropping memory alloc/dealloc in favor of linear scans of recently | 456 // we're dropping memory alloc/dealloc in favor of linear scans of recently |
378 // examined entries. | 457 // examined entries. |
379 // | 458 // |
380 // Scan through the UnsyncedMetaHandles again. If we have a deleted | 459 // Scan through the UnsyncedMetaHandles again. If we have a deleted |
381 // entry, then check if the parent is in legal_delete_parents. | 460 // entry, then check if the parent is in legal_delete_parents. |
382 // | 461 // |
383 // Parent being in legal_delete_parents means for the child: | 462 // Parent being in legal_delete_parents means for the child: |
384 // a recursive delete is not currently happening (no recent deletes in same | 463 // a recursive delete is not currently happening (no recent deletes in same |
385 // folder) | 464 // folder) |
386 // parent did expect at least one old deleted child | 465 // parent did expect at least one old deleted child |
387 // parent was not deleted | 466 // parent was not deleted |
388 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); | 467 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); |
389 !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) { | 468 !IsFull() && iter != ready_unsynced_set.end(); ++iter) { |
390 int64 metahandle = *iter; | 469 int64 metahandle = *iter; |
391 if (commit_set_->HaveCommitItem(metahandle)) | 470 if (HaveItem(metahandle)) |
392 continue; | 471 continue; |
393 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, | 472 syncable::Entry entry(trans_, syncable::GET_BY_HANDLE, |
394 metahandle); | 473 metahandle); |
395 if (entry.Get(syncable::IS_DEL)) { | 474 if (entry.Get(syncable::IS_DEL)) { |
396 syncable::Id parent_id = entry.Get(syncable::PARENT_ID); | 475 syncable::Id parent_id = entry.Get(syncable::PARENT_ID); |
397 if (legal_delete_parents.count(parent_id)) { | 476 if (legal_delete_parents.count(parent_id)) { |
398 commit_set_->AddCommitItem(metahandle, entry.GetModelType()); | 477 AppendToTraversal(metahandle); |
399 } | 478 } |
400 } | 479 } |
401 } | 480 } |
402 } | 481 } |
403 | 482 |
404 void GetCommitIdsCommand::BuildCommitIds( | 483 // Given a set of commit metahandles that are ready for commit |
484 // (|ready_unsynced_set|), sorts these into commit order and places up to | |
485 // |max_entries| of them in the output parameter |out|. | |
486 // | |
487 // See the header file for an explanation of commit ordering. | |
488 void OrderCommitIds( | |
405 syncable::BaseTransaction* trans, | 489 syncable::BaseTransaction* trans, |
406 const ModelSafeRoutingInfo& routes, | 490 size_t max_entries, |
407 const std::set<int64>& ready_unsynced_set) { | 491 const std::set<int64>& ready_unsynced_set, |
492 syncable::Directory::Metahandles* out) { | |
408 // Commits follow these rules: | 493 // Commits follow these rules: |
409 // 1. Moves or creates are preceded by needed folder creates, from | 494 // 1. Moves or creates are preceded by needed folder creates, from |
410 // root to leaf. For folders whose contents are ordered, moves | 495 // root to leaf. For folders whose contents are ordered, moves |
411 // and creates appear in order. | 496 // and creates appear in order. |
412 // 2. Moves/Creates before deletes. | 497 // 2. Moves/Creates before deletes. |
413 // 3. Deletes, collapsed. | 498 // 3. Deletes, collapsed. |
414 // We commit deleted moves under deleted items as moves when collapsing | 499 // We commit deleted moves under deleted items as moves when collapsing |
415 // delete trees. | 500 // delete trees. |
416 | 501 |
502 Traversal traversal(trans, max_entries, out); | |
503 | |
417 // Add moves and creates, and prepend their uncommitted parents. | 504 // Add moves and creates, and prepend their uncommitted parents. |
418 AddCreatesAndMoves(trans, routes, ready_unsynced_set); | 505 traversal.AddCreatesAndMoves(ready_unsynced_set); |
419 | 506 |
420 // Add all deletes. | 507 // Add all deletes. |
421 AddDeletes(trans, ready_unsynced_set); | 508 traversal.AddDeletes(ready_unsynced_set); |
509 } | |
510 | |
511 } // namespace | |
512 | |
513 void GetCommitIds( | |
514 syncable::BaseTransaction* trans, | |
515 ModelTypeSet requested_types, | |
516 size_t commit_batch_size, | |
517 sessions::OrderedCommitSet* ordered_commit_set) { | |
518 for (ModelTypeSet::Iterator it = requested_types.First(); | |
519 it.Good(); it.Inc()) { | |
520 DCHECK_LE(ordered_commit_set->Size(), commit_batch_size); | |
521 if (ordered_commit_set->Size() >= commit_batch_size) | |
522 break; | |
523 size_t space_remaining = commit_batch_size - ordered_commit_set->Size(); | |
524 syncable::Directory::Metahandles out; | |
525 GetCommitIdsForType( | |
526 trans, | |
527 it.Get(), | |
528 space_remaining, | |
529 &out); | |
530 ordered_commit_set->AddCommitItems(out, it.Get()); | |
531 } | |
422 } | 532 } |
423 | 533 |
424 } // namespace syncer | 534 } // namespace syncer |
OLD | NEW |