Chromium Code Reviews| 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 "content/browser/loader/resource_scheduler.h" | 5 #include "content/browser/loader/resource_scheduler.h" |
| 6 | 6 |
| 7 #include "base/stl_util.h" | 7 #include "base/stl_util.h" |
| 8 #include "content/common/resource_messages.h" | 8 #include "content/common/resource_messages.h" |
| 9 #include "content/browser/loader/resource_message_delegate.h" | 9 #include "content/browser/loader/resource_message_delegate.h" |
| 10 #include "content/public/browser/resource_controller.h" | 10 #include "content/public/browser/resource_controller.h" |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 170 ClientId client_id_; | 170 ClientId client_id_; |
| 171 net::URLRequest* request_; | 171 net::URLRequest* request_; |
| 172 bool ready_; | 172 bool ready_; |
| 173 bool deferred_; | 173 bool deferred_; |
| 174 ResourceScheduler* scheduler_; | 174 ResourceScheduler* scheduler_; |
| 175 | 175 |
| 176 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); | 176 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); |
| 177 }; | 177 }; |
| 178 | 178 |
| 179 // Each client represents a tab. | 179 // Each client represents a tab. |
| 180 struct ResourceScheduler::Client { | 180 struct ResourceScheduler::Client { |
|
James Simonsen
2014/03/05 02:30:59
This isn't a struct anymore. To keep these methods
| |
| 181 Client() : has_body(false), using_spdy_proxy(false) {} | 181 Client() |
| 182 : has_body(false), | |
| 183 using_spdy_proxy(false), | |
| 184 total_delayable_count(0) {} | |
| 182 ~Client() {} | 185 ~Client() {} |
| 183 | 186 |
| 184 bool has_body; | 187 bool has_body; |
| 185 bool using_spdy_proxy; | 188 bool using_spdy_proxy; |
| 186 RequestQueue pending_requests; | 189 RequestQueue pending_requests; |
| 187 RequestSet in_flight_requests; | 190 RequestSet in_flight_requests; |
| 191 size_t total_delayable_count; | |
| 192 | |
| 193 bool IsDelayableRequest(ScheduledResourceRequest* request) { | |
| 194 if (request->url_request()->priority() < net::LOW) { | |
| 195 net::HostPortPair host_port_pair = | |
| 196 net::HostPortPair::FromURL(request->url_request()->url()); | |
| 197 const net::HttpServerProperties& http_server_properties = | |
| 198 *request->url_request()->context()->http_server_properties(); | |
| 199 if (!http_server_properties.SupportsSpdy(host_port_pair)) { | |
| 200 return true; | |
| 201 } | |
| 202 } | |
| 203 return false; | |
| 204 } | |
| 205 | |
| 206 void InsertFlightRequests(ScheduledResourceRequest* request) { | |
|
James Simonsen
2014/03/05 02:30:59
This should be InsertInFlightRequest().
| |
| 207 in_flight_requests.insert(request); | |
| 208 if (IsDelayableRequest(request)) | |
| 209 total_delayable_count++; | |
| 210 } | |
| 211 | |
| 212 size_t EraseFlightRequests(ScheduledResourceRequest* request) { | |
|
James Simonsen
2014/03/05 02:30:59
And EraseInFlightRequest().
| |
| 213 size_t erased = in_flight_requests.erase(request); | |
| 214 if (in_flight_requests.size() == 0) { | |
| 215 total_delayable_count = 0; | |
| 216 } else if (IsDelayableRequest(request)) { | |
| 217 total_delayable_count--; | |
| 218 } | |
| 219 return erased; | |
| 220 } | |
| 221 | |
| 222 void ClearFlightRequests() { | |
|
James Simonsen
2014/03/05 02:30:59
ClearInFlightRequests()
| |
| 223 in_flight_requests.clear(); | |
| 224 total_delayable_count = 0; | |
| 225 } | |
| 188 }; | 226 }; |
| 189 | 227 |
| 190 ResourceScheduler::ResourceScheduler() { | 228 ResourceScheduler::ResourceScheduler() { |
| 191 } | 229 } |
| 192 | 230 |
| 193 ResourceScheduler::~ResourceScheduler() { | 231 ResourceScheduler::~ResourceScheduler() { |
| 194 DCHECK(unowned_requests_.empty()); | 232 DCHECK(unowned_requests_.empty()); |
| 195 DCHECK(client_map_.empty()); | 233 DCHECK(client_map_.empty()); |
| 196 } | 234 } |
| 197 | 235 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 235 if (client_it == client_map_.end()) { | 273 if (client_it == client_map_.end()) { |
| 236 return; | 274 return; |
| 237 } | 275 } |
| 238 | 276 |
| 239 Client* client = client_it->second; | 277 Client* client = client_it->second; |
| 240 | 278 |
| 241 if (client->pending_requests.IsQueued(request)) { | 279 if (client->pending_requests.IsQueued(request)) { |
| 242 client->pending_requests.Erase(request); | 280 client->pending_requests.Erase(request); |
| 243 DCHECK(!ContainsKey(client->in_flight_requests, request)); | 281 DCHECK(!ContainsKey(client->in_flight_requests, request)); |
| 244 } else { | 282 } else { |
| 245 size_t erased = client->in_flight_requests.erase(request); | 283 size_t erased = client->EraseFlightRequests(request); |
| 246 DCHECK(erased); | 284 DCHECK(erased); |
| 247 | 285 |
| 248 // Removing this request may have freed up another to load. | 286 // Removing this request may have freed up another to load. |
| 249 LoadAnyStartablePendingRequests(client); | 287 LoadAnyStartablePendingRequests(client); |
| 250 } | 288 } |
| 251 } | 289 } |
| 252 | 290 |
| 253 void ResourceScheduler::OnClientCreated(int child_id, int route_id) { | 291 void ResourceScheduler::OnClientCreated(int child_id, int route_id) { |
| 254 DCHECK(CalledOnValidThread()); | 292 DCHECK(CalledOnValidThread()); |
| 255 ClientId client_id = MakeClientId(child_id, route_id); | 293 ClientId client_id = MakeClientId(child_id, route_id); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 268 | 306 |
| 269 Client* client = it->second; | 307 Client* client = it->second; |
| 270 | 308 |
| 271 // FYI, ResourceDispatcherHost cancels all of the requests after this function | 309 // FYI, ResourceDispatcherHost cancels all of the requests after this function |
| 272 // is called. It should end up canceling all of the requests except for a | 310 // is called. It should end up canceling all of the requests except for a |
| 273 // cross-renderer navigation. | 311 // cross-renderer navigation. |
| 274 for (RequestSet::iterator it = client->in_flight_requests.begin(); | 312 for (RequestSet::iterator it = client->in_flight_requests.begin(); |
| 275 it != client->in_flight_requests.end(); ++it) { | 313 it != client->in_flight_requests.end(); ++it) { |
| 276 unowned_requests_.insert(*it); | 314 unowned_requests_.insert(*it); |
| 277 } | 315 } |
| 278 client->in_flight_requests.clear(); | 316 client->ClearFlightRequests(); |
| 279 | 317 |
| 280 delete client; | 318 delete client; |
| 281 client_map_.erase(it); | 319 client_map_.erase(it); |
| 282 } | 320 } |
| 283 | 321 |
| 284 void ResourceScheduler::OnNavigate(int child_id, int route_id) { | 322 void ResourceScheduler::OnNavigate(int child_id, int route_id) { |
| 285 DCHECK(CalledOnValidThread()); | 323 DCHECK(CalledOnValidThread()); |
| 286 ClientId client_id = MakeClientId(child_id, route_id); | 324 ClientId client_id = MakeClientId(child_id, route_id); |
| 287 | 325 |
| 288 ClientMap::iterator it = client_map_.find(client_id); | 326 ClientMap::iterator it = client_map_.find(client_id); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 324 Client* client = client_it->second; | 362 Client* client = client_it->second; |
| 325 | 363 |
| 326 if (!client->using_spdy_proxy) { | 364 if (!client->using_spdy_proxy) { |
| 327 client->using_spdy_proxy = true; | 365 client->using_spdy_proxy = true; |
| 328 LoadAnyStartablePendingRequests(client); | 366 LoadAnyStartablePendingRequests(client); |
| 329 } | 367 } |
| 330 } | 368 } |
| 331 | 369 |
| 332 void ResourceScheduler::StartRequest(ScheduledResourceRequest* request, | 370 void ResourceScheduler::StartRequest(ScheduledResourceRequest* request, |
| 333 Client* client) { | 371 Client* client) { |
| 334 client->in_flight_requests.insert(request); | 372 client->InsertFlightRequests(request); |
| 335 request->Start(); | 373 request->Start(); |
| 336 } | 374 } |
| 337 | 375 |
| 338 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, | 376 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, |
| 339 net::RequestPriority new_priority) { | 377 net::RequestPriority new_priority) { |
| 340 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { | 378 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { |
| 341 // We should not be re-prioritizing requests with the | 379 // We should not be re-prioritizing requests with the |
| 342 // IGNORE_LIMITS flag. | 380 // IGNORE_LIMITS flag. |
| 343 NOTREACHED(); | 381 NOTREACHED(); |
| 344 return; | 382 return; |
| 345 } | 383 } |
| 346 net::RequestPriority old_priority = request->url_request()->priority(); | 384 net::RequestPriority old_priority = request->url_request()->priority(); |
| 347 DCHECK_NE(new_priority, old_priority); | 385 DCHECK_NE(new_priority, old_priority); |
| 348 request->url_request()->SetPriority(new_priority); | 386 request->url_request()->SetPriority(new_priority); |
| 349 ClientMap::iterator client_it = client_map_.find(request->client_id()); | 387 ClientMap::iterator client_it = client_map_.find(request->client_id()); |
| 350 if (client_it == client_map_.end()) { | 388 if (client_it == client_map_.end()) { |
| 351 // The client was likely deleted shortly before we received this IPC. | 389 // The client was likely deleted shortly before we received this IPC. |
| 352 return; | 390 return; |
| 353 } | 391 } |
| 354 | 392 |
| 355 Client *client = client_it->second; | 393 Client *client = client_it->second; |
| 356 if (!client->pending_requests.IsQueued(request)) { | 394 if (!client->pending_requests.IsQueued(request)) { |
| 357 DCHECK(ContainsKey(client->in_flight_requests, request)); | 395 DCHECK(ContainsKey(client->in_flight_requests, request)); |
| 396 if (new_priority >= net::LOW) { | |
| 397 if (client->IsDelayableRequest(request)) | |
| 398 client->total_delayable_count--; | |
|
James Simonsen
2014/03/05 02:30:59
Please add a unit test that shows the old code was
James Simonsen
2014/03/05 02:30:59
I don't like that total_delayable_count is sometim
| |
| 399 } | |
| 358 // Request has already started. | 400 // Request has already started. |
| 359 return; | 401 return; |
| 360 } | 402 } |
| 361 | 403 |
| 362 client->pending_requests.Erase(request); | 404 client->pending_requests.Erase(request); |
| 363 client->pending_requests.Insert(request, | 405 client->pending_requests.Insert(request, |
| 364 request->url_request()->priority()); | 406 request->url_request()->priority()); |
| 365 | 407 |
| 366 if (new_priority > old_priority) { | 408 if (new_priority > old_priority) { |
| 367 // Check if this request is now able to load at its new priority. | 409 // Check if this request is now able to load at its new priority. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 399 } else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) { | 441 } else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) { |
| 400 ++request_iter; | 442 ++request_iter; |
| 401 continue; | 443 continue; |
| 402 } else { | 444 } else { |
| 403 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING); | 445 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING); |
| 404 break; | 446 break; |
| 405 } | 447 } |
| 406 } | 448 } |
| 407 } | 449 } |
| 408 | 450 |
| 409 void ResourceScheduler::GetNumDelayableRequestsInFlight( | 451 size_t ResourceScheduler::GetNumSameHostRequestsInFlight( |
| 410 Client* client, | 452 Client* client, |
| 411 const net::HostPortPair& active_request_host, | 453 const net::HostPortPair& active_request_host) const { |
| 412 size_t* total_delayable, | 454 DCHECK(client != NULL); |
| 413 size_t* total_for_active_host) const { | |
| 414 DCHECK(client != NULL && total_delayable != NULL && | |
| 415 total_for_active_host != NULL); | |
| 416 | 455 |
| 417 size_t total_delayable_count = 0; | |
| 418 size_t same_host_count = 0; | 456 size_t same_host_count = 0; |
| 419 for (RequestSet::iterator it = client->in_flight_requests.begin(); | 457 for (RequestSet::iterator it = client->in_flight_requests.begin(); |
| 420 it != client->in_flight_requests.end(); ++it) { | 458 it != client->in_flight_requests.end(); ++it) { |
| 421 net::HostPortPair host_port_pair = | 459 net::HostPortPair host_port_pair = |
| 422 net::HostPortPair::FromURL((*it)->url_request()->url()); | 460 net::HostPortPair::FromURL((*it)->url_request()->url()); |
| 423 | 461 |
| 424 if (active_request_host.Equals(host_port_pair)) { | 462 if (active_request_host.Equals(host_port_pair)) { |
| 425 same_host_count++; | 463 same_host_count++; |
| 426 } | 464 } |
| 427 | |
| 428 if ((*it)->url_request()->priority() < net::LOW) { | |
| 429 const net::HttpServerProperties& http_server_properties = | |
| 430 *(*it)->url_request()->context()->http_server_properties(); | |
| 431 | |
| 432 if (!http_server_properties.SupportsSpdy(host_port_pair)) { | |
| 433 ++total_delayable_count; | |
| 434 } | |
| 435 } | |
| 436 } | 465 } |
| 437 *total_delayable = total_delayable_count; | 466 return same_host_count; |
| 438 *total_for_active_host = same_host_count; | |
| 439 } | 467 } |
| 440 | 468 |
| 441 // ShouldStartRequest is the main scheduling algorithm. | 469 // ShouldStartRequest is the main scheduling algorithm. |
| 442 // | 470 // |
| 443 // Requests are categorized into two categories: | 471 // Requests are categorized into two categories: |
| 444 // | 472 // |
| 445 // 1. Immediately issued requests, which are: | 473 // 1. Immediately issued requests, which are: |
| 446 // | 474 // |
| 447 // * Higher priority requests (>= net::LOW). | 475 // * Higher priority requests (>= net::LOW). |
| 448 // * Synchronous requests. | 476 // * Synchronous requests. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 483 net::HostPortPair host_port_pair = | 511 net::HostPortPair host_port_pair = |
| 484 net::HostPortPair::FromURL(url_request.url()); | 512 net::HostPortPair::FromURL(url_request.url()); |
| 485 | 513 |
| 486 // TODO(willchan): We should really improve this algorithm as described in | 514 // TODO(willchan): We should really improve this algorithm as described in |
| 487 // crbug.com/164101. Also, theoretically we should not count a SPDY request | 515 // crbug.com/164101. Also, theoretically we should not count a SPDY request |
| 488 // against the delayable requests limit. | 516 // against the delayable requests limit. |
| 489 if (http_server_properties.SupportsSpdy(host_port_pair)) { | 517 if (http_server_properties.SupportsSpdy(host_port_pair)) { |
| 490 return START_REQUEST; | 518 return START_REQUEST; |
| 491 } | 519 } |
| 492 | 520 |
| 493 size_t num_delayable_requests_in_flight = 0; | 521 size_t num_delayable_requests_in_flight = client->total_delayable_count; |
| 494 size_t num_requests_in_flight_for_host = 0; | 522 size_t num_requests_in_flight_for_host = |
| 495 GetNumDelayableRequestsInFlight(client, host_port_pair, | 523 GetNumSameHostRequestsInFlight(client, host_port_pair); |
| 496 &num_delayable_requests_in_flight, | |
| 497 &num_requests_in_flight_for_host); | |
| 498 | 524 |
| 499 if (num_delayable_requests_in_flight >= kMaxNumDelayableRequestsPerClient) { | 525 if (num_delayable_requests_in_flight >= kMaxNumDelayableRequestsPerClient) { |
| 500 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; | 526 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; |
| 501 } | 527 } |
| 502 | 528 |
| 503 if (num_requests_in_flight_for_host >= kMaxNumDelayableRequestsPerHost) { | 529 if (num_requests_in_flight_for_host >= kMaxNumDelayableRequestsPerHost) { |
| 504 // There may be other requests for other hosts we'd allow, so keep checking. | 530 // There may be other requests for other hosts we'd allow, so keep checking. |
| 505 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; | 531 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; |
| 506 } | 532 } |
| 507 | 533 |
| 508 bool have_immediate_requests_in_flight = | 534 bool have_immediate_requests_in_flight = |
| 509 client->in_flight_requests.size() > num_delayable_requests_in_flight; | 535 client->in_flight_requests.size() > num_delayable_requests_in_flight; |
| 510 if (have_immediate_requests_in_flight && !client->has_body && | 536 if (have_immediate_requests_in_flight && !client->has_body && |
| 511 num_delayable_requests_in_flight != 0) { | 537 num_delayable_requests_in_flight != 0) { |
| 512 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; | 538 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; |
| 513 } | 539 } |
| 514 | 540 |
| 515 return START_REQUEST; | 541 return START_REQUEST; |
| 516 } | 542 } |
| 517 | 543 |
| 518 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( | 544 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( |
| 519 int child_id, int route_id) { | 545 int child_id, int route_id) { |
| 520 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; | 546 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
| 521 } | 547 } |
| 522 | 548 |
| 523 } // namespace content | 549 } // namespace content |
| OLD | NEW |