summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync/glue/typed_url_model_associator.h
blob: 4fbc318d506d2d72cd4b69c2c6feac46fff8d156 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_SYNC_GLUE_TYPED_URL_MODEL_ASSOCIATOR_H_
#define CHROME_BROWSER_SYNC_GLUE_TYPED_URL_MODEL_ASSOCIATOR_H_

#include <map>
#include <string>
#include <utility>
#include <vector>

#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/strings/string16.h"
#include "components/history/core/browser/history_types.h"
#include "components/sync_driver/data_type_error_handler.h"
#include "components/sync_driver/model_associator.h"
#include "sync/protocol/typed_url_specifics.pb.h"

class GURL;
class ProfileSyncService;

namespace base {
class MessageLoop;
}

namespace history {
class HistoryBackend;
class URLRow;
};

namespace syncer {
class WriteNode;
class WriteTransaction;
};

namespace browser_sync {

// Contains all model association related logic:
// * Algorithm to associate typed_url model and sync model.
// * Persisting model associations and loading them back.
// We do not check if we have local data before this run; we always
// merge and sync.
class TypedUrlModelAssociator : public sync_driver::AssociatorInterface {
 public:
  typedef std::vector<std::pair<GURL, std::vector<history::VisitInfo> > >
      TypedUrlVisitVector;

  static syncer::ModelType model_type() { return syncer::TYPED_URLS; }
  TypedUrlModelAssociator(ProfileSyncService* sync_service,
                          history::HistoryBackend* history_backend,
                          sync_driver::DataTypeErrorHandler* error_handler);
  virtual ~TypedUrlModelAssociator();

  // AssociatorInterface implementation.
  //
  // Iterates through the sync model looking for matched pairs of items.
  virtual syncer::SyncError AssociateModels(
      syncer::SyncMergeResult* local_merge_result,
      syncer::SyncMergeResult* syncer_merge_result) override;

  // Clears all associations.
  virtual syncer::SyncError DisassociateModels() override;

  // Called from the main thread, to abort the currently active model
  // association (for example, if we are shutting down).
  virtual void AbortAssociation() override;

  // The has_nodes out param is true if the sync model has nodes other
  // than the permanent tagged nodes.
  virtual bool SyncModelHasUserCreatedNodes(bool* has_nodes) override;

  virtual bool CryptoReadyIfNecessary() override;

  // Delete all typed url nodes.
  bool DeleteAllNodes(syncer::WriteTransaction* trans);

  void WriteToHistoryBackend(const history::URLRows* new_urls,
                             const history::URLRows* updated_urls,
                             const TypedUrlVisitVector* new_visits,
                             const history::VisitVector* deleted_visits);

  // Given a typed URL in the sync DB, looks for an existing entry in the
  // local history DB and generates a list of visits to add to the
  // history DB to bring it up to date (avoiding duplicates).
  // Updates the passed |visits_to_add| and |visits_to_remove| vectors with the
  // visits to add to/remove from the history DB, and adds a new entry to either
  // |updated_urls| or |new_urls| depending on whether the URL already existed
  // in the history DB.
  void UpdateFromSyncDB(const sync_pb::TypedUrlSpecifics& typed_url,
                        TypedUrlVisitVector* visits_to_add,
                        history::VisitVector* visits_to_remove,
                        history::URLRows* updated_urls,
                        history::URLRows* new_urls);

  // Given a TypedUrlSpecifics object, removes all visits that are older than
  // the current expiration time. Note that this can result in having no visits
  // at all.
  sync_pb::TypedUrlSpecifics FilterExpiredVisits(
      const sync_pb::TypedUrlSpecifics& specifics);

  // Returns the percentage of DB accesses that have resulted in an error.
  int GetErrorPercentage() const;

  // Bitfield returned from MergeUrls to specify the result of the merge.
  typedef uint32 MergeResult;
  static const MergeResult DIFF_NONE                = 0;
  static const MergeResult DIFF_UPDATE_NODE         = 1 << 0;
  static const MergeResult DIFF_LOCAL_ROW_CHANGED   = 1 << 1;
  static const MergeResult DIFF_LOCAL_VISITS_ADDED  = 1 << 2;

  // Merges the URL information in |typed_url| with the URL information from the
  // history database in |url| and |visits|, and returns a bitmask with the
  // results of the merge:
  // DIFF_UPDATE_NODE - changes have been made to |new_url| and |visits| which
  //   should be persisted to the sync node.
  // DIFF_LOCAL_ROW_CHANGED - The history data in |new_url| should be persisted
  //   to the history DB.
  // DIFF_LOCAL_VISITS_ADDED - |new_visits| contains a list of visits that
  //   should be written to the history DB for this URL. Deletions are not
  //   written to the DB - each client is left to age out visits on their own.
  static MergeResult MergeUrls(const sync_pb::TypedUrlSpecifics& typed_url,
                               const history::URLRow& url,
                               history::VisitVector* visits,
                               history::URLRow* new_url,
                               std::vector<history::VisitInfo>* new_visits);
  static void WriteToSyncNode(const history::URLRow& url,
                              const history::VisitVector& visits,
                              syncer::WriteNode* node);

  // Diffs the set of visits between the history DB and the sync DB, using the
  // sync DB as the canonical copy. Result is the set of |new_visits| and
  // |removed_visits| that can be applied to the history DB to make it match
  // the sync DB version. |removed_visits| can be null if the caller does not
  // care about which visits to remove.
  static void DiffVisits(const history::VisitVector& old_visits,
                         const sync_pb::TypedUrlSpecifics& new_url,
                         std::vector<history::VisitInfo>* new_visits,
                         history::VisitVector* removed_visits);

  // Converts the passed URL information to a TypedUrlSpecifics structure for
  // writing to the sync DB
  static void WriteToTypedUrlSpecifics(const history::URLRow& url,
                                       const history::VisitVector& visits,
                                       sync_pb::TypedUrlSpecifics* specifics);

  // Fetches visits from the history DB corresponding to the passed URL. This
  // function compensates for the fact that the history DB has rather poor data
  // integrity (duplicate visits, visit timestamps that don't match the
  // last_visit timestamp, huge data sets that exhaust memory when fetched,
  // etc) by modifying the passed |url| object and |visits| vector.
  // Returns false if we could not fetch the visits for the passed URL, and
  // tracks DB error statistics internally for reporting via UMA.
  bool FixupURLAndGetVisits(history::URLRow* url,
                            history::VisitVector* visits);

  // Updates the passed |url_row| based on the values in |specifics|. Fields
  // that are not contained in |specifics| (such as typed_count) are left
  // unchanged.
  static void UpdateURLRowFromTypedUrlSpecifics(
      const sync_pb::TypedUrlSpecifics& specifics, history::URLRow* url_row);

  // Helper function that determines if we should ignore a URL for the purposes
  // of sync, because it contains invalid data.
  bool ShouldIgnoreUrl(const GURL& url);

 protected:
  // Helper function that clears our error counters (used to reset stats after
  // model association so we can track model association errors separately).
  // Overridden by tests.
  virtual void ClearErrorStats();

 private:

  // Helper routine that actually does the work of associating models.
  syncer::SyncError DoAssociateModels();

  // Helper function that determines if we should ignore a URL for the purposes
  // of sync, based on the visits the URL had.
  bool ShouldIgnoreVisits(const history::VisitVector& visits);

  ProfileSyncService* sync_service_;
  history::HistoryBackend* history_backend_;

  base::MessageLoop* expected_loop_;

  bool abort_requested_;
  base::Lock abort_lock_;

  // Guaranteed to outlive datatypes.
  sync_driver::DataTypeErrorHandler* error_handler_;

  // Statistics for the purposes of tracking the percentage of DB accesses that
  // fail for each client via UMA.
  int num_db_accesses_;
  int num_db_errors_;

  DISALLOW_COPY_AND_ASSIGN(TypedUrlModelAssociator);
};

}  // namespace browser_sync

#endif  // CHROME_BROWSER_SYNC_GLUE_TYPED_URL_MODEL_ASSOCIATOR_H_