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
|
// Copyright (c) 2010 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_ENGINE_SYNCER_H_
#define CHROME_BROWSER_SYNC_ENGINE_SYNCER_H_
#pragma once
#include <utility>
#include <vector>
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/lock.h"
#include "base/scoped_ptr.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/sessions/sync_session.h"
#include "chrome/browser/sync/syncable/directory_event.h"
#include "chrome/browser/sync/util/extensions_activity_monitor.h"
#include "chrome/common/deprecated/event_sys.h"
#include "chrome/common/deprecated/event_sys-inl.h"
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 URLFactory;
struct HttpResponse;
static const int kDefaultMaxCommitBatchSize = 25;
enum SyncerStep {
SYNCER_BEGIN,
CLEANUP_DISABLED_TYPES,
DOWNLOAD_UPDATES,
PROCESS_CLIENT_COMMAND,
VERIFY_UPDATES,
PROCESS_UPDATES,
STORE_TIMESTAMPS,
APPLY_UPDATES,
BUILD_COMMIT_REQUEST,
POST_COMMIT_MESSAGE,
PROCESS_COMMIT_RESPONSE,
BUILD_AND_PROCESS_CONFLICT_SETS,
RESOLVE_CONFLICTS,
APPLY_UPDATES_TO_RESOLVE_CONFLICTS,
CLEAR_PRIVATE_DATA,
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.
explicit Syncer(sessions::SyncSessionContext* context);
~Syncer();
// Called by other threads to tell the syncer to stop what it's doing
// and return early from SyncShare, if possible.
bool ExitRequested();
void RequestEarlyExit();
// 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(sessions::SyncSession::Delegate* delegate);
bool SyncShare(SyncerStep first_step, SyncerStep last_step,
sessions::SyncSession::Delegate* delegate);
// 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; }
// 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::GetUpdatesSource TestAndSetUpdatesSource() {
sync_pb::GetUpdatesCallerInfo::GetUpdatesSource old_source =
updates_source_;
set_updates_source(sync_pb::GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION);
return old_source;
}
void set_updates_source(
sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) {
updates_source_ = source;
}
private:
void RequestNudge(int milliseconds);
// Implements the PROCESS_CLIENT_COMMAND syncer step.
void ProcessClientCommand(sessions::SyncSession *session);
// Resets transient state and runs from SYNCER_BEGIN to SYNCER_END.
bool SyncShare(sessions::SyncSession* session);
// This is the bottom-most SyncShare variant, and does not cause transient
// state to be reset in session.
void SyncShare(sessions::SyncSession* session,
SyncerStep first_step,
SyncerStep last_step);
bool early_exit_requested_;
Lock early_exit_requested_lock_;
int32 max_commit_batch_size_;
ConflictResolver resolver_;
sessions::ScopedSessionContextConflictResolver resolver_scoper_;
sessions::SyncSessionContext* context_;
// The source of the last nudge.
sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source_;
// A callback hook used in unittests to simulate changes between conflict set
// building and conflict resolution.
Callback0::Type* pre_conflict_resolution_closure_;
friend class SyncerTest;
FRIEND_TEST_ALL_PREFIXES(SyncerTest, NameClashWithResolver);
FRIEND_TEST_ALL_PREFIXES(SyncerTest, IllegalAndLegalUpdates);
FRIEND_TEST_ALL_PREFIXES(SusanDeletingTest,
NewServerItemInAFolderHierarchyWeHaveDeleted3);
FRIEND_TEST_ALL_PREFIXES(SyncerTest, TestCommitListOrderingAndNewParent);
FRIEND_TEST_ALL_PREFIXES(SyncerTest,
TestCommitListOrderingAndNewParentAndChild);
FRIEND_TEST_ALL_PREFIXES(SyncerTest, TestCommitListOrderingCounterexample);
FRIEND_TEST_ALL_PREFIXES(SyncerTest, TestCommitListOrderingWithNesting);
FRIEND_TEST_ALL_PREFIXES(SyncerTest, TestCommitListOrderingWithNewItems);
FRIEND_TEST_ALL_PREFIXES(SyncerTest, TestGetUnsyncedAndSimpleCommit);
FRIEND_TEST_ALL_PREFIXES(SyncerTest, TestPurgeWhileUnsynced);
FRIEND_TEST_ALL_PREFIXES(SyncerTest, TestPurgeWhileUnapplied);
FRIEND_TEST_ALL_PREFIXES(SyncerTest, UnappliedUpdateDuringCommit);
FRIEND_TEST_ALL_PREFIXES(SyncerTest, DeletingEntryInFolder);
FRIEND_TEST_ALL_PREFIXES(SyncerTest,
LongChangelistCreatesFakeOrphanedEntries);
FRIEND_TEST_ALL_PREFIXES(SyncerTest, QuicklyMergeDualCreatedHierarchy);
FRIEND_TEST_ALL_PREFIXES(SyncerTest, LongChangelistWithApplicationConflict);
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 CopyServerFields(syncable::Entry* src, syncable::MutableEntry* dest);
void ClearServerData(syncable::MutableEntry* entry);
} // namespace browser_sync
#endif // CHROME_BROWSER_SYNC_ENGINE_SYNCER_H_
|