summaryrefslogtreecommitdiffstats
path: root/chromium/sync/notifier/registration_manager.h
blob: e190a7fad55caeb38e947981190524ca074f3c42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// 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_