Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: net/base/network_throttle_manager_impl.h

Issue 2130493002: Implement THROTTLED priority semantics. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@NetworkStreamThrottler
Patch Set: Added (currently failing) URLRequest unit test. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef NET_BASE_NETWORK_THROTTLE_MANAGER_IMPL_H_
6 #define NET_BASE_NETWORK_THROTTLE_MANAGER_IMPL_H_
7
8 #include <list>
9 #include <memory>
10 #include <set>
11
12 #include "base/time/tick_clock.h"
13 #include "base/time/time.h"
14 #include "base/timer/timer.h"
15 #include "net/base/network_throttle_manager.h"
16 #include "net/base/quantile_estimator.h"
17
18 namespace net {
19
20 // The NetworkThrottleManagerImpl implements the following semantics:
21 // * All throttles of priority above THROTTLED are created unblocked.
22 // * Throttles of priority THROTTLED are created unblocked, unless
23 // there are |kActiveRequestThrottlingLimit| or more throttles active,
24 // in which case they are created blocked.
25 // When that condition is no longer true, throttles of priority
26 // THROTTLED are unblocked, in priority order.
27 // * Throttles that have been alive for more than |kMedianLifetimeMultiple|
28 // times the current estimate of the throttle median lifetime do
29 // not count against the |kActiveRequestThrottlingLimit| limit.
30 class NET_EXPORT NetworkThrottleManagerImpl : public NetworkThrottleManager {
31 public:
32 // Maximum number of active requests before new THROTTLED throttles
33 // are created blocked. Throttles are unblocked as the active requests
34 // fall below this limit.
35 static const size_t kActiveRequestThrottlingLimit;
36
37 // Note that the following constants are implementation details exposed in the
38 // header file only for testing, and should not be relied on by consumers.
39
40 // Constants used for the running estimate of the median lifetime
41 // for throttles created by this class. That estimate is used to detect
42 // throttles that are "unusually old" and hence may represent hanging GETs
43 // or long-running streams. Such throttles should not be considered
44 // "active" for the purposes of determining whether THROTTLED throttles
45 // should be created in a blocked state.
46 // Note that the precise details of this algorithm aren't very important;
47 // specifically, if it takes a while for the median estimate to reach the
48 // "actual" median of a request stream, the consequence is either a bit more
49 // of a delay in unblocking THROTTLED requests or more THROTTLED requests
50 // being unblocked than would be ideal (i.e. performance tweaks at
51 // the margins).
52
53 // Multiple of the current median lifetime beyond which a throttle is
54 // considered "unusually old" and not considered in counting active
55 // requests.
56 static const int kMedianLifetimeMultiple;
Charlie Harrison 2016/09/01 18:17:52 Why not just implement the algorithm that calculat
Randy Smith (Not in Mondays) 2016/09/18 19:12:34 I want things that are qualitatively different to
57
58 // The median lifetime estimate starts at class creation at
59 // |kInitialMedianInMs|.
60 static const int kInitialMedianInMs;
61
62 NetworkThrottleManagerImpl();
63 ~NetworkThrottleManagerImpl() override;
64
65 // NetworkThrottleManager:
66 std::unique_ptr<Throttle> CreateThrottle(ThrottleDelegate* delegate,
67 RequestPriority priority,
68 bool ignore_limits) override;
69
70 void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock);
71
72 // If the |NowTicks()| value of |tick_clock_| is greater than the
73 // time the outstanding_recomputation_timer_ has set to go off, Stop()
74 // the timer and manually run the associated user task. This is to allow
75 // "fast-forwarding" of the clock for testing by working around
76 // base::Timer's direct use of base::TimeTicks rather than a base::TickClock.
77 //
78 // Note specifically that base::Timer::Start takes a time delta into the
79 // future and adds it to base::TimeTicks::Now() to get
80 // base::Timer::desired_run_time(), which is what this method compares
81 // |tick_clock_->NowTicks()| against. So tests should be written so that
82 // the timer Start() routine whose callback should be run is called
83 // with |tick_clock_| in accord with wallclock time. This routine can then
84 // be called with |tick_clock_| set into the future.
85 void ConditionallyTriggerTimerForTesting();
86
87 private:
88 class ThrottleImpl : public NetworkThrottleManager::Throttle {
89 public:
90 using ThrottleList = std::list<ThrottleImpl*>;
91 using QueuePointer = ThrottleList::iterator;
92
93 // Caller must arrange that |*delegate| and |*manager| outlive
94 // the ThrottleImpl class.
95 ThrottleImpl(bool blocked,
96 RequestPriority priority,
97 ThrottleDelegate* delegate,
98 NetworkThrottleManagerImpl* manager,
99 QueuePointer queue_pointer);
100
101 ~ThrottleImpl() override;
102
103 // Throttle:
104 bool IsBlocked() const override;
105 RequestPriority Priority() const override;
106 void SetPriority(RequestPriority priority) override;
107
108 RequestPriority priority() const { return priority_; }
109 QueuePointer queue_pointer() const { return queue_pointer_; }
110 void set_queue_pointer(const QueuePointer& pointer) {
111 queue_pointer_ = pointer;
112 }
113 base::TimeTicks start_time() const { return start_time_; }
114 void set_start_time(base::TimeTicks start_time) {
115 start_time_ = start_time;
116 }
117
118 // Note that this call calls the delegate, and hence
119 // may result in re-entrant calls into the manager or
120 // ThrottleImpl. The manager should not rely on
121 // any state other than its own existence being persistent
122 // across this call.
123 void NotifyUnblocked();
124
125 private:
126 bool blocked_;
127 RequestPriority priority_;
128 ThrottleDelegate* const delegate_;
129 NetworkThrottleManagerImpl* const manager_;
130
131 base::TimeTicks start_time_;
132
133 // For deletion from owning queue.
134 QueuePointer queue_pointer_;
135
136 DISALLOW_COPY_AND_ASSIGN(ThrottleImpl);
137 };
138
139 // Comparison function used to define the ordering relationship
140 // for |CreationOrderingSet| below.
141 static bool CompareThrottlesForCreationTime(ThrottleImpl* throttle1,
142 ThrottleImpl* throttle2);
mmenke 2016/09/01 19:14:23 This does need to be in this file, right?
Randy Smith (Not in Mondays) 2016/09/18 19:12:34 It needs access to the start time of the throttles
143
144 using CreationOrderingSet =
mmenke 2016/09/01 19:14:23 CreationTimeOrderedSet? This it's better to name
Randy Smith (Not in Mondays) 2016/09/18 19:12:34 Done.
145 std::set<ThrottleImpl*, bool (*)(ThrottleImpl*, ThrottleImpl*)>;
146
147 void OnThrottlePriorityChanged(ThrottleImpl* throttle,
148 RequestPriority old_priority,
149 RequestPriority new_priority);
150 void OnThrottleDestroyed(ThrottleImpl* throttle);
151
152 // Recompute how many requests "count" as outstanding (i.e.
153 // are not older than kMedianLifetimeMultiple * MedianThrottleLifetime()).
154 void RecomputeOutstanding();
155
156 // Unblock the specified throttle. May result in re-entrant calls
157 // into NetworkThrottleManagerImpl.
158 void UnblockThrottle(ThrottleImpl* throttle);
159
160 // Recomputes how many requests count as outstanding, checks to see
161 // if any currently blocked throttles should be unblocked,
162 // and unblock them if so. Note that unblocking may result in
163 // re-entrant calls to this class, so no assumptions about state persistence
164 // should be made across this call.
165 void MaybeUnblockThrottles();
166
167 // Convenience functions to determine which of the ThrottleLists
168 // from {blocked,unblocked}_requests_ apply to a given
169 // throttle/(blocked, priority) pair.
170 ThrottleImpl::ThrottleList* ListForThrottle(bool blocked,
Charlie Harrison 2016/09/01 18:17:52 Technically not really the list for a throttle, bu
Randy Smith (Not in Mondays) 2016/09/18 19:12:34 Done.
171 RequestPriority priority);
172 ThrottleImpl::ThrottleList* ListForThrottle(ThrottleImpl* throttle);
173
174 // For DCHECK assertions: Could the number of blocked throttles.
175 size_t NumberBlockedThrottles() const;
176
177 QuantileEstimator lifetime_median_estimate_;
178
179 // Only contains unblocked throttles; blocked throttles haven't started
180 // and hence don't have a start time.
181 CreationOrderingSet start_time_ordering_set_;
182
183 size_t num_throttles_blocked_;
184
185 // Count of throttles that are considered as outstanding. Throttles that
186 // are too old or blocked are not counted.
187 size_t num_effective_outstanding_;
188
189 // base::Timer controlling outstanding request recomputation.
190 base::Timer outstanding_recomputation_timer_;
191
192 // Lists of blocked/unblocked request at each priority level.
193 // It is safe to store a raw pointer in these lists because the
194 // manager will be notified by OnThrottleDestroyed before a ThrottleImpl
195 // is destroyed, and will remove the pointer from the appropriate list
196 // at that point.
197 ThrottleImpl::ThrottleList blocked_requests_[NUM_PRIORITIES];
198 ThrottleImpl::ThrottleList unblocked_requests_[NUM_PRIORITIES];
199
200 // For testing.
201 std::unique_ptr<base::TickClock> tick_clock_;
202
203 DISALLOW_COPY_AND_ASSIGN(NetworkThrottleManagerImpl);
204 };
205
206 } // namespace net
207
208 #endif // NET_BASE_NETWORK_THROTTLE_MANAGER_IMPL_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698