Home | History | Annotate | Download | only in glue
      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