| 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 #ifndef CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_H_ | 5 #ifndef CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_H_ |
| 6 #define CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_H_ | 6 #define CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_H_ |
| 7 #pragma once | 7 #pragma once |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <bitset> | 10 #include <bitset> |
| 11 #include <iosfwd> | 11 #include <iosfwd> |
| 12 #include <limits> | 12 #include <limits> |
| 13 #include <set> | 13 #include <set> |
| 14 #include <string> | 14 #include <string> |
| 15 #include <vector> | 15 #include <vector> |
| 16 | 16 |
| 17 #include "base/atomicops.h" | 17 #include "base/atomicops.h" |
| 18 #include "base/basictypes.h" | 18 #include "base/basictypes.h" |
| 19 #include "base/file_path.h" | 19 #include "base/file_path.h" |
| 20 #include "base/gtest_prod_util.h" | 20 #include "base/gtest_prod_util.h" |
| 21 #include "base/observer_list.h" | 21 #include "base/memory/ref_counted.h" |
| 22 #include "base/observer_list_threadsafe.h" |
| 22 #include "base/synchronization/lock.h" | 23 #include "base/synchronization/lock.h" |
| 23 #include "base/time.h" | 24 #include "base/time.h" |
| 25 #include "base/tracked.h" |
| 24 #include "chrome/browser/sync/protocol/sync.pb.h" | 26 #include "chrome/browser/sync/protocol/sync.pb.h" |
| 25 #include "chrome/browser/sync/syncable/autofill_migration.h" | 27 #include "chrome/browser/sync/syncable/autofill_migration.h" |
| 26 #include "chrome/browser/sync/syncable/blob.h" | 28 #include "chrome/browser/sync/syncable/blob.h" |
| 27 #include "chrome/browser/sync/syncable/dir_open_result.h" | 29 #include "chrome/browser/sync/syncable/dir_open_result.h" |
| 28 #include "chrome/browser/sync/syncable/directory_event.h" | 30 #include "chrome/browser/sync/syncable/directory_event.h" |
| 29 #include "chrome/browser/sync/syncable/syncable_id.h" | 31 #include "chrome/browser/sync/syncable/syncable_id.h" |
| 30 #include "chrome/browser/sync/syncable/model_type.h" | 32 #include "chrome/browser/sync/syncable/model_type.h" |
| 31 #include "chrome/browser/sync/util/dbgq.h" | 33 #include "chrome/browser/sync/util/dbgq.h" |
| 32 #include "chrome/common/deprecated/event_sys.h" | 34 #include "chrome/common/deprecated/event_sys.h" |
| 33 | 35 |
| 34 class DictionaryValue; | 36 class DictionaryValue; |
| 35 struct PurgeInfo; | 37 struct PurgeInfo; |
| 36 | 38 |
| 37 namespace sync_api { | 39 namespace sync_api { |
| 38 class ReadTransaction; | 40 class ReadTransaction; |
| 39 class WriteNode; | 41 class WriteNode; |
| 40 class ReadNode; | 42 class ReadNode; |
| 41 } | 43 } // sync_api |
| 42 | 44 |
| 43 namespace syncable { | 45 namespace syncable { |
| 44 class DirectoryChangeListener; | 46 class DirectoryChangeDelegate; |
| 47 class TransactionObserver; |
| 45 class Entry; | 48 class Entry; |
| 46 | 49 |
| 47 std::ostream& operator<<(std::ostream& s, const Entry& e); | 50 std::ostream& operator<<(std::ostream& s, const Entry& e); |
| 48 | 51 |
| 49 class DirectoryBackingStore; | 52 class DirectoryBackingStore; |
| 50 | 53 |
| 51 static const int64 kInvalidMetaHandle = 0; | 54 static const int64 kInvalidMetaHandle = 0; |
| 52 | 55 |
| 53 // Update syncable_enum_conversions{.h,.cc,_unittest.cc} if you change | 56 // Update syncable_enum_conversions{.h,.cc,_unittest.cc} if you change |
| 54 // any fields in this file. | 57 // any fields in this file. |
| (...skipping 692 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 747 | 750 |
| 748 KernelShareInfoStatus kernel_info_status; | 751 KernelShareInfoStatus kernel_info_status; |
| 749 PersistedKernelInfo kernel_info; | 752 PersistedKernelInfo kernel_info; |
| 750 OriginalEntries dirty_metas; | 753 OriginalEntries dirty_metas; |
| 751 MetahandleSet metahandles_to_purge; | 754 MetahandleSet metahandles_to_purge; |
| 752 }; | 755 }; |
| 753 | 756 |
| 754 Directory(); | 757 Directory(); |
| 755 virtual ~Directory(); | 758 virtual ~Directory(); |
| 756 | 759 |
| 757 DirOpenResult Open(const FilePath& file_path, const std::string& name); | 760 // Does not take ownership of |delegate|, which must not be NULL. |
| 761 // Starts sending events to |delegate| if the returned result is |
| 762 // OPENED. Note that events to |delegate| may be sent from *any* |
| 763 // thread. |
| 764 DirOpenResult Open(const FilePath& file_path, const std::string& name, |
| 765 DirectoryChangeDelegate* delegate); |
| 758 | 766 |
| 767 // Stops sending events to the delegate. |
| 759 void Close(); | 768 void Close(); |
| 760 | 769 |
| 761 int64 NextMetahandle(); | 770 int64 NextMetahandle(); |
| 762 // Always returns a negative id. Positive client ids are generated | 771 // Always returns a negative id. Positive client ids are generated |
| 763 // by the server only. | 772 // by the server only. |
| 764 Id NextId(); | 773 Id NextId(); |
| 765 | 774 |
| 766 const FilePath& file_path() const { return kernel_->db_path; } | 775 const FilePath& file_path() const { return kernel_->db_path; } |
| 767 bool good() const { return NULL != store_; } | 776 bool good() const { return NULL != store_; } |
| 768 | 777 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 798 // later. | 807 // later. |
| 799 std::string store_birthday() const; | 808 std::string store_birthday() const; |
| 800 void set_store_birthday(const std::string& store_birthday); | 809 void set_store_birthday(const std::string& store_birthday); |
| 801 | 810 |
| 802 std::string GetAndClearNotificationState(); | 811 std::string GetAndClearNotificationState(); |
| 803 void SetNotificationState(const std::string& notification_state); | 812 void SetNotificationState(const std::string& notification_state); |
| 804 | 813 |
| 805 // Unique to each account / client pair. | 814 // Unique to each account / client pair. |
| 806 std::string cache_guid() const; | 815 std::string cache_guid() const; |
| 807 | 816 |
| 808 void AddChangeListener(DirectoryChangeListener* listener); | 817 // These are backed by a thread-safe observer list, and so can be |
| 809 void RemoveChangeListener(DirectoryChangeListener* listener); | 818 // called on any thread, and events will be sent to the observer on |
| 819 // the same thread that it was added on. |
| 820 void AddTransactionObserver(TransactionObserver* observer); |
| 821 void RemoveTransactionObserver(TransactionObserver* observer); |
| 810 | 822 |
| 811 protected: // for friends, mainly used by Entry constructors | 823 protected: // for friends, mainly used by Entry constructors |
| 812 virtual EntryKernel* GetEntryByHandle(int64 handle); | 824 virtual EntryKernel* GetEntryByHandle(int64 handle); |
| 813 virtual EntryKernel* GetEntryByHandle(int64 metahandle, | 825 virtual EntryKernel* GetEntryByHandle(int64 metahandle, |
| 814 ScopedKernelLock* lock); | 826 ScopedKernelLock* lock); |
| 815 virtual EntryKernel* GetEntryById(const Id& id); | 827 virtual EntryKernel* GetEntryById(const Id& id); |
| 816 EntryKernel* GetEntryByServerTag(const std::string& tag); | 828 EntryKernel* GetEntryByServerTag(const std::string& tag); |
| 817 virtual EntryKernel* GetEntryByClientTag(const std::string& tag); | 829 virtual EntryKernel* GetEntryByClientTag(const std::string& tag); |
| 818 EntryKernel* GetRootEntry(); | 830 EntryKernel* GetRootEntry(); |
| 819 bool ReindexId(EntryKernel* const entry, const Id& new_id); | 831 bool ReindexId(EntryKernel* const entry, const Id& new_id); |
| 820 void ReindexParentId(EntryKernel* const entry, const Id& new_parent_id); | 832 void ReindexParentId(EntryKernel* const entry, const Id& new_parent_id); |
| 821 void ClearDirtyMetahandles(); | 833 void ClearDirtyMetahandles(); |
| 822 | 834 |
| 823 // These don't do semantic checking. | 835 // These don't do semantic checking. |
| 824 // The semantic checking is implemented higher up. | 836 // The semantic checking is implemented higher up. |
| 825 void UnlinkEntryFromOrder(EntryKernel* entry, | 837 void UnlinkEntryFromOrder(EntryKernel* entry, |
| 826 WriteTransaction* trans, | 838 WriteTransaction* trans, |
| 827 ScopedKernelLock* lock); | 839 ScopedKernelLock* lock); |
| 828 | 840 |
| 829 // Overridden by tests. | 841 // Overridden by tests. |
| 830 virtual DirectoryBackingStore* CreateBackingStore( | 842 virtual DirectoryBackingStore* CreateBackingStore( |
| 831 const std::string& dir_name, | 843 const std::string& dir_name, |
| 832 const FilePath& backing_filepath); | 844 const FilePath& backing_filepath); |
| 833 | 845 |
| 834 private: | 846 private: |
| 835 // These private versions expect the kernel lock to already be held | 847 // These private versions expect the kernel lock to already be held |
| 836 // before calling. | 848 // before calling. |
| 837 EntryKernel* GetEntryById(const Id& id, ScopedKernelLock* const lock); | 849 EntryKernel* GetEntryById(const Id& id, ScopedKernelLock* const lock); |
| 838 | 850 |
| 839 DirOpenResult OpenImpl(const FilePath& file_path, const std::string& name); | 851 DirOpenResult OpenImpl(const FilePath& file_path, const std::string& name, |
| 852 DirectoryChangeDelegate* delegate); |
| 840 | 853 |
| 841 template <class T> void TestAndSet(T* kernel_data, const T* data_to_set); | 854 template <class T> void TestAndSet(T* kernel_data, const T* data_to_set); |
| 842 | 855 |
| 843 struct DirectoryEventTraits { | 856 struct DirectoryEventTraits { |
| 844 typedef DirectoryEvent EventType; | 857 typedef DirectoryEvent EventType; |
| 845 static inline bool IsChannelShutdownEvent(const DirectoryEvent& event) { | 858 static inline bool IsChannelShutdownEvent(const DirectoryEvent& event) { |
| 846 return DIRECTORY_DESTROYED == event; | 859 return DIRECTORY_DESTROYED == event; |
| 847 } | 860 } |
| 848 }; | 861 }; |
| 849 public: | 862 public: |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 976 typedef Index<ParentIdAndHandleIndexer>::Set ParentIdChildIndex; | 989 typedef Index<ParentIdAndHandleIndexer>::Set ParentIdChildIndex; |
| 977 | 990 |
| 978 // Contains both deleted and existing entries with tags. | 991 // Contains both deleted and existing entries with tags. |
| 979 // We can't store only existing tags because the client would create | 992 // We can't store only existing tags because the client would create |
| 980 // items that had a duplicated ID in the end, resulting in a DB key | 993 // items that had a duplicated ID in the end, resulting in a DB key |
| 981 // violation. ID reassociation would fail after an attempted commit. | 994 // violation. ID reassociation would fail after an attempted commit. |
| 982 typedef Index<ClientTagIndexer>::Set ClientTagIndex; | 995 typedef Index<ClientTagIndexer>::Set ClientTagIndex; |
| 983 | 996 |
| 984 protected: | 997 protected: |
| 985 // Used by tests. | 998 // Used by tests. |
| 986 void init_kernel(const std::string& name); | 999 void InitKernel(const std::string& name, DirectoryChangeDelegate* delegate); |
| 987 | 1000 |
| 988 private: | 1001 private: |
| 989 | 1002 |
| 990 struct Kernel { | 1003 struct Kernel { |
| 1004 // |delegate| can be NULL. |
| 991 Kernel(const FilePath& db_path, const std::string& name, | 1005 Kernel(const FilePath& db_path, const std::string& name, |
| 992 const KernelLoadInfo& info); | 1006 const KernelLoadInfo& info, DirectoryChangeDelegate* delegate); |
| 993 | 1007 |
| 994 ~Kernel(); | 1008 ~Kernel(); |
| 995 | 1009 |
| 996 void AddRef(); // For convenience. | 1010 void AddRef(); // For convenience. |
| 997 void Release(); | 1011 void Release(); |
| 998 | 1012 |
| 999 void AddChangeListener(DirectoryChangeListener* listener); | |
| 1000 void RemoveChangeListener(DirectoryChangeListener* listener); | |
| 1001 | |
| 1002 void CopyChangeListeners( | |
| 1003 ObserverList<DirectoryChangeListener>* change_listeners); | |
| 1004 | |
| 1005 FilePath const db_path; | 1013 FilePath const db_path; |
| 1006 // TODO(timsteele): audit use of the member and remove if possible | 1014 // TODO(timsteele): audit use of the member and remove if possible |
| 1007 volatile base::subtle::AtomicWord refcount; | 1015 volatile base::subtle::AtomicWord refcount; |
| 1008 | 1016 |
| 1009 // Implements ReadTransaction / WriteTransaction using a simple lock. | 1017 // Implements ReadTransaction / WriteTransaction using a simple lock. |
| 1010 base::Lock transaction_mutex; | 1018 base::Lock transaction_mutex; |
| 1011 | 1019 |
| 1012 // The name of this directory. | 1020 // The name of this directory. |
| 1013 std::string const name; | 1021 std::string const name; |
| 1014 | 1022 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1061 // time; this mutex protects that activity. | 1069 // time; this mutex protects that activity. |
| 1062 base::Lock save_changes_mutex; | 1070 base::Lock save_changes_mutex; |
| 1063 | 1071 |
| 1064 // The next metahandle is protected by kernel mutex. | 1072 // The next metahandle is protected by kernel mutex. |
| 1065 int64 next_metahandle; | 1073 int64 next_metahandle; |
| 1066 | 1074 |
| 1067 // Keep a history of recently flushed metahandles for debugging | 1075 // Keep a history of recently flushed metahandles for debugging |
| 1068 // purposes. Protected by the save_changes_mutex. | 1076 // purposes. Protected by the save_changes_mutex. |
| 1069 DebugQueue<int64, 1000> flushed_metahandles; | 1077 DebugQueue<int64, 1000> flushed_metahandles; |
| 1070 | 1078 |
| 1071 private: | 1079 // The delegate for directory change events. Can be NULL. |
| 1072 // The listeners for directory change events, triggered when the | 1080 DirectoryChangeDelegate* const delegate; |
| 1073 // transaction is ending (and its lock). | 1081 |
| 1074 base::Lock change_listeners_lock_; | 1082 // The transaction observers. |
| 1075 ObserverList<DirectoryChangeListener> change_listeners_; | 1083 scoped_refptr<ObserverListThreadSafe<TransactionObserver> > observers; |
| 1076 }; | 1084 }; |
| 1077 | 1085 |
| 1078 // Helper method used to do searches on |parent_id_child_index|. | 1086 // Helper method used to do searches on |parent_id_child_index|. |
| 1079 ParentIdChildIndex::iterator LocateInParentChildIndex( | 1087 ParentIdChildIndex::iterator LocateInParentChildIndex( |
| 1080 const ScopedKernelLock& lock, | 1088 const ScopedKernelLock& lock, |
| 1081 const Id& parent_id, | 1089 const Id& parent_id, |
| 1082 int64 position_in_parent, | 1090 int64 position_in_parent, |
| 1083 const Id& item_id_for_tiebreaking); | 1091 const Id& item_id_for_tiebreaking); |
| 1084 | 1092 |
| 1085 // Return an iterator to the beginning of the range of the children of | 1093 // Return an iterator to the beginning of the range of the children of |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1117 // Transactions are now processed FIFO with a straight lock | 1125 // Transactions are now processed FIFO with a straight lock |
| 1118 class BaseTransaction { | 1126 class BaseTransaction { |
| 1119 friend class Entry; | 1127 friend class Entry; |
| 1120 public: | 1128 public: |
| 1121 inline Directory* directory() const { return directory_; } | 1129 inline Directory* directory() const { return directory_; } |
| 1122 inline Id root_id() const { return Id(); } | 1130 inline Id root_id() const { return Id(); } |
| 1123 | 1131 |
| 1124 virtual ~BaseTransaction(); | 1132 virtual ~BaseTransaction(); |
| 1125 | 1133 |
| 1126 protected: | 1134 protected: |
| 1127 BaseTransaction(Directory* directory, const char* name, | 1135 BaseTransaction(Directory* directory, |
| 1128 const char* source_file, int line, WriterTag writer); | 1136 const char* name, |
| 1129 | 1137 const tracked_objects::Location& from_here, |
| 1130 // For unit testing. Everything will be mocked out no point initializing. | 1138 WriterTag writer); |
| 1131 explicit BaseTransaction(Directory* directory); | |
| 1132 | 1139 |
| 1133 void UnlockAndLog(OriginalEntries* entries); | 1140 void UnlockAndLog(OriginalEntries* entries); |
| 1134 virtual bool NotifyTransactionChangingAndEnding( | 1141 virtual bool NotifyTransactionChangingAndEnding( |
| 1135 OriginalEntries* entries, | 1142 OriginalEntries* entries, |
| 1136 ModelTypeBitSet* models_with_changes); | 1143 ModelTypeBitSet* models_with_changes); |
| 1137 virtual void NotifyTransactionComplete(ModelTypeBitSet models_with_changes); | 1144 virtual void NotifyTransactionComplete(ModelTypeBitSet models_with_changes); |
| 1138 | 1145 |
| 1139 Directory* const directory_; | 1146 Directory* const directory_; |
| 1140 Directory::Kernel* const dirkernel_; // for brevity | 1147 Directory::Kernel* const dirkernel_; // for brevity |
| 1141 const char* const name_; | 1148 const char* const name_; |
| 1142 base::TimeTicks time_acquired_; | 1149 base::TimeTicks time_acquired_; |
| 1143 const char* const source_file_; | 1150 const tracked_objects::Location from_here_; |
| 1144 const int line_; | |
| 1145 WriterTag writer_; | 1151 WriterTag writer_; |
| 1146 | 1152 |
| 1147 private: | 1153 private: |
| 1148 void Lock(); | 1154 void Lock(); |
| 1149 | 1155 |
| 1150 DISALLOW_COPY_AND_ASSIGN(BaseTransaction); | 1156 DISALLOW_COPY_AND_ASSIGN(BaseTransaction); |
| 1151 }; | 1157 }; |
| 1152 | 1158 |
| 1153 // Locks db in constructor, unlocks in destructor. | 1159 // Locks db in constructor, unlocks in destructor. |
| 1154 class ReadTransaction : public BaseTransaction { | 1160 class ReadTransaction : public BaseTransaction { |
| 1155 public: | 1161 public: |
| 1156 ReadTransaction(Directory* directory, const char* source_file, | 1162 ReadTransaction(Directory* directory, |
| 1157 int line); | 1163 const tracked_objects::Location& from_here); |
| 1158 ReadTransaction(const ScopedDirLookup& scoped_dir, | 1164 ReadTransaction(const ScopedDirLookup& scoped_dir, |
| 1159 const char* source_file, int line); | 1165 const tracked_objects::Location& from_here); |
| 1160 | 1166 |
| 1161 virtual ~ReadTransaction(); | 1167 virtual ~ReadTransaction(); |
| 1162 | 1168 |
| 1163 protected: // Don't allow creation on heap, except by sync API wrapper. | 1169 protected: // Don't allow creation on heap, except by sync API wrapper. |
| 1164 friend class sync_api::ReadTransaction; | 1170 friend class sync_api::ReadTransaction; |
| 1165 void* operator new(size_t size) { return (::operator new)(size); } | 1171 void* operator new(size_t size) { return (::operator new)(size); } |
| 1166 | 1172 |
| 1167 DISALLOW_COPY_AND_ASSIGN(ReadTransaction); | 1173 DISALLOW_COPY_AND_ASSIGN(ReadTransaction); |
| 1168 }; | 1174 }; |
| 1169 | 1175 |
| 1170 // Locks db in constructor, unlocks in destructor. | 1176 // Locks db in constructor, unlocks in destructor. |
| 1171 class WriteTransaction : public BaseTransaction { | 1177 class WriteTransaction : public BaseTransaction { |
| 1172 friend class MutableEntry; | 1178 friend class MutableEntry; |
| 1173 public: | 1179 public: |
| 1174 explicit WriteTransaction(Directory* directory, WriterTag writer, | 1180 WriteTransaction(Directory* directory, WriterTag writer, |
| 1175 const char* source_file, int line); | 1181 const tracked_objects::Location& from_here); |
| 1176 explicit WriteTransaction(const ScopedDirLookup& directory, | 1182 WriteTransaction(const ScopedDirLookup& directory, WriterTag writer, |
| 1177 WriterTag writer, const char* source_file, | 1183 const tracked_objects::Location& from_here); |
| 1178 int line); | |
| 1179 virtual ~WriteTransaction(); | 1184 virtual ~WriteTransaction(); |
| 1180 | 1185 |
| 1181 void SaveOriginal(EntryKernel* entry); | 1186 void SaveOriginal(EntryKernel* entry); |
| 1182 | 1187 |
| 1183 protected: | 1188 protected: |
| 1184 // Before an entry gets modified, we copy the original into a list | 1189 // Before an entry gets modified, we copy the original into a list |
| 1185 // so that we can issue change notifications when the transaction | 1190 // so that we can issue change notifications when the transaction |
| 1186 // is done. | 1191 // is done. |
| 1187 OriginalEntries* const originals_; | 1192 OriginalEntries* const originals_; |
| 1188 | 1193 |
| 1189 explicit WriteTransaction(Directory *directory); | |
| 1190 | |
| 1191 DISALLOW_COPY_AND_ASSIGN(WriteTransaction); | 1194 DISALLOW_COPY_AND_ASSIGN(WriteTransaction); |
| 1192 }; | 1195 }; |
| 1193 | 1196 |
| 1194 bool IsLegalNewParent(BaseTransaction* trans, const Id& id, const Id& parentid); | 1197 bool IsLegalNewParent(BaseTransaction* trans, const Id& id, const Id& parentid); |
| 1195 | 1198 |
| 1196 int64 Now(); | 1199 int64 Now(); |
| 1197 | 1200 |
| 1198 // This function sets only the flags needed to get this entry to sync. | 1201 // This function sets only the flags needed to get this entry to sync. |
| 1199 void MarkForSyncing(syncable::MutableEntry* e); | 1202 void MarkForSyncing(syncable::MutableEntry* e); |
| 1200 | 1203 |
| 1201 // This is not a reset. It just sets the numeric fields which are not | 1204 // This is not a reset. It just sets the numeric fields which are not |
| 1202 // initialized by the constructor to zero. | 1205 // initialized by the constructor to zero. |
| 1203 void ZeroFields(EntryKernel* entry, int first_field); | 1206 void ZeroFields(EntryKernel* entry, int first_field); |
| 1204 | 1207 |
| 1205 } // namespace syncable | 1208 } // namespace syncable |
| 1206 | 1209 |
| 1207 std::ostream& operator <<(std::ostream&, const syncable::Blob&); | 1210 std::ostream& operator <<(std::ostream&, const syncable::Blob&); |
| 1208 | 1211 |
| 1209 #endif // CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_H_ | 1212 #endif // CHROME_BROWSER_SYNC_SYNCABLE_SYNCABLE_H_ |
| OLD | NEW |