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_TYPED_URL_MODEL_ASSOCIATOR_H_
6 #define CHROME_BROWSER_SYNC_GLUE_TYPED_URL_MODEL_ASSOCIATOR_H_
13 #include "base/basictypes.h"
14 #include "base/compiler_specific.h"
15 #include "base/strings/string16.h"
16 #include "components/history/core/browser/history_types.h"
17 #include "components/sync_driver/data_type_error_handler.h"
18 #include "components/sync_driver/model_associator.h"
19 #include "sync/protocol/typed_url_specifics.pb.h"
22 class ProfileSyncService;
35 class WriteTransaction;
38 namespace browser_sync {
40 // Contains all model association related logic:
41 // * Algorithm to associate typed_url model and sync model.
42 // * Persisting model associations and loading them back.
43 // We do not check if we have local data before this run; we always
45 class TypedUrlModelAssociator : public sync_driver::AssociatorInterface {
47 typedef std::vector<std::pair<GURL, std::vector<history::VisitInfo> > >
50 static syncer::ModelType model_type() { return syncer::TYPED_URLS; }
51 TypedUrlModelAssociator(ProfileSyncService* sync_service,
52 history::HistoryBackend* history_backend,
53 sync_driver::DataTypeErrorHandler* error_handler);
54 virtual ~TypedUrlModelAssociator();
56 // AssociatorInterface implementation.
58 // Iterates through the sync model looking for matched pairs of items.
59 virtual syncer::SyncError AssociateModels(
60 syncer::SyncMergeResult* local_merge_result,
61 syncer::SyncMergeResult* syncer_merge_result) OVERRIDE;
63 // Clears all associations.
64 virtual syncer::SyncError DisassociateModels() OVERRIDE;
66 // Called from the main thread, to abort the currently active model
67 // association (for example, if we are shutting down).
68 virtual void AbortAssociation() OVERRIDE;
70 // The has_nodes out param is true if the sync model has nodes other
71 // than the permanent tagged nodes.
72 virtual bool SyncModelHasUserCreatedNodes(bool* has_nodes) OVERRIDE;
74 virtual bool CryptoReadyIfNecessary() OVERRIDE;
76 // Delete all typed url nodes.
77 bool DeleteAllNodes(syncer::WriteTransaction* trans);
79 void WriteToHistoryBackend(const history::URLRows* new_urls,
80 const history::URLRows* updated_urls,
81 const TypedUrlVisitVector* new_visits,
82 const history::VisitVector* deleted_visits);
84 // Given a typed URL in the sync DB, looks for an existing entry in the
85 // local history DB and generates a list of visits to add to the
86 // history DB to bring it up to date (avoiding duplicates).
87 // Updates the passed |visits_to_add| and |visits_to_remove| vectors with the
88 // visits to add to/remove from the history DB, and adds a new entry to either
89 // |updated_urls| or |new_urls| depending on whether the URL already existed
91 void UpdateFromSyncDB(const sync_pb::TypedUrlSpecifics& typed_url,
92 TypedUrlVisitVector* visits_to_add,
93 history::VisitVector* visits_to_remove,
94 history::URLRows* updated_urls,
95 history::URLRows* new_urls);
97 // Given a TypedUrlSpecifics object, removes all visits that are older than
98 // the current expiration time. Note that this can result in having no visits
100 sync_pb::TypedUrlSpecifics FilterExpiredVisits(
101 const sync_pb::TypedUrlSpecifics& specifics);
103 // Returns the percentage of DB accesses that have resulted in an error.
104 int GetErrorPercentage() const;
106 // Bitfield returned from MergeUrls to specify the result of the merge.
107 typedef uint32 MergeResult;
108 static const MergeResult DIFF_NONE = 0;
109 static const MergeResult DIFF_UPDATE_NODE = 1 << 0;
110 static const MergeResult DIFF_LOCAL_ROW_CHANGED = 1 << 1;
111 static const MergeResult DIFF_LOCAL_VISITS_ADDED = 1 << 2;
113 // Merges the URL information in |typed_url| with the URL information from the
114 // history database in |url| and |visits|, and returns a bitmask with the
115 // results of the merge:
116 // DIFF_UPDATE_NODE - changes have been made to |new_url| and |visits| which
117 // should be persisted to the sync node.
118 // DIFF_LOCAL_ROW_CHANGED - The history data in |new_url| should be persisted
119 // to the history DB.
120 // DIFF_LOCAL_VISITS_ADDED - |new_visits| contains a list of visits that
121 // should be written to the history DB for this URL. Deletions are not
122 // written to the DB - each client is left to age out visits on their own.
123 static MergeResult MergeUrls(const sync_pb::TypedUrlSpecifics& typed_url,
124 const history::URLRow& url,
125 history::VisitVector* visits,
126 history::URLRow* new_url,
127 std::vector<history::VisitInfo>* new_visits);
128 static void WriteToSyncNode(const history::URLRow& url,
129 const history::VisitVector& visits,
130 syncer::WriteNode* node);
132 // Diffs the set of visits between the history DB and the sync DB, using the
133 // sync DB as the canonical copy. Result is the set of |new_visits| and
134 // |removed_visits| that can be applied to the history DB to make it match
135 // the sync DB version. |removed_visits| can be null if the caller does not
136 // care about which visits to remove.
137 static void DiffVisits(const history::VisitVector& old_visits,
138 const sync_pb::TypedUrlSpecifics& new_url,
139 std::vector<history::VisitInfo>* new_visits,
140 history::VisitVector* removed_visits);
142 // Converts the passed URL information to a TypedUrlSpecifics structure for
143 // writing to the sync DB
144 static void WriteToTypedUrlSpecifics(const history::URLRow& url,
145 const history::VisitVector& visits,
146 sync_pb::TypedUrlSpecifics* specifics);
148 // Fetches visits from the history DB corresponding to the passed URL. This
149 // function compensates for the fact that the history DB has rather poor data
150 // integrity (duplicate visits, visit timestamps that don't match the
151 // last_visit timestamp, huge data sets that exhaust memory when fetched,
152 // etc) by modifying the passed |url| object and |visits| vector.
153 // Returns false if we could not fetch the visits for the passed URL, and
154 // tracks DB error statistics internally for reporting via UMA.
155 bool FixupURLAndGetVisits(history::URLRow* url,
156 history::VisitVector* visits);
158 // Updates the passed |url_row| based on the values in |specifics|. Fields
159 // that are not contained in |specifics| (such as typed_count) are left
161 static void UpdateURLRowFromTypedUrlSpecifics(
162 const sync_pb::TypedUrlSpecifics& specifics, history::URLRow* url_row);
164 // Helper function that determines if we should ignore a URL for the purposes
165 // of sync, because it contains invalid data.
166 bool ShouldIgnoreUrl(const GURL& url);
169 // Helper function that clears our error counters (used to reset stats after
170 // model association so we can track model association errors separately).
171 // Overridden by tests.
172 virtual void ClearErrorStats();
176 // Helper routine that actually does the work of associating models.
177 syncer::SyncError DoAssociateModels();
179 // Helper function that determines if we should ignore a URL for the purposes
180 // of sync, based on the visits the URL had.
181 bool ShouldIgnoreVisits(const history::VisitVector& visits);
183 ProfileSyncService* sync_service_;
184 history::HistoryBackend* history_backend_;
186 base::MessageLoop* expected_loop_;
188 bool abort_requested_;
189 base::Lock abort_lock_;
191 // Guaranteed to outlive datatypes.
192 sync_driver::DataTypeErrorHandler* error_handler_;
194 // Statistics for the purposes of tracking the percentage of DB accesses that
195 // fail for each client via UMA.
196 int num_db_accesses_;
199 DISALLOW_COPY_AND_ASSIGN(TypedUrlModelAssociator);
202 } // namespace browser_sync
204 #endif // CHROME_BROWSER_SYNC_GLUE_TYPED_URL_MODEL_ASSOCIATOR_H_