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 "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" 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 sync_driver::AssociatorInterface { 46 public: 47 typedef std::vector<std::pair<GURL, std::vector<history::VisitInfo> > > 48 TypedUrlVisitVector; 49 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(); 55 56 // AssociatorInterface implementation. 57 // 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; 62 63 // Clears all associations. 64 virtual syncer::SyncError DisassociateModels() OVERRIDE; 65 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; 69 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; 73 74 virtual bool CryptoReadyIfNecessary() OVERRIDE; 75 76 // Delete all typed url nodes. 77 bool DeleteAllNodes(syncer::WriteTransaction* trans); 78 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); 83 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 90 // in the history DB. 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); 96 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 99 // at all. 100 sync_pb::TypedUrlSpecifics FilterExpiredVisits( 101 const sync_pb::TypedUrlSpecifics& specifics); 102 103 // Returns the percentage of DB accesses that have resulted in an error. 104 int GetErrorPercentage() const; 105 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; 112 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); 131 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); 141 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); 147 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); 157 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 160 // unchanged. 161 static void UpdateURLRowFromTypedUrlSpecifics( 162 const sync_pb::TypedUrlSpecifics& specifics, history::URLRow* url_row); 163 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); 167 168 protected: 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(); 173 174 private: 175 176 // Helper routine that actually does the work of associating models. 177 syncer::SyncError DoAssociateModels(); 178 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); 182 183 ProfileSyncService* sync_service_; 184 history::HistoryBackend* history_backend_; 185 186 base::MessageLoop* expected_loop_; 187 188 bool abort_requested_; 189 base::Lock abort_lock_; 190 191 // Guaranteed to outlive datatypes. 192 sync_driver::DataTypeErrorHandler* error_handler_; 193 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_; 197 int num_db_errors_; 198 199 DISALLOW_COPY_AND_ASSIGN(TypedUrlModelAssociator); 200 }; 201 202 } // namespace browser_sync 203 204 #endif // CHROME_BROWSER_SYNC_GLUE_TYPED_URL_MODEL_ASSOCIATOR_H_ 205