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 21class GURL; 22class ProfileSyncService; 23 24namespace base { 25class MessageLoop; 26} 27 28namespace history { 29class HistoryBackend; 30class URLRow; 31}; 32 33namespace syncer { 34class WriteNode; 35class WriteTransaction; 36}; 37 38namespace 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. 45class 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 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