blob: 8b2705417db5406a6c57f540f14e6ba06b6442b9 [file] [log] [blame]
// Copyright (c) 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_
#pragma once
#include <map>
#include "base/basictypes.h"
#include "base/threading/non_thread_safe.h"
#include "base/threading/non_thread_safe.h"
#include "base/time.h"
#include "base/timer.h"
#include "sync/internal_api/public/syncable/model_type.h"
// For invalidation::InvalidationListener::RegistrationState.
#include "google/cacheinvalidation/include/invalidation-listener.h"
namespace sync_notifier {
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 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 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 (that are not
// already disabled) and sets all other types to be unregistered.
void SetRegisteredTypes(syncable::ModelTypeSet types);
// Marks the registration for the |model_type| lost and re-registers
// it (unless it's disabled).
void MarkRegistrationLost(syncable::ModelType model_type);
// Marks registrations lost for all enabled types and re-registers
// them.
void MarkAllRegistrationsLost();
// Marks the registration for the |model_type| permanently lost and
// blocks any future registration attempts.
void DisableType(syncable::ModelType model_type);
// 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|). Should only be called if |enabled| is
// true.
void DoRegister();
// Sets |enabled| to false and resets other variables.
void Disable();
// The model type for which this is the status.
syncable::ModelType model_type;
// The parent registration manager.
RegistrationManager* 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;
};
// Does nothing if the given type 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 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;
RegistrationStatus registration_statuses_[syncable::MODEL_TYPE_COUNT];
// Weak pointer.
invalidation::InvalidationClient* invalidation_client_;
DISALLOW_COPY_AND_ASSIGN(RegistrationManager);
};
} // namespace sync_notifier
#endif // SYNC_NOTIFIER_REGISTRATION_MANAGER_H_