// Copyright (c) 2010 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.
//
// A class that manages the registration of types for server-issued
// notifications.
#ifndef CHROME_BROWSER_SYNC_NOTIFIER_REGISTRATION_MANAGER_H_
#define CHROME_BROWSER_SYNC_NOTIFIER_REGISTRATION_MANAGER_H_
#pragma once
#include <map>
#include "base/basictypes.h"
#include "base/time.h"
#include "base/timer.h"
#include "base/threading/non_thread_safe.h"
#include "chrome/browser/sync/syncable/model_type.h"
// For invalidation::RegistrationState.
#include "google/cacheinvalidation/invalidation-client.h"
namespace sync_notifier {
// Manages the details of registering types for invalidation.
// Implements exponential backoff for repeated registration attempts
// to the invalidation client.
//
// TODO(akalin): Consolidate exponential backoff code. Other
// implementations include the syncer thread (both versions) and XMPP
// retries. The most sophisticated one is URLRequestThrottler; making
// that generic should work for everyone.
class RegistrationManager {
public:
// Constants for exponential backoff (used by tests).
static const int kInitialRegistrationDelaySeconds;
static const int kRegistrationDelayExponent;
static const double kRegistrationDelayMaxJitter;
static const int kMinRegistrationDelaySeconds;
static const int kMaxRegistrationDelaySeconds;
// Types used by testing functions.
struct PendingRegistrationInfo {
PendingRegistrationInfo();
// Last time a registration request was actually sent.
base::Time last_registration_request;
// Time the registration was attempted.
base::Time registration_attempt;
// The calculated delay of the pending registration (which may be
// negative).
base::TimeDelta delay;
// The delay of the timer, which should be max(delay, 0).
base::TimeDelta actual_delay;
};
// Map from types with pending registrations to info about the
// pending registration.
typedef std::map<syncable::ModelType, PendingRegistrationInfo>
PendingRegistrationMap;
// Does not take ownership of |invalidation_client_|.
explicit RegistrationManager(
invalidation::InvalidationClient* invalidation_client);
virtual ~RegistrationManager();
// Registers all types included in the given set and sets all other
// types to be unregistered.
void SetRegisteredTypes(const syncable::ModelTypeSet& types);
// Marks the registration for the |model_type| lost and re-registers
// it.
void MarkRegistrationLost(syncable::ModelType model_type);
// Marks all registrations lost and re-registers them.
void MarkAllRegistrationsLost();
// The functions below should only be used in tests.
// Gets all currently-registered types.
syncable::ModelTypeSet GetRegisteredTypes() const;
// Gets all pending registrations and their next min delays.
PendingRegistrationMap GetPendingRegistrations() const;
// Run pending registrations immediately.
void FirePendingRegistrationsForTest();
// Calculate exponential backoff. |jitter| must be Uniform[-1.0,
// 1.0].
static double CalculateBackoff(double retry_interval,
double initial_retry_interval,
double min_retry_interval,
double max_retry_interval,
double backoff_exponent,
double jitter,
double max_jitter);
protected:
// Overrideable for testing purposes.
virtual double GetJitter();
private:
struct RegistrationStatus {
RegistrationStatus();
~RegistrationStatus();
// Calls registration_manager->DoRegister(model_type). (needed by
// |registration_timer|).
void DoRegister();
// The model type for which this is the status.
syncable::ModelType model_type;
// The parent registration manager.
RegistrationManager* registration_manager;
// The current registration state.
invalidation::RegistrationState state;
// When we last sent a registration request.
base::Time last_registration_request;
// When we last tried to register.
base::Time last_registration_attempt;
// The calculated delay of any pending registration (which may be
// negative).
base::TimeDelta delay;
// The minimum time to wait until any next registration attempt.
// Increased after each consecutive failure.
base::TimeDelta next_delay;
// The actual timer for registration.
base::OneShotTimer<RegistrationStatus> registration_timer;
};
// If |is_retry| is not set, registers the given type immediately
// and resets all backoff parameters. If |is_retry| is set,
// registers the given type at some point in the future and
// increases the delay until the next retry.
void TryRegisterType(syncable::ModelType model_type,
bool is_retry);
// Registers the given type, which must be valid, immediately.
// Updates |last_registration| in the appropriate
// RegistrationStatus. Should only be called by
// RegistrationStatus::DoRegister().
void DoRegisterType(syncable::ModelType model_type);
// Unregisters the given type, which must be valid.
void UnregisterType(syncable::ModelType model_type);
// Returns true iff the given type, which must be valid, is registered.
bool IsTypeRegistered(syncable::ModelType model_type) const;
base::NonThreadSafe non_thread_safe_;
RegistrationStatus registration_statuses_[syncable::MODEL_TYPE_COUNT];
// Weak pointer.
invalidation::InvalidationClient* invalidation_client_;
DISALLOW_COPY_AND_ASSIGN(RegistrationManager);
};
} // namespace sync_notifier
#endif // CHROME_BROWSER_SYNC_NOTIFIER_REGISTRATION_MANAGER_H_