| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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.h" | 5 #include "sync/engine/get_commit_ids.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <set> | 10 #include <set> |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 bool HasAttachmentNotOnServer(const syncable::Entry& entry) { | 112 bool HasAttachmentNotOnServer(const syncable::Entry& entry) { |
| 113 const sync_pb::AttachmentMetadata& metadata = entry.GetAttachmentMetadata(); | 113 const sync_pb::AttachmentMetadata& metadata = entry.GetAttachmentMetadata(); |
| 114 for (int i = 0; i < metadata.record_size(); ++i) { | 114 for (int i = 0; i < metadata.record_size(); ++i) { |
| 115 if (!metadata.record(i).is_on_server()) { | 115 if (!metadata.record(i).is_on_server()) { |
| 116 return true; | 116 return true; |
| 117 } | 117 } |
| 118 } | 118 } |
| 119 return false; | 119 return false; |
| 120 } | 120 } |
| 121 | 121 |
| 122 // An entry is not considered ready for commit if any are true: | 122 // An entry may not commit if any are true: |
| 123 // 1. It's in conflict. | 123 // 1. It requires encryption (either the type is encrypted but a passphrase |
| 124 // 2. It requires encryption (either the type is encrypted but a passphrase | |
| 125 // is missing from the cryptographer, or the entry itself wasn't properly | 124 // is missing from the cryptographer, or the entry itself wasn't properly |
| 126 // encrypted). | 125 // encrypted). |
| 127 // 3. It's type is currently throttled. | 126 // 2. It's type is currently throttled. |
| 128 // 4. It's a delete but has not been committed. | 127 // 3. It's a delete but has not been committed. |
| 129 bool IsEntryReadyForCommit(ModelTypeSet requested_types, | 128 bool MayEntryCommit(ModelTypeSet requested_types, |
| 130 ModelTypeSet encrypted_types, | 129 ModelTypeSet encrypted_types, |
| 131 bool passphrase_missing, | 130 bool passphrase_missing, |
| 132 const syncable::Entry& entry) { | 131 const syncable::Entry& entry) { |
| 133 DCHECK(entry.GetIsUnsynced()); | 132 DCHECK(entry.GetIsUnsynced()); |
| 134 if (IsEntryInConflict(entry)) | |
| 135 return false; | |
| 136 | 133 |
| 137 const ModelType type = entry.GetModelType(); | 134 const ModelType type = entry.GetModelType(); |
| 138 // We special case the nigori node because even though it is considered an | 135 // We special case the nigori node because even though it is considered an |
| 139 // "encrypted type", not all nigori node changes require valid encryption | 136 // "encrypted type", not all nigori node changes require valid encryption |
| 140 // (ex: sync_tabs). | 137 // (ex: sync_tabs). |
| 141 if ((type != NIGORI) && encrypted_types.Has(type) && | 138 if ((type != NIGORI) && encrypted_types.Has(type) && |
| 142 (passphrase_missing || | 139 (passphrase_missing || |
| 143 syncable::EntryNeedsEncryption(encrypted_types, entry))) { | 140 syncable::EntryNeedsEncryption(encrypted_types, entry))) { |
| 144 // This entry requires encryption but is not properly encrypted (possibly | 141 // This entry requires encryption but is not properly encrypted (possibly |
| 145 // due to the cryptographer not being initialized or the user hasn't | 142 // due to the cryptographer not being initialized or the user hasn't |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 // This entry is not ready to be sent to the server because it has one or | 176 // This entry is not ready to be sent to the server because it has one or |
| 180 // more attachments that have not yet been uploaded to the server. The idea | 177 // more attachments that have not yet been uploaded to the server. The idea |
| 181 // here is avoid propagating an entry with dangling attachment references. | 178 // here is avoid propagating an entry with dangling attachment references. |
| 182 return false; | 179 return false; |
| 183 } | 180 } |
| 184 | 181 |
| 185 DVLOG(2) << "Entry is ready for commit: " << entry; | 182 DVLOG(2) << "Entry is ready for commit: " << entry; |
| 186 return true; | 183 return true; |
| 187 } | 184 } |
| 188 | 185 |
| 186 bool SupportsHierarchy(const syncable::Entry& item) { |
| 187 // Types with explicit server supported hierarchy only. |
| 188 return IsTypeWithServerGeneratedRoot(item.GetModelType()); |
| 189 } |
| 190 |
| 191 // Excludes ancestors of deleted conflicted items from |
| 192 // |ready_unsynced_set|. |
| 193 void ExcludeDeletedAncestors( |
| 194 syncable::BaseTransaction* trans, |
| 195 const std::vector<int64_t>& deleted_conflicted_items, |
| 196 std::set<int64_t>* ready_unsynced_set) { |
| 197 for (auto iter = deleted_conflicted_items.begin(); |
| 198 iter != deleted_conflicted_items.end(); ++iter) { |
| 199 syncable::Entry item(trans, syncable::GET_BY_HANDLE, *iter); |
| 200 syncable::Id parent_id = item.GetParentId(); |
| 201 DCHECK(!parent_id.IsNull()); |
| 202 |
| 203 while (!parent_id.IsRoot()) { |
| 204 syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id); |
| 205 CHECK(parent.good()) << "Bad user-only parent in item path."; |
| 206 int64_t handle = parent.GetMetahandle(); |
| 207 |
| 208 if (!parent.GetIsDel()) |
| 209 break; |
| 210 |
| 211 auto ready_iter = ready_unsynced_set->find(handle); |
| 212 if (ready_iter == ready_unsynced_set->end()) |
| 213 break; |
| 214 |
| 215 // Remove this entry from |ready_unsynced_set|. |
| 216 ready_unsynced_set->erase(ready_iter); |
| 217 parent_id = parent.GetParentId(); |
| 218 } |
| 219 } |
| 220 } |
| 221 |
| 222 // Iterates over children of items from |conflicted_items| list that are in |
| 223 // |ready_unsynced_set|, exludes them from |ready_unsynced_set| and adds them |
| 224 // to |excluded_items| list. |
| 225 void ExcludeChildren(syncable::BaseTransaction* trans, |
| 226 const std::vector<int64_t>& conflicted_items, |
| 227 std::vector<int64_t>* excluded_items, |
| 228 std::set<int64_t>* ready_unsynced_set) { |
| 229 for (auto iter = conflicted_items.begin(); iter != conflicted_items.end(); |
| 230 ++iter) { |
| 231 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); |
| 232 |
| 233 if (!entry.GetIsDir() || entry.GetIsDel()) |
| 234 continue; |
| 235 |
| 236 std::vector<int64_t> children; |
| 237 entry.GetChildHandles(&children); |
| 238 |
| 239 for (std::vector<int64_t>::const_iterator child_iter = children.begin(); |
| 240 child_iter != children.end(); ++child_iter) { |
| 241 // Collect all child handles that are in |ready_unsynced_set|. |
| 242 int64_t child_handle = *child_iter; |
| 243 auto ready_iter = ready_unsynced_set->find(child_handle); |
| 244 if (ready_iter != ready_unsynced_set->end()) { |
| 245 // Remove this entry from |ready_unsynced_set| and add it |
| 246 // to |excluded_items|. |
| 247 ready_unsynced_set->erase(ready_iter); |
| 248 excluded_items->push_back(child_handle); |
| 249 } |
| 250 } |
| 251 } |
| 252 } |
| 253 |
| 189 // Filters |unsynced_handles| to remove all entries that do not belong to the | 254 // Filters |unsynced_handles| to remove all entries that do not belong to the |
| 190 // specified |requested_types|, or are not eligible for a commit at this time. | 255 // specified |requested_types|, or are not eligible for a commit at this time. |
| 191 void FilterUnreadyEntries( | 256 void FilterUnreadyEntries( |
| 192 syncable::BaseTransaction* trans, | 257 syncable::BaseTransaction* trans, |
| 193 ModelTypeSet requested_types, | 258 ModelTypeSet requested_types, |
| 194 ModelTypeSet encrypted_types, | 259 ModelTypeSet encrypted_types, |
| 195 bool passphrase_missing, | 260 bool passphrase_missing, |
| 196 const syncable::Directory::Metahandles& unsynced_handles, | 261 const syncable::Directory::Metahandles& unsynced_handles, |
| 197 std::set<int64_t>* ready_unsynced_set) { | 262 std::set<int64_t>* ready_unsynced_set) { |
| 198 for (syncable::Directory::Metahandles::const_iterator iter = | 263 std::vector<int64_t> deleted_conflicted_items; |
| 199 unsynced_handles.begin(); iter != unsynced_handles.end(); ++iter) { | 264 std::vector<int64_t> conflicted_items; |
| 265 |
| 266 // Go over all unsynced handles, filter the ones that might be committed based |
| 267 // on type / encryption, then based on whether they are in conflict add them |
| 268 // to either |ready_unsynced_set| or one of the conflicted lists. |
| 269 for (auto iter = unsynced_handles.begin(); iter != unsynced_handles.end(); |
| 270 ++iter) { |
| 200 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); | 271 syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); |
| 201 // TODO(maniscalco): While we check if entry is ready to be committed, we | 272 // TODO(maniscalco): While we check if entry is ready to be committed, we |
| 202 // also need to check that all of its ancestors (parents, transitive) are | 273 // also need to check that all of its ancestors (parents, transitive) are |
| 203 // ready to be committed. Once attachments can prevent an entry from being | 274 // ready to be committed. Once attachments can prevent an entry from being |
| 204 // committable, this method must ensure all ancestors are ready for commit | 275 // committable, this method must ensure all ancestors are ready for commit |
| 205 // (bug 356273). | 276 // (bug 356273). |
| 206 if (IsEntryReadyForCommit(requested_types, | 277 if (MayEntryCommit(requested_types, encrypted_types, passphrase_missing, |
| 207 encrypted_types, | 278 entry)) { |
| 208 passphrase_missing, | 279 if (IsEntryInConflict(entry)) { |
| 209 entry)) { | 280 // Conflicting hierarchical entries might prevent their ancestors or |
| 210 ready_unsynced_set->insert(*iter); | 281 // descendants from being committed. |
| 282 if (SupportsHierarchy(entry)) { |
| 283 if (entry.GetIsDel()) { |
| 284 deleted_conflicted_items.push_back(*iter); |
| 285 } else if (entry.GetIsDir()) { |
| 286 // Populate the initial version of |conflicted_items| with folder |
| 287 // items that are in conflict. |
| 288 conflicted_items.push_back(*iter); |
| 289 } |
| 290 } |
| 291 } else { |
| 292 ready_unsynced_set->insert(*iter); |
| 293 } |
| 211 } | 294 } |
| 212 } | 295 } |
| 296 |
| 297 // If there are any deleted conflicted entries, remove their deleted ancestors |
| 298 // from |ready_unsynced_set| as well. |
| 299 ExcludeDeletedAncestors(trans, deleted_conflicted_items, ready_unsynced_set); |
| 300 |
| 301 // Starting with conflicted_items containing conflicted folders go down and |
| 302 // exclude all descendants from |ready_unsynced_set|. |
| 303 while (!conflicted_items.empty()) { |
| 304 std::vector<int64_t> new_list; |
| 305 ExcludeChildren(trans, conflicted_items, &new_list, ready_unsynced_set); |
| 306 conflicted_items.swap(new_list); |
| 307 } |
| 213 } | 308 } |
| 214 | 309 |
| 215 // This class helps to implement OrderCommitIds(). Its members track the | 310 // This class helps to implement OrderCommitIds(). Its members track the |
| 216 // progress of a traversal while its methods extend it. It can return early if | 311 // progress of a traversal while its methods extend it. It can return early if |
| 217 // the traversal reaches the desired size before the full traversal is complete. | 312 // the traversal reaches the desired size before the full traversal is complete. |
| 218 class Traversal { | 313 class Traversal { |
| 219 public: | 314 public: |
| 220 Traversal(syncable::BaseTransaction* trans, | 315 Traversal(syncable::BaseTransaction* trans, |
| 221 int64_t max_entries, | 316 int64_t max_entries, |
| 222 syncable::Directory::Metahandles* out); | 317 syncable::Directory::Metahandles* out); |
| 223 ~Traversal(); | 318 ~Traversal(); |
| 224 | 319 |
| 225 // First step of traversal building. Adds non-deleted items in order. | 320 // First step of traversal building. Adds non-deleted items in order. |
| 226 void AddCreatesAndMoves(const std::set<int64_t>& ready_unsynced_set); | 321 void AddCreatesAndMoves(const std::set<int64_t>& ready_unsynced_set); |
| 227 | 322 |
| 228 // Second step of traverals building. Appends deleted items. | 323 // Second step of traverals building. Appends deleted items. |
| 229 void AddDeletes(const std::set<int64_t>& ready_unsynced_set); | 324 void AddDeletes(const std::set<int64_t>& ready_unsynced_set); |
| 230 | 325 |
| 231 private: | 326 private: |
| 232 // The following functions do not modify the traversal directly. They return | 327 // The following functions do not modify the traversal directly. They return |
| 233 // their results in the |result| vector instead. | 328 // their results in the |result| vector instead. |
| 234 bool AddUncommittedParents(const std::set<int64_t>& ready_unsynced_set, | 329 void AddUncommittedParents(const std::set<int64_t>& ready_unsynced_set, |
| 235 const syncable::Entry& item, | 330 const syncable::Entry& item, |
| 236 syncable::Directory::Metahandles* result) const; | 331 syncable::Directory::Metahandles* result) const; |
| 237 | 332 |
| 238 void TryAddItem(const std::set<int64_t>& ready_unsynced_set, | 333 bool TryAddItem(const std::set<int64_t>& ready_unsynced_set, |
| 239 const syncable::Entry& item, | 334 const syncable::Entry& item, |
| 240 syncable::Directory::Metahandles* result) const; | 335 syncable::Directory::Metahandles* result) const; |
| 241 | 336 |
| 242 bool AddDeletedParents(const std::set<int64_t>& ready_unsynced_set, | 337 void AddDeletedParents(const std::set<int64_t>& ready_unsynced_set, |
| 243 const syncable::Entry& item, | 338 const syncable::Entry& item, |
| 244 const syncable::Directory::Metahandles& traversed, | 339 const syncable::Directory::Metahandles& traversed, |
| 245 syncable::Directory::Metahandles* result) const; | 340 syncable::Directory::Metahandles* result) const; |
| 246 | 341 |
| 247 bool SupportsHierarchy(const syncable::Entry& item) const; | |
| 248 | |
| 249 // Returns true if we've collected enough items. | 342 // Returns true if we've collected enough items. |
| 250 bool IsFull() const; | 343 bool IsFull() const; |
| 251 | 344 |
| 252 // Returns true if the specified handle is already in the traversal. | 345 // Returns true if the specified handle is already in the traversal. |
| 253 bool HaveItem(int64_t handle) const; | 346 bool HaveItem(int64_t handle) const; |
| 254 | 347 |
| 255 // Adds the specified handles to the traversal. | 348 // Adds the specified handles to the traversal. |
| 256 void AppendManyToTraversal(const syncable::Directory::Metahandles& handles); | 349 void AppendManyToTraversal(const syncable::Directory::Metahandles& handles); |
| 257 | 350 |
| 258 // Adds the specifed handle to the traversal. | 351 // Adds the specifed handle to the traversal. |
| 259 void AppendToTraversal(int64_t handle); | 352 void AppendToTraversal(int64_t handle); |
| 260 | 353 |
| 261 syncable::Directory::Metahandles* out_; | 354 syncable::Directory::Metahandles* out_; |
| 262 std::set<int64_t> added_handles_; | 355 std::set<int64_t> added_handles_; |
| 263 const size_t max_entries_; | 356 const size_t max_entries_; |
| 264 syncable::BaseTransaction* trans_; | 357 syncable::BaseTransaction* trans_; |
| 265 | 358 |
| 266 DISALLOW_COPY_AND_ASSIGN(Traversal); | 359 DISALLOW_COPY_AND_ASSIGN(Traversal); |
| 267 }; | 360 }; |
| 268 | 361 |
| 269 Traversal::Traversal(syncable::BaseTransaction* trans, | 362 Traversal::Traversal(syncable::BaseTransaction* trans, |
| 270 int64_t max_entries, | 363 int64_t max_entries, |
| 271 syncable::Directory::Metahandles* out) | 364 syncable::Directory::Metahandles* out) |
| 272 : out_(out), max_entries_(max_entries), trans_(trans) {} | 365 : out_(out), max_entries_(max_entries), trans_(trans) {} |
| 273 | 366 |
| 274 Traversal::~Traversal() {} | 367 Traversal::~Traversal() {} |
| 275 | 368 |
| 276 bool Traversal::AddUncommittedParents( | 369 void Traversal::AddUncommittedParents( |
| 277 const std::set<int64_t>& ready_unsynced_set, | 370 const std::set<int64_t>& ready_unsynced_set, |
| 278 const syncable::Entry& item, | 371 const syncable::Entry& item, |
| 279 syncable::Directory::Metahandles* result) const { | 372 syncable::Directory::Metahandles* result) const { |
| 280 DCHECK(SupportsHierarchy(item)); | 373 DCHECK(SupportsHierarchy(item)); |
| 281 syncable::Directory::Metahandles dependencies; | 374 syncable::Directory::Metahandles dependencies; |
| 282 syncable::Id parent_id = item.GetParentId(); | 375 syncable::Id parent_id = item.GetParentId(); |
| 283 | 376 |
| 284 // Climb the tree adding entries leaf -> root. | 377 // Climb the tree adding entries leaf -> root. |
| 285 while (!parent_id.ServerKnows()) { | 378 while (!parent_id.ServerKnows()) { |
| 286 syncable::Entry parent(trans_, syncable::GET_BY_ID, parent_id); | 379 syncable::Entry parent(trans_, syncable::GET_BY_ID, parent_id); |
| 287 CHECK(parent.good()) << "Bad user-only parent in item path."; | 380 CHECK(parent.good()) << "Bad user-only parent in item path."; |
| 288 int64_t handle = parent.GetMetahandle(); | 381 int64_t handle = parent.GetMetahandle(); |
| 289 if (HaveItem(handle)) { | 382 if (HaveItem(handle)) { |
| 290 // We've already added this parent (and therefore all of its parents). | 383 // We've already added this parent (and therefore all of its parents). |
| 291 // We can return early. | 384 // We can return early. |
| 292 break; | 385 break; |
| 293 } | 386 } |
| 294 if (IsEntryInConflict(parent)) { | 387 |
| 295 // We ignore all entries that are children of a conflicing item. Return | 388 if (!TryAddItem(ready_unsynced_set, parent, &dependencies)) { |
| 296 // false immediately to forget the traversal we've built up so far. | 389 // The parent isn't in |ready_unsynced_set|. |
| 297 DVLOG(1) << "Parent was in conflict, omitting " << item; | 390 break; |
| 298 return false; | |
| 299 } | 391 } |
| 300 TryAddItem(ready_unsynced_set, parent, &dependencies); | 392 |
| 301 parent_id = parent.GetParentId(); | 393 parent_id = parent.GetParentId(); |
| 302 } | 394 } |
| 303 | 395 |
| 304 // Reverse what we added to get the correct order. | 396 // Reverse what we added to get the correct order. |
| 305 result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); | 397 result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); |
| 306 return true; | |
| 307 } | 398 } |
| 308 | 399 |
| 309 // Adds the given item to the list if it is unsynced and ready for commit. | 400 // Adds the given item to the list if it is unsynced and ready for commit. |
| 310 void Traversal::TryAddItem(const std::set<int64_t>& ready_unsynced_set, | 401 bool Traversal::TryAddItem(const std::set<int64_t>& ready_unsynced_set, |
| 311 const syncable::Entry& item, | 402 const syncable::Entry& item, |
| 312 syncable::Directory::Metahandles* result) const { | 403 syncable::Directory::Metahandles* result) const { |
| 313 DCHECK(item.GetIsUnsynced()); | 404 DCHECK(item.GetIsUnsynced()); |
| 314 int64_t item_handle = item.GetMetahandle(); | 405 int64_t item_handle = item.GetMetahandle(); |
| 315 if (ready_unsynced_set.count(item_handle) != 0) { | 406 if (ready_unsynced_set.count(item_handle) != 0) { |
| 316 result->push_back(item_handle); | 407 result->push_back(item_handle); |
| 408 return true; |
| 317 } | 409 } |
| 410 return false; |
| 318 } | 411 } |
| 319 | 412 |
| 320 // Traverses the tree from bottom to top, adding the deleted parents of the | 413 // Traverses the tree from bottom to top, adding the deleted parents of the |
| 321 // given |item|. Stops traversing if it encounters a non-deleted node, or | 414 // given |item|. Stops traversing if it encounters a non-deleted node, or |
| 322 // a node that was already listed in the |traversed| list. Returns an error | 415 // a node that was already listed in the |traversed| list. |
| 323 // (false) if a node along the traversal is in a conflict state. | |
| 324 // | 416 // |
| 325 // The result list is reversed before it is returned, so the resulting | 417 // The result list is reversed before it is returned, so the resulting |
| 326 // traversal is in top to bottom order. Also note that this function appends | 418 // traversal is in top to bottom order. Also note that this function appends |
| 327 // to the result list without clearing it. | 419 // to the result list without clearing it. |
| 328 bool Traversal::AddDeletedParents( | 420 void Traversal::AddDeletedParents( |
| 329 const std::set<int64_t>& ready_unsynced_set, | 421 const std::set<int64_t>& ready_unsynced_set, |
| 330 const syncable::Entry& item, | 422 const syncable::Entry& item, |
| 331 const syncable::Directory::Metahandles& traversed, | 423 const syncable::Directory::Metahandles& traversed, |
| 332 syncable::Directory::Metahandles* result) const { | 424 syncable::Directory::Metahandles* result) const { |
| 333 DCHECK(SupportsHierarchy(item)); | 425 DCHECK(SupportsHierarchy(item)); |
| 334 syncable::Directory::Metahandles dependencies; | 426 syncable::Directory::Metahandles dependencies; |
| 335 syncable::Id parent_id = item.GetParentId(); | 427 syncable::Id parent_id = item.GetParentId(); |
| 336 | 428 |
| 337 // Climb the tree adding entries leaf -> root. | 429 // Climb the tree adding entries leaf -> root. |
| 338 while (!parent_id.IsRoot()) { | 430 while (!parent_id.IsRoot()) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 356 if (!parent.GetIsDel()) { | 448 if (!parent.GetIsDel()) { |
| 357 // We're not intersted in non-deleted parents. | 449 // We're not intersted in non-deleted parents. |
| 358 break; | 450 break; |
| 359 } | 451 } |
| 360 if (std::find(traversed.begin(), traversed.end(), handle) != | 452 if (std::find(traversed.begin(), traversed.end(), handle) != |
| 361 traversed.end()) { | 453 traversed.end()) { |
| 362 // We've already added this parent (and therefore all of its parents). | 454 // We've already added this parent (and therefore all of its parents). |
| 363 // We can return early. | 455 // We can return early. |
| 364 break; | 456 break; |
| 365 } | 457 } |
| 366 if (IsEntryInConflict(parent)) { | 458 |
| 367 // We ignore all entries that are children of a conflicing item. Return | 459 if (!TryAddItem(ready_unsynced_set, parent, &dependencies)) { |
| 368 // false immediately to forget the traversal we've built up so far. | 460 // The parent isn't in ready_unsynced_set. |
| 369 DVLOG(1) << "Parent was in conflict, omitting " << item; | 461 break; |
| 370 return false; | |
| 371 } | 462 } |
| 372 TryAddItem(ready_unsynced_set, parent, &dependencies); | 463 |
| 373 parent_id = parent.GetParentId(); | 464 parent_id = parent.GetParentId(); |
| 374 } | 465 } |
| 375 | 466 |
| 376 // Reverse what we added to get the correct order. | 467 // Reverse what we added to get the correct order. |
| 377 result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); | 468 result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); |
| 378 return true; | |
| 379 } | 469 } |
| 380 | 470 |
| 381 bool Traversal::IsFull() const { | 471 bool Traversal::IsFull() const { |
| 382 return out_->size() >= max_entries_; | 472 return out_->size() >= max_entries_; |
| 383 } | 473 } |
| 384 | 474 |
| 385 bool Traversal::HaveItem(int64_t handle) const { | 475 bool Traversal::HaveItem(int64_t handle) const { |
| 386 return added_handles_.find(handle) != added_handles_.end(); | 476 return added_handles_.find(handle) != added_handles_.end(); |
| 387 } | 477 } |
| 388 | 478 |
| 389 bool Traversal::SupportsHierarchy(const syncable::Entry& item) const { | |
| 390 // Types with explicit server supported hierarchy only. | |
| 391 return IsTypeWithServerGeneratedRoot(item.GetModelType()); | |
| 392 } | |
| 393 | |
| 394 void Traversal::AppendManyToTraversal( | 479 void Traversal::AppendManyToTraversal( |
| 395 const syncable::Directory::Metahandles& handles) { | 480 const syncable::Directory::Metahandles& handles) { |
| 396 out_->insert(out_->end(), handles.begin(), handles.end()); | 481 out_->insert(out_->end(), handles.begin(), handles.end()); |
| 397 added_handles_.insert(handles.begin(), handles.end()); | 482 added_handles_.insert(handles.begin(), handles.end()); |
| 398 } | 483 } |
| 399 | 484 |
| 400 void Traversal::AppendToTraversal(int64_t metahandle) { | 485 void Traversal::AppendToTraversal(int64_t metahandle) { |
| 401 out_->push_back(metahandle); | 486 out_->push_back(metahandle); |
| 402 added_handles_.insert(metahandle); | 487 added_handles_.insert(metahandle); |
| 403 } | 488 } |
| 404 | 489 |
| 405 void Traversal::AddCreatesAndMoves( | 490 void Traversal::AddCreatesAndMoves( |
| 406 const std::set<int64_t>& ready_unsynced_set) { | 491 const std::set<int64_t>& ready_unsynced_set) { |
| 407 // Add moves and creates, and prepend their uncommitted parents. | 492 // Add moves and creates, and prepend their uncommitted parents. |
| 408 for (std::set<int64_t>::const_iterator iter = ready_unsynced_set.begin(); | 493 for (std::set<int64_t>::const_iterator iter = ready_unsynced_set.begin(); |
| 409 !IsFull() && iter != ready_unsynced_set.end(); ++iter) { | 494 !IsFull() && iter != ready_unsynced_set.end(); ++iter) { |
| 410 int64_t metahandle = *iter; | 495 int64_t metahandle = *iter; |
| 411 if (HaveItem(metahandle)) | 496 if (HaveItem(metahandle)) |
| 412 continue; | 497 continue; |
| 413 | 498 |
| 414 syncable::Entry entry(trans_, | 499 syncable::Entry entry(trans_, |
| 415 syncable::GET_BY_HANDLE, | 500 syncable::GET_BY_HANDLE, |
| 416 metahandle); | 501 metahandle); |
| 417 if (!entry.GetIsDel()) { | 502 if (!entry.GetIsDel()) { |
| 418 if (SupportsHierarchy(entry)) { | 503 if (SupportsHierarchy(entry)) { |
| 419 // We only commit an item + its dependencies if it and all its | 504 // We only commit an item + its dependencies if it and all its |
| 420 // dependencies are not in conflict. | 505 // dependencies are not in conflict. |
| 421 syncable::Directory::Metahandles item_dependencies; | 506 syncable::Directory::Metahandles item_dependencies; |
| 422 if (AddUncommittedParents(ready_unsynced_set, entry, | 507 AddUncommittedParents(ready_unsynced_set, entry, &item_dependencies); |
| 423 &item_dependencies)) { | 508 TryAddItem(ready_unsynced_set, entry, &item_dependencies); |
| 424 TryAddItem(ready_unsynced_set, entry, &item_dependencies); | 509 AppendManyToTraversal(item_dependencies); |
| 425 AppendManyToTraversal(item_dependencies); | |
| 426 } | |
| 427 } else { | 510 } else { |
| 428 // No hierarchy dependencies, just commit the item itself. | 511 // No hierarchy dependencies, just commit the item itself. |
| 429 AppendToTraversal(metahandle); | 512 AppendToTraversal(metahandle); |
| 430 } | 513 } |
| 431 } | 514 } |
| 432 } | 515 } |
| 433 | 516 |
| 434 // It's possible that we overcommitted while trying to expand dependent | 517 // It's possible that we overcommitted while trying to expand dependent |
| 435 // items. If so, truncate the set down to the allowed size. | 518 // items. If so, truncate the set down to the allowed size. |
| 436 if (out_->size() > max_entries_) | 519 if (out_->size() > max_entries_) |
| (...skipping 17 matching lines...) Expand all Loading... |
| 454 deletion_list.end()) { | 537 deletion_list.end()) { |
| 455 continue; | 538 continue; |
| 456 } | 539 } |
| 457 | 540 |
| 458 syncable::Entry entry(trans_, syncable::GET_BY_HANDLE, | 541 syncable::Entry entry(trans_, syncable::GET_BY_HANDLE, |
| 459 metahandle); | 542 metahandle); |
| 460 | 543 |
| 461 if (entry.GetIsDel()) { | 544 if (entry.GetIsDel()) { |
| 462 if (SupportsHierarchy(entry)) { | 545 if (SupportsHierarchy(entry)) { |
| 463 syncable::Directory::Metahandles parents; | 546 syncable::Directory::Metahandles parents; |
| 464 if (AddDeletedParents(ready_unsynced_set, entry, deletion_list, | 547 AddDeletedParents(ready_unsynced_set, entry, deletion_list, &parents); |
| 465 &parents)) { | 548 // Append parents and chilren in top to bottom order. |
| 466 // Append parents and chilren in top to bottom order. | 549 deletion_list.insert(deletion_list.end(), parents.begin(), |
| 467 deletion_list.insert(deletion_list.end(), parents.begin(), | 550 parents.end()); |
| 468 parents.end()); | |
| 469 deletion_list.push_back(metahandle); | |
| 470 } | |
| 471 } else { | |
| 472 deletion_list.push_back(metahandle); | |
| 473 } | 551 } |
| 552 deletion_list.push_back(metahandle); |
| 474 } | 553 } |
| 475 } | 554 } |
| 476 | 555 |
| 477 // We've been gathering deletions in top to bottom order. Now we reverse the | 556 // We've been gathering deletions in top to bottom order. Now we reverse the |
| 478 // order as we prepare the list. | 557 // order as we prepare the list. |
| 479 std::reverse(deletion_list.begin(), deletion_list.end()); | 558 std::reverse(deletion_list.begin(), deletion_list.end()); |
| 480 AppendManyToTraversal(deletion_list); | 559 AppendManyToTraversal(deletion_list); |
| 481 | 560 |
| 482 // It's possible that we overcommitted while trying to expand dependent | 561 // It's possible that we overcommitted while trying to expand dependent |
| 483 // items. If so, truncate the set down to the allowed size. | 562 // items. If so, truncate the set down to the allowed size. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 502 // Add moves and creates, and prepend their uncommitted parents. | 581 // Add moves and creates, and prepend their uncommitted parents. |
| 503 traversal.AddCreatesAndMoves(ready_unsynced_set); | 582 traversal.AddCreatesAndMoves(ready_unsynced_set); |
| 504 | 583 |
| 505 // Add all deletes. | 584 // Add all deletes. |
| 506 traversal.AddDeletes(ready_unsynced_set); | 585 traversal.AddDeletes(ready_unsynced_set); |
| 507 } | 586 } |
| 508 | 587 |
| 509 } // namespace | 588 } // namespace |
| 510 | 589 |
| 511 } // namespace syncer | 590 } // namespace syncer |
| OLD | NEW |