summaryrefslogtreecommitdiffstats
path: root/sync/notifier/registration_manager.h
blob: e8639d00e54c9dbe0e05b56889675e9ad88a700a (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
// 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/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:
  // 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;

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