OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "chrome/browser/sync/syncable/syncable.h" | 5 #include "chrome/browser/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 1699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1710 LOG(ERROR) << "Predecessor is not good : " | 1710 LOG(ERROR) << "Predecessor is not good : " |
1711 << predecessor_id.GetServerId(); | 1711 << predecessor_id.GetServerId(); |
1712 return false; | 1712 return false; |
1713 } | 1713 } |
1714 if (predecessor.Get(PARENT_ID) != Get(PARENT_ID)) | 1714 if (predecessor.Get(PARENT_ID) != Get(PARENT_ID)) |
1715 return false; | 1715 return false; |
1716 successor_id = predecessor.Get(NEXT_ID); | 1716 successor_id = predecessor.Get(NEXT_ID); |
1717 predecessor.Put(NEXT_ID, Get(ID)); | 1717 predecessor.Put(NEXT_ID, Get(ID)); |
1718 } else { | 1718 } else { |
1719 syncable::Directory* dir = trans()->directory(); | 1719 syncable::Directory* dir = trans()->directory(); |
1720 successor_id = dir->GetFirstChildId(trans(), Get(PARENT_ID)); | 1720 if (!dir->GetFirstChildId(trans(), Get(PARENT_ID), &successor_id)) { |
| 1721 return false; |
| 1722 } |
1721 } | 1723 } |
1722 if (!successor_id.IsRoot()) { | 1724 if (!successor_id.IsRoot()) { |
1723 MutableEntry successor(write_transaction(), GET_BY_ID, successor_id); | 1725 MutableEntry successor(write_transaction(), GET_BY_ID, successor_id); |
1724 if (!successor.good()) { | 1726 if (!successor.good()) { |
1725 LOG(ERROR) << "Successor is not good: " | 1727 LOG(ERROR) << "Successor is not good: " |
1726 << successor_id.GetServerId(); | 1728 << successor_id.GetServerId(); |
1727 return false; | 1729 return false; |
1728 } | 1730 } |
1729 if (successor.Get(PARENT_ID) != Get(PARENT_ID)) | 1731 if (successor.Get(PARENT_ID) != Get(PARENT_ID)) |
1730 return false; | 1732 return false; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1763 } | 1765 } |
1764 DCHECK_LT(result, 0); | 1766 DCHECK_LT(result, 0); |
1765 return Id::CreateFromClientString(base::Int64ToString(result)); | 1767 return Id::CreateFromClientString(base::Int64ToString(result)); |
1766 } | 1768 } |
1767 | 1769 |
1768 bool Directory::HasChildren(BaseTransaction* trans, const Id& id) { | 1770 bool Directory::HasChildren(BaseTransaction* trans, const Id& id) { |
1769 ScopedKernelLock lock(this); | 1771 ScopedKernelLock lock(this); |
1770 return (GetPossibleFirstChild(lock, id) != NULL); | 1772 return (GetPossibleFirstChild(lock, id) != NULL); |
1771 } | 1773 } |
1772 | 1774 |
1773 Id Directory::GetFirstChildId(BaseTransaction* trans, | 1775 bool Directory::GetFirstChildId(BaseTransaction* trans, |
1774 const Id& parent_id) { | 1776 const Id& parent_id, |
| 1777 Id* first_child_id) { |
1775 ScopedKernelLock lock(this); | 1778 ScopedKernelLock lock(this); |
1776 EntryKernel* entry = GetPossibleFirstChild(lock, parent_id); | 1779 EntryKernel* entry = GetPossibleFirstChild(lock, parent_id); |
1777 if (!entry) | 1780 if (!entry) { |
1778 return Id(); | 1781 *first_child_id = Id(); |
| 1782 return true; |
| 1783 } |
1779 | 1784 |
1780 // Walk to the front of the list; the server position ordering | 1785 // Walk to the front of the list; the server position ordering |
1781 // is commonly identical to the linked-list ordering, but pending | 1786 // is commonly identical to the linked-list ordering, but pending |
1782 // unsynced or unapplied items may diverge. | 1787 // unsynced or unapplied items may diverge. |
1783 while (!entry->ref(PREV_ID).IsRoot()) { | 1788 while (!entry->ref(PREV_ID).IsRoot()) { |
1784 // TODO(akalin): Gracefully handle GetEntryById returning NULL | |
1785 // (http://crbug.com/100907). | |
1786 entry = GetEntryById(entry->ref(PREV_ID), &lock); | 1789 entry = GetEntryById(entry->ref(PREV_ID), &lock); |
| 1790 if (!entry) { |
| 1791 *first_child_id = Id(); |
| 1792 return false; |
| 1793 } |
1787 } | 1794 } |
1788 return entry->ref(ID); | 1795 *first_child_id = entry->ref(ID); |
| 1796 return true; |
1789 } | 1797 } |
1790 | 1798 |
1791 Id Directory::GetLastChildId(BaseTransaction* trans, | 1799 bool Directory::GetLastChildIdForTest( |
1792 const Id& parent_id) { | 1800 BaseTransaction* trans, const Id& parent_id, Id* last_child_id) { |
1793 ScopedKernelLock lock(this); | 1801 ScopedKernelLock lock(this); |
1794 // We can use the server positional ordering as a hint because it's generally | 1802 EntryKernel* entry = GetPossibleLastChildForTest(lock, parent_id); |
1795 // in sync with the local (linked-list) positional ordering, and we have an | 1803 if (!entry) { |
1796 // index on it. | 1804 *last_child_id = Id(); |
1797 ParentIdChildIndex::iterator begin_range = | 1805 return true; |
1798 GetParentChildIndexLowerBound(lock, parent_id); | 1806 } |
1799 ParentIdChildIndex::iterator candidate = | |
1800 GetParentChildIndexUpperBound(lock, parent_id); | |
1801 | 1807 |
1802 while (begin_range != candidate) { | 1808 // Walk to the back of the list; the server position ordering |
1803 --candidate; | 1809 // is commonly identical to the linked-list ordering, but pending |
1804 EntryKernel* entry = *candidate; | 1810 // unsynced or unapplied items may diverge. |
1805 | 1811 while (!entry->ref(NEXT_ID).IsRoot()) { |
1806 // Filter out self-looped items, which are temporarily not in the child | 1812 entry = GetEntryById(entry->ref(NEXT_ID), &lock); |
1807 // ordering. | 1813 if (!entry) { |
1808 if (entry->ref(NEXT_ID).IsRoot() || | 1814 *last_child_id = Id(); |
1809 entry->ref(NEXT_ID) != entry->ref(PREV_ID)) { | 1815 return false; |
1810 // Walk to the back of the list; the server position ordering | |
1811 // is commonly identical to the linked-list ordering, but pending | |
1812 // unsynced or unapplied items may diverge. | |
1813 while (!entry->ref(NEXT_ID).IsRoot()) | |
1814 // TODO(akalin): Gracefully handle GetEntryById returning NULL | |
1815 // (http://crbug.com/100907). | |
1816 entry = GetEntryById(entry->ref(NEXT_ID), &lock); | |
1817 return entry->ref(ID); | |
1818 } | 1816 } |
1819 } | 1817 } |
1820 // There were no children in the linked list. | 1818 |
1821 return Id(); | 1819 *last_child_id = entry->ref(ID); |
| 1820 return true; |
1822 } | 1821 } |
1823 | 1822 |
1824 Id Directory::ComputePrevIdFromServerPosition( | 1823 Id Directory::ComputePrevIdFromServerPosition( |
1825 const EntryKernel* entry, | 1824 const EntryKernel* entry, |
1826 const syncable::Id& parent_id) { | 1825 const syncable::Id& parent_id) { |
1827 ScopedKernelLock lock(this); | 1826 ScopedKernelLock lock(this); |
1828 | 1827 |
1829 // Find the natural insertion point in the parent_id_child_index, and | 1828 // Find the natural insertion point in the parent_id_child_index, and |
1830 // work back from there, filtering out ineligible candidates. | 1829 // work back from there, filtering out ineligible candidates. |
1831 ParentIdChildIndex::iterator sibling = LocateInParentChildIndex(lock, | 1830 ParentIdChildIndex::iterator sibling = LocateInParentChildIndex(lock, |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1994 // ordering. | 1993 // ordering. |
1995 if (entry->ref(PREV_ID).IsRoot() || | 1994 if (entry->ref(PREV_ID).IsRoot() || |
1996 entry->ref(PREV_ID) != entry->ref(NEXT_ID)) { | 1995 entry->ref(PREV_ID) != entry->ref(NEXT_ID)) { |
1997 return entry; | 1996 return entry; |
1998 } | 1997 } |
1999 } | 1998 } |
2000 // There were no children in the linked list. | 1999 // There were no children in the linked list. |
2001 return NULL; | 2000 return NULL; |
2002 } | 2001 } |
2003 | 2002 |
| 2003 EntryKernel* Directory::GetPossibleLastChildForTest( |
| 2004 const ScopedKernelLock& lock, const Id& parent_id) { |
| 2005 // We can use the server positional ordering as a hint because it's generally |
| 2006 // in sync with the local (linked-list) positional ordering, and we have an |
| 2007 // index on it. |
| 2008 ParentIdChildIndex::iterator begin_range = |
| 2009 GetParentChildIndexLowerBound(lock, parent_id); |
| 2010 ParentIdChildIndex::iterator candidate = |
| 2011 GetParentChildIndexUpperBound(lock, parent_id); |
| 2012 |
| 2013 while (begin_range != candidate) { |
| 2014 --candidate; |
| 2015 EntryKernel* entry = *candidate; |
| 2016 |
| 2017 // Filter out self-looped items, which are temporarily not in the child |
| 2018 // ordering. |
| 2019 if (entry->ref(NEXT_ID).IsRoot() || |
| 2020 entry->ref(NEXT_ID) != entry->ref(PREV_ID)) { |
| 2021 return entry; |
| 2022 } |
| 2023 } |
| 2024 // There were no children in the linked list. |
| 2025 return NULL; |
| 2026 } |
| 2027 |
2004 } // namespace syncable | 2028 } // namespace syncable |
OLD | NEW |