OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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/syncable/syncable.h" | 5 #include "sync/syncable/syncable.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cstring> | 8 #include <cstring> |
9 #include <functional> | 9 #include <functional> |
10 #include <iomanip> | 10 #include <iomanip> |
(...skipping 1718 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1729 | 1729 |
1730 bool MutableEntry::PutIsDel(bool is_del) { | 1730 bool MutableEntry::PutIsDel(bool is_del) { |
1731 DCHECK(kernel_); | 1731 DCHECK(kernel_); |
1732 if (is_del == kernel_->ref(IS_DEL)) { | 1732 if (is_del == kernel_->ref(IS_DEL)) { |
1733 return true; | 1733 return true; |
1734 } | 1734 } |
1735 if (is_del) { | 1735 if (is_del) { |
1736 if (!UnlinkFromOrder()) { | 1736 if (!UnlinkFromOrder()) { |
1737 return false; | 1737 return false; |
1738 } | 1738 } |
| 1739 |
| 1740 // If the server never knew about this item and it's deleted then we don't |
| 1741 // need to keep it around. Unsetting IS_UNSYNCED will: |
| 1742 // - Ensure that the item is never committed to the server. |
| 1743 // - Allow any items with the same UNIQUE_CLIENT_TAG created on other |
| 1744 // clients to override this entry. |
| 1745 // - Let us delete this entry permanently through |
| 1746 // DirectoryBackingStore::DropDeletedEntries() when we next restart sync. |
| 1747 // This will save memory and avoid crbug.com/125381. |
| 1748 if (!Get(ID).ServerKnows()) { |
| 1749 Put(IS_UNSYNCED, false); |
| 1750 } |
1739 } | 1751 } |
1740 | 1752 |
1741 { | 1753 { |
1742 ScopedKernelLock lock(dir()); | 1754 ScopedKernelLock lock(dir()); |
1743 // Some indices don't include deleted items and must be updated | 1755 // Some indices don't include deleted items and must be updated |
1744 // upon a value change. | 1756 // upon a value change. |
1745 ScopedIndexUpdater<ParentIdAndHandleIndexer> updater(lock, kernel_, | 1757 ScopedIndexUpdater<ParentIdAndHandleIndexer> updater(lock, kernel_, |
1746 dir()->kernel_->parent_id_child_index); | 1758 dir()->kernel_->parent_id_child_index); |
1747 | 1759 |
1748 kernel_->put(IS_DEL, is_del); | 1760 kernel_->put(IS_DEL, is_del); |
(...skipping 620 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2369 // ordering. | 2381 // ordering. |
2370 if (entry->ref(NEXT_ID).IsRoot() || | 2382 if (entry->ref(NEXT_ID).IsRoot() || |
2371 entry->ref(NEXT_ID) != entry->ref(PREV_ID)) { | 2383 entry->ref(NEXT_ID) != entry->ref(PREV_ID)) { |
2372 return entry; | 2384 return entry; |
2373 } | 2385 } |
2374 } | 2386 } |
2375 // There were no children in the linked list. | 2387 // There were no children in the linked list. |
2376 return NULL; | 2388 return NULL; |
2377 } | 2389 } |
2378 | 2390 |
| 2391 void ChangeEntryIDAndUpdateChildren( |
| 2392 syncable::WriteTransaction* trans, |
| 2393 syncable::MutableEntry* entry, |
| 2394 const syncable::Id& new_id) { |
| 2395 syncable::Id old_id = entry->Get(ID); |
| 2396 if (!entry->Put(ID, new_id)) { |
| 2397 Entry old_entry(trans, GET_BY_ID, new_id); |
| 2398 CHECK(old_entry.good()); |
| 2399 LOG(FATAL) << "Attempt to change ID to " << new_id |
| 2400 << " conflicts with existing entry.\n\n" |
| 2401 << *entry << "\n\n" << old_entry; |
| 2402 } |
| 2403 if (entry->Get(IS_DIR)) { |
| 2404 // Get all child entries of the old id. |
| 2405 syncable::Directory::ChildHandles children; |
| 2406 trans->directory()->GetChildHandlesById(trans, old_id, &children); |
| 2407 Directory::ChildHandles::iterator i = children.begin(); |
| 2408 while (i != children.end()) { |
| 2409 MutableEntry child_entry(trans, GET_BY_HANDLE, *i++); |
| 2410 CHECK(child_entry.good()); |
| 2411 // Use the unchecked setter here to avoid touching the child's NEXT_ID |
| 2412 // and PREV_ID fields (which Put(PARENT_ID) would normally do to |
| 2413 // maintain linked-list invariants). In this case, NEXT_ID and PREV_ID |
| 2414 // among the children will be valid after the loop, since we update all |
| 2415 // the children at once. |
| 2416 child_entry.PutParentIdPropertyOnly(new_id); |
| 2417 } |
| 2418 } |
| 2419 // Update Id references on the previous and next nodes in the sibling |
| 2420 // order. Do this by reinserting into the linked list; the first |
| 2421 // step in PutPredecessor is to Unlink from the existing order, which |
| 2422 // will overwrite the stale Id value from the adjacent nodes. |
| 2423 if (entry->Get(PREV_ID) == entry->Get(NEXT_ID) && |
| 2424 entry->Get(PREV_ID) == old_id) { |
| 2425 // We just need a shallow update to |entry|'s fields since it is already |
| 2426 // self looped. |
| 2427 entry->Put(NEXT_ID, new_id); |
| 2428 entry->Put(PREV_ID, new_id); |
| 2429 } else { |
| 2430 entry->PutPredecessor(entry->Get(PREV_ID)); |
| 2431 } |
| 2432 } |
| 2433 |
2379 } // namespace syncable | 2434 } // namespace syncable |
OLD | NEW |