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 "chrome/browser/sync/glue/data_type_error_handler.h" 18 #include "chrome/browser/sync/glue/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 extern const char kTypedUrlTag[]; 41 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 46 // merge and sync. 47 class TypedUrlModelAssociator : public AssociatorInterface { 48 public: 49 typedef std::vector<std::pair<history::URLID, history::URLRow> > 50 TypedUrlUpdateVector; 51 typedef std::vector<std::pair<GURL, std::vector<history::VisitInfo> > > 52 TypedUrlVisitVector; 53 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(); 59 60 // AssociatorInterface implementation. 61 // 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; 66 67 // Clears all associations. 68 virtual syncer::SyncError DisassociateModels() OVERRIDE; 69 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; 73 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; 77 78 virtual bool CryptoReadyIfNecessary() OVERRIDE; 79 80 // Delete all typed url nodes. 81 bool DeleteAllNodes(syncer::WriteTransaction* trans); 82 83 void WriteToHistoryBackend(const history::URLRows* new_urls, 84 const TypedUrlUpdateVector* updated_urls, 85 const TypedUrlVisitVector* new_visits, 86 const history::VisitVector* deleted_visits); 87 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 94 // in the history DB. 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); 100 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 103 // at all. 104 sync_pb::TypedUrlSpecifics FilterExpiredVisits( 105 const sync_pb::TypedUrlSpecifics& specifics); 106 107 // Returns the percentage of DB accesses that have resulted in an error. 108 int GetErrorPercentage() const; 109 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; 116 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); 135 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); 145 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); 151 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); 161 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 164 // unchanged. 165 static void UpdateURLRowFromTypedUrlSpecifics( 166 const sync_pb::TypedUrlSpecifics& specifics, history::URLRow* url_row); 167 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); 171 172 protected: 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(); 177 178 private: 179 180 // Helper routine that actually does the work of associating models. 181 syncer::SyncError DoAssociateModels(); 182 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); 186 187 ProfileSyncService* sync_service_; 188 history::HistoryBackend* history_backend_; 189 190 base::MessageLoop* expected_loop_; 191 192 bool abort_requested_; 193 base::Lock abort_lock_; 194 195 DataTypeErrorHandler* error_handler_; // Guaranteed to outlive datatypes. 196 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_; 200 int num_db_errors_; 201 202 DISALLOW_COPY_AND_ASSIGN(TypedUrlModelAssociator); 203 }; 204 205 } // namespace browser_sync 206 207 #endif // CHROME_BROWSER_SYNC_GLUE_TYPED_URL_MODEL_ASSOCIATOR_H_ 208