Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package


// 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 file.

// StatusController handles all counter and status related number crunching and
// state tracking on behalf of a SyncSession.  It 'controls' the model data
// defined in session_state.h.  The most important feature of StatusController
// is the ScopedModelSafetyRestriction. When one of these is active, the
// underlying data set exposed via accessors is swapped out to the appropriate
// set for the restricted ModelSafeGroup behind the scenes.  For example, if
// GROUP_UI is set, then accessors such as conflict_progress() and commit_ids()
// are implicitly restricted to returning only data pertaining to GROUP_UI.
// You can see which parts of status fall into this "restricted" category, the
// global "shared" category for all model types, or the single per-model type
// category by looking at the struct declarations in session_state.h.
// If these accessors are invoked without a restriction in place, this is a
// violation and will cause debug assertions to surface improper use of the API
// in development.  Likewise for invocation of "shared" accessors when a
// restriction is in place; for safety's sake, an assertion will fire.
// NOTE: There is no concurrent access protection provided by this class. It
// assumes one single thread is accessing this class for each unique
// ModelSafeGroup, and also only one single thread (in practice, the
// SyncerThread) responsible for all "shared" access when no restriction is in
// place. Thus, every bit of data is to be accessed mutually exclusively with
// respect to threads.
// StatusController can also track if changes occur to certain parts of state
// so that various parts of the sync engine can avoid broadcasting
// notifications if no changes occurred.


#include <map>

#include "base/stl_util-inl.h"
#include "chrome/browser/sync/sessions/ordered_commit_set.h"
#include "chrome/browser/sync/sessions/session_state.h"

namespace browser_sync {
namespace sessions {

class StatusController {
  explicit StatusController(const ModelSafeRoutingInfo& routes);

  // Returns true if some portion of the session state has changed (is dirty)
  // since it was created or was last reset.
  bool TestAndClearIsDirty();

  // Progress counters.
  const ConflictProgress& conflict_progress() {
    return GetOrCreateModelSafeGroupState(true,
  ConflictProgress* mutable_conflict_progress() {
    return &GetOrCreateModelSafeGroupState(true,
  const UpdateProgress& update_progress() {
    return GetOrCreateModelSafeGroupState(true,
  UpdateProgress* mutable_update_progress() {
    return &GetOrCreateModelSafeGroupState(true,
  // Some unrestricted, non-ModelChangingSyncerCommand commands need to store
  // meta information about updates.
  UpdateProgress* GetUnrestrictedUpdateProgress(ModelSafeGroup group) {
    return &GetOrCreateModelSafeGroupState(false, group)->update_progress;

  // ClientToServer messages.
  const ClientToServerMessage& commit_message() {
    return shared_.commit_message;
  ClientToServerMessage* mutable_commit_message() {
    return &shared_.commit_message;
  const ClientToServerResponse& commit_response() const {
    return shared_.commit_response;
  ClientToServerResponse* mutable_commit_response() {
    return &shared_.commit_response;
  const syncable::MultiTypeTimeStamp& updates_request_parameters() const {
    return shared_.updates_request_parameters;
  void set_updates_request_parameters(
      const syncable::MultiTypeTimeStamp& value) {
    shared_.updates_request_parameters = value;
  const ClientToServerResponse& updates_response() const {
    return shared_.updates_response;
  ClientToServerResponse* mutable_updates_response() {
    return &shared_.updates_response;

  // Errors and SyncerStatus.
  const ErrorCounters& error_counters() const {
    return shared_.error_counters.value();
  const SyncerStatus& syncer_status() const {
    return shared_.syncer_status.value();

  // Changelog related state.
  int64 num_server_changes_remaining() const {
    return shared_.num_server_changes_remaining.value();
  // Aggregate max over all data type timestamps, used for UI reporting.
  int64 ComputeMaxLocalTimestamp() const;

  // Commit path data.
  const std::vector<syncable::Id>& commit_ids() const {
    DCHECK(!group_restriction_in_effect_) << "Group restriction in effect!";
    return shared_.commit_set.GetAllCommitIds();
  const OrderedCommitSet::Projection& commit_id_projection() {
        << "No group restriction for projection.";
    return shared_.commit_set.GetCommitIdProjection(group_restriction_);
  const syncable::Id& GetCommitIdAt(size_t index) {
    return shared_.commit_set.GetCommitIdAt(index);
  syncable::ModelType GetCommitIdModelTypeAt(size_t index) {
    return shared_.commit_set.GetModelTypeAt(index);
  const std::vector<int64>& unsynced_handles() const {
        << "unsynced_handles is unrestricted.";
    return shared_.unsynced_handles.value();

  // Control parameters for sync cycles.
  bool conflict_sets_built() const {
    return shared_.control_params.conflict_sets_built;
  bool conflicts_resolved() const {
    return shared_.control_params.conflicts_resolved;
  bool did_commit_items() const {
    return shared_.control_params.items_committed;

  // If a GetUpdates for any data type resulted in downloading an update that
  // is in conflict, this method returns true.
  bool HasConflictingUpdates() const;

  // Aggregate sum of ConflictingItemSize() over all ConflictProgress objects
  // (one for each ModelSafeGroup currently in-use).
  int TotalNumConflictingItems() const;

  // Returns the number of updates received from the sync server.
  int64 CountUpdates() const;

  // Returns true iff any of the commit ids added during this session are
  // bookmark related, and the bookmark group restriction is in effect.
  bool HasBookmarkCommitActivity() const {
    return ActiveGroupRestrictionIncludesModel(syncable::BOOKMARKS) &&

  // Returns true if the last download_updates_command received a valid
  // server response.
  bool download_updates_succeeded() const {
    return updates_response().has_get_updates();

  // Returns true if the last updates response indicated that we were fully
  // up to date.  This is subtle: if it's false, it could either mean that
  // the server said there WAS more to download, or it could mean that we
  // were unable to reach the server.  If we didn't request every enabled
  // datatype, then we can't say for sure that there's nothing left to
  // download: in that case, this also returns false.
  bool ServerSaysNothingMoreToDownload() const;

  ModelSafeGroup group_restriction() const {
    return group_restriction_;

  // Check whether a particular model is included by the active group
  // restriction.
  bool ActiveGroupRestrictionIncludesModel(syncable::ModelType model) const {
    if (!group_restriction_in_effect_)
      return true;
    ModelSafeRoutingInfo::const_iterator it = routing_info_.find(model);
    if (it == routing_info_.end())
      return false;
    return group_restriction() == it->second;

  // A toolbelt full of methods for updating counters and flags.
  void increment_num_conflicting_commits_by(int value);
  void reset_num_conflicting_commits();
  void set_num_consecutive_transient_error_commits(int value);
  void increment_num_consecutive_transient_error_commits_by(int value);
  void set_num_consecutive_errors(int value);
  void increment_num_consecutive_errors();
  void increment_num_consecutive_errors_by(int value);
  void set_current_download_timestamp(syncable::ModelType model,
                                      int64 current_timestamp);
  void set_num_server_changes_remaining(int64 changes_remaining);
  void set_over_quota(bool over_quota);
  void set_invalid_store(bool invalid_store);
  void set_syncer_stuck(bool syncer_stuck);
  void set_syncing(bool syncing);
  void set_num_successful_bookmark_commits(int value);
  void increment_num_successful_commits();
  void increment_num_successful_bookmark_commits();
  void set_unsynced_handles(const std::vector<int64>& unsynced_handles);

  void set_commit_set(const OrderedCommitSet& commit_set);
  void update_conflict_sets_built(bool built);
  void update_conflicts_resolved(bool resolved);
  void reset_conflicts_resolved();
  void set_items_committed();

  friend class ScopedModelSafeGroupRestriction;

  // Returns true iff the commit id projection for |group_restriction_|
  // references position |index| into the full set of commit ids in play.
  bool CurrentCommitIdProjectionHasIndex(size_t index);

  // Helper to lazily create objects for per-ModelSafeGroup state.
  PerModelSafeGroupState* GetOrCreateModelSafeGroupState(bool restrict,
                                                         ModelSafeGroup group);
  // Helper to lazily create objects for per-model type state.
  PerModelTypeState* GetOrCreateModelTypeState(bool restrict,
                                               syncable::ModelType model);

  AllModelTypeState shared_;
  std::map<ModelSafeGroup, PerModelSafeGroupState*> per_model_group_;
  std::map<syncable::ModelType, PerModelTypeState*> per_model_type_;

  STLValueDeleter<std::map<ModelSafeGroup, PerModelSafeGroupState*> >
  STLValueDeleter<std::map<syncable::ModelType, PerModelTypeState*> >

  // Set to true if any DirtyOnWrite pieces of state we maintain are changed.
  // Reset to false by TestAndClearIsDirty.
  bool is_dirty_;

  // Used to fail read/write operations on state that don't obey the current
  // active ModelSafeWorker contract.
  bool group_restriction_in_effect_;
  ModelSafeGroup group_restriction_;

  const ModelSafeRoutingInfo routing_info_;


// A utility to restrict access to only those parts of the given
// StatusController that pertain to the specified ModelSafeGroup.
class ScopedModelSafeGroupRestriction {
  ScopedModelSafeGroupRestriction(StatusController* to_restrict,
                                  ModelSafeGroup restriction)
      : status_(to_restrict) {
    status_->group_restriction_ = restriction;
    status_->group_restriction_in_effect_ = true;
  ~ScopedModelSafeGroupRestriction() {
    status_->group_restriction_in_effect_ = false;
  StatusController* status_;



Generated by  Doxygen 1.6.0   Back to index