summaryrefslogtreecommitdiff
path: root/chromium/components/history/core/browser/typed_url_sync_bridge.h
blob: 3596e394706a909485fd45da537050e79b1b3d52 (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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// Copyright 2017 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 COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_SYNC_BRIDGE_H_
#define COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_SYNC_BRIDGE_H_

#include "base/scoped_observer.h"
#include "components/history/core/browser/history_backend_observer.h"
#include "components/history/core/browser/typed_url_sync_metadata_database.h"
#include "components/sync/model/metadata_change_list.h"
#include "components/sync/model/model_type_sync_bridge.h"
#include "components/sync/model/sync_error.h"

namespace history {

class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
                           public history::HistoryBackendObserver {
 public:
  // |sync_metadata_store| is owned by |history_backend|, and must outlive
  // TypedURLSyncBridge.
  TypedURLSyncBridge(HistoryBackend* history_backend,
                     TypedURLSyncMetadataDatabase* sync_metadata_store,
                     const ChangeProcessorFactory& change_processor_factory);
  ~TypedURLSyncBridge() override;

  // syncer::ModelTypeService implementation.
  std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList()
      override;
  base::Optional<syncer::ModelError> MergeSyncData(
      std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
      syncer::EntityChangeList entity_data) override;
  base::Optional<syncer::ModelError> ApplySyncChanges(
      std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
      syncer::EntityChangeList entity_changes) override;
  void GetData(StorageKeyList storage_keys, DataCallback callback) override;
  void GetAllData(DataCallback callback) override;
  std::string GetClientTag(const syncer::EntityData& entity_data) override;
  std::string GetStorageKey(const syncer::EntityData& entity_data) override;
  bool SupportsGetStorageKey() const override;

  // history::HistoryBackendObserver:
  void OnURLVisited(HistoryBackend* history_backend,
                    ui::PageTransition transition,
                    const URLRow& row,
                    const RedirectList& redirects,
                    base::Time visit_time) override;
  void OnURLsModified(HistoryBackend* history_backend,
                      const URLRows& changed_urls) override;
  void OnURLsDeleted(HistoryBackend* history_backend,
                     bool all_history,
                     bool expired,
                     const URLRows& deleted_rows,
                     const std::set<GURL>& favicon_urls) override;

  // Must be called after creation and before any operations.
  void Init();

  // Called by HistoryBackend when database error is reported through
  // DatabaseErrorCallback.
  void OnDatabaseError();

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

  // Return true if this function successfully converts the passed URL
  // information to a TypedUrlSpecifics structure for writing to the sync DB.
  static bool WriteToTypedUrlSpecifics(const URLRow& url,
                                       const VisitVector& visits,
                                       sync_pb::TypedUrlSpecifics* specifics)
      WARN_UNUSED_RESULT;

 private:
  friend class TypedURLSyncBridgeTest;

  typedef std::vector<std::pair<GURL, std::vector<VisitInfo>>>
      TypedURLVisitVector;

  // This is a helper map used only in Merge functions.
  typedef std::map<GURL, URLRow> TypedURLMap;

  // This is a helper map used to associate visit vectors from the history db
  // to the typed urls in the above map |TypedURLMap|.
  typedef std::map<GURL, VisitVector> URLVisitVectorMap;

  // Bitfield returned from MergeUrls to specify the result of a merge.
  typedef uint32_t 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 URLRow& url,
                               VisitVector* visits,
                               URLRow* new_url,
                               std::vector<VisitInfo>* new_visits);

  // 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 VisitVector& history_visits,
                         const sync_pb::TypedUrlSpecifics& sync_specifics,
                         std::vector<VisitInfo>* new_visits,
                         VisitVector* removed_visits);

  // Fills |new_url| with formatted data from |typed_url|.
  static void UpdateURLRowFromTypedUrlSpecifics(
      const sync_pb::TypedUrlSpecifics& typed_url,
      URLRow* new_url);

  // Synchronously load sync metadata from the TypedURLSyncMetadataDatabase and
  // pass it to the processor so that it can start tracking changes.
  void LoadMetadata();

  // Helper function that clears our error counters (used to reset stats after
  // merge so we can track merge errors separately).
  void ClearErrorStats();

  // Compares |server_typed_url| from the server against local history to decide
  // how to merge any existing data, and updates appropriate data containers to
  // write to server and backend.
  void MergeURLWithSync(const sync_pb::TypedUrlSpecifics& server_typed_url,
                        TypedURLMap* local_typed_urls,
                        URLVisitVectorMap* visit_vectors,
                        URLRows* new_synced_urls,
                        TypedURLVisitVector* new_synced_visits,
                        URLRows* updated_synced_urls);

  // 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 UpdateFromSync(const sync_pb::TypedUrlSpecifics& typed_url,
                      TypedURLVisitVector* visits_to_add,
                      VisitVector* visits_to_remove,
                      URLRows* updated_urls,
                      URLRows* new_urls);

  // Utility routine that either updates an existing sync node or creates a
  // new one for the passed |typed_url| if one does not already exist.
  void UpdateSyncFromLocal(URLRow typed_url,
                           syncer::MetadataChangeList* metadata_change_list);

  // Writes new typed url data from sync server to history backend.
  base::Optional<syncer::ModelError> WriteToHistoryBackend(
      const URLRows* new_urls,
      const URLRows* updated_urls,
      const std::vector<GURL>* deleted_urls,
      const TypedURLVisitVector* new_visits,
      const VisitVector* deleted_visits);

  // 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);

  // 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);

  // 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 VisitVector& visits);

  // Returns true if the caller should sync as a result of the passed visit
  // notification. We use this to throttle the number of sync changes we send
  // to the server so we don't hit the server for every
  // single typed URL visit.
  bool ShouldSyncVisit(int typed_count, ui::PageTransition transition);

  // 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,
  // expired visits that are not deleted by |ExpireHistoryBackend|, etc) by
  // modifying the passed |url| object and |visits| vector. The order of
  // |visits| will be from the oldest to the newest order.
  // Returns false in two cases.
  // 1. we could not fetch the visits for the passed URL, DB error.
  // 2. No visits for the passed url, or all the visits are expired.
  bool FixupURLAndGetVisits(URLRow* url, VisitVector* visits);

  // Create an EntityData by URL |row| and its visits |visits|.
  std::unique_ptr<syncer::EntityData> CreateEntityData(
      const URLRow& row,
      const VisitVector& visits);

  // Get all the typed urls and visits from the history db, after filtering
  // them, put them into |url_to_visit| and |url_to_urlrow|.
  // Return false if cannot get urls from HistoryBackend.
  bool GetValidURLsAndVisits(URLVisitVectorMap* url_to_visit,
                             TypedURLMap* url_to_urlrow);

  // Get URLID from HistoryBackend, and return URLID as storage key.
  std::string GetStorageKeyInternal(const std::string& url);

  // Send local typed url to processor().
  void SendTypedURLToProcessor(
      const URLRow& row,
      const VisitVector& visits,
      syncer::MetadataChangeList* metadata_change_list);

  // A non-owning pointer to the backend, which we're syncing local changes from
  // and sync changes to.
  HistoryBackend* const history_backend_;

  // Whether we're currently processing changes from the syncer. While this is
  // true, we ignore any local url changes, since we triggered them.
  bool processing_syncer_changes_;

  // A non-owning pointer to the database, which is for storing typed urls sync
  // metadata and state.
  TypedURLSyncMetadataDatabase* sync_metadata_database_;

  // 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_;

  // Since HistoryBackend use SequencedTaskRunner, so should use SequenceChecker
  // here.
  base::SequenceChecker sequence_checker_;

  // Tracks observed history backend, for receiving updates from history
  // backend.
  ScopedObserver<HistoryBackend, HistoryBackendObserver>
      history_backend_observer_;

  DISALLOW_COPY_AND_ASSIGN(TypedURLSyncBridge);
};

}  // namespace history

#endif  // COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_SYNC_BRIDGE_H_