OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <set> | 5 #include <set> |
6 | 6 |
7 #include "content/browser/loader/resource_scheduler.h" | 7 #include "content/browser/loader/resource_scheduler.h" |
8 | 8 |
9 #include "base/metrics/field_trial.h" | 9 #include "base/metrics/field_trial.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
13 #include "base/strings/string_piece.h" | 13 #include "base/strings/string_piece.h" |
14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
15 #include "content/common/resource_messages.h" | 15 #include "content/common/resource_messages.h" |
16 #include "content/browser/loader/resource_message_delegate.h" | |
17 #include "content/public/browser/resource_controller.h" | 16 #include "content/public/browser/resource_controller.h" |
18 #include "content/public/browser/resource_request_info.h" | 17 #include "content/public/browser/resource_request_info.h" |
19 #include "content/public/browser/resource_throttle.h" | 18 #include "content/public/browser/resource_throttle.h" |
20 #include "ipc/ipc_message_macros.h" | |
21 #include "net/base/host_port_pair.h" | 19 #include "net/base/host_port_pair.h" |
22 #include "net/base/load_flags.h" | 20 #include "net/base/load_flags.h" |
23 #include "net/base/request_priority.h" | 21 #include "net/base/request_priority.h" |
24 #include "net/http/http_server_properties.h" | 22 #include "net/http/http_server_properties.h" |
25 #include "net/url_request/url_request.h" | 23 #include "net/url_request/url_request.h" |
26 #include "net/url_request/url_request_context.h" | 24 #include "net/url_request/url_request_context.h" |
27 | 25 |
28 namespace content { | 26 namespace content { |
29 | 27 |
30 namespace { | 28 namespace { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 return "Over30Clients"; | 69 return "Over30Clients"; |
72 } | 70 } |
73 | 71 |
74 } // namespace | 72 } // namespace |
75 | 73 |
76 static const size_t kCoalescedTimerPeriod = 5000; | 74 static const size_t kCoalescedTimerPeriod = 5000; |
77 static const size_t kMaxNumDelayableRequestsPerClient = 10; | 75 static const size_t kMaxNumDelayableRequestsPerClient = 10; |
78 static const size_t kMaxNumDelayableRequestsPerHost = 6; | 76 static const size_t kMaxNumDelayableRequestsPerHost = 6; |
79 static const size_t kMaxNumThrottledRequestsPerClient = 1; | 77 static const size_t kMaxNumThrottledRequestsPerClient = 1; |
80 | 78 |
| 79 ScheduledResourceRequest::ScheduledResourceRequest() {} |
| 80 ScheduledResourceRequest::~ScheduledResourceRequest() {} |
| 81 |
81 struct ResourceScheduler::RequestPriorityParams { | 82 struct ResourceScheduler::RequestPriorityParams { |
82 RequestPriorityParams() | 83 RequestPriorityParams() |
83 : priority(net::DEFAULT_PRIORITY), | 84 : priority(net::DEFAULT_PRIORITY), |
84 intra_priority(0) { | 85 intra_priority(0) { |
85 } | 86 } |
86 | 87 |
87 RequestPriorityParams(net::RequestPriority priority, int intra_priority) | 88 RequestPriorityParams(net::RequestPriority priority, int intra_priority) |
88 : priority(priority), | 89 : priority(priority), |
89 intra_priority(intra_priority) { | 90 intra_priority(intra_priority) { |
90 } | 91 } |
(...skipping 12 matching lines...) Expand all Loading... |
103 return priority > other.priority; | 104 return priority > other.priority; |
104 return intra_priority > other.intra_priority; | 105 return intra_priority > other.intra_priority; |
105 } | 106 } |
106 | 107 |
107 net::RequestPriority priority; | 108 net::RequestPriority priority; |
108 int intra_priority; | 109 int intra_priority; |
109 }; | 110 }; |
110 | 111 |
111 class ResourceScheduler::RequestQueue { | 112 class ResourceScheduler::RequestQueue { |
112 public: | 113 public: |
113 typedef std::multiset<ScheduledResourceRequest*, ScheduledResourceSorter> | 114 typedef std::multiset<ScheduledResourceRequestImpl*, ScheduledResourceSorter> |
114 NetQueue; | 115 NetQueue; |
115 | 116 |
116 RequestQueue() : fifo_ordering_ids_(0) {} | 117 RequestQueue() : fifo_ordering_ids_(0) {} |
117 ~RequestQueue() {} | 118 ~RequestQueue() {} |
118 | 119 |
119 // Adds |request| to the queue with given |priority|. | 120 // Adds |request| to the queue with given |priority|. |
120 void Insert(ScheduledResourceRequest* request); | 121 void Insert(ScheduledResourceRequestImpl* request); |
121 | 122 |
122 // Removes |request| from the queue. | 123 // Removes |request| from the queue. |
123 void Erase(ScheduledResourceRequest* request) { | 124 void Erase(ScheduledResourceRequestImpl* request) { |
124 PointerMap::iterator it = pointers_.find(request); | 125 PointerMap::iterator it = pointers_.find(request); |
125 DCHECK(it != pointers_.end()); | 126 DCHECK(it != pointers_.end()); |
126 if (it == pointers_.end()) | 127 if (it == pointers_.end()) |
127 return; | 128 return; |
128 queue_.erase(it->second); | 129 queue_.erase(it->second); |
129 pointers_.erase(it); | 130 pointers_.erase(it); |
130 } | 131 } |
131 | 132 |
132 NetQueue::iterator GetNextHighestIterator() { | 133 NetQueue::iterator GetNextHighestIterator() { |
133 return queue_.begin(); | 134 return queue_.begin(); |
134 } | 135 } |
135 | 136 |
136 NetQueue::iterator End() { | 137 NetQueue::iterator End() { |
137 return queue_.end(); | 138 return queue_.end(); |
138 } | 139 } |
139 | 140 |
140 // Returns true if |request| is queued. | 141 // Returns true if |request| is queued. |
141 bool IsQueued(ScheduledResourceRequest* request) const { | 142 bool IsQueued(ScheduledResourceRequestImpl* request) const { |
142 return ContainsKey(pointers_, request); | 143 return ContainsKey(pointers_, request); |
143 } | 144 } |
144 | 145 |
145 // Returns true if no requests are queued. | 146 // Returns true if no requests are queued. |
146 bool IsEmpty() const { return queue_.size() == 0; } | 147 bool IsEmpty() const { return queue_.size() == 0; } |
147 | 148 |
148 private: | 149 private: |
149 typedef std::map<ScheduledResourceRequest*, NetQueue::iterator> PointerMap; | 150 typedef std::map<ScheduledResourceRequestImpl*, NetQueue::iterator> |
| 151 PointerMap; |
150 | 152 |
151 uint32 MakeFifoOrderingId() { | 153 uint32 MakeFifoOrderingId() { |
152 fifo_ordering_ids_ += 1; | 154 fifo_ordering_ids_ += 1; |
153 return fifo_ordering_ids_; | 155 return fifo_ordering_ids_; |
154 } | 156 } |
155 | 157 |
156 // Used to create an ordering ID for scheduled resources so that resources | 158 // Used to create an ordering ID for scheduled resources so that resources |
157 // with same priority/intra_priority stay in fifo order. | 159 // with same priority/intra_priority stay in fifo order. |
158 uint32 fifo_ordering_ids_; | 160 uint32 fifo_ordering_ids_; |
159 | 161 |
160 NetQueue queue_; | 162 NetQueue queue_; |
161 PointerMap pointers_; | 163 PointerMap pointers_; |
162 }; | 164 }; |
163 | 165 |
164 // This is the handle we return to the ResourceDispatcherHostImpl so it can | 166 // This is the handle we return to the ResourceDispatcherHostImpl so it can |
165 // interact with the request. | 167 // interact with the request. |
166 class ResourceScheduler::ScheduledResourceRequest | 168 class ResourceScheduler::ScheduledResourceRequestImpl |
167 : public ResourceMessageDelegate, | 169 : public ScheduledResourceRequest { |
168 public ResourceThrottle { | |
169 public: | 170 public: |
170 ScheduledResourceRequest(const ClientId& client_id, | 171 ScheduledResourceRequestImpl(const ClientId& client_id, |
171 net::URLRequest* request, | 172 net::URLRequest* request, |
172 ResourceScheduler* scheduler, | 173 ResourceScheduler* scheduler, |
173 const RequestPriorityParams& priority) | 174 const RequestPriorityParams& priority, |
174 : ResourceMessageDelegate(request), | 175 bool is_async) |
175 client_id_(client_id), | 176 : client_id_(client_id), |
176 client_state_on_creation_(scheduler->GetClientState(client_id_)), | 177 client_state_on_creation_(scheduler->GetClientState(client_id_)), |
177 request_(request), | 178 request_(request), |
178 ready_(false), | 179 ready_(false), |
179 deferred_(false), | 180 deferred_(false), |
| 181 is_async_(is_async), |
180 classification_(NORMAL_REQUEST), | 182 classification_(NORMAL_REQUEST), |
181 scheduler_(scheduler), | 183 scheduler_(scheduler), |
182 priority_(priority), | 184 priority_(priority), |
183 fifo_ordering_(0) { | 185 fifo_ordering_(0) {} |
| 186 |
| 187 ~ScheduledResourceRequestImpl() override { scheduler_->RemoveRequest(this); } |
| 188 |
| 189 void ChangePriority(net::RequestPriority new_priority, |
| 190 int intra_priority_value) override { |
| 191 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value); |
184 } | 192 } |
185 | 193 |
186 ~ScheduledResourceRequest() override { scheduler_->RemoveRequest(this); } | |
187 | |
188 void Start() { | 194 void Start() { |
189 ready_ = true; | 195 ready_ = true; |
190 if (!request_->status().is_success()) | 196 if (!request_->status().is_success()) |
191 return; | 197 return; |
192 base::TimeTicks time = base::TimeTicks::Now(); | 198 base::TimeTicks time = base::TimeTicks::Now(); |
193 ClientState current_state = scheduler_->GetClientState(client_id_); | 199 ClientState current_state = scheduler_->GetClientState(client_id_); |
194 // Note: the client state isn't perfectly accurate since it won't capture | 200 // Note: the client state isn't perfectly accurate since it won't capture |
195 // tabs which have switched between active and background multiple times. | 201 // tabs which have switched between active and background multiple times. |
196 // Ex: A tab with the following transitions Active -> Background -> Active | 202 // Ex: A tab with the following transitions Active -> Background -> Active |
197 // will be recorded as Active. | 203 // will be recorded as Active. |
(...skipping 21 matching lines...) Expand all Loading... |
219 | 225 |
220 void set_request_priority_params(const RequestPriorityParams& priority) { | 226 void set_request_priority_params(const RequestPriorityParams& priority) { |
221 priority_ = priority; | 227 priority_ = priority; |
222 } | 228 } |
223 const RequestPriorityParams& get_request_priority_params() const { | 229 const RequestPriorityParams& get_request_priority_params() const { |
224 return priority_; | 230 return priority_; |
225 } | 231 } |
226 const ClientId& client_id() const { return client_id_; } | 232 const ClientId& client_id() const { return client_id_; } |
227 net::URLRequest* url_request() { return request_; } | 233 net::URLRequest* url_request() { return request_; } |
228 const net::URLRequest* url_request() const { return request_; } | 234 const net::URLRequest* url_request() const { return request_; } |
| 235 bool is_async() const { return is_async_; } |
229 uint32 fifo_ordering() const { return fifo_ordering_; } | 236 uint32 fifo_ordering() const { return fifo_ordering_; } |
230 void set_fifo_ordering(uint32 fifo_ordering) { | 237 void set_fifo_ordering(uint32 fifo_ordering) { |
231 fifo_ordering_ = fifo_ordering; | 238 fifo_ordering_ = fifo_ordering; |
232 } | 239 } |
233 RequestClassification classification() const { | 240 RequestClassification classification() const { |
234 return classification_; | 241 return classification_; |
235 } | 242 } |
236 void set_classification(RequestClassification classification) { | 243 void set_classification(RequestClassification classification) { |
237 classification_ = classification; | 244 classification_ = classification; |
238 } | 245 } |
239 | 246 |
240 private: | 247 private: |
241 // ResourceMessageDelegate interface: | |
242 bool OnMessageReceived(const IPC::Message& message) override { | |
243 bool handled = true; | |
244 IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message) | |
245 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority) | |
246 IPC_MESSAGE_UNHANDLED(handled = false) | |
247 IPC_END_MESSAGE_MAP() | |
248 return handled; | |
249 } | |
250 | |
251 // ResourceThrottle interface: | 248 // ResourceThrottle interface: |
252 void WillStartRequest(bool* defer) override { | 249 void WillStartRequest(bool* defer) override { |
253 deferred_ = *defer = !ready_; | 250 deferred_ = *defer = !ready_; |
254 time_deferred_ = base::TimeTicks::Now(); | 251 time_deferred_ = base::TimeTicks::Now(); |
255 } | 252 } |
256 | 253 |
257 const char* GetNameForLogging() const override { return "ResourceScheduler"; } | 254 const char* GetNameForLogging() const override { return "ResourceScheduler"; } |
258 | 255 |
259 void DidChangePriority(int request_id, net::RequestPriority new_priority, | |
260 int intra_priority_value) { | |
261 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value); | |
262 } | |
263 | |
264 const ClientId client_id_; | 256 const ClientId client_id_; |
265 const ResourceScheduler::ClientState client_state_on_creation_; | 257 const ResourceScheduler::ClientState client_state_on_creation_; |
266 net::URLRequest* request_; | 258 net::URLRequest* request_; |
267 bool ready_; | 259 bool ready_; |
268 bool deferred_; | 260 bool deferred_; |
| 261 bool is_async_; |
269 RequestClassification classification_; | 262 RequestClassification classification_; |
270 ResourceScheduler* scheduler_; | 263 ResourceScheduler* scheduler_; |
271 RequestPriorityParams priority_; | 264 RequestPriorityParams priority_; |
272 uint32 fifo_ordering_; | 265 uint32 fifo_ordering_; |
273 base::TimeTicks time_deferred_; | 266 base::TimeTicks time_deferred_; |
274 | 267 |
275 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); | 268 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequestImpl); |
276 }; | 269 }; |
277 | 270 |
278 bool ResourceScheduler::ScheduledResourceSorter::operator()( | 271 bool ResourceScheduler::ScheduledResourceSorter::operator()( |
279 const ScheduledResourceRequest* a, | 272 const ScheduledResourceRequestImpl* a, |
280 const ScheduledResourceRequest* b) const { | 273 const ScheduledResourceRequestImpl* b) const { |
281 // Want the set to be ordered first by decreasing priority, then by | 274 // Want the set to be ordered first by decreasing priority, then by |
282 // decreasing intra_priority. | 275 // decreasing intra_priority. |
283 // ie. with (priority, intra_priority) | 276 // ie. with (priority, intra_priority) |
284 // [(1, 0), (1, 0), (0, 100), (0, 0)] | 277 // [(1, 0), (1, 0), (0, 100), (0, 0)] |
285 if (a->get_request_priority_params() != b->get_request_priority_params()) | 278 if (a->get_request_priority_params() != b->get_request_priority_params()) |
286 return a->get_request_priority_params().GreaterThan( | 279 return a->get_request_priority_params().GreaterThan( |
287 b->get_request_priority_params()); | 280 b->get_request_priority_params()); |
288 | 281 |
289 // If priority/intra_priority is the same, fall back to fifo ordering. | 282 // If priority/intra_priority is the same, fall back to fifo ordering. |
290 // std::multiset doesn't guarantee this until c++11. | 283 // std::multiset doesn't guarantee this until c++11. |
291 return a->fifo_ordering() < b->fifo_ordering(); | 284 return a->fifo_ordering() < b->fifo_ordering(); |
292 } | 285 } |
293 | 286 |
294 void ResourceScheduler::RequestQueue::Insert( | 287 void ResourceScheduler::RequestQueue::Insert( |
295 ScheduledResourceRequest* request) { | 288 ScheduledResourceRequestImpl* request) { |
296 DCHECK(!ContainsKey(pointers_, request)); | 289 DCHECK(!ContainsKey(pointers_, request)); |
297 request->set_fifo_ordering(MakeFifoOrderingId()); | 290 request->set_fifo_ordering(MakeFifoOrderingId()); |
298 pointers_[request] = queue_.insert(request); | 291 pointers_[request] = queue_.insert(request); |
299 } | 292 } |
300 | 293 |
301 // Each client represents a tab. | 294 // Each client represents a tab. |
302 class ResourceScheduler::Client { | 295 class ResourceScheduler::Client { |
303 public: | 296 public: |
304 explicit Client(ResourceScheduler* scheduler, | 297 explicit Client(ResourceScheduler* scheduler, |
305 bool is_visible, | 298 bool is_visible, |
(...skipping 12 matching lines...) Expand all Loading... |
318 | 311 |
319 ~Client() { | 312 ~Client() { |
320 // Update to default state and pause to ensure the scheduler has a | 313 // Update to default state and pause to ensure the scheduler has a |
321 // correct count of relevant types of clients. | 314 // correct count of relevant types of clients. |
322 is_visible_ = false; | 315 is_visible_ = false; |
323 is_audible_ = false; | 316 is_audible_ = false; |
324 is_paused_ = true; | 317 is_paused_ = true; |
325 UpdateThrottleState(); | 318 UpdateThrottleState(); |
326 } | 319 } |
327 | 320 |
328 void ScheduleRequest( | 321 void ScheduleRequest(net::URLRequest* url_request, |
329 net::URLRequest* url_request, | 322 ScheduledResourceRequestImpl* request) { |
330 ScheduledResourceRequest* request) { | |
331 if (ShouldStartRequest(request) == START_REQUEST) | 323 if (ShouldStartRequest(request) == START_REQUEST) |
332 StartRequest(request); | 324 StartRequest(request); |
333 else | 325 else |
334 pending_requests_.Insert(request); | 326 pending_requests_.Insert(request); |
335 SetRequestClassification(request, ClassifyRequest(request)); | 327 SetRequestClassification(request, ClassifyRequest(request)); |
336 } | 328 } |
337 | 329 |
338 void RemoveRequest(ScheduledResourceRequest* request) { | 330 void RemoveRequest(ScheduledResourceRequestImpl* request) { |
339 if (pending_requests_.IsQueued(request)) { | 331 if (pending_requests_.IsQueued(request)) { |
340 pending_requests_.Erase(request); | 332 pending_requests_.Erase(request); |
341 DCHECK(!ContainsKey(in_flight_requests_, request)); | 333 DCHECK(!ContainsKey(in_flight_requests_, request)); |
342 } else { | 334 } else { |
343 EraseInFlightRequest(request); | 335 EraseInFlightRequest(request); |
344 | 336 |
345 // Removing this request may have freed up another to load. | 337 // Removing this request may have freed up another to load. |
346 LoadAnyStartablePendingRequests(); | 338 LoadAnyStartablePendingRequests(); |
347 } | 339 } |
348 } | 340 } |
349 | 341 |
350 RequestSet StartAndRemoveAllRequests() { | 342 RequestSet StartAndRemoveAllRequests() { |
351 // First start any pending requests so that they will be moved into | 343 // First start any pending requests so that they will be moved into |
352 // in_flight_requests_. This may exceed the limits | 344 // in_flight_requests_. This may exceed the limits |
353 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and | 345 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and |
354 // kMaxNumThrottledRequestsPerClient, so this method must not do anything | 346 // kMaxNumThrottledRequestsPerClient, so this method must not do anything |
355 // that depends on those limits before calling ClearInFlightRequests() | 347 // that depends on those limits before calling ClearInFlightRequests() |
356 // below. | 348 // below. |
357 while (!pending_requests_.IsEmpty()) { | 349 while (!pending_requests_.IsEmpty()) { |
358 ScheduledResourceRequest* request = | 350 ScheduledResourceRequestImpl* request = |
359 *pending_requests_.GetNextHighestIterator(); | 351 *pending_requests_.GetNextHighestIterator(); |
360 pending_requests_.Erase(request); | 352 pending_requests_.Erase(request); |
361 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? | 353 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? |
362 StartRequest(request); | 354 StartRequest(request); |
363 } | 355 } |
364 RequestSet unowned_requests; | 356 RequestSet unowned_requests; |
365 for (RequestSet::iterator it = in_flight_requests_.begin(); | 357 for (RequestSet::iterator it = in_flight_requests_.begin(); |
366 it != in_flight_requests_.end(); ++it) { | 358 it != in_flight_requests_.end(); ++it) { |
367 unowned_requests.insert(*it); | 359 unowned_requests.insert(*it); |
368 (*it)->set_classification(NORMAL_REQUEST); | 360 (*it)->set_classification(NORMAL_REQUEST); |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 LoadAnyStartablePendingRequests(); | 471 LoadAnyStartablePendingRequests(); |
480 } | 472 } |
481 | 473 |
482 void OnReceivedSpdyProxiedHttpResponse() { | 474 void OnReceivedSpdyProxiedHttpResponse() { |
483 if (!using_spdy_proxy_) { | 475 if (!using_spdy_proxy_) { |
484 using_spdy_proxy_ = true; | 476 using_spdy_proxy_ = true; |
485 LoadAnyStartablePendingRequests(); | 477 LoadAnyStartablePendingRequests(); |
486 } | 478 } |
487 } | 479 } |
488 | 480 |
489 void ReprioritizeRequest(ScheduledResourceRequest* request, | 481 void ReprioritizeRequest(ScheduledResourceRequestImpl* request, |
490 RequestPriorityParams old_priority_params, | 482 RequestPriorityParams old_priority_params, |
491 RequestPriorityParams new_priority_params) { | 483 RequestPriorityParams new_priority_params) { |
492 request->url_request()->SetPriority(new_priority_params.priority); | 484 request->url_request()->SetPriority(new_priority_params.priority); |
493 request->set_request_priority_params(new_priority_params); | 485 request->set_request_priority_params(new_priority_params); |
494 if (!pending_requests_.IsQueued(request)) { | 486 if (!pending_requests_.IsQueued(request)) { |
495 DCHECK(ContainsKey(in_flight_requests_, request)); | 487 DCHECK(ContainsKey(in_flight_requests_, request)); |
496 // The priority of the request and priority support of the server may | 488 // The priority of the request and priority support of the server may |
497 // have changed, so update the delayable count. | 489 // have changed, so update the delayable count. |
498 SetRequestClassification(request, ClassifyRequest(request)); | 490 SetRequestClassification(request, ClassifyRequest(request)); |
499 // Request has already started. | 491 // Request has already started. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 SetThrottleState(COALESCED); | 545 SetThrottleState(COALESCED); |
554 } | 546 } |
555 | 547 |
556 private: | 548 private: |
557 enum ShouldStartReqResult { | 549 enum ShouldStartReqResult { |
558 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, | 550 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, |
559 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, | 551 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, |
560 START_REQUEST, | 552 START_REQUEST, |
561 }; | 553 }; |
562 | 554 |
563 void InsertInFlightRequest(ScheduledResourceRequest* request) { | 555 void InsertInFlightRequest(ScheduledResourceRequestImpl* request) { |
564 in_flight_requests_.insert(request); | 556 in_flight_requests_.insert(request); |
565 SetRequestClassification(request, ClassifyRequest(request)); | 557 SetRequestClassification(request, ClassifyRequest(request)); |
566 } | 558 } |
567 | 559 |
568 void EraseInFlightRequest(ScheduledResourceRequest* request) { | 560 void EraseInFlightRequest(ScheduledResourceRequestImpl* request) { |
569 size_t erased = in_flight_requests_.erase(request); | 561 size_t erased = in_flight_requests_.erase(request); |
570 DCHECK_EQ(1u, erased); | 562 DCHECK_EQ(1u, erased); |
571 // Clear any special state that we were tracking for this request. | 563 // Clear any special state that we were tracking for this request. |
572 SetRequestClassification(request, NORMAL_REQUEST); | 564 SetRequestClassification(request, NORMAL_REQUEST); |
573 } | 565 } |
574 | 566 |
575 void ClearInFlightRequests() { | 567 void ClearInFlightRequests() { |
576 in_flight_requests_.clear(); | 568 in_flight_requests_.clear(); |
577 in_flight_delayable_count_ = 0; | 569 in_flight_delayable_count_ = 0; |
578 total_layout_blocking_count_ = 0; | 570 total_layout_blocking_count_ = 0; |
(...skipping 11 matching lines...) Expand all Loading... |
590 for (RequestQueue::NetQueue::const_iterator | 582 for (RequestQueue::NetQueue::const_iterator |
591 it = pending_requests_.GetNextHighestIterator(); | 583 it = pending_requests_.GetNextHighestIterator(); |
592 it != pending_requests_.End(); ++it) { | 584 it != pending_requests_.End(); ++it) { |
593 if ((*it)->classification() == classification) | 585 if ((*it)->classification() == classification) |
594 classification_request_count++; | 586 classification_request_count++; |
595 } | 587 } |
596 } | 588 } |
597 return classification_request_count; | 589 return classification_request_count; |
598 } | 590 } |
599 | 591 |
600 void SetRequestClassification(ScheduledResourceRequest* request, | 592 void SetRequestClassification(ScheduledResourceRequestImpl* request, |
601 RequestClassification classification) { | 593 RequestClassification classification) { |
602 RequestClassification old_classification = request->classification(); | 594 RequestClassification old_classification = request->classification(); |
603 if (old_classification == classification) | 595 if (old_classification == classification) |
604 return; | 596 return; |
605 | 597 |
606 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) | 598 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) |
607 in_flight_delayable_count_--; | 599 in_flight_delayable_count_--; |
608 if (old_classification == LAYOUT_BLOCKING_REQUEST) | 600 if (old_classification == LAYOUT_BLOCKING_REQUEST) |
609 total_layout_blocking_count_--; | 601 total_layout_blocking_count_--; |
610 | 602 |
611 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) | 603 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) |
612 in_flight_delayable_count_++; | 604 in_flight_delayable_count_++; |
613 if (classification == LAYOUT_BLOCKING_REQUEST) | 605 if (classification == LAYOUT_BLOCKING_REQUEST) |
614 total_layout_blocking_count_++; | 606 total_layout_blocking_count_++; |
615 | 607 |
616 request->set_classification(classification); | 608 request->set_classification(classification); |
617 DCHECK_EQ( | 609 DCHECK_EQ( |
618 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), | 610 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), |
619 in_flight_delayable_count_); | 611 in_flight_delayable_count_); |
620 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), | 612 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), |
621 total_layout_blocking_count_); | 613 total_layout_blocking_count_); |
622 } | 614 } |
623 | 615 |
624 RequestClassification ClassifyRequest(ScheduledResourceRequest* request) { | 616 RequestClassification ClassifyRequest(ScheduledResourceRequestImpl* request) { |
625 // If a request is already marked as layout-blocking make sure to keep the | 617 // If a request is already marked as layout-blocking make sure to keep the |
626 // classification across redirects unless the priority was lowered. | 618 // classification across redirects unless the priority was lowered. |
627 if (request->classification() == LAYOUT_BLOCKING_REQUEST && | 619 if (request->classification() == LAYOUT_BLOCKING_REQUEST && |
628 request->url_request()->priority() > net::LOW) { | 620 request->url_request()->priority() > net::LOW) { |
629 return LAYOUT_BLOCKING_REQUEST; | 621 return LAYOUT_BLOCKING_REQUEST; |
630 } | 622 } |
631 | 623 |
632 if (!has_body_ && request->url_request()->priority() > net::LOW) | 624 if (!has_body_ && request->url_request()->priority() > net::LOW) |
633 return LAYOUT_BLOCKING_REQUEST; | 625 return LAYOUT_BLOCKING_REQUEST; |
634 | 626 |
(...skipping 19 matching lines...) Expand all Loading... |
654 net::HostPortPair::FromURL((*it)->url_request()->url()); | 646 net::HostPortPair::FromURL((*it)->url_request()->url()); |
655 if (active_request_host.Equals(host_port_pair)) { | 647 if (active_request_host.Equals(host_port_pair)) { |
656 same_host_count++; | 648 same_host_count++; |
657 if (same_host_count >= kMaxNumDelayableRequestsPerHost) | 649 if (same_host_count >= kMaxNumDelayableRequestsPerHost) |
658 return true; | 650 return true; |
659 } | 651 } |
660 } | 652 } |
661 return false; | 653 return false; |
662 } | 654 } |
663 | 655 |
664 void StartRequest(ScheduledResourceRequest* request) { | 656 void StartRequest(ScheduledResourceRequestImpl* request) { |
665 InsertInFlightRequest(request); | 657 InsertInFlightRequest(request); |
666 request->Start(); | 658 request->Start(); |
667 } | 659 } |
668 | 660 |
669 // ShouldStartRequest is the main scheduling algorithm. | 661 // ShouldStartRequest is the main scheduling algorithm. |
670 // | 662 // |
671 // Requests are evaluated on five attributes: | 663 // Requests are evaluated on five attributes: |
672 // | 664 // |
673 // 1. Non-delayable requests: | 665 // 1. Non-delayable requests: |
674 // * Synchronous requests. | 666 // * Synchronous requests. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
712 // * If no high priority requests are in flight, start loading low priority | 704 // * If no high priority requests are in flight, start loading low priority |
713 // requests. | 705 // requests. |
714 // | 706 // |
715 // COALESCED Clients never load requests, with the following exceptions: | 707 // COALESCED Clients never load requests, with the following exceptions: |
716 // * Non-delayable requests are issued imediately. | 708 // * Non-delayable requests are issued imediately. |
717 // * On a (currently 5 second) heart beat, they load all requests as an | 709 // * On a (currently 5 second) heart beat, they load all requests as an |
718 // UNTHROTTLED Client, and then return to the COALESCED state. | 710 // UNTHROTTLED Client, and then return to the COALESCED state. |
719 // * When an active Client makes a request, they are THROTTLED until the | 711 // * When an active Client makes a request, they are THROTTLED until the |
720 // active Client finishes loading. | 712 // active Client finishes loading. |
721 ShouldStartReqResult ShouldStartRequest( | 713 ShouldStartReqResult ShouldStartRequest( |
722 ScheduledResourceRequest* request) const { | 714 ScheduledResourceRequestImpl* request) const { |
723 const net::URLRequest& url_request = *request->url_request(); | 715 const net::URLRequest& url_request = *request->url_request(); |
724 // Syncronous requests could block the entire render, which could impact | 716 // Syncronous requests could block the entire render, which could impact |
725 // user-observable Clients. | 717 // user-observable Clients. |
726 if (!ResourceRequestInfo::ForRequest(&url_request)->IsAsync()) { | 718 if (!request->is_async()) { |
727 return START_REQUEST; | 719 return START_REQUEST; |
728 } | 720 } |
729 | 721 |
730 // TODO(simonjam): This may end up causing disk contention. We should | 722 // TODO(simonjam): This may end up causing disk contention. We should |
731 // experiment with throttling if that happens. | 723 // experiment with throttling if that happens. |
732 // TODO(aiolos): We probably want to Coalesce these as well to avoid | 724 // TODO(aiolos): We probably want to Coalesce these as well to avoid |
733 // waking the disk. | 725 // waking the disk. |
734 if (!url_request.url().SchemeIsHTTPOrHTTPS()) { | 726 if (!url_request.url().SchemeIsHTTPOrHTTPS()) { |
735 return START_REQUEST; | 727 return START_REQUEST; |
736 } | 728 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
803 // 1) We start the request, remove it from the list, and keep checking. | 795 // 1) We start the request, remove it from the list, and keep checking. |
804 // 2) We do NOT start the request, but ShouldStartRequest() signals us that | 796 // 2) We do NOT start the request, but ShouldStartRequest() signals us that |
805 // there may be room for other requests, so we keep checking and leave | 797 // there may be room for other requests, so we keep checking and leave |
806 // the previous request still in the list. | 798 // the previous request still in the list. |
807 // 3) We do not start the request, same as above, but StartRequest() tells | 799 // 3) We do not start the request, same as above, but StartRequest() tells |
808 // us there's no point in checking any further requests. | 800 // us there's no point in checking any further requests. |
809 RequestQueue::NetQueue::iterator request_iter = | 801 RequestQueue::NetQueue::iterator request_iter = |
810 pending_requests_.GetNextHighestIterator(); | 802 pending_requests_.GetNextHighestIterator(); |
811 | 803 |
812 while (request_iter != pending_requests_.End()) { | 804 while (request_iter != pending_requests_.End()) { |
813 ScheduledResourceRequest* request = *request_iter; | 805 ScheduledResourceRequestImpl* request = *request_iter; |
814 ShouldStartReqResult query_result = ShouldStartRequest(request); | 806 ShouldStartReqResult query_result = ShouldStartRequest(request); |
815 | 807 |
816 if (query_result == START_REQUEST) { | 808 if (query_result == START_REQUEST) { |
817 pending_requests_.Erase(request); | 809 pending_requests_.Erase(request); |
818 StartRequest(request); | 810 StartRequest(request); |
819 | 811 |
820 // StartRequest can modify the pending list, so we (re)start evaluation | 812 // StartRequest can modify the pending list, so we (re)start evaluation |
821 // from the currently highest priority request. Avoid copying a singular | 813 // from the currently highest priority request. Avoid copying a singular |
822 // iterator, which would trigger undefined behavior. | 814 // iterator, which would trigger undefined behavior. |
823 if (pending_requests_.GetNextHighestIterator() == | 815 if (pending_requests_.GetNextHighestIterator() == |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
898 OnLoadingActiveClientsStateChangedForAllClients(); | 890 OnLoadingActiveClientsStateChangedForAllClients(); |
899 } | 891 } |
900 | 892 |
901 ResourceScheduler::ClientThrottleState | 893 ResourceScheduler::ClientThrottleState |
902 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { | 894 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { |
903 Client* client = GetClient(child_id, route_id); | 895 Client* client = GetClient(child_id, route_id); |
904 DCHECK(client); | 896 DCHECK(client); |
905 return client->throttle_state(); | 897 return client->throttle_state(); |
906 } | 898 } |
907 | 899 |
908 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( | 900 scoped_ptr<ScheduledResourceRequest> ResourceScheduler::ScheduleRequest( |
909 int child_id, | 901 int child_id, |
910 int route_id, | 902 int route_id, |
| 903 bool is_async, |
911 net::URLRequest* url_request) { | 904 net::URLRequest* url_request) { |
912 DCHECK(CalledOnValidThread()); | 905 DCHECK(CalledOnValidThread()); |
913 ClientId client_id = MakeClientId(child_id, route_id); | 906 ClientId client_id = MakeClientId(child_id, route_id); |
914 scoped_ptr<ScheduledResourceRequest> request(new ScheduledResourceRequest( | 907 scoped_ptr<ScheduledResourceRequestImpl> request( |
915 client_id, | 908 new ScheduledResourceRequestImpl( |
916 url_request, | 909 client_id, url_request, this, |
917 this, | 910 RequestPriorityParams(url_request->priority(), 0), is_async)); |
918 RequestPriorityParams(url_request->priority(), 0))); | |
919 | 911 |
920 ClientMap::iterator it = client_map_.find(client_id); | 912 ClientMap::iterator it = client_map_.find(client_id); |
921 if (it == client_map_.end()) { | 913 if (it == client_map_.end()) { |
922 // There are several ways this could happen: | 914 // There are several ways this could happen: |
923 // 1. <a ping> requests don't have a route_id. | 915 // 1. <a ping> requests don't have a route_id. |
924 // 2. Most unittests don't send the IPCs needed to register Clients. | 916 // 2. Most unittests don't send the IPCs needed to register Clients. |
925 // 3. The tab is closed while a RequestResource IPC is in flight. | 917 // 3. The tab is closed while a RequestResource IPC is in flight. |
926 unowned_requests_.insert(request.get()); | 918 unowned_requests_.insert(request.get()); |
927 request->Start(); | 919 request->Start(); |
928 return request.Pass(); | 920 return request.Pass(); |
929 } | 921 } |
930 | 922 |
931 Client* client = it->second; | 923 Client* client = it->second; |
932 client->ScheduleRequest(url_request, request.get()); | 924 client->ScheduleRequest(url_request, request.get()); |
933 return request.Pass(); | 925 return request.Pass(); |
934 } | 926 } |
935 | 927 |
936 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) { | 928 void ResourceScheduler::RemoveRequest(ScheduledResourceRequestImpl* request) { |
937 DCHECK(CalledOnValidThread()); | 929 DCHECK(CalledOnValidThread()); |
938 if (ContainsKey(unowned_requests_, request)) { | 930 if (ContainsKey(unowned_requests_, request)) { |
939 unowned_requests_.erase(request); | 931 unowned_requests_.erase(request); |
940 return; | 932 return; |
941 } | 933 } |
942 | 934 |
943 ClientMap::iterator client_it = client_map_.find(request->client_id()); | 935 ClientMap::iterator client_it = client_map_.find(request->client_id()); |
944 if (client_it == client_map_.end()) { | 936 if (client_it == client_map_.end()) { |
945 return; | 937 return; |
946 } | 938 } |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1164 } | 1156 } |
1165 | 1157 |
1166 ResourceScheduler::ClientState ResourceScheduler::GetClientState( | 1158 ResourceScheduler::ClientState ResourceScheduler::GetClientState( |
1167 ClientId client_id) const { | 1159 ClientId client_id) const { |
1168 ClientMap::const_iterator client_it = client_map_.find(client_id); | 1160 ClientMap::const_iterator client_it = client_map_.find(client_id); |
1169 if (client_it == client_map_.end()) | 1161 if (client_it == client_map_.end()) |
1170 return UNKNOWN; | 1162 return UNKNOWN; |
1171 return client_it->second->is_active() ? ACTIVE : BACKGROUND; | 1163 return client_it->second->is_active() ? ACTIVE : BACKGROUND; |
1172 } | 1164 } |
1173 | 1165 |
1174 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, | 1166 void ResourceScheduler::ReprioritizeRequest( |
1175 net::RequestPriority new_priority, | 1167 ScheduledResourceRequestImpl* request, |
1176 int new_intra_priority_value) { | 1168 net::RequestPriority new_priority, |
| 1169 int new_intra_priority_value) { |
1177 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { | 1170 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { |
1178 // We should not be re-prioritizing requests with the | 1171 // We should not be re-prioritizing requests with the |
1179 // IGNORE_LIMITS flag. | 1172 // IGNORE_LIMITS flag. |
1180 NOTREACHED(); | 1173 NOTREACHED(); |
1181 return; | 1174 return; |
1182 } | 1175 } |
1183 RequestPriorityParams new_priority_params(new_priority, | 1176 RequestPriorityParams new_priority_params(new_priority, |
1184 new_intra_priority_value); | 1177 new_intra_priority_value); |
1185 RequestPriorityParams old_priority_params = | 1178 RequestPriorityParams old_priority_params = |
1186 request->get_request_priority_params(); | 1179 request->get_request_priority_params(); |
(...skipping 15 matching lines...) Expand all Loading... |
1202 client->ReprioritizeRequest( | 1195 client->ReprioritizeRequest( |
1203 request, old_priority_params, new_priority_params); | 1196 request, old_priority_params, new_priority_params); |
1204 } | 1197 } |
1205 | 1198 |
1206 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( | 1199 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( |
1207 int child_id, int route_id) { | 1200 int child_id, int route_id) { |
1208 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; | 1201 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
1209 } | 1202 } |
1210 | 1203 |
1211 } // namespace content | 1204 } // namespace content |
OLD | NEW |