blob: 4dbc09553f03bff52b148b2f06e81ba19e9f03d5 [file] [log] [blame]
[email protected]6a1d0f52010-06-30 05:11:531// Copyright (c) 2010 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/notifier/registration_manager.h"
6
[email protected]b7af0f92011-03-10 23:35:487#include <algorithm>
8#include <cstddef>
[email protected]6a1d0f52010-06-30 05:11:539#include <string>
10
[email protected]b7af0f92011-03-10 23:35:4811#include "base/rand_util.h"
[email protected]6a1d0f52010-06-30 05:11:5312#include "chrome/browser/sync/notifier/invalidation_util.h"
13#include "chrome/browser/sync/syncable/model_type.h"
[email protected]6a1d0f52010-06-30 05:11:5314
15namespace sync_notifier {
16
[email protected]2ea4caeb2011-03-11 00:15:0617RegistrationManager::PendingRegistrationInfo::PendingRegistrationInfo() {}
18
[email protected]b7af0f92011-03-10 23:35:4819RegistrationManager::RegistrationStatus::RegistrationStatus()
20 : model_type(syncable::UNSPECIFIED),
21 registration_manager(NULL),
22 state(invalidation::RegistrationState_UNREGISTERED) {}
23
[email protected]8ba7fa52011-03-11 00:44:3024RegistrationManager::RegistrationStatus::~RegistrationStatus() {}
25
[email protected]b7af0f92011-03-10 23:35:4826void RegistrationManager::RegistrationStatus::DoRegister() {
27 DCHECK_NE(model_type, syncable::UNSPECIFIED);
28 DCHECK(registration_manager);
29 // We might be called explicitly, so stop the timer manually and
30 // reset the delay.
31 registration_timer.Stop();
32 delay = base::TimeDelta();
33 registration_manager->DoRegisterType(model_type);
34 DCHECK(!last_registration_request.is_null());
35}
36
37const int RegistrationManager::kInitialRegistrationDelaySeconds = 5;
38const int RegistrationManager::kRegistrationDelayExponent = 2;
39const double RegistrationManager::kRegistrationDelayMaxJitter = 0.5;
40const int RegistrationManager::kMinRegistrationDelaySeconds = 1;
41// 1 hour.
42const int RegistrationManager::kMaxRegistrationDelaySeconds = 60 * 60;
43
[email protected]6a1d0f52010-06-30 05:11:5344RegistrationManager::RegistrationManager(
45 invalidation::InvalidationClient* invalidation_client)
46 : invalidation_client_(invalidation_client) {
47 DCHECK(invalidation_client_);
[email protected]b7af0f92011-03-10 23:35:4848 // Initialize statuses.
49 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
50 i < syncable::MODEL_TYPE_COUNT; ++i) {
51 syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
52 RegistrationStatus* status = &registration_statuses_[model_type];
53 status->model_type = model_type;
54 status->registration_manager = this;
55 }
[email protected]6a1d0f52010-06-30 05:11:5356}
57
58RegistrationManager::~RegistrationManager() {
59 DCHECK(non_thread_safe_.CalledOnValidThread());
60}
61
[email protected]58d16662011-02-16 01:44:4562void RegistrationManager::SetRegisteredTypes(
63 const syncable::ModelTypeSet& types) {
[email protected]6a1d0f52010-06-30 05:11:5364 DCHECK(non_thread_safe_.CalledOnValidThread());
[email protected]58d16662011-02-16 01:44:4565
[email protected]b7af0f92011-03-10 23:35:4866 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
67 i < syncable::MODEL_TYPE_COUNT; ++i) {
68 syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
69 if (types.count(model_type) > 0) {
70 if (!IsTypeRegistered(model_type)) {
71 TryRegisterType(model_type, false /* is_retry */);
72 }
[email protected]58d16662011-02-16 01:44:4573 } else {
[email protected]b7af0f92011-03-10 23:35:4874 if (IsTypeRegistered(model_type)) {
75 UnregisterType(model_type);
76 }
[email protected]58d16662011-02-16 01:44:4577 }
[email protected]6a1d0f52010-06-30 05:11:5378 }
[email protected]6a1d0f52010-06-30 05:11:5379}
80
[email protected]6a1d0f52010-06-30 05:11:5381void RegistrationManager::MarkRegistrationLost(
82 syncable::ModelType model_type) {
83 DCHECK(non_thread_safe_.CalledOnValidThread());
[email protected]b7af0f92011-03-10 23:35:4884 registration_statuses_[model_type].state =
85 invalidation::RegistrationState_UNREGISTERED;
86 TryRegisterType(model_type, true /* is_retry */);
[email protected]6a1d0f52010-06-30 05:11:5387}
88
89void RegistrationManager::MarkAllRegistrationsLost() {
90 DCHECK(non_thread_safe_.CalledOnValidThread());
[email protected]b7af0f92011-03-10 23:35:4891 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
92 i < syncable::MODEL_TYPE_COUNT; ++i) {
93 syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
94 if (IsTypeRegistered(model_type)) {
95 MarkRegistrationLost(model_type);
[email protected]6a1d0f52010-06-30 05:11:5396 }
[email protected]6a1d0f52010-06-30 05:11:5397 }
98}
99
[email protected]b7af0f92011-03-10 23:35:48100syncable::ModelTypeSet RegistrationManager::GetRegisteredTypes() const {
101 DCHECK(non_thread_safe_.CalledOnValidThread());
102 syncable::ModelTypeSet registered_types;
103 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
104 i < syncable::MODEL_TYPE_COUNT; ++i) {
105 syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
106 if (IsTypeRegistered(model_type)) {
107 registered_types.insert(model_type);
108 }
109 }
110 return registered_types;
111}
112
113RegistrationManager::PendingRegistrationMap
114 RegistrationManager::GetPendingRegistrations() const {
115 DCHECK(non_thread_safe_.CalledOnValidThread());
116 PendingRegistrationMap pending_registrations;
117 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
118 i < syncable::MODEL_TYPE_COUNT; ++i) {
119 syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
120 const RegistrationStatus& status = registration_statuses_[model_type];
121 if (status.registration_timer.IsRunning()) {
122 pending_registrations[model_type].last_registration_request =
123 status.last_registration_request;
124 pending_registrations[model_type].registration_attempt =
125 status.last_registration_attempt;
126 pending_registrations[model_type].delay = status.delay;
127 pending_registrations[model_type].actual_delay =
128 status.registration_timer.GetCurrentDelay();
129 }
130 }
131 return pending_registrations;
132}
133
134void RegistrationManager::FirePendingRegistrationsForTest() {
135 DCHECK(non_thread_safe_.CalledOnValidThread());
136 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
137 i < syncable::MODEL_TYPE_COUNT; ++i) {
138 syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
139 RegistrationStatus* status = &registration_statuses_[model_type];
140 if (status->registration_timer.IsRunning()) {
141 status->DoRegister();
142 }
143 }
144}
145
146// static
147double RegistrationManager::CalculateBackoff(
148 double retry_interval,
149 double initial_retry_interval,
150 double min_retry_interval,
151 double max_retry_interval,
152 double backoff_exponent,
153 double jitter,
154 double max_jitter) {
155 // scaled_jitter lies in [-max_jitter, max_jitter].
156 double scaled_jitter = jitter * max_jitter;
157 double new_retry_interval =
158 (retry_interval == 0.0) ?
159 (initial_retry_interval * (1.0 + scaled_jitter)) :
160 (retry_interval * (backoff_exponent + scaled_jitter));
161 return std::max(min_retry_interval,
162 std::min(max_retry_interval, new_retry_interval));
163}
164
165double RegistrationManager::GetJitter() {
166 // |jitter| lies in [-1.0, 1.0), which is low-biased, but only
167 // barely.
168 //
169 // TODO(akalin): Fix the bias.
170 return 2.0 * base::RandDouble() - 1.0;
171}
172
173void RegistrationManager::TryRegisterType(syncable::ModelType model_type,
174 bool is_retry) {
175 DCHECK(non_thread_safe_.CalledOnValidThread());
176 RegistrationStatus* status = &registration_statuses_[model_type];
177 status->last_registration_attempt = base::Time::Now();
178 if (is_retry) {
179 // If we're a retry, we must have tried at least once before.
180 DCHECK(!status->last_registration_request.is_null());
181 // delay = max(0, (now - last request) + next_delay)
182 status->delay =
183 (status->last_registration_request -
184 status->last_registration_attempt) +
185 status->next_delay;
186 base::TimeDelta delay =
187 (status->delay <= base::TimeDelta()) ?
188 base::TimeDelta() : status->delay;
189 VLOG(2) << "Registering "
190 << syncable::ModelTypeToString(model_type) << " in "
191 << delay.InMilliseconds() << " ms";
192 status->registration_timer.Stop();
193 status->registration_timer.Start(
194 delay, status, &RegistrationManager::RegistrationStatus::DoRegister);
195 double next_delay_seconds =
196 CalculateBackoff(static_cast<double>(status->next_delay.InSeconds()),
197 kInitialRegistrationDelaySeconds,
198 kMinRegistrationDelaySeconds,
199 kMaxRegistrationDelaySeconds,
200 kRegistrationDelayExponent,
201 GetJitter(),
202 kRegistrationDelayMaxJitter);
203 status->next_delay =
204 base::TimeDelta::FromSeconds(static_cast<int64>(next_delay_seconds));
205 VLOG(2) << "New next delay for "
206 << syncable::ModelTypeToString(model_type) << " is "
207 << status->next_delay.InSeconds() << " seconds";
208 } else {
209 VLOG(2) << "Not a retry -- registering "
210 << syncable::ModelTypeToString(model_type) << " immediately";
211 status->delay = base::TimeDelta();
212 status->next_delay = base::TimeDelta();
213 status->DoRegister();
214 }
215}
216
217void RegistrationManager::DoRegisterType(syncable::ModelType model_type) {
[email protected]58d16662011-02-16 01:44:45218 DCHECK(non_thread_safe_.CalledOnValidThread());
219 invalidation::ObjectId object_id;
220 if (!RealModelTypeToObjectId(model_type, &object_id)) {
221 LOG(DFATAL) << "Invalid model type: " << model_type;
222 return;
223 }
[email protected]b7af0f92011-03-10 23:35:48224 invalidation_client_->Register(object_id);
225 RegistrationStatus* status = &registration_statuses_[model_type];
226 status->state = invalidation::RegistrationState_REGISTERED;
227 status->last_registration_request = base::Time::Now();
[email protected]58d16662011-02-16 01:44:45228}
229
230void RegistrationManager::UnregisterType(syncable::ModelType model_type) {
231 DCHECK(non_thread_safe_.CalledOnValidThread());
232 invalidation::ObjectId object_id;
233 if (!RealModelTypeToObjectId(model_type, &object_id)) {
234 LOG(DFATAL) << "Invalid model type: " << model_type;
235 return;
236 }
[email protected]b7af0f92011-03-10 23:35:48237 invalidation_client_->Unregister(object_id);
238 RegistrationStatus* status = &registration_statuses_[model_type];
239 status->state = invalidation::RegistrationState_UNREGISTERED;
[email protected]58d16662011-02-16 01:44:45240}
241
[email protected]b7af0f92011-03-10 23:35:48242bool RegistrationManager::IsTypeRegistered(
243 syncable::ModelType model_type) const {
244 DCHECK(non_thread_safe_.CalledOnValidThread());
245 return registration_statuses_[model_type].state ==
246 invalidation::RegistrationState_REGISTERED;
[email protected]6a1d0f52010-06-30 05:11:53247}
[email protected]b7af0f92011-03-10 23:35:48248
[email protected]6a1d0f52010-06-30 05:11:53249} // namespace sync_notifier