// Copyright 2012 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 SYNC_NOTIFIER_REGISTRATION_MANAGER_H_
#define SYNC_NOTIFIER_REGISTRATION_MANAGER_H_
#include <map>
#include "base/basictypes.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
// For invalidation::InvalidationListener::RegistrationState.
#include "google/cacheinvalidation/include/invalidation-listener.h"
#include "google/cacheinvalidation/include/types.h"
#include "sync/base/sync_export.h"
#include "sync/notifier/invalidation_util.h"
namespace syncer {
using ::invalidation::InvalidationListener;
// 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 SYNC_EXPORT_PRIVATE RegistrationManager : public base::NonThreadSafe {
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 of object IDs with pending registrations to info about the
// pending registration.
typedef std::map<invalidation::ObjectId,
PendingRegistrationInfo,
ObjectIdLessThan>
PendingRegistrationMap;
// Does not take ownership of |invalidation_client_|.
explicit RegistrationManager(
invalidation::InvalidationClient* invalidation_client);
virtual ~RegistrationManager();
// Registers all object IDs included in the given set (that are not
// already disabled) and unregisters all other object IDs. The return value is
// the set of IDs that was unregistered.
ObjectIdSet UpdateRegisteredIds(const ObjectIdSet& ids);
// Marks the registration for the |id| lost and re-registers
// it (unless it's disabled).
void MarkRegistrationLost(const invalidation::ObjectId& id);
// Marks registrations lost for all enabled object IDs and re-registers them.
void MarkAllRegistrationsLost();
// Marks the registration for the |id| permanently lost and blocks any future
// registration attempts.
void DisableId(const invalidation::ObjectId& id);
// 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);
// The functions below should only be used in tests.
// Gets all currently registered ids.
ObjectIdSet GetRegisteredIdsForTest() const;
// Gets all pending registrations and their next min delays.
PendingRegistrationMap GetPendingRegistrationsForTest() const;
// Run pending registrations immediately.
void FirePendingRegistrationsForTest();
protected:
// Overrideable for testing purposes.
virtual double GetJitter();
private:
struct RegistrationStatus {
RegistrationStatus(const invalidation::ObjectId& id,
RegistrationManager* manager);
~RegistrationStatus();
// Calls registration_manager->DoRegister(model_type). (needed by
// |registration_timer|). Should only be called if |enabled| is
// true.
void DoRegister();
// Sets |enabled| to false and resets other variables.
void Disable();
// The object for which this is the status.
const invalidation::ObjectId id;
// The parent registration manager.
RegistrationManager* const registration_manager;
// Whether this data type should be registered. Set to false if
// we get a non-transient registration failure.
bool enabled;
// The current registration state.
InvalidationListener::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;
DISALLOW_COPY_AND_ASSIGN(RegistrationStatus);
};
typedef std::map<invalidation::ObjectId,
RegistrationStatus*,
ObjectIdLessThan>
RegistrationStatusMap;
// Does nothing if the given id is disabled. Otherwise, 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 TryRegisterId(const invalidation::ObjectId& id,
bool is_retry);
// Registers the given id, which must be valid, immediately.
// Updates |last_registration| in the appropriate
// RegistrationStatus. Should only be called by
// RegistrationStatus::DoRegister().
void DoRegisterId(const invalidation::ObjectId& id);
// Unregisters the given object ID.
void UnregisterId(const invalidation::ObjectId& id);
// Gets all currently registered ids.
ObjectIdSet GetRegisteredIds() const;
// Returns true iff the given object ID is registered.
bool IsIdRegistered(const invalidation::ObjectId& id) const;
RegistrationStatusMap registration_statuses_;
// Weak pointer.
invalidation::InvalidationClient* invalidation_client_;
DISALLOW_COPY_AND_ASSIGN(RegistrationManager);
};
} // namespace syncer
#endif // SYNC_NOTIFIER_REGISTRATION_MANAGER_H_