blob: b505729f37ad3325869e732e383353365d04e337 [file] [log] [blame]
[email protected]1bfd03f2011-07-02 19:04:181// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]6a1d0f52010-06-30 05:11:532// 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]d49f46332011-07-15 21:31:0714#include "google/cacheinvalidation/v2/invalidation-client.h"
[email protected]6a1d0f52010-06-30 05:11:5315
16namespace sync_notifier {
17
[email protected]2ea4caeb2011-03-11 00:15:0618RegistrationManager::PendingRegistrationInfo::PendingRegistrationInfo() {}
19
[email protected]b7af0f92011-03-10 23:35:4820RegistrationManager::RegistrationStatus::RegistrationStatus()
21 : model_type(syncable::UNSPECIFIED),
22 registration_manager(NULL),
[email protected]1bfd03f2011-07-02 19:04:1823 state(invalidation::InvalidationListener::UNREGISTERED) {}
[email protected]b7af0f92011-03-10 23:35:4824
[email protected]8ba7fa52011-03-11 00:44:3025RegistrationManager::RegistrationStatus::~RegistrationStatus() {}
26
[email protected]b7af0f92011-03-10 23:35:4827void RegistrationManager::RegistrationStatus::DoRegister() {
28 DCHECK_NE(model_type, syncable::UNSPECIFIED);
29 DCHECK(registration_manager);
30 // We might be called explicitly, so stop the timer manually and
31 // reset the delay.
32 registration_timer.Stop();
33 delay = base::TimeDelta();
34 registration_manager->DoRegisterType(model_type);
35 DCHECK(!last_registration_request.is_null());
36}
37
38const int RegistrationManager::kInitialRegistrationDelaySeconds = 5;
39const int RegistrationManager::kRegistrationDelayExponent = 2;
40const double RegistrationManager::kRegistrationDelayMaxJitter = 0.5;
41const int RegistrationManager::kMinRegistrationDelaySeconds = 1;
42// 1 hour.
43const int RegistrationManager::kMaxRegistrationDelaySeconds = 60 * 60;
44
[email protected]6a1d0f52010-06-30 05:11:5345RegistrationManager::RegistrationManager(
46 invalidation::InvalidationClient* invalidation_client)
47 : invalidation_client_(invalidation_client) {
48 DCHECK(invalidation_client_);
[email protected]b7af0f92011-03-10 23:35:4849 // Initialize statuses.
50 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
51 i < syncable::MODEL_TYPE_COUNT; ++i) {
52 syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
53 RegistrationStatus* status = &registration_statuses_[model_type];
54 status->model_type = model_type;
55 status->registration_manager = this;
56 }
[email protected]6a1d0f52010-06-30 05:11:5357}
58
59RegistrationManager::~RegistrationManager() {
60 DCHECK(non_thread_safe_.CalledOnValidThread());
61}
62
[email protected]58d16662011-02-16 01:44:4563void RegistrationManager::SetRegisteredTypes(
64 const syncable::ModelTypeSet& types) {
[email protected]6a1d0f52010-06-30 05:11:5365 DCHECK(non_thread_safe_.CalledOnValidThread());
[email protected]58d16662011-02-16 01:44:4566
[email protected]b7af0f92011-03-10 23:35:4867 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
68 i < syncable::MODEL_TYPE_COUNT; ++i) {
69 syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
70 if (types.count(model_type) > 0) {
71 if (!IsTypeRegistered(model_type)) {
72 TryRegisterType(model_type, false /* is_retry */);
73 }
[email protected]58d16662011-02-16 01:44:4574 } else {
[email protected]b7af0f92011-03-10 23:35:4875 if (IsTypeRegistered(model_type)) {
76 UnregisterType(model_type);
77 }
[email protected]58d16662011-02-16 01:44:4578 }
[email protected]6a1d0f52010-06-30 05:11:5379 }
[email protected]6a1d0f52010-06-30 05:11:5380}
81
[email protected]6a1d0f52010-06-30 05:11:5382void RegistrationManager::MarkRegistrationLost(
83 syncable::ModelType model_type) {
84 DCHECK(non_thread_safe_.CalledOnValidThread());
[email protected]d49f46332011-07-15 21:31:0785 RegistrationStatus* status = &registration_statuses_[model_type];
86 status->state = invalidation::InvalidationListener::UNREGISTERED;
87 bool is_retry = !status->last_registration_request.is_null();
88 TryRegisterType(model_type, is_retry);
[email protected]6a1d0f52010-06-30 05:11:5389}
90
91void RegistrationManager::MarkAllRegistrationsLost() {
92 DCHECK(non_thread_safe_.CalledOnValidThread());
[email protected]b7af0f92011-03-10 23:35:4893 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
94 i < syncable::MODEL_TYPE_COUNT; ++i) {
95 syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
96 if (IsTypeRegistered(model_type)) {
97 MarkRegistrationLost(model_type);
[email protected]6a1d0f52010-06-30 05:11:5398 }
[email protected]6a1d0f52010-06-30 05:11:5399 }
100}
101
[email protected]b7af0f92011-03-10 23:35:48102syncable::ModelTypeSet RegistrationManager::GetRegisteredTypes() const {
103 DCHECK(non_thread_safe_.CalledOnValidThread());
104 syncable::ModelTypeSet registered_types;
105 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
106 i < syncable::MODEL_TYPE_COUNT; ++i) {
107 syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
108 if (IsTypeRegistered(model_type)) {
109 registered_types.insert(model_type);
110 }
111 }
112 return registered_types;
113}
114
115RegistrationManager::PendingRegistrationMap
116 RegistrationManager::GetPendingRegistrations() const {
117 DCHECK(non_thread_safe_.CalledOnValidThread());
118 PendingRegistrationMap pending_registrations;
119 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
120 i < syncable::MODEL_TYPE_COUNT; ++i) {
121 syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
122 const RegistrationStatus& status = registration_statuses_[model_type];
123 if (status.registration_timer.IsRunning()) {
124 pending_registrations[model_type].last_registration_request =
125 status.last_registration_request;
126 pending_registrations[model_type].registration_attempt =
127 status.last_registration_attempt;
128 pending_registrations[model_type].delay = status.delay;
129 pending_registrations[model_type].actual_delay =
130 status.registration_timer.GetCurrentDelay();
131 }
132 }
133 return pending_registrations;
134}
135
136void RegistrationManager::FirePendingRegistrationsForTest() {
137 DCHECK(non_thread_safe_.CalledOnValidThread());
138 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
139 i < syncable::MODEL_TYPE_COUNT; ++i) {
140 syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
141 RegistrationStatus* status = &registration_statuses_[model_type];
142 if (status->registration_timer.IsRunning()) {
143 status->DoRegister();
144 }
145 }
146}
147
148// static
149double RegistrationManager::CalculateBackoff(
150 double retry_interval,
151 double initial_retry_interval,
152 double min_retry_interval,
153 double max_retry_interval,
154 double backoff_exponent,
155 double jitter,
156 double max_jitter) {
157 // scaled_jitter lies in [-max_jitter, max_jitter].
158 double scaled_jitter = jitter * max_jitter;
159 double new_retry_interval =
160 (retry_interval == 0.0) ?
161 (initial_retry_interval * (1.0 + scaled_jitter)) :
162 (retry_interval * (backoff_exponent + scaled_jitter));
163 return std::max(min_retry_interval,
164 std::min(max_retry_interval, new_retry_interval));
165}
166
167double RegistrationManager::GetJitter() {
168 // |jitter| lies in [-1.0, 1.0), which is low-biased, but only
169 // barely.
170 //
171 // TODO(akalin): Fix the bias.
172 return 2.0 * base::RandDouble() - 1.0;
173}
174
175void RegistrationManager::TryRegisterType(syncable::ModelType model_type,
176 bool is_retry) {
177 DCHECK(non_thread_safe_.CalledOnValidThread());
178 RegistrationStatus* status = &registration_statuses_[model_type];
179 status->last_registration_attempt = base::Time::Now();
180 if (is_retry) {
181 // If we're a retry, we must have tried at least once before.
182 DCHECK(!status->last_registration_request.is_null());
183 // delay = max(0, (now - last request) + next_delay)
184 status->delay =
185 (status->last_registration_request -
186 status->last_registration_attempt) +
187 status->next_delay;
188 base::TimeDelta delay =
189 (status->delay <= base::TimeDelta()) ?
190 base::TimeDelta() : status->delay;
191 VLOG(2) << "Registering "
192 << syncable::ModelTypeToString(model_type) << " in "
193 << delay.InMilliseconds() << " ms";
194 status->registration_timer.Stop();
[email protected]d323a172011-09-02 18:23:02195 status->registration_timer.Start(FROM_HERE,
[email protected]b7af0f92011-03-10 23:35:48196 delay, status, &RegistrationManager::RegistrationStatus::DoRegister);
197 double next_delay_seconds =
198 CalculateBackoff(static_cast<double>(status->next_delay.InSeconds()),
199 kInitialRegistrationDelaySeconds,
200 kMinRegistrationDelaySeconds,
201 kMaxRegistrationDelaySeconds,
202 kRegistrationDelayExponent,
203 GetJitter(),
204 kRegistrationDelayMaxJitter);
205 status->next_delay =
206 base::TimeDelta::FromSeconds(static_cast<int64>(next_delay_seconds));
207 VLOG(2) << "New next delay for "
208 << syncable::ModelTypeToString(model_type) << " is "
209 << status->next_delay.InSeconds() << " seconds";
210 } else {
211 VLOG(2) << "Not a retry -- registering "
212 << syncable::ModelTypeToString(model_type) << " immediately";
213 status->delay = base::TimeDelta();
214 status->next_delay = base::TimeDelta();
215 status->DoRegister();
216 }
217}
218
219void RegistrationManager::DoRegisterType(syncable::ModelType model_type) {
[email protected]58d16662011-02-16 01:44:45220 DCHECK(non_thread_safe_.CalledOnValidThread());
221 invalidation::ObjectId object_id;
222 if (!RealModelTypeToObjectId(model_type, &object_id)) {
223 LOG(DFATAL) << "Invalid model type: " << model_type;
224 return;
225 }
[email protected]b7af0f92011-03-10 23:35:48226 invalidation_client_->Register(object_id);
227 RegistrationStatus* status = &registration_statuses_[model_type];
[email protected]1bfd03f2011-07-02 19:04:18228 status->state = invalidation::InvalidationListener::REGISTERED;
[email protected]b7af0f92011-03-10 23:35:48229 status->last_registration_request = base::Time::Now();
[email protected]58d16662011-02-16 01:44:45230}
231
232void RegistrationManager::UnregisterType(syncable::ModelType model_type) {
233 DCHECK(non_thread_safe_.CalledOnValidThread());
234 invalidation::ObjectId object_id;
235 if (!RealModelTypeToObjectId(model_type, &object_id)) {
236 LOG(DFATAL) << "Invalid model type: " << model_type;
237 return;
238 }
[email protected]b7af0f92011-03-10 23:35:48239 invalidation_client_->Unregister(object_id);
240 RegistrationStatus* status = &registration_statuses_[model_type];
[email protected]1bfd03f2011-07-02 19:04:18241 status->state = invalidation::InvalidationListener::UNREGISTERED;
[email protected]58d16662011-02-16 01:44:45242}
243
[email protected]b7af0f92011-03-10 23:35:48244bool RegistrationManager::IsTypeRegistered(
245 syncable::ModelType model_type) const {
246 DCHECK(non_thread_safe_.CalledOnValidThread());
247 return registration_statuses_[model_type].state ==
[email protected]1bfd03f2011-07-02 19:04:18248 invalidation::InvalidationListener::REGISTERED;
[email protected]6a1d0f52010-06-30 05:11:53249}
[email protected]b7af0f92011-03-10 23:35:48250
[email protected]6a1d0f52010-06-30 05:11:53251} // namespace sync_notifier