Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(413)

Side by Side Diff: sync/engine/get_commit_ids.cc

Issue 23809005: sync: Implement per-type GetCommitIds (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove unnecessary whitespace Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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(
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++)
82 DVLOG(1) << "Debug commit batch result:" << (*out)[i];
tim (not reviewing) 2013/09/08 19:48:20 nit - It's a generally followed convention / good
rlarocque 2013/09/09 17:41:29 Done.
78 } 83 }
79 84
80 namespace { 85 namespace {
81 86
82 bool IsEntryInConflict(const syncable::Entry& entry) { 87 bool IsEntryInConflict(const syncable::Entry& entry) {
83 if (entry.Get(syncable::IS_UNSYNCED) && 88 if (entry.Get(syncable::IS_UNSYNCED) &&
84 entry.Get(syncable::SERVER_VERSION) > 0 && 89 entry.Get(syncable::SERVER_VERSION) > 0 &&
85 (entry.Get(syncable::SERVER_VERSION) > 90 (entry.Get(syncable::SERVER_VERSION) >
86 entry.Get(syncable::BASE_VERSION))) { 91 entry.Get(syncable::BASE_VERSION))) {
87 // The local and server versions don't match. The item must be in 92 // 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
147 152
148 if (entry.IsRoot()) { 153 if (entry.IsRoot()) {
149 NOTREACHED() << "Permanent item became unsynced " << entry; 154 NOTREACHED() << "Permanent item became unsynced " << entry;
150 return false; 155 return false;
151 } 156 }
152 157
153 DVLOG(2) << "Entry is ready for commit: " << entry; 158 DVLOG(2) << "Entry is ready for commit: " << entry;
154 return true; 159 return true;
155 } 160 }
156 161
157 } // namespace 162 // Filters |unsynced_handles| to remove all entries that do not belong to the
158 163 // specified |requested_types|, or are not eligible for a commit at this time.
159 void GetCommitIdsCommand::FilterUnreadyEntries( 164 void FilterUnreadyEntries(
160 syncable::BaseTransaction* trans, 165 syncable::BaseTransaction* trans,
161 ModelTypeSet requested_types, 166 ModelTypeSet requested_types,
162 ModelTypeSet encrypted_types, 167 ModelTypeSet encrypted_types,
163 bool passphrase_missing, 168 bool passphrase_missing,
164 const syncable::Directory::Metahandles& unsynced_handles, 169 const syncable::Directory::Metahandles& unsynced_handles,
165 std::set<int64>* ready_unsynced_set) { 170 std::set<int64>* ready_unsynced_set) {
166 for (syncable::Directory::Metahandles::const_iterator iter = 171 for (syncable::Directory::Metahandles::const_iterator iter =
167 unsynced_handles.begin(); iter != unsynced_handles.end(); ++iter) { 172 unsynced_handles.begin(); iter != unsynced_handles.end(); ++iter) {
168 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); 173 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter);
169 if (IsEntryReadyForCommit(requested_types, 174 if (IsEntryReadyForCommit(requested_types,
170 encrypted_types, 175 encrypted_types,
171 passphrase_missing, 176 passphrase_missing,
172 entry)) { 177 entry)) {
173 ready_unsynced_set->insert(*iter); 178 ready_unsynced_set->insert(*iter);
174 } 179 }
175 } 180 }
176 } 181 }
177 182
178 bool GetCommitIdsCommand::AddUncommittedParentsAndTheirPredecessors( 183 // This class helps to implement OrderCommitIds(). Its members track the
184 // progress of a traversal while its methods extend it. It can return early if
185 // the traversal reaches the desired size before the full traversal is complete.
186 class Traversal {
187 public:
188 Traversal(
179 syncable::BaseTransaction* trans, 189 syncable::BaseTransaction* trans,
180 const ModelSafeRoutingInfo& routes, 190 int64 max_entries,
191 syncable::Directory::Metahandles* out);
192 ~Traversal();
193
194 // First step of traversal building. Adds non-deleted items in order.
195 void AddCreatesAndMoves(const std::set<int64>& ready_unsynced_set);
196
197 // Second step of traverals building. Appends deleted items.
198 void AddDeletes(const std::set<int64>& ready_unsynced_set);
199
200 private:
201 // The following functions do not modify the traversal directly. They return
202 // their results in the |result| vector instead.
203 bool AddUncommittedParentsAndTheirPredecessors(
204 const std::set<int64>& ready_unsynced_set,
205 const syncable::Entry& item,
206 syncable::Directory::Metahandles* result) const;
207
208 void TryAddItem(const std::set<int64>& ready_unsynced_set,
209 const syncable::Entry& item,
210 syncable::Directory::Metahandles* result) const;
211
212 void AddItemThenPredecessors(
213 const std::set<int64>& ready_unsynced_set,
214 const syncable::Entry& item,
215 syncable::Directory::Metahandles* result) const;
216
217 void AddPredecessorsThenItem(
218 const std::set<int64>& ready_unsynced_set,
219 const syncable::Entry& item,
220 syncable::Directory::Metahandles* result) const;
221
222 // Returns true if we've collected enough items.
223 bool IsFull() const;
224
225 // Returns true if the specified handle is already in the traversal.
226 bool HaveItem(int64 handle) const;
227
228 // Adds the specified handles to the traversal.
229 void AppendManyToTraversal(const syncable::Directory::Metahandles& handles);
230
231 // Adds the specifed handle to the traversal.
232 void AppendToTraversal(int64 handle);
233
234 syncable::Directory::Metahandles* out_;
235 std::set<int64> added_handles_;
236 const size_t max_entries_;
237 syncable::BaseTransaction* trans_;
238
239 DISALLOW_COPY_AND_ASSIGN(Traversal);
240 };
241
242 Traversal::Traversal(
243 syncable::BaseTransaction* trans,
244 int64 max_entries,
245 syncable::Directory::Metahandles* out)
246 : out_(out),
247 max_entries_(max_entries),
248 trans_(trans) { }
249
250 Traversal::~Traversal() {}
251
252 bool Traversal::AddUncommittedParentsAndTheirPredecessors(
181 const std::set<int64>& ready_unsynced_set, 253 const std::set<int64>& ready_unsynced_set,
182 const syncable::Entry& item, 254 const syncable::Entry& item,
183 sessions::OrderedCommitSet* result) const { 255 syncable::Directory::Metahandles* result) const {
184 OrderedCommitSet item_dependencies(routes); 256 syncable::Directory::Metahandles dependencies;
185 syncable::Id parent_id = item.Get(syncable::PARENT_ID); 257 syncable::Id parent_id = item.Get(syncable::PARENT_ID);
186 258
187 // Climb the tree adding entries leaf -> root. 259 // Climb the tree adding entries leaf -> root.
188 while (!parent_id.ServerKnows()) { 260 while (!parent_id.ServerKnows()) {
189 syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id); 261 syncable::Entry parent(trans_, syncable::GET_BY_ID, parent_id);
190 CHECK(parent.good()) << "Bad user-only parent in item path."; 262 CHECK(parent.good()) << "Bad user-only parent in item path.";
191 int64 handle = parent.Get(syncable::META_HANDLE); 263 int64 handle = parent.Get(syncable::META_HANDLE);
192 if (commit_set_->HaveCommitItem(handle)) { 264 if (HaveItem(handle)) {
193 // We've already added this parent (and therefore all of its parents). 265 // We've already added this parent (and therefore all of its parents).
194 // We can return early. 266 // We can return early.
195 break; 267 break;
196 } 268 }
197 if (IsEntryInConflict(parent)) { 269 if (IsEntryInConflict(parent)) {
198 // We ignore all entries that are children of a conflicing item. Return 270 // 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. 271 // false immediately to forget the traversal we've built up so far.
200 DVLOG(1) << "Parent was in conflict, omitting " << item; 272 DVLOG(1) << "Parent was in conflict, omitting " << item;
201 return false; 273 return false;
202 } 274 }
203 AddItemThenPredecessors(trans, 275 AddItemThenPredecessors(ready_unsynced_set,
204 ready_unsynced_set,
205 parent, 276 parent,
206 &item_dependencies); 277 &dependencies);
207 parent_id = parent.Get(syncable::PARENT_ID); 278 parent_id = parent.Get(syncable::PARENT_ID);
208 } 279 }
209 280
210 // Reverse what we added to get the correct order. 281 // Reverse what we added to get the correct order.
211 result->AppendReverse(item_dependencies); 282 result->insert(result->end(), dependencies.rbegin(), dependencies.rend());
212 return true; 283 return true;
213 } 284 }
214 285
215 // Adds the given item to the list if it is unsynced and ready for commit. 286 // 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, 287 void Traversal::TryAddItem(const std::set<int64>& ready_unsynced_set,
217 const syncable::Entry& item, 288 const syncable::Entry& item,
218 OrderedCommitSet* result) const { 289 syncable::Directory::Metahandles* result) const {
219 DCHECK(item.Get(syncable::IS_UNSYNCED)); 290 DCHECK(item.Get(syncable::IS_UNSYNCED));
220 int64 item_handle = item.Get(syncable::META_HANDLE); 291 int64 item_handle = item.Get(syncable::META_HANDLE);
221 if (ready_unsynced_set.count(item_handle) != 0) { 292 if (ready_unsynced_set.count(item_handle) != 0) {
222 result->AddCommitItem(item_handle, item.GetModelType()); 293 result->push_back(item_handle);
223 } 294 }
224 } 295 }
225 296
226 // Adds the given item, and all its unsynced predecessors. The traversal will 297 // 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 298 // 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 299 // 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 300 // not 'ready' for commit (see IsEntryReadyForCommit()) will not be added to the
230 // list, though they will not stop the traversal. 301 // list, though they will not stop the traversal.
231 void GetCommitIdsCommand::AddItemThenPredecessors( 302 void Traversal::AddItemThenPredecessors(
232 syncable::BaseTransaction* trans,
233 const std::set<int64>& ready_unsynced_set, 303 const std::set<int64>& ready_unsynced_set,
234 const syncable::Entry& item, 304 const syncable::Entry& item,
235 OrderedCommitSet* result) const { 305 syncable::Directory::Metahandles* result) const {
236 int64 item_handle = item.Get(syncable::META_HANDLE); 306 int64 item_handle = item.Get(syncable::META_HANDLE);
237 if (commit_set_->HaveCommitItem(item_handle)) { 307 if (HaveItem(item_handle)) {
238 // We've already added this item to the commit set, and so must have 308 // We've already added this item to the commit set, and so must have
239 // already added the predecessors as well. 309 // already added the predecessors as well.
240 return; 310 return;
241 } 311 }
242 TryAddItem(ready_unsynced_set, item, result); 312 TryAddItem(ready_unsynced_set, item, result);
243 if (item.Get(syncable::IS_DEL)) 313 if (item.Get(syncable::IS_DEL))
244 return; // Deleted items have no predecessors. 314 return; // Deleted items have no predecessors.
245 315
246 syncable::Id prev_id = item.GetPredecessorId(); 316 syncable::Id prev_id = item.GetPredecessorId();
247 while (!prev_id.IsRoot()) { 317 while (!prev_id.IsRoot()) {
248 syncable::Entry prev(trans, syncable::GET_BY_ID, prev_id); 318 syncable::Entry prev(trans_, syncable::GET_BY_ID, prev_id);
249 CHECK(prev.good()) << "Bad id when walking predecessors."; 319 CHECK(prev.good()) << "Bad id when walking predecessors.";
250 if (!prev.Get(syncable::IS_UNSYNCED)) { 320 if (!prev.Get(syncable::IS_UNSYNCED)) {
251 // We're interested in "runs" of unsynced items. This item breaks 321 // We're interested in "runs" of unsynced items. This item breaks
252 // the streak, so we stop traversing. 322 // the streak, so we stop traversing.
253 return; 323 return;
254 } 324 }
255 int64 handle = prev.Get(syncable::META_HANDLE); 325 int64 handle = prev.Get(syncable::META_HANDLE);
256 if (commit_set_->HaveCommitItem(handle)) { 326 if (HaveItem(handle)) {
257 // We've already added this item to the commit set, and so must have 327 // We've already added this item to the commit set, and so must have
258 // already added the predecessors as well. 328 // already added the predecessors as well.
259 return; 329 return;
260 } 330 }
261 TryAddItem(ready_unsynced_set, prev, result); 331 TryAddItem(ready_unsynced_set, prev, result);
262 prev_id = prev.GetPredecessorId(); 332 prev_id = prev.GetPredecessorId();
263 } 333 }
264 } 334 }
265 335
266 // Same as AddItemThenPredecessor, but the traversal order will be reversed. 336 // Same as AddItemThenPredecessor, but the traversal order will be reversed.
267 void GetCommitIdsCommand::AddPredecessorsThenItem( 337 void Traversal::AddPredecessorsThenItem(
268 syncable::BaseTransaction* trans,
269 const ModelSafeRoutingInfo& routes,
270 const std::set<int64>& ready_unsynced_set, 338 const std::set<int64>& ready_unsynced_set,
271 const syncable::Entry& item, 339 const syncable::Entry& item,
272 OrderedCommitSet* result) const { 340 syncable::Directory::Metahandles* result) const {
273 OrderedCommitSet item_dependencies(routes); 341 syncable::Directory::Metahandles dependencies;
274 AddItemThenPredecessors(trans, ready_unsynced_set, item, &item_dependencies); 342 AddItemThenPredecessors(ready_unsynced_set, item, &dependencies);
275 343
276 // Reverse what we added to get the correct order. 344 // Reverse what we added to get the correct order.
277 result->AppendReverse(item_dependencies); 345 result->insert(result->end(), dependencies.rbegin(), dependencies.rend());
278 } 346 }
279 347
280 bool GetCommitIdsCommand::IsCommitBatchFull() const { 348 bool Traversal::IsFull() const {
281 return commit_set_->Size() >= requested_commit_batch_size_; 349 return out_->size() >= max_entries_;
282 } 350 }
283 351
284 void GetCommitIdsCommand::AddCreatesAndMoves( 352 bool Traversal::HaveItem(int64 handle) const {
285 syncable::BaseTransaction* trans, 353 return added_handles_.find(handle) != added_handles_.end();
286 const ModelSafeRoutingInfo& routes, 354 }
355
356 void Traversal::AppendManyToTraversal(
357 const syncable::Directory::Metahandles& handles) {
358 out_->insert(out_->end(), handles.begin(), handles.end());
359 added_handles_.insert(handles.begin(), handles.end());
360 }
361
362 void Traversal::AppendToTraversal(int64 metahandle) {
363 out_->push_back(metahandle);
364 added_handles_.insert(metahandle);
365 }
366
367 void Traversal::AddCreatesAndMoves(
287 const std::set<int64>& ready_unsynced_set) { 368 const std::set<int64>& ready_unsynced_set) {
288 // Add moves and creates, and prepend their uncommitted parents. 369 // Add moves and creates, and prepend their uncommitted parents.
289 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); 370 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin();
290 !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) { 371 !IsFull() && iter != ready_unsynced_set.end(); ++iter) {
291 int64 metahandle = *iter; 372 int64 metahandle = *iter;
292 if (commit_set_->HaveCommitItem(metahandle)) 373 if (HaveItem(metahandle))
293 continue; 374 continue;
294 375
295 syncable::Entry entry(trans, 376 syncable::Entry entry(trans_,
296 syncable::GET_BY_HANDLE, 377 syncable::GET_BY_HANDLE,
297 metahandle); 378 metahandle);
298 if (!entry.Get(syncable::IS_DEL)) { 379 if (!entry.Get(syncable::IS_DEL)) {
299 // We only commit an item + its dependencies if it and all its 380 // We only commit an item + its dependencies if it and all its
300 // dependencies are not in conflict. 381 // dependencies are not in conflict.
301 OrderedCommitSet item_dependencies(routes); 382 syncable::Directory::Metahandles item_dependencies;
302 if (AddUncommittedParentsAndTheirPredecessors( 383 if (AddUncommittedParentsAndTheirPredecessors(
303 trans,
304 routes,
305 ready_unsynced_set, 384 ready_unsynced_set,
306 entry, 385 entry,
307 &item_dependencies)) { 386 &item_dependencies)) {
308 AddPredecessorsThenItem(trans, 387 AddPredecessorsThenItem(ready_unsynced_set,
309 routes,
310 ready_unsynced_set,
311 entry, 388 entry,
312 &item_dependencies); 389 &item_dependencies);
313 commit_set_->Append(item_dependencies); 390 AppendManyToTraversal(item_dependencies);
314 } 391 }
315 } 392 }
316 } 393 }
317 394
318 // It's possible that we overcommitted while trying to expand dependent 395 // It's possible that we overcommitted while trying to expand dependent
319 // items. If so, truncate the set down to the allowed size. 396 // items. If so, truncate the set down to the allowed size.
320 commit_set_->Truncate(requested_commit_batch_size_); 397 if (out_->size() > max_entries_) {
398 out_->resize(max_entries_);
399 }
321 } 400 }
322 401
323 void GetCommitIdsCommand::AddDeletes( 402 void Traversal::AddDeletes(
324 syncable::BaseTransaction* trans,
325 const std::set<int64>& ready_unsynced_set) { 403 const std::set<int64>& ready_unsynced_set) {
326 set<syncable::Id> legal_delete_parents; 404 set<syncable::Id> legal_delete_parents;
327 405
328 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); 406 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin();
329 !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) { 407 !IsFull() && iter != ready_unsynced_set.end(); ++iter) {
330 int64 metahandle = *iter; 408 int64 metahandle = *iter;
331 if (commit_set_->HaveCommitItem(metahandle)) 409 if (HaveItem(metahandle))
332 continue; 410 continue;
333 411
334 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, 412 syncable::Entry entry(trans_, syncable::GET_BY_HANDLE,
335 metahandle); 413 metahandle);
336 414
337 if (entry.Get(syncable::IS_DEL)) { 415 if (entry.Get(syncable::IS_DEL)) {
338 syncable::Entry parent(trans, syncable::GET_BY_ID, 416 syncable::Entry parent(trans_, syncable::GET_BY_ID,
339 entry.Get(syncable::PARENT_ID)); 417 entry.Get(syncable::PARENT_ID));
340 // If the parent is deleted and unsynced, then any children of that 418 // If the parent is deleted and unsynced, then any children of that
341 // parent don't need to be added to the delete queue. 419 // parent don't need to be added to the delete queue.
342 // 420 //
343 // Note: the parent could be synced if there was an update deleting a 421 // Note: the parent could be synced if there was an update deleting a
344 // folder when we had a deleted all items in it. 422 // folder when we had a deleted all items in it.
345 // We may get more updates, or we may want to delete the entry. 423 // We may get more updates, or we may want to delete the entry.
346 if (parent.good() && 424 if (parent.good() &&
347 parent.Get(syncable::IS_DEL) && 425 parent.Get(syncable::IS_DEL) &&
348 parent.Get(syncable::IS_UNSYNCED)) { 426 parent.Get(syncable::IS_UNSYNCED)) {
349 // However, if an entry is moved, these rules can apply differently. 427 // However, if an entry is moved, these rules can apply differently.
350 // 428 //
351 // If the entry was moved, then the destination parent was deleted, 429 // 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. 430 // 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: 431 // TODO(chron): Unit test for move / delete cases:
354 // Case 1: Locally moved, then parent deleted 432 // Case 1: Locally moved, then parent deleted
355 // Case 2: Server moved, then locally issue recursive delete. 433 // Case 2: Server moved, then locally issue recursive delete.
356 if (entry.Get(syncable::ID).ServerKnows() && 434 if (entry.Get(syncable::ID).ServerKnows() &&
357 entry.Get(syncable::PARENT_ID) != 435 entry.Get(syncable::PARENT_ID) !=
358 entry.Get(syncable::SERVER_PARENT_ID)) { 436 entry.Get(syncable::SERVER_PARENT_ID)) {
359 DVLOG(1) << "Inserting moved and deleted entry, will be missed by " 437 DVLOG(1) << "Inserting moved and deleted entry, will be missed by "
360 << "delete roll." << entry.Get(syncable::ID); 438 << "delete roll." << entry.Get(syncable::ID);
361 439
362 commit_set_->AddCommitItem(metahandle, entry.GetModelType()); 440 AppendToTraversal(metahandle);
363 } 441 }
364 442
365 // Skip this entry since it's a child of a parent that will be 443 // 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 444 // deleted. The server will unroll the delete and delete the
367 // child as well. 445 // child as well.
368 continue; 446 continue;
369 } 447 }
370 448
371 legal_delete_parents.insert(entry.Get(syncable::PARENT_ID)); 449 legal_delete_parents.insert(entry.Get(syncable::PARENT_ID));
372 } 450 }
373 } 451 }
374 452
375 // We could store all the potential entries with a particular parent during 453 // 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 454 // 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 455 // we're dropping memory alloc/dealloc in favor of linear scans of recently
378 // examined entries. 456 // examined entries.
379 // 457 //
380 // Scan through the UnsyncedMetaHandles again. If we have a deleted 458 // Scan through the UnsyncedMetaHandles again. If we have a deleted
381 // entry, then check if the parent is in legal_delete_parents. 459 // entry, then check if the parent is in legal_delete_parents.
382 // 460 //
383 // Parent being in legal_delete_parents means for the child: 461 // Parent being in legal_delete_parents means for the child:
384 // a recursive delete is not currently happening (no recent deletes in same 462 // a recursive delete is not currently happening (no recent deletes in same
385 // folder) 463 // folder)
386 // parent did expect at least one old deleted child 464 // parent did expect at least one old deleted child
387 // parent was not deleted 465 // parent was not deleted
388 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin(); 466 for (std::set<int64>::const_iterator iter = ready_unsynced_set.begin();
389 !IsCommitBatchFull() && iter != ready_unsynced_set.end(); ++iter) { 467 !IsFull() && iter != ready_unsynced_set.end(); ++iter) {
390 int64 metahandle = *iter; 468 int64 metahandle = *iter;
391 if (commit_set_->HaveCommitItem(metahandle)) 469 if (HaveItem(metahandle))
392 continue; 470 continue;
393 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, 471 syncable::Entry entry(trans_, syncable::GET_BY_HANDLE,
394 metahandle); 472 metahandle);
395 if (entry.Get(syncable::IS_DEL)) { 473 if (entry.Get(syncable::IS_DEL)) {
396 syncable::Id parent_id = entry.Get(syncable::PARENT_ID); 474 syncable::Id parent_id = entry.Get(syncable::PARENT_ID);
397 if (legal_delete_parents.count(parent_id)) { 475 if (legal_delete_parents.count(parent_id)) {
398 commit_set_->AddCommitItem(metahandle, entry.GetModelType()); 476 AppendToTraversal(metahandle);
399 } 477 }
400 } 478 }
401 } 479 }
402 } 480 }
403 481
404 void GetCommitIdsCommand::BuildCommitIds( 482 // Given a set of commit metahandles that are ready for commit
483 // (|ready_unsynced_set|), sorts these into commit order and places up to
484 // |max_entries| of them in the output parameter |out|.
485 //
486 // In "commit order", the metahandles are ordered so that parents are before
487 // children, and predecessors are before successors. Deletions are always
488 // placed last.
tim (not reviewing) 2013/09/08 19:48:20 Wouldn't hurt to put this in the header file where
rlarocque 2013/09/09 17:41:29 Done.
489 //
490 // Since the implementation of UniquePositions, it is probably no longer
tim (not reviewing) 2013/09/08 19:48:20 nit - It's better to succinctly state why things w
rlarocque 2013/09/09 17:41:29 I don't think it can be avoided in this case. The
491 // necessary to put predecessors before successors. That functionality may be
492 // removed in the future.
tim (not reviewing) 2013/09/08 19:48:20 nit - bug or todo for things that "may be removed
rlarocque 2013/09/09 17:41:29 Done.
493 void OrderCommitIds(
405 syncable::BaseTransaction* trans, 494 syncable::BaseTransaction* trans,
406 const ModelSafeRoutingInfo& routes, 495 size_t max_entries,
407 const std::set<int64>& ready_unsynced_set) { 496 const std::set<int64>& ready_unsynced_set,
497 syncable::Directory::Metahandles* out) {
408 // Commits follow these rules: 498 // Commits follow these rules:
409 // 1. Moves or creates are preceded by needed folder creates, from 499 // 1. Moves or creates are preceded by needed folder creates, from
410 // root to leaf. For folders whose contents are ordered, moves 500 // root to leaf. For folders whose contents are ordered, moves
411 // and creates appear in order. 501 // and creates appear in order.
412 // 2. Moves/Creates before deletes. 502 // 2. Moves/Creates before deletes.
413 // 3. Deletes, collapsed. 503 // 3. Deletes, collapsed.
414 // We commit deleted moves under deleted items as moves when collapsing 504 // We commit deleted moves under deleted items as moves when collapsing
415 // delete trees. 505 // delete trees.
416 506
507 Traversal traversal(trans, max_entries, out);
508
417 // Add moves and creates, and prepend their uncommitted parents. 509 // Add moves and creates, and prepend their uncommitted parents.
418 AddCreatesAndMoves(trans, routes, ready_unsynced_set); 510 traversal.AddCreatesAndMoves(ready_unsynced_set);
419 511
420 // Add all deletes. 512 // Add all deletes.
421 AddDeletes(trans, ready_unsynced_set); 513 traversal.AddDeletes(ready_unsynced_set);
514 }
515
516 } // namespace
517
518 void GetCommitIds(
519 syncable::BaseTransaction* trans,
520 ModelTypeSet requested_types,
521 size_t commit_batch_size,
522 sessions::OrderedCommitSet* ordered_commit_set) {
523 for (ModelTypeSet::Iterator it = requested_types.First();
524 it.Good(); it.Inc()) {
525 DCHECK_LE(ordered_commit_set->Size(), commit_batch_size);
526 if (ordered_commit_set->Size() >= commit_batch_size)
527 break;
528 size_t space_remaining = commit_batch_size - ordered_commit_set->Size();
529 syncable::Directory::Metahandles out;
530 GetCommitIdsForType(
531 trans,
532 it.Get(),
533 space_remaining,
534 &out);
535 ordered_commit_set->AddCommitItems(out, it.Get());
536 }
422 } 537 }
423 538
424 } // namespace syncer 539 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698