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