summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sync/engine/syncer.h
blob: c25ddca98e4b4fe51991ca515bd6e3f34ea9d98f (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
// Copyright (c) 2009 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 entry.

#ifndef CHROME_BROWSER_SYNC_ENGINE_SYNCER_H_
#define CHROME_BROWSER_SYNC_ENGINE_SYNCER_H_

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

#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "chrome/browser/sync/engine/client_command_channel.h"
#include "chrome/browser/sync/engine/conflict_resolver.h"
#include "chrome/browser/sync/engine/syncer_types.h"
#include "chrome/browser/sync/engine/syncproto.h"
#include "chrome/browser/sync/syncable/directory_event.h"
#include "chrome/browser/sync/util/closure.h"
#include "chrome/browser/sync/util/event_sys-inl.h"
#include "chrome/browser/sync/util/event_sys.h"
#include "chrome/browser/sync/util/extensions_activity_monitor.h"
#include "testing/gtest/include/gtest/gtest_prod.h"  // For FRIEND_TEST

namespace syncable {
class Directory;
class DirectoryManager;
class Entry;
class Id;
class MutableEntry;
class WriteTransaction;
}  // namespace syncable

namespace browser_sync {

class ModelSafeWorker;
class ServerConnectionManager;
class SyncProcessState;
class SyncerSession;
class URLFactory;
struct HttpResponse;

static const int kDefaultMaxCommitBatchSize = 25;

enum SyncerStep {
  SYNCER_BEGIN,
  DOWNLOAD_UPDATES,
  PROCESS_CLIENT_COMMAND,
  VERIFY_UPDATES,
  PROCESS_UPDATES,
  APPLY_UPDATES,
  BUILD_COMMIT_REQUEST,
  POST_COMMIT_MESSAGE,
  PROCESS_COMMIT_RESPONSE,
  BUILD_AND_PROCESS_CONFLICT_SETS,
  RESOLVE_CONFLICTS,
  APPLY_UPDATES_TO_RESOLVE_CONFLICTS,
  SYNCER_END
};

// A Syncer provides a control interface for driving the individual steps
// of the sync cycle.  Each cycle (hopefully) moves the client into closer
// synchronization with the server.  The individual steps are modeled
// as SyncerCommands, and the ordering of the steps is expressed using
// the SyncerStep enum.
//
// A Syncer instance expects to run on a dedicated thread.  Calls
// to SyncShare() may take an unbounded amount of time, as SyncerCommands
// may block on network i/o, on lock contention, or on tasks posted to
// other threads.
class Syncer {
 public:
  typedef std::vector<int64> UnsyncedMetaHandles;

  // The constructor may be called from a thread that is not the Syncer's
  // dedicated thread, to allow some flexibility in the setup.
  Syncer(syncable::DirectoryManager* dirman, const PathString& account_name,
      ServerConnectionManager* connection_manager,
      ModelSafeWorker* model_safe_worker);
  ~Syncer();

  // Called by other threads to tell the syncer to stop what it's doing
  // and return early from SyncShare, if possible.
  bool ExitRequested() { return early_exit_requested_; }
  void RequestEarlyExit() { early_exit_requested_ = true; }

  // SyncShare(...) variants cause one sync cycle to occur.  The return value
  // indicates whether we should sync again.  If we should not sync again,
  // it doesn't necessarily mean everything is OK; we could be throttled for
  // example.  Like a good parent, it is the caller's responsibility to clean up
  // after the syncer when it finishes a sync share operation and honor
  // server mandated throttles.
  // The zero-argument version of SyncShare is provided for unit tests.
  // When |sync_process_state| is provided, it is used as the syncer state
  // for the sync cycle.  It is treated as an input/output parameter.
  // When |first_step| and |last_step| are provided, this means to perform
  // a partial sync cycle, stopping after |last_step| is performed.
  bool SyncShare();
  bool SyncShare(SyncProcessState* sync_process_state);
  bool SyncShare(SyncerStep first_step, SyncerStep last_step);

  // Limit the batch size of commit operations to a specified number of items.
  void set_max_commit_batch_size(int x) { max_commit_batch_size_ = x; }

  ConflictResolver* conflict_resolver() { return &resolver_; }

  PathString account_name() { return account_name_; }

  SyncerEventChannel* channel() const { return syncer_event_channel_.get(); }

  ShutdownChannel* shutdown_channel() const { return shutdown_channel_.get(); }

  ModelSafeWorker* model_safe_worker() { return model_safe_worker_; }

  // Syncer will take ownership of this channel and it will be destroyed along
  // with the Syncer instance.
  void set_shutdown_channel(ShutdownChannel* channel) {
    shutdown_channel_.reset(channel);
  }

  void set_command_channel(ClientCommandChannel* channel) {
    command_channel_ = channel;
  }

  // Volatile reader for the source member of the syncer session object.  The
  // value is set to the SYNC_CYCLE_CONTINUATION value to signal that it has
  // been read.
  sync_pb::GetUpdatesCallerInfo::GET_UPDATES_SOURCE TestAndSetUpdatesSource() {
    sync_pb::GetUpdatesCallerInfo::GET_UPDATES_SOURCE old_source =
        updates_source_;
    set_updates_source(sync_pb::GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION);
    return old_source;
  }

  void set_updates_source(
      sync_pb::GetUpdatesCallerInfo::GET_UPDATES_SOURCE source) {
    updates_source_ = source;
  }

  bool notifications_enabled() const {
    return notifications_enabled_;
  }

  void set_notifications_enabled(bool state) {
    notifications_enabled_ = state;
  }

  base::TimeTicks silenced_until() const { return silenced_until_; }
  bool is_silenced() const { return !silenced_until_.is_null(); }
 private:
  void RequestNudge(int milliseconds);

  // Implements the PROCESS_CLIENT_COMMAND syncer step.
  void ProcessClientCommand(SyncerSession *session);

  void SyncShare(SyncerSession* session);
  void SyncShare(SyncerSession* session,
                 SyncerStep first_step,
                 SyncerStep last_step);

  PathString account_name_;
  bool early_exit_requested_;

  int32 max_commit_batch_size_;

  ServerConnectionManager* connection_manager_;

  ConflictResolver resolver_;
  syncable::DirectoryManager* const dirman_;

  // When we're over bandwidth quota, we don't update until past this time.
  base::TimeTicks silenced_until_;

  scoped_ptr<SyncerEventChannel> syncer_event_channel_;
  scoped_ptr<ShutdownChannel> shutdown_channel_;
  ClientCommandChannel* command_channel_;

  // A worker capable of processing work closures on a thread that is
  // guaranteed to be safe for model modifications. This is created and owned
  // by the SyncerThread that created us.
  ModelSafeWorker* model_safe_worker_;

  // We use this to stuff extensions activity into CommitMessages so the server
  // can correlate commit traffic with extension-related bookmark mutations.
  ExtensionsActivityMonitor* extensions_monitor_;

  // The source of the last nudge.
  sync_pb::GetUpdatesCallerInfo::GET_UPDATES_SOURCE updates_source_;

  // True only if the notification channel is authorized and open.
  bool notifications_enabled_;

  // A callback hook used in unittests to simulate changes between conflict set
  // building and conflict resolution.
  Closure* pre_conflict_resolution_closure_;

  FRIEND_TEST(SusanDeletingTest,
              NewServerItemInAFolderHierarchyWeHaveDeleted3);
  FRIEND_TEST(SyncerTest, TestCommitListOrderingAndNewParent);
  FRIEND_TEST(SyncerTest, TestCommitListOrderingAndNewParentAndChild);
  FRIEND_TEST(SyncerTest, TestCommitListOrderingCounterexample);
  FRIEND_TEST(SyncerTest, TestCommitListOrderingWithNesting);
  FRIEND_TEST(SyncerTest, TestCommitListOrderingWithNewItems);
  FRIEND_TEST(SyncerTest, TestGetUnsyncedAndSimpleCommit);

  DISALLOW_COPY_AND_ASSIGN(Syncer);
};

// Inline utility functions.

// Given iterator ranges from two collections sorted according to a common
// strict weak ordering, return true if the two ranges contain any common
// items, and false if they do not. This function is in this header so that it
// can be tested.
template <class Iterator1, class Iterator2>
bool SortedCollectionsIntersect(Iterator1 begin1, Iterator1 end1,
                                Iterator2 begin2, Iterator2 end2) {
  Iterator1 i1 = begin1;
  Iterator2 i2 = begin2;
  while (i1 != end1 && i2 != end2) {
    if (*i1 == *i2)
      return true;
    if (*i1 > *i2)
      ++i2;
    else
      ++i1;
  }
  return false;
}
// Utility function declarations.
void SplitServerInformationIntoNewEntry(syncable::WriteTransaction* trans,
                                        syncable::MutableEntry* entry);
void CopyServerFields(syncable::Entry* src, syncable::MutableEntry* dest);
void ClearServerData(syncable::MutableEntry* entry);

// Get update contents as a string. Intended for logging, and intended
// to have a smaller footprint than the protobuf's built-in pretty printer.
std::string SyncEntityDebugString(const sync_pb::SyncEntity& entry);

}  // namespace browser_sync

#endif  // CHROME_BROWSER_SYNC_ENGINE_SYNCER_H_