summaryrefslogtreecommitdiffstats
path: root/net/base/backoff_entry.h
blob: 2aa3a96aca8de51ea95442abe0d69d1aa372e8e8 (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
// 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.

#ifndef NET_BASE_BACKOFF_ENTRY_H_
#define NET_BASE_BACKOFF_ENTRY_H_

#include "base/macros.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
#include "net/base/net_export.h"

namespace base {
class TickClock;
}

namespace net {

// Provides the core logic needed for randomized exponential back-off
// on requests to a given resource, given a back-off policy.
//
// This utility class knows nothing about network specifics; it is
// intended for reuse in various networking scenarios.
class NET_EXPORT BackoffEntry : NON_EXPORTED_BASE(public base::NonThreadSafe) {
 public:
  // The set of parameters that define a back-off policy. When modifying this,
  // increment SERIALIZATION_VERSION_NUMBER in backoff_entry_serializer.cc.
  struct Policy {
    // Number of initial errors (in sequence) to ignore before applying
    // exponential back-off rules.
    int num_errors_to_ignore;

    // Initial delay.  The interpretation of this value depends on
    // always_use_initial_delay.  It's either how long we wait between
    // requests before backoff starts, or how much we delay the first request
    // after backoff starts.
    int initial_delay_ms;

    // Factor by which the waiting time will be multiplied.
    double multiply_factor;

    // Fuzzing percentage. ex: 10% will spread requests randomly
    // between 90%-100% of the calculated time.
    double jitter_factor;

    // Maximum amount of time we are willing to delay our request, -1
    // for no maximum.
    int64_t maximum_backoff_ms;

    // Time to keep an entry from being discarded even when it
    // has no significant state, -1 to never discard.
    int64_t entry_lifetime_ms;

    // If true, we always use a delay of initial_delay_ms, even before
    // we've seen num_errors_to_ignore errors.  Otherwise, initial_delay_ms
    // is the first delay once we start exponential backoff.
    //
    // So if we're ignoring 1 error, we'll see (N, N, Nm, Nm^2, ...) if true,
    // and (0, 0, N, Nm, ...) when false, where N is initial_backoff_ms and
    // m is multiply_factor, assuming we've already seen one success.
    bool always_use_initial_delay;
  };

  // Lifetime of policy must enclose lifetime of BackoffEntry. The
  // pointer must be valid but is not dereferenced during construction.
  explicit BackoffEntry(const Policy* policy);
  // Lifetime of policy and clock must enclose lifetime of BackoffEntry.
  // |policy| pointer must be valid but isn't dereferenced during construction.
  // |clock| pointer may be null.
  BackoffEntry(const Policy* policy, base::TickClock* clock);
  virtual ~BackoffEntry();

  // Inform this item that a request for the network resource it is
  // tracking was made, and whether it failed or succeeded.
  void InformOfRequest(bool succeeded);

  // Returns true if a request for the resource this item tracks should
  // be rejected at the present time due to exponential back-off policy.
  bool ShouldRejectRequest() const;

  // Returns the absolute time after which this entry (given its present
  // state) will no longer reject requests.
  base::TimeTicks GetReleaseTime() const;

  // Returns the time until a request can be sent (will be zero if the release
  // time is in the past).
  base::TimeDelta GetTimeUntilRelease() const;

  // Converts |backoff_duration| to a release time, by adding it to
  // GetTimeTicksNow(), limited by maximum_backoff_ms.
  base::TimeTicks BackoffDurationToReleaseTime(
      base::TimeDelta backoff_duration) const;

  // Causes this object reject requests until the specified absolute time.
  // This can be used to e.g. implement support for a Retry-After header.
  void SetCustomReleaseTime(const base::TimeTicks& release_time);

  // Returns true if this object has no significant state (i.e. you could
  // just as well start with a fresh BackoffEntry object), and hasn't
  // had for Policy::entry_lifetime_ms.
  bool CanDiscard() const;

  // Resets this entry to a fresh (as if just constructed) state.
  void Reset();

  // Returns the failure count for this entry.
  int failure_count() const { return failure_count_; }

  // Returns the TickClock passed in to the constructor. May be NULL.
  base::TickClock* tick_clock() const { return clock_; }

 private:
  // Calculates when requests should again be allowed through.
  base::TimeTicks CalculateReleaseTime() const;

  // Equivalent to TimeTicks::Now(), using clock_ if provided.
  base::TimeTicks GetTimeTicksNow() const;

  // Timestamp calculated by the exponential back-off algorithm at which we are
  // allowed to start sending requests again.
  base::TimeTicks exponential_backoff_release_time_;

  // Counts request errors; decremented on success.
  int failure_count_;

  const Policy* const policy_;  // Not owned.

  base::TickClock* const clock_;  // Not owned.

  DISALLOW_COPY_AND_ASSIGN(BackoffEntry);
};

}  // namespace net

#endif  // NET_BASE_BACKOFF_ENTRY_H_