status_controller.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
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#include "chrome/browser/sync/sessions/status_controller.h"
6
7#include "base/basictypes.h"
8#include "chrome/browser/sync/syncable/model_type.h"
9
10namespace browser_sync {
11namespace sessions {
12
13using syncable::FIRST_REAL_MODEL_TYPE;
14using syncable::MODEL_TYPE_COUNT;
15
16StatusController::StatusController(const ModelSafeRoutingInfo& routes)
17    : shared_(&is_dirty_),
18      per_model_group_deleter_(&per_model_group_),
19      per_model_type_deleter_(&per_model_type_),
20      is_dirty_(false),
21      group_restriction_in_effect_(false),
22      group_restriction_(GROUP_PASSIVE),
23      routing_info_(routes) {
24}
25
26bool StatusController::TestAndClearIsDirty() {
27  bool is_dirty = is_dirty_;
28  is_dirty_ = false;
29  return is_dirty;
30}
31
32PerModelSafeGroupState* StatusController::GetOrCreateModelSafeGroupState(
33    bool restrict, ModelSafeGroup group) {
34  DCHECK(restrict == group_restriction_in_effect_) << "Group violation!";
35  if (per_model_group_.find(group) == per_model_group_.end()) {
36    PerModelSafeGroupState* state = new PerModelSafeGroupState(&is_dirty_);
37    per_model_group_[group] = state;
38    return state;
39  }
40  return per_model_group_[group];
41}
42
43PerModelTypeState* StatusController::GetOrCreateModelTypeState(
44    bool restrict, syncable::ModelType model) {
45  if (restrict) {
46    DCHECK(group_restriction_in_effect_) << "No group restriction in effect!";
47    DCHECK_EQ(group_restriction_, GetGroupForModelType(model, routing_info_));
48  }
49  if (per_model_type_.find(model) == per_model_type_.end()) {
50    PerModelTypeState* state = new PerModelTypeState(&is_dirty_);
51    per_model_type_[model] = state;
52    return state;
53  }
54  return per_model_type_[model];
55}
56
57void StatusController::increment_num_conflicting_commits_by(int value) {
58  if (value == 0)
59    return;
60  shared_.error_counters.mutate()->num_conflicting_commits += value;
61}
62
63void StatusController::reset_num_conflicting_commits() {
64  if (shared_.error_counters.value().num_conflicting_commits != 0)
65    shared_.error_counters.mutate()->num_conflicting_commits = 0;
66}
67
68void StatusController::set_num_consecutive_transient_error_commits(int value) {
69  if (shared_.error_counters.value().consecutive_transient_error_commits !=
70      value) {
71    shared_.error_counters.mutate()->consecutive_transient_error_commits =
72        value;
73  }
74}
75
76void StatusController::increment_num_consecutive_transient_error_commits_by(
77    int value) {
78  set_num_consecutive_transient_error_commits(
79      shared_.error_counters.value().consecutive_transient_error_commits +
80      value);
81}
82
83void StatusController::set_num_consecutive_errors(int value) {
84  if (shared_.error_counters.value().consecutive_errors != value)
85    shared_.error_counters.mutate()->consecutive_errors = value;
86}
87
88void StatusController::set_current_download_timestamp(
89    syncable::ModelType model,
90    int64 current_timestamp) {
91  PerModelTypeState* state = GetOrCreateModelTypeState(false, model);
92  if (current_timestamp > state->current_download_timestamp.value())
93    *(state->current_download_timestamp.mutate()) = current_timestamp;
94}
95
96void StatusController::set_num_server_changes_remaining(
97    int64 changes_remaining) {
98  if (shared_.num_server_changes_remaining.value() != changes_remaining)
99    *(shared_.num_server_changes_remaining.mutate()) = changes_remaining;
100}
101
102void StatusController::set_over_quota(bool over_quota) {
103  if (shared_.syncer_status.value().over_quota != over_quota)
104    shared_.syncer_status.mutate()->over_quota = over_quota;
105}
106
107void StatusController::set_invalid_store(bool invalid_store) {
108  if (shared_.syncer_status.value().invalid_store != invalid_store)
109    shared_.syncer_status.mutate()->invalid_store = invalid_store;
110}
111
112void StatusController::set_syncer_stuck(bool syncer_stuck) {
113  if (shared_.syncer_status.value().syncer_stuck != syncer_stuck)
114    shared_.syncer_status.mutate()->syncer_stuck = syncer_stuck;
115}
116
117void StatusController::set_syncing(bool syncing) {
118  if (shared_.syncer_status.value().syncing != syncing)
119    shared_.syncer_status.mutate()->syncing = syncing;
120}
121
122void StatusController::set_num_successful_bookmark_commits(int value) {
123  if (shared_.syncer_status.value().num_successful_bookmark_commits != value)
124    shared_.syncer_status.mutate()->num_successful_bookmark_commits = value;
125}
126
127void StatusController::set_unsynced_handles(
128    const std::vector<int64>& unsynced_handles) {
129  if (!operator==(unsynced_handles, shared_.unsynced_handles.value())) {
130    *(shared_.unsynced_handles.mutate()) = unsynced_handles;
131  }
132}
133
134void StatusController::increment_num_consecutive_errors() {
135  set_num_consecutive_errors(
136      shared_.error_counters.value().consecutive_errors + 1);
137}
138
139void StatusController::increment_num_consecutive_errors_by(int value) {
140  set_num_consecutive_errors(
141      shared_.error_counters.value().consecutive_errors + value);
142}
143
144void StatusController::increment_num_successful_bookmark_commits() {
145  set_num_successful_bookmark_commits(
146      shared_.syncer_status.value().num_successful_bookmark_commits + 1);
147}
148
149void StatusController::increment_num_successful_commits() {
150  shared_.syncer_status.mutate()->num_successful_commits++;
151}
152
153void StatusController::set_commit_set(const OrderedCommitSet& commit_set) {
154  DCHECK(!group_restriction_in_effect_);
155  shared_.commit_set = commit_set;
156}
157
158void StatusController::update_conflict_sets_built(bool built) {
159  shared_.control_params.conflict_sets_built |= built;
160}
161void StatusController::update_conflicts_resolved(bool resolved) {
162  shared_.control_params.conflict_sets_built |= resolved;
163}
164void StatusController::reset_conflicts_resolved() {
165  shared_.control_params.conflicts_resolved = false;
166}
167void StatusController::set_items_committed() {
168  shared_.control_params.items_committed = true;
169}
170
171// Returns the number of updates received from the sync server.
172int64 StatusController::CountUpdates() const {
173  const ClientToServerResponse& updates = shared_.updates_response;
174  if (updates.has_get_updates()) {
175    return updates.get_updates().entries().size();
176  } else {
177    return 0;
178  }
179}
180
181bool StatusController::CurrentCommitIdProjectionHasIndex(size_t index) {
182  OrderedCommitSet::Projection proj =
183      shared_.commit_set.GetCommitIdProjection(group_restriction_);
184  return std::binary_search(proj.begin(), proj.end(), index);
185}
186
187int64 StatusController::ComputeMaxLocalTimestamp() const {
188  std::map<syncable::ModelType, PerModelTypeState*>::const_iterator it =
189      per_model_type_.begin();
190  int64 max_timestamp = 0;
191  for (; it != per_model_type_.end(); ++it) {
192    if (it->second->current_download_timestamp.value() > max_timestamp)
193      max_timestamp = it->second->current_download_timestamp.value();
194  }
195  return max_timestamp;
196}
197
198bool StatusController::HasConflictingUpdates() const {
199  DCHECK(!group_restriction_in_effect_)
200      << "HasConflictingUpdates applies to all ModelSafeGroups";
201  std::map<ModelSafeGroup, PerModelSafeGroupState*>::const_iterator it =
202    per_model_group_.begin();
203  for (; it != per_model_group_.end(); ++it) {
204    if (it->second->update_progress.HasConflictingUpdates())
205      return true;
206  }
207  return false;
208}
209
210int StatusController::TotalNumConflictingItems() const {
211  DCHECK(!group_restriction_in_effect_)
212      << "TotalNumConflictingItems applies to all ModelSafeGroups";
213  std::map<ModelSafeGroup, PerModelSafeGroupState*>::const_iterator it =
214    per_model_group_.begin();
215  int sum = 0;
216  for (; it != per_model_group_.end(); ++it) {
217    sum += it->second->conflict_progress.ConflictingItemsSize();
218  }
219  return sum;
220}
221
222bool StatusController::ServerSaysNothingMoreToDownload() const {
223  if (!download_updates_succeeded())
224    return false;
225  // If we didn't request every enabled datatype, then we can't say for
226  // sure that there's nothing left to download.
227  for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
228    if (!updates_request_parameters().data_types[i] &&
229        routing_info_.count(syncable::ModelTypeFromInt(i)) != 0) {
230      return false;
231    }
232  }
233  // The server indicates "you're up to date" by not sending a new
234  // timestamp.
235  return !updates_response().get_updates().has_new_timestamp();
236}
237
238}  // namespace sessions
239}  // namespace browser_sync
240