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/supports_user_data.h" | |
14 #include "base/time/time.h" | 15 #include "base/time/time.h" |
15 #include "content/common/resource_messages.h" | 16 #include "content/common/resource_messages.h" |
16 #include "content/browser/loader/resource_message_delegate.h" | |
17 #include "content/public/browser/resource_controller.h" | 17 #include "content/public/browser/resource_controller.h" |
18 #include "content/public/browser/resource_request_info.h" | 18 #include "content/public/browser/resource_request_info.h" |
19 #include "content/public/browser/resource_throttle.h" | 19 #include "content/public/browser/resource_throttle.h" |
20 #include "ipc/ipc_message_macros.h" | |
21 #include "net/base/host_port_pair.h" | 20 #include "net/base/host_port_pair.h" |
22 #include "net/base/load_flags.h" | 21 #include "net/base/load_flags.h" |
23 #include "net/base/request_priority.h" | 22 #include "net/base/request_priority.h" |
24 #include "net/http/http_server_properties.h" | 23 #include "net/http/http_server_properties.h" |
25 #include "net/url_request/url_request.h" | 24 #include "net/url_request/url_request.h" |
26 #include "net/url_request/url_request_context.h" | 25 #include "net/url_request/url_request_context.h" |
27 | 26 |
28 namespace content { | 27 namespace content { |
29 | 28 |
30 namespace { | 29 namespace { |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
103 return priority > other.priority; | 102 return priority > other.priority; |
104 return intra_priority > other.intra_priority; | 103 return intra_priority > other.intra_priority; |
105 } | 104 } |
106 | 105 |
107 net::RequestPriority priority; | 106 net::RequestPriority priority; |
108 int intra_priority; | 107 int intra_priority; |
109 }; | 108 }; |
110 | 109 |
111 class ResourceScheduler::RequestQueue { | 110 class ResourceScheduler::RequestQueue { |
112 public: | 111 public: |
113 typedef std::multiset<ScheduledResourceRequest*, ScheduledResourceSorter> | 112 typedef std::multiset<ScheduledResourceRequestImpl*, ScheduledResourceSorter> |
114 NetQueue; | 113 NetQueue; |
115 | 114 |
116 RequestQueue() : fifo_ordering_ids_(0) {} | 115 RequestQueue() : fifo_ordering_ids_(0) {} |
117 ~RequestQueue() {} | 116 ~RequestQueue() {} |
118 | 117 |
119 // Adds |request| to the queue with given |priority|. | 118 // Adds |request| to the queue with given |priority|. |
120 void Insert(ScheduledResourceRequest* request); | 119 void Insert(ScheduledResourceRequestImpl* request); |
121 | 120 |
122 // Removes |request| from the queue. | 121 // Removes |request| from the queue. |
123 void Erase(ScheduledResourceRequest* request) { | 122 void Erase(ScheduledResourceRequestImpl* request) { |
124 PointerMap::iterator it = pointers_.find(request); | 123 PointerMap::iterator it = pointers_.find(request); |
125 DCHECK(it != pointers_.end()); | 124 DCHECK(it != pointers_.end()); |
126 if (it == pointers_.end()) | 125 if (it == pointers_.end()) |
127 return; | 126 return; |
128 queue_.erase(it->second); | 127 queue_.erase(it->second); |
129 pointers_.erase(it); | 128 pointers_.erase(it); |
130 } | 129 } |
131 | 130 |
132 NetQueue::iterator GetNextHighestIterator() { | 131 NetQueue::iterator GetNextHighestIterator() { |
133 return queue_.begin(); | 132 return queue_.begin(); |
134 } | 133 } |
135 | 134 |
136 NetQueue::iterator End() { | 135 NetQueue::iterator End() { |
137 return queue_.end(); | 136 return queue_.end(); |
138 } | 137 } |
139 | 138 |
140 // Returns true if |request| is queued. | 139 // Returns true if |request| is queued. |
141 bool IsQueued(ScheduledResourceRequest* request) const { | 140 bool IsQueued(ScheduledResourceRequestImpl* request) const { |
142 return ContainsKey(pointers_, request); | 141 return ContainsKey(pointers_, request); |
143 } | 142 } |
144 | 143 |
145 // Returns true if no requests are queued. | 144 // Returns true if no requests are queued. |
146 bool IsEmpty() const { return queue_.size() == 0; } | 145 bool IsEmpty() const { return queue_.size() == 0; } |
147 | 146 |
148 private: | 147 private: |
149 typedef std::map<ScheduledResourceRequest*, NetQueue::iterator> PointerMap; | 148 typedef std::map<ScheduledResourceRequestImpl*, NetQueue::iterator> |
149 PointerMap; | |
150 | 150 |
151 uint32 MakeFifoOrderingId() { | 151 uint32 MakeFifoOrderingId() { |
152 fifo_ordering_ids_ += 1; | 152 fifo_ordering_ids_ += 1; |
153 return fifo_ordering_ids_; | 153 return fifo_ordering_ids_; |
154 } | 154 } |
155 | 155 |
156 // Used to create an ordering ID for scheduled resources so that resources | 156 // Used to create an ordering ID for scheduled resources so that resources |
157 // with same priority/intra_priority stay in fifo order. | 157 // with same priority/intra_priority stay in fifo order. |
158 uint32 fifo_ordering_ids_; | 158 uint32 fifo_ordering_ids_; |
159 | 159 |
160 NetQueue queue_; | 160 NetQueue queue_; |
161 PointerMap pointers_; | 161 PointerMap pointers_; |
162 }; | 162 }; |
163 | 163 |
164 // This is the handle we return to the ResourceDispatcherHostImpl so it can | 164 // This is the handle we return to the ResourceDispatcherHostImpl so it can |
165 // interact with the request. | 165 // interact with the request. |
166 class ResourceScheduler::ScheduledResourceRequest | 166 class ResourceScheduler::ScheduledResourceRequestImpl |
167 : public ResourceMessageDelegate, | 167 : public ScheduledResourceRequest { |
168 public ResourceThrottle { | |
169 public: | 168 public: |
170 ScheduledResourceRequest(const ClientId& client_id, | 169 ScheduledResourceRequestImpl(const ClientId& client_id, |
171 net::URLRequest* request, | 170 net::URLRequest* request, |
172 ResourceScheduler* scheduler, | 171 ResourceScheduler* scheduler, |
173 const RequestPriorityParams& priority) | 172 const RequestPriorityParams& priority, |
174 : ResourceMessageDelegate(request), | 173 bool is_async) |
175 client_id_(client_id), | 174 : client_id_(client_id), |
176 client_state_on_creation_(scheduler->GetClientState(client_id_)), | 175 client_state_on_creation_(scheduler->GetClientState(client_id_)), |
177 request_(request), | 176 request_(request), |
178 ready_(false), | 177 ready_(false), |
179 deferred_(false), | 178 deferred_(false), |
179 is_async_(is_async), | |
180 classification_(NORMAL_REQUEST), | 180 classification_(NORMAL_REQUEST), |
181 scheduler_(scheduler), | 181 scheduler_(scheduler), |
182 priority_(priority), | 182 priority_(priority), |
183 fifo_ordering_(0) { | 183 fifo_ordering_(0) { |
184 request_->SetUserData(kUserDataKey, new UnownedPointer(this)); | |
184 } | 185 } |
185 | 186 |
186 ~ScheduledResourceRequest() override { scheduler_->RemoveRequest(this); } | 187 ~ScheduledResourceRequestImpl() override { |
188 request_->RemoveUserData(kUserDataKey); | |
189 scheduler_->RemoveRequest(this); | |
190 } | |
191 | |
192 void ChangePriority(net::RequestPriority new_priority, | |
193 int intra_priority_value) override { | |
194 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value); | |
195 } | |
196 | |
197 static ScheduledResourceRequest* ForRequest(net::URLRequest* request) { | |
198 return static_cast<UnownedPointer*>(request->GetUserData(kUserDataKey)) | |
199 ->pointer; | |
200 } | |
187 | 201 |
188 void Start() { | 202 void Start() { |
189 ready_ = true; | 203 ready_ = true; |
190 if (!request_->status().is_success()) | 204 if (!request_->status().is_success()) |
191 return; | 205 return; |
192 base::TimeTicks time = base::TimeTicks::Now(); | 206 base::TimeTicks time = base::TimeTicks::Now(); |
193 ClientState current_state = scheduler_->GetClientState(client_id_); | 207 ClientState current_state = scheduler_->GetClientState(client_id_); |
194 // Note: the client state isn't perfectly accurate since it won't capture | 208 // Note: the client state isn't perfectly accurate since it won't capture |
195 // tabs which have switched between active and background multiple times. | 209 // tabs which have switched between active and background multiple times. |
196 // Ex: A tab with the following transitions Active -> Background -> Active | 210 // Ex: A tab with the following transitions Active -> Background -> Active |
(...skipping 22 matching lines...) Expand all Loading... | |
219 | 233 |
220 void set_request_priority_params(const RequestPriorityParams& priority) { | 234 void set_request_priority_params(const RequestPriorityParams& priority) { |
221 priority_ = priority; | 235 priority_ = priority; |
222 } | 236 } |
223 const RequestPriorityParams& get_request_priority_params() const { | 237 const RequestPriorityParams& get_request_priority_params() const { |
224 return priority_; | 238 return priority_; |
225 } | 239 } |
226 const ClientId& client_id() const { return client_id_; } | 240 const ClientId& client_id() const { return client_id_; } |
227 net::URLRequest* url_request() { return request_; } | 241 net::URLRequest* url_request() { return request_; } |
228 const net::URLRequest* url_request() const { return request_; } | 242 const net::URLRequest* url_request() const { return request_; } |
243 bool is_async() const { return is_async_; } | |
229 uint32 fifo_ordering() const { return fifo_ordering_; } | 244 uint32 fifo_ordering() const { return fifo_ordering_; } |
230 void set_fifo_ordering(uint32 fifo_ordering) { | 245 void set_fifo_ordering(uint32 fifo_ordering) { |
231 fifo_ordering_ = fifo_ordering; | 246 fifo_ordering_ = fifo_ordering; |
232 } | 247 } |
233 RequestClassification classification() const { | 248 RequestClassification classification() const { |
234 return classification_; | 249 return classification_; |
235 } | 250 } |
236 void set_classification(RequestClassification classification) { | 251 void set_classification(RequestClassification classification) { |
237 classification_ = classification; | 252 classification_ = classification; |
238 } | 253 } |
239 | 254 |
240 private: | 255 private: |
241 // ResourceMessageDelegate interface: | 256 class UnownedPointer : public base::SupportsUserData::Data { |
242 bool OnMessageReceived(const IPC::Message& message) override { | 257 public: |
243 bool handled = true; | 258 UnownedPointer(ScheduledResourceRequestImpl* pointer) : pointer(pointer) {} |
mmenke
2015/08/14 15:23:14
explicit
Adam Rice
2015/08/14 17:17:22
Done.
| |
244 IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message) | 259 |
245 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority) | 260 ScheduledResourceRequestImpl* const pointer; |
mmenke
2015/08/14 15:23:15
This should be private, with an accessor, per Goog
Adam Rice
2015/08/14 17:17:23
Done.
| |
246 IPC_MESSAGE_UNHANDLED(handled = false) | 261 |
247 IPC_END_MESSAGE_MAP() | 262 private: |
248 return handled; | 263 DISALLOW_COPY_AND_ASSIGN(UnownedPointer); |
249 } | 264 }; |
265 | |
266 static const void* const kUserDataKey; | |
250 | 267 |
251 // ResourceThrottle interface: | 268 // ResourceThrottle interface: |
252 void WillStartRequest(bool* defer) override { | 269 void WillStartRequest(bool* defer) override { |
253 deferred_ = *defer = !ready_; | 270 deferred_ = *defer = !ready_; |
254 time_deferred_ = base::TimeTicks::Now(); | 271 time_deferred_ = base::TimeTicks::Now(); |
255 } | 272 } |
256 | 273 |
257 const char* GetNameForLogging() const override { return "ResourceScheduler"; } | 274 const char* GetNameForLogging() const override { return "ResourceScheduler"; } |
258 | 275 |
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_; | 276 const ClientId client_id_; |
265 const ResourceScheduler::ClientState client_state_on_creation_; | 277 const ResourceScheduler::ClientState client_state_on_creation_; |
266 net::URLRequest* request_; | 278 net::URLRequest* request_; |
267 bool ready_; | 279 bool ready_; |
268 bool deferred_; | 280 bool deferred_; |
281 bool is_async_; | |
269 RequestClassification classification_; | 282 RequestClassification classification_; |
270 ResourceScheduler* scheduler_; | 283 ResourceScheduler* scheduler_; |
271 RequestPriorityParams priority_; | 284 RequestPriorityParams priority_; |
272 uint32 fifo_ordering_; | 285 uint32 fifo_ordering_; |
273 base::TimeTicks time_deferred_; | 286 base::TimeTicks time_deferred_; |
274 | 287 |
275 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); | 288 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequestImpl); |
276 }; | 289 }; |
277 | 290 |
291 const void* const | |
292 ResourceScheduler::ScheduledResourceRequestImpl::kUserDataKey = | |
293 &ResourceScheduler::ScheduledResourceRequestImpl::kUserDataKey; | |
294 | |
295 ResourceScheduler::ScheduledResourceRequest::ScheduledResourceRequest() {} | |
296 ResourceScheduler::ScheduledResourceRequest::~ScheduledResourceRequest() {} | |
297 ResourceScheduler::ScheduledResourceRequest* | |
298 ResourceScheduler::ScheduledResourceRequest::ForRequest( | |
299 net::URLRequest* request) { | |
300 return ResourceScheduler::ScheduledResourceRequestImpl::ForRequest(request); | |
301 } | |
mmenke
2015/08/14 15:23:14
nit: believe there should be a blank line between
Adam Rice
2015/08/14 17:17:23
Removed.
| |
302 | |
278 bool ResourceScheduler::ScheduledResourceSorter::operator()( | 303 bool ResourceScheduler::ScheduledResourceSorter::operator()( |
279 const ScheduledResourceRequest* a, | 304 const ScheduledResourceRequestImpl* a, |
280 const ScheduledResourceRequest* b) const { | 305 const ScheduledResourceRequestImpl* b) const { |
281 // Want the set to be ordered first by decreasing priority, then by | 306 // Want the set to be ordered first by decreasing priority, then by |
282 // decreasing intra_priority. | 307 // decreasing intra_priority. |
283 // ie. with (priority, intra_priority) | 308 // ie. with (priority, intra_priority) |
284 // [(1, 0), (1, 0), (0, 100), (0, 0)] | 309 // [(1, 0), (1, 0), (0, 100), (0, 0)] |
285 if (a->get_request_priority_params() != b->get_request_priority_params()) | 310 if (a->get_request_priority_params() != b->get_request_priority_params()) |
286 return a->get_request_priority_params().GreaterThan( | 311 return a->get_request_priority_params().GreaterThan( |
287 b->get_request_priority_params()); | 312 b->get_request_priority_params()); |
288 | 313 |
289 // If priority/intra_priority is the same, fall back to fifo ordering. | 314 // If priority/intra_priority is the same, fall back to fifo ordering. |
290 // std::multiset doesn't guarantee this until c++11. | 315 // std::multiset doesn't guarantee this until c++11. |
291 return a->fifo_ordering() < b->fifo_ordering(); | 316 return a->fifo_ordering() < b->fifo_ordering(); |
292 } | 317 } |
293 | 318 |
294 void ResourceScheduler::RequestQueue::Insert( | 319 void ResourceScheduler::RequestQueue::Insert( |
295 ScheduledResourceRequest* request) { | 320 ScheduledResourceRequestImpl* request) { |
296 DCHECK(!ContainsKey(pointers_, request)); | 321 DCHECK(!ContainsKey(pointers_, request)); |
297 request->set_fifo_ordering(MakeFifoOrderingId()); | 322 request->set_fifo_ordering(MakeFifoOrderingId()); |
298 pointers_[request] = queue_.insert(request); | 323 pointers_[request] = queue_.insert(request); |
299 } | 324 } |
300 | 325 |
301 // Each client represents a tab. | 326 // Each client represents a tab. |
302 class ResourceScheduler::Client { | 327 class ResourceScheduler::Client { |
303 public: | 328 public: |
304 explicit Client(ResourceScheduler* scheduler, | 329 explicit Client(ResourceScheduler* scheduler, |
305 bool is_visible, | 330 bool is_visible, |
(...skipping 12 matching lines...) Expand all Loading... | |
318 | 343 |
319 ~Client() { | 344 ~Client() { |
320 // Update to default state and pause to ensure the scheduler has a | 345 // Update to default state and pause to ensure the scheduler has a |
321 // correct count of relevant types of clients. | 346 // correct count of relevant types of clients. |
322 is_visible_ = false; | 347 is_visible_ = false; |
323 is_audible_ = false; | 348 is_audible_ = false; |
324 is_paused_ = true; | 349 is_paused_ = true; |
325 UpdateThrottleState(); | 350 UpdateThrottleState(); |
326 } | 351 } |
327 | 352 |
328 void ScheduleRequest( | 353 void ScheduleRequest(net::URLRequest* url_request, |
329 net::URLRequest* url_request, | 354 ScheduledResourceRequestImpl* request) { |
330 ScheduledResourceRequest* request) { | |
331 if (ShouldStartRequest(request) == START_REQUEST) | 355 if (ShouldStartRequest(request) == START_REQUEST) |
332 StartRequest(request); | 356 StartRequest(request); |
333 else | 357 else |
334 pending_requests_.Insert(request); | 358 pending_requests_.Insert(request); |
335 SetRequestClassification(request, ClassifyRequest(request)); | 359 SetRequestClassification(request, ClassifyRequest(request)); |
336 } | 360 } |
337 | 361 |
338 void RemoveRequest(ScheduledResourceRequest* request) { | 362 void RemoveRequest(ScheduledResourceRequestImpl* request) { |
339 if (pending_requests_.IsQueued(request)) { | 363 if (pending_requests_.IsQueued(request)) { |
340 pending_requests_.Erase(request); | 364 pending_requests_.Erase(request); |
341 DCHECK(!ContainsKey(in_flight_requests_, request)); | 365 DCHECK(!ContainsKey(in_flight_requests_, request)); |
342 } else { | 366 } else { |
343 EraseInFlightRequest(request); | 367 EraseInFlightRequest(request); |
344 | 368 |
345 // Removing this request may have freed up another to load. | 369 // Removing this request may have freed up another to load. |
346 LoadAnyStartablePendingRequests(); | 370 LoadAnyStartablePendingRequests(); |
347 } | 371 } |
348 } | 372 } |
349 | 373 |
350 RequestSet StartAndRemoveAllRequests() { | 374 RequestSet StartAndRemoveAllRequests() { |
351 // First start any pending requests so that they will be moved into | 375 // First start any pending requests so that they will be moved into |
352 // in_flight_requests_. This may exceed the limits | 376 // in_flight_requests_. This may exceed the limits |
353 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and | 377 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and |
354 // kMaxNumThrottledRequestsPerClient, so this method must not do anything | 378 // kMaxNumThrottledRequestsPerClient, so this method must not do anything |
355 // that depends on those limits before calling ClearInFlightRequests() | 379 // that depends on those limits before calling ClearInFlightRequests() |
356 // below. | 380 // below. |
357 while (!pending_requests_.IsEmpty()) { | 381 while (!pending_requests_.IsEmpty()) { |
358 ScheduledResourceRequest* request = | 382 ScheduledResourceRequestImpl* request = |
359 *pending_requests_.GetNextHighestIterator(); | 383 *pending_requests_.GetNextHighestIterator(); |
360 pending_requests_.Erase(request); | 384 pending_requests_.Erase(request); |
361 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? | 385 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? |
362 StartRequest(request); | 386 StartRequest(request); |
363 } | 387 } |
364 RequestSet unowned_requests; | 388 RequestSet unowned_requests; |
365 for (RequestSet::iterator it = in_flight_requests_.begin(); | 389 for (RequestSet::iterator it = in_flight_requests_.begin(); |
366 it != in_flight_requests_.end(); ++it) { | 390 it != in_flight_requests_.end(); ++it) { |
367 unowned_requests.insert(*it); | 391 unowned_requests.insert(*it); |
368 (*it)->set_classification(NORMAL_REQUEST); | 392 (*it)->set_classification(NORMAL_REQUEST); |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
479 LoadAnyStartablePendingRequests(); | 503 LoadAnyStartablePendingRequests(); |
480 } | 504 } |
481 | 505 |
482 void OnReceivedSpdyProxiedHttpResponse() { | 506 void OnReceivedSpdyProxiedHttpResponse() { |
483 if (!using_spdy_proxy_) { | 507 if (!using_spdy_proxy_) { |
484 using_spdy_proxy_ = true; | 508 using_spdy_proxy_ = true; |
485 LoadAnyStartablePendingRequests(); | 509 LoadAnyStartablePendingRequests(); |
486 } | 510 } |
487 } | 511 } |
488 | 512 |
489 void ReprioritizeRequest(ScheduledResourceRequest* request, | 513 void ReprioritizeRequest(ScheduledResourceRequestImpl* request, |
490 RequestPriorityParams old_priority_params, | 514 RequestPriorityParams old_priority_params, |
491 RequestPriorityParams new_priority_params) { | 515 RequestPriorityParams new_priority_params) { |
492 request->url_request()->SetPriority(new_priority_params.priority); | 516 request->url_request()->SetPriority(new_priority_params.priority); |
493 request->set_request_priority_params(new_priority_params); | 517 request->set_request_priority_params(new_priority_params); |
494 if (!pending_requests_.IsQueued(request)) { | 518 if (!pending_requests_.IsQueued(request)) { |
495 DCHECK(ContainsKey(in_flight_requests_, request)); | 519 DCHECK(ContainsKey(in_flight_requests_, request)); |
496 // The priority of the request and priority support of the server may | 520 // The priority of the request and priority support of the server may |
497 // have changed, so update the delayable count. | 521 // have changed, so update the delayable count. |
498 SetRequestClassification(request, ClassifyRequest(request)); | 522 SetRequestClassification(request, ClassifyRequest(request)); |
499 // Request has already started. | 523 // Request has already started. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
553 SetThrottleState(COALESCED); | 577 SetThrottleState(COALESCED); |
554 } | 578 } |
555 | 579 |
556 private: | 580 private: |
557 enum ShouldStartReqResult { | 581 enum ShouldStartReqResult { |
558 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, | 582 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, |
559 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, | 583 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, |
560 START_REQUEST, | 584 START_REQUEST, |
561 }; | 585 }; |
562 | 586 |
563 void InsertInFlightRequest(ScheduledResourceRequest* request) { | 587 void InsertInFlightRequest(ScheduledResourceRequestImpl* request) { |
564 in_flight_requests_.insert(request); | 588 in_flight_requests_.insert(request); |
565 SetRequestClassification(request, ClassifyRequest(request)); | 589 SetRequestClassification(request, ClassifyRequest(request)); |
566 } | 590 } |
567 | 591 |
568 void EraseInFlightRequest(ScheduledResourceRequest* request) { | 592 void EraseInFlightRequest(ScheduledResourceRequestImpl* request) { |
569 size_t erased = in_flight_requests_.erase(request); | 593 size_t erased = in_flight_requests_.erase(request); |
570 DCHECK_EQ(1u, erased); | 594 DCHECK_EQ(1u, erased); |
571 // Clear any special state that we were tracking for this request. | 595 // Clear any special state that we were tracking for this request. |
572 SetRequestClassification(request, NORMAL_REQUEST); | 596 SetRequestClassification(request, NORMAL_REQUEST); |
573 } | 597 } |
574 | 598 |
575 void ClearInFlightRequests() { | 599 void ClearInFlightRequests() { |
576 in_flight_requests_.clear(); | 600 in_flight_requests_.clear(); |
577 in_flight_delayable_count_ = 0; | 601 in_flight_delayable_count_ = 0; |
578 total_layout_blocking_count_ = 0; | 602 total_layout_blocking_count_ = 0; |
(...skipping 11 matching lines...) Expand all Loading... | |
590 for (RequestQueue::NetQueue::const_iterator | 614 for (RequestQueue::NetQueue::const_iterator |
591 it = pending_requests_.GetNextHighestIterator(); | 615 it = pending_requests_.GetNextHighestIterator(); |
592 it != pending_requests_.End(); ++it) { | 616 it != pending_requests_.End(); ++it) { |
593 if ((*it)->classification() == classification) | 617 if ((*it)->classification() == classification) |
594 classification_request_count++; | 618 classification_request_count++; |
595 } | 619 } |
596 } | 620 } |
597 return classification_request_count; | 621 return classification_request_count; |
598 } | 622 } |
599 | 623 |
600 void SetRequestClassification(ScheduledResourceRequest* request, | 624 void SetRequestClassification(ScheduledResourceRequestImpl* request, |
601 RequestClassification classification) { | 625 RequestClassification classification) { |
602 RequestClassification old_classification = request->classification(); | 626 RequestClassification old_classification = request->classification(); |
603 if (old_classification == classification) | 627 if (old_classification == classification) |
604 return; | 628 return; |
605 | 629 |
606 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) | 630 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) |
607 in_flight_delayable_count_--; | 631 in_flight_delayable_count_--; |
608 if (old_classification == LAYOUT_BLOCKING_REQUEST) | 632 if (old_classification == LAYOUT_BLOCKING_REQUEST) |
609 total_layout_blocking_count_--; | 633 total_layout_blocking_count_--; |
610 | 634 |
611 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) | 635 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) |
612 in_flight_delayable_count_++; | 636 in_flight_delayable_count_++; |
613 if (classification == LAYOUT_BLOCKING_REQUEST) | 637 if (classification == LAYOUT_BLOCKING_REQUEST) |
614 total_layout_blocking_count_++; | 638 total_layout_blocking_count_++; |
615 | 639 |
616 request->set_classification(classification); | 640 request->set_classification(classification); |
617 DCHECK_EQ( | 641 DCHECK_EQ( |
618 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), | 642 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), |
619 in_flight_delayable_count_); | 643 in_flight_delayable_count_); |
620 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), | 644 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), |
621 total_layout_blocking_count_); | 645 total_layout_blocking_count_); |
622 } | 646 } |
623 | 647 |
624 RequestClassification ClassifyRequest(ScheduledResourceRequest* request) { | 648 RequestClassification ClassifyRequest(ScheduledResourceRequestImpl* request) { |
625 // If a request is already marked as layout-blocking make sure to keep the | 649 // If a request is already marked as layout-blocking make sure to keep the |
626 // classification across redirects unless the priority was lowered. | 650 // classification across redirects unless the priority was lowered. |
627 if (request->classification() == LAYOUT_BLOCKING_REQUEST && | 651 if (request->classification() == LAYOUT_BLOCKING_REQUEST && |
628 request->url_request()->priority() > net::LOW) { | 652 request->url_request()->priority() > net::LOW) { |
629 return LAYOUT_BLOCKING_REQUEST; | 653 return LAYOUT_BLOCKING_REQUEST; |
630 } | 654 } |
631 | 655 |
632 if (!has_body_ && request->url_request()->priority() > net::LOW) | 656 if (!has_body_ && request->url_request()->priority() > net::LOW) |
633 return LAYOUT_BLOCKING_REQUEST; | 657 return LAYOUT_BLOCKING_REQUEST; |
634 | 658 |
(...skipping 19 matching lines...) Expand all Loading... | |
654 net::HostPortPair::FromURL((*it)->url_request()->url()); | 678 net::HostPortPair::FromURL((*it)->url_request()->url()); |
655 if (active_request_host.Equals(host_port_pair)) { | 679 if (active_request_host.Equals(host_port_pair)) { |
656 same_host_count++; | 680 same_host_count++; |
657 if (same_host_count >= kMaxNumDelayableRequestsPerHost) | 681 if (same_host_count >= kMaxNumDelayableRequestsPerHost) |
658 return true; | 682 return true; |
659 } | 683 } |
660 } | 684 } |
661 return false; | 685 return false; |
662 } | 686 } |
663 | 687 |
664 void StartRequest(ScheduledResourceRequest* request) { | 688 void StartRequest(ScheduledResourceRequestImpl* request) { |
665 InsertInFlightRequest(request); | 689 InsertInFlightRequest(request); |
666 request->Start(); | 690 request->Start(); |
667 } | 691 } |
668 | 692 |
669 // ShouldStartRequest is the main scheduling algorithm. | 693 // ShouldStartRequest is the main scheduling algorithm. |
670 // | 694 // |
671 // Requests are evaluated on five attributes: | 695 // Requests are evaluated on five attributes: |
672 // | 696 // |
673 // 1. Non-delayable requests: | 697 // 1. Non-delayable requests: |
674 // * Synchronous requests. | 698 // * 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 | 736 // * If no high priority requests are in flight, start loading low priority |
713 // requests. | 737 // requests. |
714 // | 738 // |
715 // COALESCED Clients never load requests, with the following exceptions: | 739 // COALESCED Clients never load requests, with the following exceptions: |
716 // * Non-delayable requests are issued imediately. | 740 // * Non-delayable requests are issued imediately. |
717 // * On a (currently 5 second) heart beat, they load all requests as an | 741 // * On a (currently 5 second) heart beat, they load all requests as an |
718 // UNTHROTTLED Client, and then return to the COALESCED state. | 742 // UNTHROTTLED Client, and then return to the COALESCED state. |
719 // * When an active Client makes a request, they are THROTTLED until the | 743 // * When an active Client makes a request, they are THROTTLED until the |
720 // active Client finishes loading. | 744 // active Client finishes loading. |
721 ShouldStartReqResult ShouldStartRequest( | 745 ShouldStartReqResult ShouldStartRequest( |
722 ScheduledResourceRequest* request) const { | 746 ScheduledResourceRequestImpl* request) const { |
723 const net::URLRequest& url_request = *request->url_request(); | 747 const net::URLRequest& url_request = *request->url_request(); |
724 // Syncronous requests could block the entire render, which could impact | 748 // Syncronous requests could block the entire render, which could impact |
725 // user-observable Clients. | 749 // user-observable Clients. |
726 if (!ResourceRequestInfo::ForRequest(&url_request)->IsAsync()) { | 750 if (!request->is_async()) { |
727 return START_REQUEST; | 751 return START_REQUEST; |
728 } | 752 } |
729 | 753 |
730 // TODO(simonjam): This may end up causing disk contention. We should | 754 // TODO(simonjam): This may end up causing disk contention. We should |
731 // experiment with throttling if that happens. | 755 // experiment with throttling if that happens. |
732 // TODO(aiolos): We probably want to Coalesce these as well to avoid | 756 // TODO(aiolos): We probably want to Coalesce these as well to avoid |
733 // waking the disk. | 757 // waking the disk. |
734 if (!url_request.url().SchemeIsHTTPOrHTTPS()) { | 758 if (!url_request.url().SchemeIsHTTPOrHTTPS()) { |
735 return START_REQUEST; | 759 return START_REQUEST; |
736 } | 760 } |
(...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. | 827 // 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 | 828 // 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 | 829 // there may be room for other requests, so we keep checking and leave |
806 // the previous request still in the list. | 830 // the previous request still in the list. |
807 // 3) We do not start the request, same as above, but StartRequest() tells | 831 // 3) We do not start the request, same as above, but StartRequest() tells |
808 // us there's no point in checking any further requests. | 832 // us there's no point in checking any further requests. |
809 RequestQueue::NetQueue::iterator request_iter = | 833 RequestQueue::NetQueue::iterator request_iter = |
810 pending_requests_.GetNextHighestIterator(); | 834 pending_requests_.GetNextHighestIterator(); |
811 | 835 |
812 while (request_iter != pending_requests_.End()) { | 836 while (request_iter != pending_requests_.End()) { |
813 ScheduledResourceRequest* request = *request_iter; | 837 ScheduledResourceRequestImpl* request = *request_iter; |
814 ShouldStartReqResult query_result = ShouldStartRequest(request); | 838 ShouldStartReqResult query_result = ShouldStartRequest(request); |
815 | 839 |
816 if (query_result == START_REQUEST) { | 840 if (query_result == START_REQUEST) { |
817 pending_requests_.Erase(request); | 841 pending_requests_.Erase(request); |
818 StartRequest(request); | 842 StartRequest(request); |
819 | 843 |
820 // StartRequest can modify the pending list, so we (re)start evaluation | 844 // StartRequest can modify the pending list, so we (re)start evaluation |
821 // from the currently highest priority request. Avoid copying a singular | 845 // from the currently highest priority request. Avoid copying a singular |
822 // iterator, which would trigger undefined behavior. | 846 // iterator, which would trigger undefined behavior. |
823 if (pending_requests_.GetNextHighestIterator() == | 847 if (pending_requests_.GetNextHighestIterator() == |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
898 OnLoadingActiveClientsStateChangedForAllClients(); | 922 OnLoadingActiveClientsStateChangedForAllClients(); |
899 } | 923 } |
900 | 924 |
901 ResourceScheduler::ClientThrottleState | 925 ResourceScheduler::ClientThrottleState |
902 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { | 926 ResourceScheduler::GetClientStateForTesting(int child_id, int route_id) { |
903 Client* client = GetClient(child_id, route_id); | 927 Client* client = GetClient(child_id, route_id); |
904 DCHECK(client); | 928 DCHECK(client); |
905 return client->throttle_state(); | 929 return client->throttle_state(); |
906 } | 930 } |
907 | 931 |
908 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( | 932 scoped_ptr<ResourceScheduler::ScheduledResourceRequest> |
909 int child_id, | 933 ResourceScheduler::ScheduleRequest(int child_id, |
910 int route_id, | 934 int route_id, |
911 net::URLRequest* url_request) { | 935 bool is_async, |
936 net::URLRequest* url_request) { | |
912 DCHECK(CalledOnValidThread()); | 937 DCHECK(CalledOnValidThread()); |
913 ClientId client_id = MakeClientId(child_id, route_id); | 938 ClientId client_id = MakeClientId(child_id, route_id); |
914 scoped_ptr<ScheduledResourceRequest> request(new ScheduledResourceRequest( | 939 scoped_ptr<ScheduledResourceRequestImpl> request( |
915 client_id, | 940 new ScheduledResourceRequestImpl( |
916 url_request, | 941 client_id, url_request, this, |
917 this, | 942 RequestPriorityParams(url_request->priority(), 0), is_async)); |
918 RequestPriorityParams(url_request->priority(), 0))); | |
919 | 943 |
920 ClientMap::iterator it = client_map_.find(client_id); | 944 ClientMap::iterator it = client_map_.find(client_id); |
921 if (it == client_map_.end()) { | 945 if (it == client_map_.end()) { |
922 // There are several ways this could happen: | 946 // There are several ways this could happen: |
923 // 1. <a ping> requests don't have a route_id. | 947 // 1. <a ping> requests don't have a route_id. |
924 // 2. Most unittests don't send the IPCs needed to register Clients. | 948 // 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. | 949 // 3. The tab is closed while a RequestResource IPC is in flight. |
926 unowned_requests_.insert(request.get()); | 950 unowned_requests_.insert(request.get()); |
927 request->Start(); | 951 request->Start(); |
928 return request.Pass(); | 952 return request.Pass(); |
929 } | 953 } |
930 | 954 |
931 Client* client = it->second; | 955 Client* client = it->second; |
932 client->ScheduleRequest(url_request, request.get()); | 956 client->ScheduleRequest(url_request, request.get()); |
933 return request.Pass(); | 957 return request.Pass(); |
934 } | 958 } |
935 | 959 |
936 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) { | 960 void ResourceScheduler::RemoveRequest(ScheduledResourceRequestImpl* request) { |
937 DCHECK(CalledOnValidThread()); | 961 DCHECK(CalledOnValidThread()); |
938 if (ContainsKey(unowned_requests_, request)) { | 962 if (ContainsKey(unowned_requests_, request)) { |
939 unowned_requests_.erase(request); | 963 unowned_requests_.erase(request); |
940 return; | 964 return; |
941 } | 965 } |
942 | 966 |
943 ClientMap::iterator client_it = client_map_.find(request->client_id()); | 967 ClientMap::iterator client_it = client_map_.find(request->client_id()); |
944 if (client_it == client_map_.end()) { | 968 if (client_it == client_map_.end()) { |
945 return; | 969 return; |
946 } | 970 } |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1164 } | 1188 } |
1165 | 1189 |
1166 ResourceScheduler::ClientState ResourceScheduler::GetClientState( | 1190 ResourceScheduler::ClientState ResourceScheduler::GetClientState( |
1167 ClientId client_id) const { | 1191 ClientId client_id) const { |
1168 ClientMap::const_iterator client_it = client_map_.find(client_id); | 1192 ClientMap::const_iterator client_it = client_map_.find(client_id); |
1169 if (client_it == client_map_.end()) | 1193 if (client_it == client_map_.end()) |
1170 return UNKNOWN; | 1194 return UNKNOWN; |
1171 return client_it->second->is_active() ? ACTIVE : BACKGROUND; | 1195 return client_it->second->is_active() ? ACTIVE : BACKGROUND; |
1172 } | 1196 } |
1173 | 1197 |
1174 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, | 1198 void ResourceScheduler::ReprioritizeRequest( |
1175 net::RequestPriority new_priority, | 1199 ScheduledResourceRequestImpl* request, |
1176 int new_intra_priority_value) { | 1200 net::RequestPriority new_priority, |
1201 int new_intra_priority_value) { | |
mmenke
2015/08/14 15:23:14
Why not have the RDH call this method with the URL
Adam Rice
2015/08/14 17:17:22
Oh. Thank you. Done.
| |
1177 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { | 1202 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { |
1178 // We should not be re-prioritizing requests with the | 1203 // We should not be re-prioritizing requests with the |
1179 // IGNORE_LIMITS flag. | 1204 // IGNORE_LIMITS flag. |
1180 NOTREACHED(); | 1205 NOTREACHED(); |
1181 return; | 1206 return; |
1182 } | 1207 } |
1183 RequestPriorityParams new_priority_params(new_priority, | 1208 RequestPriorityParams new_priority_params(new_priority, |
1184 new_intra_priority_value); | 1209 new_intra_priority_value); |
1185 RequestPriorityParams old_priority_params = | 1210 RequestPriorityParams old_priority_params = |
1186 request->get_request_priority_params(); | 1211 request->get_request_priority_params(); |
(...skipping 15 matching lines...) Expand all Loading... | |
1202 client->ReprioritizeRequest( | 1227 client->ReprioritizeRequest( |
1203 request, old_priority_params, new_priority_params); | 1228 request, old_priority_params, new_priority_params); |
1204 } | 1229 } |
1205 | 1230 |
1206 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( | 1231 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( |
1207 int child_id, int route_id) { | 1232 int child_id, int route_id) { |
1208 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; | 1233 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
1209 } | 1234 } |
1210 | 1235 |
1211 } // namespace content | 1236 } // namespace content |
OLD | NEW |