session_state.h revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2009 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// The 'sessions' namespace comprises all the pieces of state that are
6// combined to form a SyncSession instance. In that way, it can be thought of
7// as an extension of the SyncSession type itself. Session scoping gives
8// context to things like "conflict progress", "update progress", etc, and the
9// separation this file provides allows clients to only include the parts they
10// need rather than the entire session stack.
11
12#ifndef CHROME_BROWSER_SYNC_SESSIONS_SESSION_STATE_H_
13#define CHROME_BROWSER_SYNC_SESSIONS_SESSION_STATE_H_
14#pragma once
15
16#include <set>
17#include <vector>
18
19#include "base/basictypes.h"
20#include "chrome/browser/sync/engine/syncer_types.h"
21#include "chrome/browser/sync/engine/syncproto.h"
22#include "chrome/browser/sync/sessions/ordered_commit_set.h"
23#include "chrome/browser/sync/syncable/model_type.h"
24#include "chrome/browser/sync/syncable/syncable.h"
25
26namespace syncable {
27class DirectoryManager;
28}
29
30namespace browser_sync {
31namespace sessions {
32
33class UpdateProgress;
34
35// Data pertaining to the status of an active Syncer object.
36struct SyncerStatus {
37  SyncerStatus()
38      : invalid_store(false), syncer_stuck(false),
39        syncing(false), num_successful_commits(0),
40        num_successful_bookmark_commits(0) {}
41
42  // True when we get such an INVALID_STORE error from the server.
43  bool invalid_store;
44  // True iff we're stuck.
45  bool syncer_stuck;
46  bool syncing;
47  int num_successful_commits;
48  // This is needed for monitoring extensions activity.
49  int num_successful_bookmark_commits;
50};
51
52// Counters for various errors that can occur repeatedly during a sync session.
53struct ErrorCounters {
54  ErrorCounters() : num_conflicting_commits(0),
55                    consecutive_transient_error_commits(0),
56                    consecutive_errors(0) {}
57  int num_conflicting_commits;
58
59  // Number of commits hitting transient errors since the last successful
60  // commit.
61  int consecutive_transient_error_commits;
62
63  // Incremented when get_updates fails, commit fails, and when hitting
64  // transient errors. When any of these succeed, this counter is reset.
65  // TODO(chron): Reduce number of weird counters we use.
66  int consecutive_errors;
67};
68
69// An immutable snapshot of state from a SyncSession.  Convenient to use as
70// part of notifications as it is inherently thread-safe.
71struct SyncSessionSnapshot {
72  SyncSessionSnapshot(const SyncerStatus& syncer_status,
73      const ErrorCounters& errors,
74      int64 num_server_changes_remaining,
75      int64 max_local_timestamp,
76      bool is_share_usable,
77      const syncable::ModelTypeBitSet& initial_sync_ended,
78      bool more_to_sync,
79      bool is_silenced,
80      int64 unsynced_count,
81      int num_conflicting_updates,
82                      bool did_commit_items);
83  ~SyncSessionSnapshot();
84
85  const SyncerStatus syncer_status;
86  const ErrorCounters errors;
87  const int64 num_server_changes_remaining;
88  const int64 max_local_timestamp;
89  const bool is_share_usable;
90  const syncable::ModelTypeBitSet initial_sync_ended;
91  const bool has_more_to_sync;
92  const bool is_silenced;
93  const int64 unsynced_count;
94  const int num_conflicting_updates;
95  const bool did_commit_items;
96};
97
98// Tracks progress of conflicts and their resolution using conflict sets.
99class ConflictProgress {
100 public:
101  explicit ConflictProgress(bool* dirty_flag);
102  ~ConflictProgress();
103  // Various iterators, size, and retrieval functions for conflict sets.
104  IdToConflictSetMap::const_iterator IdToConflictSetBegin() const;
105  IdToConflictSetMap::const_iterator IdToConflictSetEnd() const;
106  IdToConflictSetMap::size_type IdToConflictSetSize() const;
107  IdToConflictSetMap::const_iterator IdToConflictSetFind(
108      const syncable::Id& the_id) const;
109  const ConflictSet* IdToConflictSetGet(const syncable::Id& the_id);
110  std::set<ConflictSet*>::const_iterator ConflictSetsBegin() const;
111  std::set<ConflictSet*>::const_iterator ConflictSetsEnd() const;
112  std::set<ConflictSet*>::size_type ConflictSetsSize() const;
113
114  // Various mutators for tracking commit conflicts.
115  void AddConflictingItemById(const syncable::Id& the_id);
116  void EraseConflictingItemById(const syncable::Id& the_id);
117  int ConflictingItemsSize() const { return conflicting_item_ids_.size(); }
118  std::set<syncable::Id>::iterator ConflictingItemsBegin();
119  std::set<syncable::Id>::const_iterator ConflictingItemsBeginConst() const;
120  std::set<syncable::Id>::const_iterator ConflictingItemsEnd() const;
121
122  void MergeSets(const syncable::Id& set1, const syncable::Id& set2);
123  void CleanupSets();
124
125 private:
126  // TODO(sync): move away from sets if it makes more sense.
127  std::set<syncable::Id> conflicting_item_ids_;
128  std::map<syncable::Id, ConflictSet*> id_to_conflict_set_;
129  std::set<ConflictSet*> conflict_sets_;
130
131  // Whether a conflicting item was added or removed since
132  // the last call to reset_progress_changed(), if any. In practice this
133  // points to StatusController::is_dirty_.
134  bool* dirty_;
135};
136
137typedef std::pair<VerifyResult, sync_pb::SyncEntity> VerifiedUpdate;
138typedef std::pair<UpdateAttemptResponse, syncable::Id> AppliedUpdate;
139
140// Tracks update application and verification.
141class UpdateProgress {
142 public:
143  UpdateProgress();
144  ~UpdateProgress();
145
146  void AddVerifyResult(const VerifyResult& verify_result,
147                       const sync_pb::SyncEntity& entity);
148
149  // Log a successful or failing update attempt.
150  void AddAppliedUpdate(const UpdateAttemptResponse& response,
151                        const syncable::Id& id);
152
153  // Various iterators.
154  std::vector<AppliedUpdate>::iterator AppliedUpdatesBegin();
155  std::vector<VerifiedUpdate>::const_iterator VerifiedUpdatesBegin() const;
156  std::vector<AppliedUpdate>::const_iterator AppliedUpdatesEnd() const;
157  std::vector<VerifiedUpdate>::const_iterator VerifiedUpdatesEnd() const;
158
159  // Returns the number of update application attempts.  This includes both
160  // failures and successes.
161  int AppliedUpdatesSize() const { return applied_updates_.size(); }
162  int VerifiedUpdatesSize() const { return verified_updates_.size(); }
163  bool HasVerifiedUpdates() const { return !verified_updates_.empty(); }
164  bool HasAppliedUpdates() const { return !applied_updates_.empty(); }
165
166  // Count the number of successful update applications that have happend this
167  // cycle. Note that if an item is successfully applied twice, it will be
168  // double counted here.
169  int SuccessfullyAppliedUpdateCount() const;
170
171  // Returns true if at least one update application failed due to a conflict
172  // during this sync cycle.
173  bool HasConflictingUpdates() const;
174
175 private:
176  // Container for updates that passed verification.
177  std::vector<VerifiedUpdate> verified_updates_;
178
179  // Stores the result of the various ApplyUpdate attempts we've made.
180  // May contain duplicate entries.
181  std::vector<AppliedUpdate> applied_updates_;
182};
183
184struct SyncCycleControlParameters {
185  SyncCycleControlParameters() : conflict_sets_built(false),
186                                 conflicts_resolved(false),
187                                 items_committed(false) {}
188  // Set to true by BuildAndProcessConflictSetsCommand if the RESOLVE_CONFLICTS
189  // step is needed.
190  bool conflict_sets_built;
191
192  // Set to true by ResolveConflictsCommand if any forward progress was made.
193  bool conflicts_resolved;
194
195  // Set to true by PostCommitMessageCommand if any commits were successful.
196  bool items_committed;
197};
198
199// DirtyOnWrite wraps a value such that any write operation will update a
200// specified dirty bit, which can be used to determine if a notification should
201// be sent due to state change.
202template <typename T>
203class DirtyOnWrite {
204 public:
205  explicit DirtyOnWrite(bool* dirty) : dirty_(dirty) {}
206  DirtyOnWrite(bool* dirty, const T& t) : t_(t), dirty_(dirty) {}
207  T* mutate() {
208    *dirty_ = true;
209    return &t_;
210  }
211  const T& value() const { return t_; }
212 private:
213  T t_;
214  bool* dirty_;
215};
216
217// The next 3 structures declare how all the state involved in running a sync
218// cycle is divided between global scope (applies to all model types),
219// ModelSafeGroup scope (applies to all data types in a group), and single
220// model type scope.  Within this breakdown, each struct declares which bits
221// of state are dirty-on-write and should incur dirty bit updates if changed.
222
223// Grouping of all state that applies to all model types.  Note that some
224// components of the global grouping can internally implement finer grained
225// scope control (such as OrderedCommitSet), but the top level entity is still
226// a singleton with respect to model types.
227struct AllModelTypeState {
228  explicit AllModelTypeState(bool* dirty_flag);
229  ~AllModelTypeState();
230
231  // Commits for all model types are bundled together into a single message.
232  ClientToServerMessage commit_message;
233  ClientToServerResponse commit_response;
234  // We GetUpdates for some combination of types at once.
235  // requested_update_types stores the set of types which were requested.
236  syncable::MultiTypeTimeStamp updates_request_parameters;
237  ClientToServerResponse updates_response;
238  // Used to build the shared commit message.
239  DirtyOnWrite<std::vector<int64> > unsynced_handles;
240  DirtyOnWrite<SyncerStatus> syncer_status;
241  DirtyOnWrite<ErrorCounters> error_counters;
242  SyncCycleControlParameters control_params;
243  DirtyOnWrite<int64> num_server_changes_remaining;
244  OrderedCommitSet commit_set;
245};
246
247// Grouping of all state that applies to a single ModelSafeGroup.
248struct PerModelSafeGroupState {
249  explicit PerModelSafeGroupState(bool* dirty_flag);
250  ~PerModelSafeGroupState();
251
252  UpdateProgress update_progress;
253  ConflictProgress conflict_progress;
254};
255
256// Grouping of all state that applies to a single ModelType.
257struct PerModelTypeState {
258  explicit PerModelTypeState(bool* dirty_flag);
259  ~PerModelTypeState();
260
261  DirtyOnWrite<int64> current_download_timestamp;
262};
263
264}  // namespace sessions
265}  // namespace browser_sync
266
267#endif  // CHROME_BROWSER_SYNC_SESSIONS_SESSION_STATE_H_
268