1// Copyright (c) 2013 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_HISTORY_TYPED_URL_SYNCABLE_SERVICE_H_
6#define CHROME_BROWSER_HISTORY_TYPED_URL_SYNCABLE_SERVICE_H_
7
8#include <set>
9#include <vector>
10
11#include "chrome/browser/history/history_notifications.h"
12#include "components/history/core/browser/history_types.h"
13#include "sync/api/sync_change.h"
14#include "sync/api/sync_data.h"
15#include "sync/api/sync_error.h"
16#include "sync/api/sync_error_factory.h"
17#include "sync/api/syncable_service.h"
18#include "ui/base/page_transition_types.h"
19
20class GURL;
21class TypedUrlSyncableServiceTest;
22
23namespace base {
24class MessageLoop;
25};
26
27namespace sync_pb {
28class TypedUrlSpecifics;
29};
30
31namespace history {
32
33class HistoryBackend;
34class URLRow;
35
36extern const char kTypedUrlTag[];
37
38class TypedUrlSyncableService : public syncer::SyncableService {
39 public:
40  explicit TypedUrlSyncableService(HistoryBackend* history_backend);
41  virtual ~TypedUrlSyncableService();
42
43  static syncer::ModelType model_type() { return syncer::TYPED_URLS; }
44
45  // syncer::SyncableService implementation.
46  virtual syncer::SyncMergeResult MergeDataAndStartSyncing(
47      syncer::ModelType type,
48      const syncer::SyncDataList& initial_sync_data,
49      scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
50      scoped_ptr<syncer::SyncErrorFactory> error_handler) OVERRIDE;
51  virtual void StopSyncing(syncer::ModelType type) OVERRIDE;
52  virtual syncer::SyncDataList GetAllSyncData(
53      syncer::ModelType type) const OVERRIDE;
54  virtual syncer::SyncError ProcessSyncChanges(
55      const tracked_objects::Location& from_here,
56      const syncer::SyncChangeList& change_list) OVERRIDE;
57
58  // Called directly by HistoryBackend when local url data changes.
59  void OnUrlsModified(URLRows* changed_urls);
60  void OnUrlVisited(ui::PageTransition transition, URLRow* row);
61  void OnUrlsDeleted(bool all_history, bool expired, URLRows* rows);
62
63 protected:
64  void GetSyncedUrls(std::set<GURL>* urls) {
65    urls->insert(synced_typed_urls_.begin(), synced_typed_urls_.end());
66  }
67
68 private:
69  typedef std::vector<std::pair<URLID, URLRow> > TypedUrlUpdateVector;
70  typedef std::vector<std::pair<GURL, std::vector<VisitInfo> > >
71      TypedUrlVisitVector;
72
73  // This is a helper map used only in Merge/Process* functions. The lifetime
74  // of the iterator is longer than the map object.
75  typedef std::map<GURL, std::pair<syncer::SyncChange::SyncChangeType,
76                                   URLRows::iterator> > TypedUrlMap;
77  // This is a helper map used to associate visit vectors from the history db
78  // to the typed urls in the above map.
79  typedef std::map<GURL, VisitVector> UrlVisitVectorMap;
80
81  // Helper function that determines if we should ignore a URL for the purposes
82  // of sync, because it contains invalid data.
83  bool ShouldIgnoreUrl(const GURL& url);
84
85  // Returns true if the caller should sync as a result of the passed visit
86  // notification. We use this to throttle the number of sync changes we send
87  // to the server so we don't hit the server for every
88  // single typed URL visit.
89  bool ShouldSyncVisit(ui::PageTransition transition, URLRow* row);
90
91  // Utility routine that either updates an existing sync node or creates a
92  // new one for the passed |typed_url| if one does not already exist. Returns
93  // false and sets an unrecoverable error if the operation failed.
94  bool CreateOrUpdateSyncNode(URLRow typed_url,
95                              syncer::SyncChangeList* changes);
96
97  void AddTypedUrlToChangeList(
98    syncer::SyncChange::SyncChangeType change_type,
99    const URLRow& row,
100    const VisitVector& visits,
101    std::string title,
102    syncer::SyncChangeList* change_list);
103
104  // Converts the passed URL information to a TypedUrlSpecifics structure for
105  // writing to the sync DB.
106  static void WriteToTypedUrlSpecifics(const URLRow& url,
107                                       const VisitVector& visits,
108                                       sync_pb::TypedUrlSpecifics* specifics);
109
110  // Fetches visits from the history DB corresponding to the passed URL. This
111  // function compensates for the fact that the history DB has rather poor data
112  // integrity (duplicate visits, visit timestamps that don't match the
113  // last_visit timestamp, huge data sets that exhaust memory when fetched,
114  // etc) by modifying the passed |url| object and |visits| vector.
115  // Returns false if we could not fetch the visits for the passed URL, and
116  // tracks DB error statistics internally for reporting via UMA.
117  virtual bool FixupURLAndGetVisits(URLRow* url,
118                                    VisitVector* visits);
119
120  // TODO(sync): Consider using "delete all" sync logic instead of in-memory
121  // cache of typed urls. See http://crbug.com/231689.
122  std::set<GURL> synced_typed_urls_;
123
124  HistoryBackend* const history_backend_;
125
126  // Whether we're currently processing changes from the syncer. While this is
127  // true, we ignore any local url changes, since we triggered them.
128  bool processing_syncer_changes_;
129
130  // We receive ownership of |sync_processor_| and |error_handler_| in
131  // MergeDataAndStartSyncing() and destroy them in StopSyncing().
132  scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
133  scoped_ptr<syncer::SyncErrorFactory> sync_error_handler_;
134
135  // Statistics for the purposes of tracking the percentage of DB accesses that
136  // fail for each client via UMA.
137  int num_db_accesses_;
138  int num_db_errors_;
139
140  base::MessageLoop* expected_loop_;
141
142  FRIEND_TEST_ALL_PREFIXES(TypedUrlSyncableServiceTest,
143                           AddLocalTypedUrlAndSync);
144  FRIEND_TEST_ALL_PREFIXES(TypedUrlSyncableServiceTest,
145                           UpdateLocalTypedUrlAndSync);
146  FRIEND_TEST_ALL_PREFIXES(TypedUrlSyncableServiceTest,
147                           LinkVisitLocalTypedUrlAndSync);
148  FRIEND_TEST_ALL_PREFIXES(TypedUrlSyncableServiceTest,
149                           TypedVisitLocalTypedUrlAndSync);
150  FRIEND_TEST_ALL_PREFIXES(TypedUrlSyncableServiceTest,
151                           DeleteLocalTypedUrlAndSync);
152  FRIEND_TEST_ALL_PREFIXES(TypedUrlSyncableServiceTest,
153                           DeleteAllLocalTypedUrlAndSync);
154  FRIEND_TEST_ALL_PREFIXES(TypedUrlSyncableServiceTest,
155                           MaxVisitLocalTypedUrlAndSync);
156  FRIEND_TEST_ALL_PREFIXES(TypedUrlSyncableServiceTest,
157                           ThrottleVisitLocalTypedUrlSync);
158
159  DISALLOW_COPY_AND_ASSIGN(TypedUrlSyncableService);
160};
161
162}  // namespace history
163
164#endif  // CHROME_BROWSER_HISTORY_TYPED_URL_SYNCABLE_SERVICE_H_
165