• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // StatusController handles all counter and status related number crunching and
6 // state tracking on behalf of a SyncSession.  It 'controls' the model data
7 // defined in session_state.h.  The most important feature of StatusController
8 // is the ScopedModelSafetyRestriction. When one of these is active, the
9 // underlying data set exposed via accessors is swapped out to the appropriate
10 // set for the restricted ModelSafeGroup behind the scenes.  For example, if
11 // GROUP_UI is set, then accessors such as conflict_progress() and commit_ids()
12 // are implicitly restricted to returning only data pertaining to GROUP_UI.
13 // You can see which parts of status fall into this "restricted" category, or
14 // the global "shared" category for all model types, by looking at the struct
15 // declarations in session_state.h. If these accessors are invoked without a
16 // restriction in place, this is a violation and will cause debug assertions
17 // to surface improper use of the API in development.  Likewise for
18 // invocation of "shared" accessors when a restriction is in place; for
19 // safety's sake, an assertion will fire.
20 //
21 // NOTE: There is no concurrent access protection provided by this class. It
22 // assumes one single thread is accessing this class for each unique
23 // ModelSafeGroup, and also only one single thread (in practice, the
24 // SyncerThread) responsible for all "shared" access when no restriction is in
25 // place. Thus, every bit of data is to be accessed mutually exclusively with
26 // respect to threads.
27 //
28 // StatusController can also track if changes occur to certain parts of state
29 // so that various parts of the sync engine can avoid broadcasting
30 // notifications if no changes occurred.
31 
32 #ifndef CHROME_BROWSER_SYNC_SESSIONS_STATUS_CONTROLLER_H_
33 #define CHROME_BROWSER_SYNC_SESSIONS_STATUS_CONTROLLER_H_
34 #pragma once
35 
36 #include <map>
37 
38 #include "base/stl_util-inl.h"
39 #include "chrome/browser/sync/sessions/ordered_commit_set.h"
40 #include "chrome/browser/sync/sessions/session_state.h"
41 
42 namespace browser_sync {
43 namespace sessions {
44 
45 class StatusController {
46  public:
47   explicit StatusController(const ModelSafeRoutingInfo& routes);
48   ~StatusController();
49 
50   // Returns true if some portion of the session state has changed (is dirty)
51   // since it was created or was last reset.
52   bool TestAndClearIsDirty();
53 
54   // Progress counters.
conflict_progress()55   const ConflictProgress& conflict_progress() {
56     return GetOrCreateModelSafeGroupState(true,
57         group_restriction_)->conflict_progress;
58   }
mutable_conflict_progress()59   ConflictProgress* mutable_conflict_progress() {
60     return &GetOrCreateModelSafeGroupState(true,
61         group_restriction_)->conflict_progress;
62   }
update_progress()63   const UpdateProgress& update_progress() {
64     return GetOrCreateModelSafeGroupState(true,
65         group_restriction_)->update_progress;
66   }
mutable_update_progress()67   UpdateProgress* mutable_update_progress() {
68     return &GetOrCreateModelSafeGroupState(true,
69         group_restriction_)->update_progress;
70   }
71   // Some unrestricted, non-ModelChangingSyncerCommand commands need to store
72   // meta information about updates.
GetUnrestrictedUpdateProgress(ModelSafeGroup group)73   UpdateProgress* GetUnrestrictedUpdateProgress(ModelSafeGroup group) {
74     return &GetOrCreateModelSafeGroupState(false, group)->update_progress;
75   }
76 
77   // ClientToServer messages.
commit_message()78   const ClientToServerMessage& commit_message() {
79     return shared_.commit_message;
80   }
mutable_commit_message()81   ClientToServerMessage* mutable_commit_message() {
82     return &shared_.commit_message;
83   }
commit_response()84   const ClientToServerResponse& commit_response() const {
85     return shared_.commit_response;
86   }
mutable_commit_response()87   ClientToServerResponse* mutable_commit_response() {
88     return &shared_.commit_response;
89   }
updates_request_types()90   const syncable::ModelTypeBitSet& updates_request_types() const {
91     return shared_.updates_request_types;
92   }
set_updates_request_types(const syncable::ModelTypeBitSet & value)93   void set_updates_request_types(const syncable::ModelTypeBitSet& value) {
94     shared_.updates_request_types = value;
95   }
updates_response()96   const ClientToServerResponse& updates_response() const {
97     return shared_.updates_response;
98   }
mutable_updates_response()99   ClientToServerResponse* mutable_updates_response() {
100     return &shared_.updates_response;
101   }
102 
103   // Errors and SyncerStatus.
error_counters()104   const ErrorCounters& error_counters() const {
105     return shared_.error_counters.value();
106   }
syncer_status()107   const SyncerStatus& syncer_status() const {
108     return shared_.syncer_status.value();
109   }
110 
111   // Changelog related state.
num_server_changes_remaining()112   int64 num_server_changes_remaining() const {
113     return shared_.num_server_changes_remaining.value();
114   }
115 
116   // Commit path data.
commit_ids()117   const std::vector<syncable::Id>& commit_ids() const {
118     DCHECK(!group_restriction_in_effect_) << "Group restriction in effect!";
119     return shared_.commit_set.GetAllCommitIds();
120   }
commit_id_projection()121   const OrderedCommitSet::Projection& commit_id_projection() {
122     DCHECK(group_restriction_in_effect_)
123         << "No group restriction for projection.";
124     return shared_.commit_set.GetCommitIdProjection(group_restriction_);
125   }
GetCommitIdAt(size_t index)126   const syncable::Id& GetCommitIdAt(size_t index) {
127     DCHECK(CurrentCommitIdProjectionHasIndex(index));
128     return shared_.commit_set.GetCommitIdAt(index);
129   }
GetCommitIdModelTypeAt(size_t index)130   syncable::ModelType GetCommitIdModelTypeAt(size_t index) {
131     DCHECK(CurrentCommitIdProjectionHasIndex(index));
132     return shared_.commit_set.GetModelTypeAt(index);
133   }
unsynced_handles()134   const std::vector<int64>& unsynced_handles() const {
135     DCHECK(!group_restriction_in_effect_)
136         << "unsynced_handles is unrestricted.";
137     return shared_.unsynced_handles.value();
138   }
139 
140   // Control parameters for sync cycles.
conflict_sets_built()141   bool conflict_sets_built() const {
142     return shared_.control_params.conflict_sets_built;
143   }
conflicts_resolved()144   bool conflicts_resolved() const {
145     return shared_.control_params.conflicts_resolved;
146   }
did_commit_items()147   bool did_commit_items() const {
148     return shared_.control_params.items_committed;
149   }
150 
151   // If a GetUpdates for any data type resulted in downloading an update that
152   // is in conflict, this method returns true.
153   bool HasConflictingUpdates() const;
154 
155   // Aggregate sum of ConflictingItemSize() over all ConflictProgress objects
156   // (one for each ModelSafeGroup currently in-use).
157   int TotalNumConflictingItems() const;
158 
159   // Returns the number of updates received from the sync server.
160   int64 CountUpdates() const;
161 
162   // Returns true iff any of the commit ids added during this session are
163   // bookmark related, and the bookmark group restriction is in effect.
HasBookmarkCommitActivity()164   bool HasBookmarkCommitActivity() const {
165     return ActiveGroupRestrictionIncludesModel(syncable::BOOKMARKS) &&
166         shared_.commit_set.HasBookmarkCommitId();
167   }
168 
169   // Returns true if the last download_updates_command received a valid
170   // server response.
download_updates_succeeded()171   bool download_updates_succeeded() const {
172     return updates_response().has_get_updates();
173   }
174 
175   // Returns true if the last updates response indicated that we were fully
176   // up to date.  This is subtle: if it's false, it could either mean that
177   // the server said there WAS more to download, or it could mean that we
178   // were unable to reach the server.  If we didn't request every enabled
179   // datatype, then we can't say for sure that there's nothing left to
180   // download: in that case, this also returns false.
181   bool ServerSaysNothingMoreToDownload() const;
182 
group_restriction()183   ModelSafeGroup group_restriction() const {
184     return group_restriction_;
185   }
186 
187   // Check whether a particular model is included by the active group
188   // restriction.
ActiveGroupRestrictionIncludesModel(syncable::ModelType model)189   bool ActiveGroupRestrictionIncludesModel(syncable::ModelType model) const {
190     if (!group_restriction_in_effect_)
191       return true;
192     ModelSafeRoutingInfo::const_iterator it = routing_info_.find(model);
193     if (it == routing_info_.end())
194       return false;
195     return group_restriction() == it->second;
196   }
197 
198   // A toolbelt full of methods for updating counters and flags.
199   void increment_num_conflicting_commits_by(int value);
200   void reset_num_conflicting_commits();
201   void set_num_consecutive_transient_error_commits(int value);
202   void increment_num_consecutive_transient_error_commits_by(int value);
203   void set_num_consecutive_errors(int value);
204   void increment_num_consecutive_errors();
205   void increment_num_consecutive_errors_by(int value);
206   void set_num_server_changes_remaining(int64 changes_remaining);
207   void set_invalid_store(bool invalid_store);
208   void set_syncer_stuck(bool syncer_stuck);
209   void set_syncing(bool syncing);
210   void set_num_successful_bookmark_commits(int value);
211   void increment_num_successful_commits();
212   void increment_num_successful_bookmark_commits();
213   void increment_num_updates_downloaded_by(int value);
214   void increment_num_tombstone_updates_downloaded_by(int value);
215   void set_types_needing_local_migration(const syncable::ModelTypeSet& types);
216   void set_unsynced_handles(const std::vector<int64>& unsynced_handles);
217 
218   void set_commit_set(const OrderedCommitSet& commit_set);
219   void update_conflict_sets_built(bool built);
220   void update_conflicts_resolved(bool resolved);
221   void reset_conflicts_resolved();
222   void set_items_committed();
223 
224  private:
225   friend class ScopedModelSafeGroupRestriction;
226 
227   // Returns true iff the commit id projection for |group_restriction_|
228   // references position |index| into the full set of commit ids in play.
229   bool CurrentCommitIdProjectionHasIndex(size_t index);
230 
231   // Helper to lazily create objects for per-ModelSafeGroup state.
232   PerModelSafeGroupState* GetOrCreateModelSafeGroupState(bool restrict,
233                                                          ModelSafeGroup group);
234 
235   AllModelTypeState shared_;
236   std::map<ModelSafeGroup, PerModelSafeGroupState*> per_model_group_;
237 
238   STLValueDeleter<std::map<ModelSafeGroup, PerModelSafeGroupState*> >
239       per_model_group_deleter_;
240 
241   // Set to true if any DirtyOnWrite pieces of state we maintain are changed.
242   // Reset to false by TestAndClearIsDirty.
243   bool is_dirty_;
244 
245   // Used to fail read/write operations on state that don't obey the current
246   // active ModelSafeWorker contract.
247   bool group_restriction_in_effect_;
248   ModelSafeGroup group_restriction_;
249 
250   const ModelSafeRoutingInfo routing_info_;
251 
252   DISALLOW_COPY_AND_ASSIGN(StatusController);
253 };
254 
255 // A utility to restrict access to only those parts of the given
256 // StatusController that pertain to the specified ModelSafeGroup.
257 class ScopedModelSafeGroupRestriction {
258  public:
ScopedModelSafeGroupRestriction(StatusController * to_restrict,ModelSafeGroup restriction)259   ScopedModelSafeGroupRestriction(StatusController* to_restrict,
260                                   ModelSafeGroup restriction)
261       : status_(to_restrict) {
262     DCHECK(!status_->group_restriction_in_effect_);
263     status_->group_restriction_ = restriction;
264     status_->group_restriction_in_effect_ = true;
265   }
~ScopedModelSafeGroupRestriction()266   ~ScopedModelSafeGroupRestriction() {
267     DCHECK(status_->group_restriction_in_effect_);
268     status_->group_restriction_in_effect_ = false;
269   }
270  private:
271   StatusController* status_;
272   DISALLOW_COPY_AND_ASSIGN(ScopedModelSafeGroupRestriction);
273 };
274 
275 }
276 }
277 
278 #endif  // CHROME_BROWSER_SYNC_SESSIONS_STATUS_CONTROLLER_H_
279