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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
|
// Copyright (c) 2011 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.
// The 'sessions' namespace comprises all the pieces of state that are
// combined to form a SyncSession instance. In that way, it can be thought of
// as an extension of the SyncSession type itself. Session scoping gives
// context to things like "conflict progress", "update progress", etc, and the
// separation this file provides allows clients to only include the parts they
// need rather than the entire session stack.
#ifndef CHROME_BROWSER_SYNC_SESSIONS_SESSION_STATE_H_
#define CHROME_BROWSER_SYNC_SESSIONS_SESSION_STATE_H_
#pragma once
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/basictypes.h"
#include "chrome/browser/sync/engine/syncer_types.h"
#include "chrome/browser/sync/engine/syncproto.h"
#include "chrome/browser/sync/sessions/ordered_commit_set.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "chrome/browser/sync/syncable/model_type_payload_map.h"
#include "chrome/browser/sync/syncable/syncable.h"
namespace base {
class DictionaryValue;
}
namespace syncable {
class DirectoryManager;
}
namespace browser_sync {
namespace sessions {
class UpdateProgress;
// A container for the source of a sync session. This includes the update
// source, the datatypes triggering the sync session, and possible session
// specific payloads which should be sent to the server.
struct SyncSourceInfo {
SyncSourceInfo();
explicit SyncSourceInfo(const syncable::ModelTypePayloadMap& t);
SyncSourceInfo(
const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& u,
const syncable::ModelTypePayloadMap& t);
~SyncSourceInfo();
// Caller takes ownership of the returned dictionary.
base::DictionaryValue* ToValue() const;
sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source;
syncable::ModelTypePayloadMap types;
};
// Data pertaining to the status of an active Syncer object.
struct SyncerStatus {
SyncerStatus();
~SyncerStatus();
// Caller takes ownership of the returned dictionary.
base::DictionaryValue* ToValue() const;
// True when we get such an INVALID_STORE error from the server.
bool invalid_store;
// True iff we're stuck.
bool syncer_stuck;
bool syncing;
int num_successful_commits;
// This is needed for monitoring extensions activity.
int num_successful_bookmark_commits;
// Download event counters.
int num_updates_downloaded_total;
int num_tombstone_updates_downloaded_total;
// If the syncer encountered a MIGRATION_DONE code, these are the types that
// the client must now "migrate", by purging and re-downloading all updates.
syncable::ModelTypeSet types_needing_local_migration;
// Overwrites due to conflict resolution counters.
int num_local_overwrites;
int num_server_overwrites;
};
// Counters for various errors that can occur repeatedly during a sync session.
struct ErrorCounters {
ErrorCounters();
// Caller takes ownership of the returned dictionary.
base::DictionaryValue* ToValue() const;
int num_conflicting_commits;
// Number of commits hitting transient errors since the last successful
// commit.
int consecutive_transient_error_commits;
// Incremented when get_updates fails, commit fails, and when hitting
// transient errors. When any of these succeed, this counter is reset.
// TODO(chron): Reduce number of weird counters we use.
int consecutive_errors;
};
// Caller takes ownership of the returned dictionary.
base::DictionaryValue* DownloadProgressMarkersToValue(
const std::string
(&download_progress_markers)[syncable::MODEL_TYPE_COUNT]);
// An immutable snapshot of state from a SyncSession. Convenient to use as
// part of notifications as it is inherently thread-safe.
struct SyncSessionSnapshot {
SyncSessionSnapshot(
const SyncerStatus& syncer_status,
const ErrorCounters& errors,
int64 num_server_changes_remaining,
bool is_share_usable,
const syncable::ModelTypeBitSet& initial_sync_ended,
const std::string
(&download_progress_markers)[syncable::MODEL_TYPE_COUNT],
bool more_to_sync,
bool is_silenced,
int64 unsynced_count,
int num_blocking_conflicting_updates,
int num_conflicting_updates,
bool did_commit_items,
const SyncSourceInfo& source,
size_t num_entries);
~SyncSessionSnapshot();
// Caller takes ownership of the returned dictionary.
base::DictionaryValue* ToValue() const;
std::string ToString() const;
const SyncerStatus syncer_status;
const ErrorCounters errors;
const int64 num_server_changes_remaining;
const bool is_share_usable;
const syncable::ModelTypeBitSet initial_sync_ended;
const std::string download_progress_markers[syncable::MODEL_TYPE_COUNT];
const bool has_more_to_sync;
const bool is_silenced;
const int64 unsynced_count;
const int num_blocking_conflicting_updates;
const int num_conflicting_updates;
const bool did_commit_items;
const SyncSourceInfo source;
const size_t num_entries;
};
// Tracks progress of conflicts and their resolution using conflict sets.
class ConflictProgress {
public:
explicit ConflictProgress(bool* dirty_flag);
~ConflictProgress();
// Various iterators, size, and retrieval functions for conflict sets.
IdToConflictSetMap::const_iterator IdToConflictSetBegin() const;
IdToConflictSetMap::const_iterator IdToConflictSetEnd() const;
IdToConflictSetMap::size_type IdToConflictSetSize() const;
IdToConflictSetMap::const_iterator IdToConflictSetFind(
const syncable::Id& the_id) const;
const ConflictSet* IdToConflictSetGet(const syncable::Id& the_id);
std::set<ConflictSet*>::const_iterator ConflictSetsBegin() const;
std::set<ConflictSet*>::const_iterator ConflictSetsEnd() const;
std::set<ConflictSet*>::size_type ConflictSetsSize() const;
// Various mutators for tracking commit conflicts.
void AddConflictingItemById(const syncable::Id& the_id);
void EraseConflictingItemById(const syncable::Id& the_id);
int ConflictingItemsSize() const { return conflicting_item_ids_.size(); }
std::set<syncable::Id>::iterator ConflictingItemsBegin();
std::set<syncable::Id>::const_iterator ConflictingItemsBeginConst() const;
std::set<syncable::Id>::const_iterator ConflictingItemsEnd() const;
// Mutators for nonblocking conflicting items (see description below).
void AddNonblockingConflictingItemById(const syncable::Id& the_id);
void EraseNonblockingConflictingItemById(const syncable::Id& the_id);
int NonblockingConflictingItemsSize() const {
return nonblocking_conflicting_item_ids_.size();
}
void MergeSets(const syncable::Id& set1, const syncable::Id& set2);
void CleanupSets();
private:
// TODO(sync): move away from sets if it makes more sense.
std::set<syncable::Id> conflicting_item_ids_;
std::map<syncable::Id, ConflictSet*> id_to_conflict_set_;
std::set<ConflictSet*> conflict_sets_;
// Nonblocking conflicts are those which should not block forward progress
// (they will not result in the syncer being stuck). This currently only
// includes entries we cannot yet decrypt because the passphrase has not
// arrived.
// With nonblocking conflicts, we want to go to the syncer's
// APPLY_UPDATES_TO_RESOLVE_CONFLICTS step, but we want to ignore them after.
// Because they are not passed to the conflict resolver, they do not trigger
// syncer_stuck.
// TODO(zea): at some point we may have nonblocking conflicts that should be
// resolved in the conflict resolver. We'll need to change this then.
// See http://crbug.com/76596.
std::set<syncable::Id> nonblocking_conflicting_item_ids_;
// Whether a conflicting item was added or removed since
// the last call to reset_progress_changed(), if any. In practice this
// points to StatusController::is_dirty_.
bool* dirty_;
};
typedef std::pair<VerifyResult, sync_pb::SyncEntity> VerifiedUpdate;
typedef std::pair<UpdateAttemptResponse, syncable::Id> AppliedUpdate;
// Tracks update application and verification.
class UpdateProgress {
public:
UpdateProgress();
~UpdateProgress();
void AddVerifyResult(const VerifyResult& verify_result,
const sync_pb::SyncEntity& entity);
// Log a successful or failing update attempt.
void AddAppliedUpdate(const UpdateAttemptResponse& response,
const syncable::Id& id);
// Various iterators.
std::vector<AppliedUpdate>::iterator AppliedUpdatesBegin();
std::vector<VerifiedUpdate>::const_iterator VerifiedUpdatesBegin() const;
std::vector<AppliedUpdate>::const_iterator AppliedUpdatesEnd() const;
std::vector<VerifiedUpdate>::const_iterator VerifiedUpdatesEnd() const;
// Returns the number of update application attempts. This includes both
// failures and successes.
int AppliedUpdatesSize() const { return applied_updates_.size(); }
int VerifiedUpdatesSize() const { return verified_updates_.size(); }
bool HasVerifiedUpdates() const { return !verified_updates_.empty(); }
bool HasAppliedUpdates() const { return !applied_updates_.empty(); }
// Count the number of successful update applications that have happend this
// cycle. Note that if an item is successfully applied twice, it will be
// double counted here.
int SuccessfullyAppliedUpdateCount() const;
// Returns true if at least one update application failed due to a conflict
// during this sync cycle.
bool HasConflictingUpdates() const;
private:
// Container for updates that passed verification.
std::vector<VerifiedUpdate> verified_updates_;
// Stores the result of the various ApplyUpdate attempts we've made.
// May contain duplicate entries.
std::vector<AppliedUpdate> applied_updates_;
};
struct SyncCycleControlParameters {
SyncCycleControlParameters() : conflict_sets_built(false),
conflicts_resolved(false),
items_committed(false) {}
// Set to true by BuildAndProcessConflictSetsCommand if the RESOLVE_CONFLICTS
// step is needed.
bool conflict_sets_built;
// Set to true by ResolveConflictsCommand if any forward progress was made.
bool conflicts_resolved;
// Set to true by PostCommitMessageCommand if any commits were successful.
bool items_committed;
};
// DirtyOnWrite wraps a value such that any write operation will update a
// specified dirty bit, which can be used to determine if a notification should
// be sent due to state change.
template <typename T>
class DirtyOnWrite {
public:
explicit DirtyOnWrite(bool* dirty) : dirty_(dirty) {}
DirtyOnWrite(bool* dirty, const T& t) : t_(t), dirty_(dirty) {}
T* mutate() {
*dirty_ = true;
return &t_;
}
const T& value() const { return t_; }
private:
T t_;
bool* dirty_;
};
// The next 3 structures declare how all the state involved in running a sync
// cycle is divided between global scope (applies to all model types),
// ModelSafeGroup scope (applies to all data types in a group), and single
// model type scope. Within this breakdown, each struct declares which bits
// of state are dirty-on-write and should incur dirty bit updates if changed.
// Grouping of all state that applies to all model types. Note that some
// components of the global grouping can internally implement finer grained
// scope control (such as OrderedCommitSet), but the top level entity is still
// a singleton with respect to model types.
struct AllModelTypeState {
explicit AllModelTypeState(bool* dirty_flag);
~AllModelTypeState();
// Commits for all model types are bundled together into a single message.
ClientToServerMessage commit_message;
ClientToServerResponse commit_response;
// We GetUpdates for some combination of types at once.
// requested_update_types stores the set of types which were requested.
syncable::ModelTypeBitSet updates_request_types;
ClientToServerResponse updates_response;
// Used to build the shared commit message.
DirtyOnWrite<std::vector<int64> > unsynced_handles;
DirtyOnWrite<SyncerStatus> syncer_status;
DirtyOnWrite<ErrorCounters> error_counters;
SyncCycleControlParameters control_params;
DirtyOnWrite<int64> num_server_changes_remaining;
OrderedCommitSet commit_set;
};
// Grouping of all state that applies to a single ModelSafeGroup.
struct PerModelSafeGroupState {
explicit PerModelSafeGroupState(bool* dirty_flag);
~PerModelSafeGroupState();
UpdateProgress update_progress;
ConflictProgress conflict_progress;
};
} // namespace sessions
} // namespace browser_sync
#endif // CHROME_BROWSER_SYNC_SESSIONS_SESSION_STATE_H_
|