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