// 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_