Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / sync / glue / bookmark_model_associator.h
blob33d08c93001b68ed7696a5eb0b0217168aa6989a
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
3 // found in the LICENSE file.
5 #ifndef CHROME_BROWSER_SYNC_GLUE_BOOKMARK_MODEL_ASSOCIATOR_H_
6 #define CHROME_BROWSER_SYNC_GLUE_BOOKMARK_MODEL_ASSOCIATOR_H_
8 #include <map>
9 #include <set>
10 #include <stack>
11 #include <string>
12 #include <vector>
14 #include "base/basictypes.h"
15 #include "base/compiler_specific.h"
16 #include "base/hash.h"
17 #include "base/memory/weak_ptr.h"
18 #include "components/sync_driver/data_type_error_handler.h"
19 #include "components/sync_driver/model_associator.h"
20 #include "sync/internal_api/public/util/unrecoverable_error_handler.h"
22 class Profile;
23 class GURL;
25 namespace bookmarks {
26 class BookmarkModel;
27 class BookmarkNode;
30 namespace syncer {
31 class BaseNode;
32 class BaseTransaction;
33 struct UserShare;
34 class WriteTransaction;
37 namespace browser_sync {
39 // Contains all model association related logic:
40 // * Algorithm to associate bookmark model and sync model.
41 // * Methods to get a bookmark node for a given sync node and vice versa.
42 // * Persisting model associations and loading them back.
43 class BookmarkModelAssociator
44 : public sync_driver::
45 PerDataTypeAssociatorInterface<bookmarks::BookmarkNode, int64> {
46 public:
47 static syncer::ModelType model_type() { return syncer::BOOKMARKS; }
48 // |expect_mobile_bookmarks_folder| controls whether or not we
49 // expect the mobile bookmarks permanent folder to be created.
50 // Should be set to true only by mobile clients.
51 BookmarkModelAssociator(
52 bookmarks::BookmarkModel* bookmark_model,
53 Profile* profile_,
54 syncer::UserShare* user_share,
55 sync_driver::DataTypeErrorHandler* unrecoverable_error_handler,
56 bool expect_mobile_bookmarks_folder);
57 ~BookmarkModelAssociator() override;
59 // Updates the visibility of the permanents node in the BookmarkModel.
60 void UpdatePermanentNodeVisibility();
62 // AssociatorInterface implementation.
64 // AssociateModels iterates through both the sync and the browser
65 // bookmark model, looking for matched pairs of items. For any pairs it
66 // finds, it will call AssociateSyncID. For any unmatched items,
67 // MergeAndAssociateModels will try to repair the match, e.g. by adding a new
68 // node. After successful completion, the models should be identical and
69 // corresponding. Returns true on success. On failure of this step, we
70 // should abort the sync operation and report an error to the user.
71 syncer::SyncError AssociateModels(
72 syncer::SyncMergeResult* local_merge_result,
73 syncer::SyncMergeResult* syncer_merge_result) override;
75 syncer::SyncError DisassociateModels() override;
77 // The has_nodes out param is true if the sync model has nodes other
78 // than the permanent tagged nodes.
79 bool SyncModelHasUserCreatedNodes(bool* has_nodes) override;
81 // Returns sync id for the given bookmark node id.
82 // Returns syncer::kInvalidId if the sync node is not found for the given
83 // bookmark node id.
84 int64 GetSyncIdFromChromeId(const int64& node_id) override;
86 // Returns the bookmark node for the given sync id.
87 // Returns NULL if no bookmark node is found for the given sync id.
88 const bookmarks::BookmarkNode* GetChromeNodeFromSyncId(
89 int64 sync_id) override;
91 // Initializes the given sync node from the given bookmark node id.
92 // Returns false if no sync node was found for the given bookmark node id or
93 // if the initialization of sync node fails.
94 bool InitSyncNodeFromChromeId(const int64& node_id,
95 syncer::BaseNode* sync_node) override;
97 // Associates the given bookmark node with the given sync node.
98 void Associate(const bookmarks::BookmarkNode* node,
99 const syncer::BaseNode& sync_node) override;
100 // Remove the association that corresponds to the given sync id.
101 void Disassociate(int64 sync_id) override;
103 void AbortAssociation() override {
104 // No implementation needed, this associator runs on the main
105 // thread.
108 // See ModelAssociator interface.
109 bool CryptoReadyIfNecessary() override;
111 private:
112 typedef std::map<int64, int64> BookmarkIdToSyncIdMap;
113 typedef std::map<int64, const bookmarks::BookmarkNode*>
114 SyncIdToBookmarkNodeMap;
115 typedef std::set<int64> DirtyAssociationsSyncIds;
116 typedef std::vector<const bookmarks::BookmarkNode*> BookmarkList;
117 typedef std::stack<const bookmarks::BookmarkNode*> BookmarkStack;
119 // Add association between native node and sync node to the maps.
120 void AddAssociation(const bookmarks::BookmarkNode* node, int64 sync_id);
122 // Posts a task to persist dirty associations.
123 void PostPersistAssociationsTask();
124 // Persists all dirty associations.
125 void PersistAssociations();
127 // Result of the native model version check against the sync
128 // version performed by CheckModelSyncState.
129 enum NativeModelSyncState {
130 // The native version is syncer::syncable::kInvalidTransactionVersion,
131 // which is the case when the version has either not been set yet or reset
132 // as a result of a previous error during the association. Basically the
133 // state should return back to UNSET on an association following the one
134 // where the state was different than IN_SYNC.
135 UNSET,
136 // The native version was in sync with the Sync version.
137 IN_SYNC,
138 // The native version was behing the sync version which indicates a failure
139 // to persist the native bookmarks model.
140 BEHIND,
141 // The native version was ahead of the sync version which indicates a
142 // a failure to persist Sync DB.
143 AHEAD,
144 NATIVE_MODEL_SYNC_STATE_COUNT
147 // Helper class used within AssociateModels to simplify the logic and
148 // minimize the number of arguments passed between private functions.
149 class Context {
150 public:
151 Context(syncer::SyncMergeResult* local_merge_result,
152 syncer::SyncMergeResult* syncer_merge_result);
153 ~Context();
155 // Push a sync node to the DFS stack.
156 void PushNode(int64 sync_id);
157 // Pops a sync node from the DFS stack. Returns false if the stack
158 // is empty.
159 bool PopNode(int64* sync_id);
161 // The following methods are used to update |local_merge_result_| and
162 // |syncer_merge_result_|.
163 void SetPreAssociationVersions(int64 native_version, int64 sync_version);
164 void SetNumItemsBeforeAssociation(int local_num, int sync_num);
165 void SetNumItemsAfterAssociation(int local_num, int sync_num);
166 void IncrementLocalItemsDeleted();
167 void IncrementLocalItemsAdded();
168 void IncrementLocalItemsModified();
169 void IncrementSyncItemsAdded();
170 void IncrementSyncItemsDeleted(int count);
172 void UpdateDuplicateCount(const base::string16& title, const GURL& url);
174 int duplicate_count() const { return duplicate_count_; }
175 NativeModelSyncState native_model_sync_state() const {
176 return native_model_sync_state_;
178 void set_native_model_sync_state(NativeModelSyncState state) {
179 native_model_sync_state_ = state;
182 // Bookmark roots participating in the sync.
183 void AddBookmarkRoot(const bookmarks::BookmarkNode* root);
184 const BookmarkList& bookmark_roots() const { return bookmark_roots_; }
186 // Index of local bookmark nodes by native ID.
187 const bookmarks::BookmarkNode* LookupNodeInIdIndex(int64 native_id);
189 void MarkForVersionUpdate(const bookmarks::BookmarkNode* node);
190 const BookmarkList& bookmarks_for_version_update() const {
191 return bookmarks_for_version_update_;
194 private:
195 // DFS stack of sync nodes traversed during association.
196 std::stack<int64> dfs_stack_;
197 // Local and merge results are not owned.
198 syncer::SyncMergeResult* local_merge_result_;
199 syncer::SyncMergeResult* syncer_merge_result_;
200 // |hashes_| contains hash codes of all native bookmarks
201 // for the purpose of detecting duplicates. A small number of
202 // false positives due to hash collisions is OK because this
203 // data is used for reporting purposes only.
204 base::hash_set<size_t> hashes_;
205 // Overall number of bookmark collisions from RecordDuplicates call.
206 int duplicate_count_;
207 // Result of the most recent BookmarkModelAssociator::CheckModelSyncState.
208 NativeModelSyncState native_model_sync_state_;
209 // List of bookmark model roots participating in the sync.
210 BookmarkList bookmark_roots_;
211 // Map of bookmark nodes by native ID. Used to lookup sync node matches
212 // by external ID.
213 typedef base::hash_map<int64, const bookmarks::BookmarkNode*> IdIndex;
214 IdIndex id_index_;
215 bool id_index_initialized_;
216 // List of bookmark nodes for which the transaction version needs to be
217 // updated.
218 BookmarkList bookmarks_for_version_update_;
220 void BuildIdIndex();
222 DISALLOW_COPY_AND_ASSIGN(Context);
225 // Matches up the bookmark model and the sync model to build model
226 // associations.
227 syncer::SyncError BuildAssociations(Context* context);
229 // Two helper functions that populate SyncMergeResult with numbers of
230 // items before/after the association.
231 void SetNumItemsBeforeAssociation(syncer::BaseTransaction* trans,
232 Context* context);
233 void SetNumItemsAfterAssociation(syncer::BaseTransaction* trans,
234 Context* context);
236 // Used by SetNumItemsBeforeAssociation.
237 // Similar to BookmarkNode::GetTotalNodeCount but also scans the native
238 // model for duplicates and records them in |context|.
239 int GetTotalBookmarkCountAndRecordDuplicates(
240 const bookmarks::BookmarkNode* node,
241 Context* context) const;
243 // Helper function that associates all tagged permanent folders and primes
244 // the provided context with sync IDs of those folders.
245 syncer::SyncError AssociatePermanentFolders(syncer::BaseTransaction* trans,
246 Context* context);
248 // Associate a top-level node of the bookmark model with a permanent node in
249 // the sync domain. Such permanent nodes are identified by a tag that is
250 // well known to the server and the client, and is unique within a particular
251 // user's share. For example, "other_bookmarks" is the tag for the Other
252 // Bookmarks folder. The sync nodes are server-created.
253 // Returns true on success, false if association failed.
254 bool AssociateTaggedPermanentNode(
255 syncer::BaseTransaction* trans,
256 const bookmarks::BookmarkNode* permanent_node,
257 const std::string& tag) WARN_UNUSED_RESULT;
259 // Removes bookmark nodes whose corresponding sync nodes have been deleted
260 // according to sync delete journals.
261 void ApplyDeletesFromSyncJournal(syncer::BaseTransaction* trans,
262 Context* context);
264 // The main part of the association process that associatiates
265 // native nodes that are children of |parent_node| with sync nodes with IDs
266 // from |sync_ids|.
267 syncer::SyncError BuildAssociations(
268 syncer::WriteTransaction* trans,
269 const bookmarks::BookmarkNode* parent_node,
270 const std::vector<int64>& sync_ids,
271 Context* context);
273 // This is a variation of BuildAssociations method above for the optimistic
274 // case where the native version of the storage is in sync or ahead of the
275 // sync version.
276 syncer::SyncError BuildAssociationsOptimistic(
277 syncer::WriteTransaction* trans,
278 const bookmarks::BookmarkNode* parent_node,
279 const std::vector<int64>& sync_ids,
280 Context* context);
282 // Helper method for creating a new native bookmark node.
283 const bookmarks::BookmarkNode* CreateBookmarkNode(
284 const bookmarks::BookmarkNode* parent_node,
285 int bookmark_index,
286 const syncer::BaseNode* sync_child_node,
287 const GURL& url,
288 Context* context,
289 syncer::SyncError* error);
291 // Helper method for deleting a sync node and all its children.
292 // Returns the number of sync nodes deleted.
293 int RemoveSyncNodeHierarchy(syncer::WriteTransaction* trans, int64 sync_id);
295 // Check whether bookmark model and sync model are synced by comparing
296 // their transaction versions.
297 // Returns a PERSISTENCE_ERROR if a transaction mismatch was detected where
298 // the native model has a newer transaction verison.
299 syncer::SyncError CheckModelSyncState(Context* context) const;
301 bookmarks::BookmarkModel* bookmark_model_;
302 Profile* profile_;
303 syncer::UserShare* user_share_;
304 sync_driver::DataTypeErrorHandler* unrecoverable_error_handler_;
305 const bool expect_mobile_bookmarks_folder_;
306 BookmarkIdToSyncIdMap id_map_;
307 SyncIdToBookmarkNodeMap id_map_inverse_;
308 // Stores sync ids for dirty associations.
309 DirtyAssociationsSyncIds dirty_associations_sync_ids_;
310 // Specifies whether optimistic association experiment is enabled.
311 bool optimistic_association_enabled_;
313 // Used to post PersistAssociation tasks to the current message loop and
314 // guarantees no invocations can occur if |this| has been deleted. (This
315 // allows this class to be non-refcounted).
316 base::WeakPtrFactory<BookmarkModelAssociator> weak_factory_;
318 DISALLOW_COPY_AND_ASSIGN(BookmarkModelAssociator);
321 } // namespace browser_sync
323 #endif // CHROME_BROWSER_SYNC_GLUE_BOOKMARK_MODEL_ASSOCIATOR_H_