summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhong.zheng@intel.com <hong.zheng@intel.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-25 08:55:49 +0000
committerhong.zheng@intel.com <hong.zheng@intel.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-25 08:55:49 +0000
commite56975691186fba63a20fa73dc0b8d245c86ca07 (patch)
treea1b09f36c76df9a71b672c7e6a72fae66fdc49af
parentf8881a71968e1b5f1af981a3196d43e25217c312 (diff)
downloadchromium_src-e56975691186fba63a20fa73dc0b8d245c86ca07.zip
chromium_src-e56975691186fba63a20fa73dc0b8d245c86ca07.tar.gz
chromium_src-e56975691186fba63a20fa73dc0b8d245c86ca07.tar.bz2
Cache total_delayable_count for in_flight_requests in ResourceScheduler
In ResourceScheduler::GetNumDelayableRequestsInFlight, total_delayable_count has no relation to active_request_host, so we do not need to compute it for each request. The patch can boost BrowsingBench workload >5% performance. BUG=347454 Review URL: https://codereview.chromium.org/180843016 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266165 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--AUTHORS1
-rw-r--r--content/browser/loader/resource_scheduler.cc485
-rw-r--r--content/browser/loader/resource_scheduler.h28
-rw-r--r--content/browser/loader/resource_scheduler_unittest.cc31
4 files changed, 317 insertions, 228 deletions
diff --git a/AUTHORS b/AUTHORS
index 8c0a049..af0ff00 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -124,6 +124,7 @@ Halton Huo <halton.huo@intel.com>
Haojian Wu <hokein.wu@gmail.com>
Hautio Kari <khautio@gmail.com>
Himanshu Joshi <h.joshi@samsung.com>
+Hong Zheng <hong.zheng@intel.com>
Hongbo Min <hongbo.min@intel.com>
Horia Olaru <horia.olaru@gmail.com>
Horia Olaru <olaru@adobe.com>
diff --git a/content/browser/loader/resource_scheduler.cc b/content/browser/loader/resource_scheduler.cc
index 4b4c832..e2a0fe2 100644
--- a/content/browser/loader/resource_scheduler.cc
+++ b/content/browser/loader/resource_scheduler.cc
@@ -126,7 +126,8 @@ class ResourceScheduler::ScheduledResourceRequest
deferred_(false),
scheduler_(scheduler),
priority_(priority),
- fifo_ordering_(0) {
+ fifo_ordering_(0),
+ accounted_as_delayable_request_(false) {
TRACE_EVENT_ASYNC_BEGIN1("net", "URLRequest", request_,
"url", request->url().spec());
}
@@ -157,6 +158,12 @@ class ResourceScheduler::ScheduledResourceRequest
void set_fifo_ordering(uint32 fifo_ordering) {
fifo_ordering_ = fifo_ordering;
}
+ bool accounted_as_delayable_request() const {
+ return accounted_as_delayable_request_;
+ }
+ void set_accounted_as_delayable_request(bool accounted) {
+ accounted_as_delayable_request_ = accounted;
+ }
private:
// ResourceMessageDelegate interface:
@@ -191,6 +198,8 @@ class ResourceScheduler::ScheduledResourceRequest
ResourceScheduler* scheduler_;
RequestPriorityParams priority_;
uint32 fifo_ordering_;
+ // True if the request is delayable in |in_flight_requests_|.
+ bool accounted_as_delayable_request_;
DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest);
};
@@ -219,14 +228,270 @@ void ResourceScheduler::RequestQueue::Insert(
}
// Each client represents a tab.
-struct ResourceScheduler::Client {
- Client() : has_body(false), using_spdy_proxy(false) {}
+class ResourceScheduler::Client {
+ public:
+ Client()
+ : has_body_(false),
+ using_spdy_proxy_(false),
+ total_delayable_count_(0) {}
~Client() {}
- bool has_body;
- bool using_spdy_proxy;
- RequestQueue pending_requests;
- RequestSet in_flight_requests;
+ void ScheduleRequest(
+ net::URLRequest* url_request,
+ ScheduledResourceRequest* request) {
+ if (ShouldStartRequest(request) == START_REQUEST) {
+ StartRequest(request);
+ } else {
+ pending_requests_.Insert(request);
+ }
+ }
+
+ void RemoveRequest(ScheduledResourceRequest* request) {
+ if (pending_requests_.IsQueued(request)) {
+ pending_requests_.Erase(request);
+ DCHECK(!ContainsKey(in_flight_requests_, request));
+ } else {
+ EraseInFlightRequest(request);
+
+ // Removing this request may have freed up another to load.
+ LoadAnyStartablePendingRequests();
+ }
+ }
+
+ RequestSet RemoveAllRequests() {
+ RequestSet unowned_requests;
+ for (RequestSet::iterator it = in_flight_requests_.begin();
+ it != in_flight_requests_.end(); ++it) {
+ unowned_requests.insert(*it);
+ (*it)->set_accounted_as_delayable_request(false);
+ }
+ ClearInFlightRequests();
+ return unowned_requests;
+ }
+
+ void OnNavigate() {
+ has_body_ = false;
+ }
+
+ void OnWillInsertBody() {
+ has_body_ = true;
+ LoadAnyStartablePendingRequests();
+ }
+
+ void OnReceivedSpdyProxiedHttpResponse() {
+ if (!using_spdy_proxy_) {
+ using_spdy_proxy_ = true;
+ LoadAnyStartablePendingRequests();
+ }
+ }
+
+ void ReprioritizeRequest(ScheduledResourceRequest* request,
+ RequestPriorityParams old_priority_params,
+ RequestPriorityParams new_priority_params) {
+ request->url_request()->SetPriority(new_priority_params.priority);
+ request->set_request_priority_params(new_priority_params);
+ if (!pending_requests_.IsQueued(request)) {
+ DCHECK(ContainsKey(in_flight_requests_, request));
+ // The priority and SPDY support may have changed, so update the
+ // delayable count.
+ SetRequestDelayable(request, IsDelayableRequest(request));
+ // Request has already started.
+ return;
+ }
+
+ pending_requests_.Erase(request);
+ pending_requests_.Insert(request);
+
+ if (new_priority_params.priority > old_priority_params.priority) {
+ // Check if this request is now able to load at its new priority.
+ LoadAnyStartablePendingRequests();
+ }
+ }
+
+ private:
+ enum ShouldStartReqResult {
+ DO_NOT_START_REQUEST_AND_STOP_SEARCHING = -2,
+ DO_NOT_START_REQUEST_AND_KEEP_SEARCHING = -1,
+ START_REQUEST = 1,
+ };
+
+ void InsertInFlightRequest(ScheduledResourceRequest* request) {
+ in_flight_requests_.insert(request);
+ if (IsDelayableRequest(request))
+ SetRequestDelayable(request, true);
+ }
+
+ void EraseInFlightRequest(ScheduledResourceRequest* request) {
+ size_t erased = in_flight_requests_.erase(request);
+ DCHECK_EQ(1u, erased);
+ SetRequestDelayable(request, false);
+ DCHECK_LE(total_delayable_count_, in_flight_requests_.size());
+ }
+
+ void ClearInFlightRequests() {
+ in_flight_requests_.clear();
+ total_delayable_count_ = 0;
+ }
+
+ bool IsDelayableRequest(ScheduledResourceRequest* request) {
+ if (request->url_request()->priority() < net::LOW) {
+ net::HostPortPair host_port_pair =
+ net::HostPortPair::FromURL(request->url_request()->url());
+ const net::HttpServerProperties& http_server_properties =
+ *request->url_request()->context()->http_server_properties();
+ if (!http_server_properties.SupportsSpdy(host_port_pair)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void SetRequestDelayable(ScheduledResourceRequest* request,
+ bool delayable) {
+ if (request->accounted_as_delayable_request() == delayable)
+ return;
+ if (delayable)
+ total_delayable_count_++;
+ else
+ total_delayable_count_--;
+ request->set_accounted_as_delayable_request(delayable);
+ }
+
+ bool ShouldKeepSearching(
+ const net::HostPortPair& active_request_host) const {
+ size_t same_host_count = 0;
+ for (RequestSet::const_iterator it = in_flight_requests_.begin();
+ it != in_flight_requests_.end(); ++it) {
+ net::HostPortPair host_port_pair =
+ net::HostPortPair::FromURL((*it)->url_request()->url());
+ if (active_request_host.Equals(host_port_pair)) {
+ same_host_count++;
+ if (same_host_count >= kMaxNumDelayableRequestsPerHost)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void StartRequest(ScheduledResourceRequest* request) {
+ InsertInFlightRequest(request);
+ request->Start();
+ }
+
+ // ShouldStartRequest is the main scheduling algorithm.
+ //
+ // Requests are categorized into two categories:
+ //
+ // 1. Immediately issued requests, which are:
+ //
+ // * Higher priority requests (>= net::LOW).
+ // * Synchronous requests.
+ // * Requests to SPDY-capable origin servers.
+ // * Non-HTTP[S] requests.
+ //
+ // 2. The remainder are delayable requests, which follow these rules:
+ //
+ // * If no high priority requests are in flight, start loading low priority
+ // requests.
+ // * Once the renderer has a <body>, start loading delayable requests.
+ // * Never exceed 10 delayable requests in flight per client.
+ // * Never exceed 6 delayable requests for a given host.
+ // * Prior to <body>, allow one delayable request to load at a time.
+ ShouldStartReqResult ShouldStartRequest(
+ ScheduledResourceRequest* request) const {
+ const net::URLRequest& url_request = *request->url_request();
+ // TODO(simonjam): This may end up causing disk contention. We should
+ // experiment with throttling if that happens.
+ if (!url_request.url().SchemeIsHTTPOrHTTPS()) {
+ return START_REQUEST;
+ }
+
+ if (using_spdy_proxy_ && url_request.url().SchemeIs("http")) {
+ return START_REQUEST;
+ }
+
+ const net::HttpServerProperties& http_server_properties =
+ *url_request.context()->http_server_properties();
+
+ if (url_request.priority() >= net::LOW ||
+ !ResourceRequestInfo::ForRequest(&url_request)->IsAsync()) {
+ return START_REQUEST;
+ }
+
+ net::HostPortPair host_port_pair =
+ net::HostPortPair::FromURL(url_request.url());
+
+ // TODO(willchan): We should really improve this algorithm as described in
+ // crbug.com/164101. Also, theoretically we should not count a SPDY request
+ // against the delayable requests limit.
+ if (http_server_properties.SupportsSpdy(host_port_pair)) {
+ return START_REQUEST;
+ }
+
+ size_t num_delayable_requests_in_flight = total_delayable_count_;
+ if (num_delayable_requests_in_flight >= kMaxNumDelayableRequestsPerClient) {
+ return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
+ }
+
+ if (ShouldKeepSearching(host_port_pair)) {
+ // There may be other requests for other hosts we'd allow,
+ // so keep checking.
+ return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
+ }
+
+ bool have_immediate_requests_in_flight =
+ in_flight_requests_.size() > num_delayable_requests_in_flight;
+ if (have_immediate_requests_in_flight && !has_body_ &&
+ num_delayable_requests_in_flight != 0) {
+ return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
+ }
+
+ return START_REQUEST;
+ }
+
+ void LoadAnyStartablePendingRequests() {
+ // We iterate through all the pending requests, starting with the highest
+ // priority one. For each entry, one of three things can happen:
+ // 1) We start the request, remove it from the list, and keep checking.
+ // 2) We do NOT start the request, but ShouldStartRequest() signals us that
+ // there may be room for other requests, so we keep checking and leave
+ // the previous request still in the list.
+ // 3) We do not start the request, same as above, but StartRequest() tells
+ // us there's no point in checking any further requests.
+ RequestQueue::NetQueue::iterator request_iter =
+ pending_requests_.GetNextHighestIterator();
+
+ while (request_iter != pending_requests_.End()) {
+ ScheduledResourceRequest* request = *request_iter;
+ ShouldStartReqResult query_result = ShouldStartRequest(request);
+
+ if (query_result == START_REQUEST) {
+ pending_requests_.Erase(request);
+ StartRequest(request);
+
+ // StartRequest can modify the pending list, so we (re)start evaluation
+ // from the currently highest priority request. Avoid copying a singular
+ // iterator, which would trigger undefined behavior.
+ if (pending_requests_.GetNextHighestIterator() ==
+ pending_requests_.End())
+ break;
+ request_iter = pending_requests_.GetNextHighestIterator();
+ } else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) {
+ ++request_iter;
+ continue;
+ } else {
+ DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING);
+ break;
+ }
+ }
+ }
+
+ bool has_body_;
+ bool using_spdy_proxy_;
+ RequestQueue pending_requests_;
+ RequestSet in_flight_requests_;
+ // The number of delayable in-flight requests.
+ size_t total_delayable_count_;
};
ResourceScheduler::ResourceScheduler() {
@@ -259,11 +524,7 @@ scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
}
Client* client = it->second;
- if (ShouldStartRequest(request.get(), client) == START_REQUEST) {
- StartRequest(request.get(), client);
- } else {
- client->pending_requests.Insert(request.get());
- }
+ client->ScheduleRequest(url_request, request.get());
return request.PassAs<ResourceThrottle>();
}
@@ -280,17 +541,7 @@ void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) {
}
Client* client = client_it->second;
-
- if (client->pending_requests.IsQueued(request)) {
- client->pending_requests.Erase(request);
- DCHECK(!ContainsKey(client->in_flight_requests, request));
- } else {
- size_t erased = client->in_flight_requests.erase(request);
- DCHECK(erased);
-
- // Removing this request may have freed up another to load.
- LoadAnyStartablePendingRequests(client);
- }
+ client->RemoveRequest(request);
}
void ResourceScheduler::OnClientCreated(int child_id, int route_id) {
@@ -314,11 +565,11 @@ void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
// FYI, ResourceDispatcherHost cancels all of the requests after this function
// is called. It should end up canceling all of the requests except for a
// cross-renderer navigation.
- for (RequestSet::iterator it = client->in_flight_requests.begin();
- it != client->in_flight_requests.end(); ++it) {
+ RequestSet client_unowned_requests = client->RemoveAllRequests();
+ for (RequestSet::iterator it = client_unowned_requests.begin();
+ it != client_unowned_requests.end(); ++it) {
unowned_requests_.insert(*it);
}
- client->in_flight_requests.clear();
delete client;
client_map_.erase(it);
@@ -335,7 +586,7 @@ void ResourceScheduler::OnNavigate(int child_id, int route_id) {
}
Client* client = it->second;
- client->has_body = false;
+ client->OnNavigate();
}
void ResourceScheduler::OnWillInsertBody(int child_id, int route_id) {
@@ -349,8 +600,7 @@ void ResourceScheduler::OnWillInsertBody(int child_id, int route_id) {
}
Client* client = it->second;
- client->has_body = true;
- LoadAnyStartablePendingRequests(client);
+ client->OnWillInsertBody();
}
void ResourceScheduler::OnReceivedSpdyProxiedHttpResponse(
@@ -365,17 +615,7 @@ void ResourceScheduler::OnReceivedSpdyProxiedHttpResponse(
}
Client* client = client_it->second;
-
- if (!client->using_spdy_proxy) {
- client->using_spdy_proxy = true;
- LoadAnyStartablePendingRequests(client);
- }
-}
-
-void ResourceScheduler::StartRequest(ScheduledResourceRequest* request,
- Client* client) {
- client->in_flight_requests.insert(request);
- request->Start();
+ client->OnReceivedSpdyProxiedHttpResponse();
}
void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request,
@@ -387,7 +627,6 @@ void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request,
NOTREACHED();
return;
}
-
RequestPriorityParams new_priority_params(new_priority,
new_intra_priority_value);
RequestPriorityParams old_priority_params =
@@ -395,11 +634,11 @@ void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request,
DCHECK(old_priority_params != new_priority_params);
- request->url_request()->SetPriority(new_priority_params.priority);
- request->set_request_priority_params(new_priority_params);
ClientMap::iterator client_it = client_map_.find(request->client_id());
if (client_it == client_map_.end()) {
// The client was likely deleted shortly before we received this IPC.
+ request->url_request()->SetPriority(new_priority_params.priority);
+ request->set_request_priority_params(new_priority_params);
return;
}
@@ -407,164 +646,8 @@ void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request,
return;
Client *client = client_it->second;
- if (!client->pending_requests.IsQueued(request)) {
- DCHECK(ContainsKey(client->in_flight_requests, request));
- // Request has already started.
- return;
- }
-
- client->pending_requests.Erase(request);
- client->pending_requests.Insert(request);
-
- if (new_priority_params.priority > old_priority_params.priority) {
- // Check if this request is now able to load at its new priority.
- LoadAnyStartablePendingRequests(client);
- }
-}
-
-void ResourceScheduler::LoadAnyStartablePendingRequests(Client* client) {
- // We iterate through all the pending requests, starting with the highest
- // priority one. For each entry, one of three things can happen:
- // 1) We start the request, remove it from the list, and keep checking.
- // 2) We do NOT start the request, but ShouldStartRequest() signals us that
- // there may be room for other requests, so we keep checking and leave
- // the previous request still in the list.
- // 3) We do not start the request, same as above, but StartRequest() tells
- // us there's no point in checking any further requests.
- RequestQueue::NetQueue::iterator request_iter =
- client->pending_requests.GetNextHighestIterator();
- while (request_iter != client->pending_requests.End()) {
- ScheduledResourceRequest* request = *request_iter;
- ShouldStartReqResult query_result = ShouldStartRequest(request, client);
-
- if (query_result == START_REQUEST) {
- client->pending_requests.Erase(request);
- StartRequest(request, client);
-
- // StartRequest can modify the pending list, so we (re)start evaluation
- // from the currently highest priority request. Avoid copying a singular
- // iterator, which would trigger undefined behavior.
- if (client->pending_requests.GetNextHighestIterator() ==
- client->pending_requests.End())
- break;
- request_iter = client->pending_requests.GetNextHighestIterator();
- } else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) {
- ++request_iter;
- continue;
- } else {
- DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING);
- break;
- }
- }
-}
-
-void ResourceScheduler::GetNumDelayableRequestsInFlight(
- Client* client,
- const net::HostPortPair& active_request_host,
- size_t* total_delayable,
- size_t* total_for_active_host) const {
- DCHECK(client != NULL && total_delayable != NULL &&
- total_for_active_host != NULL);
-
- size_t total_delayable_count = 0;
- size_t same_host_count = 0;
- for (RequestSet::iterator it = client->in_flight_requests.begin();
- it != client->in_flight_requests.end(); ++it) {
- net::HostPortPair host_port_pair =
- net::HostPortPair::FromURL((*it)->url_request()->url());
-
- if (active_request_host.Equals(host_port_pair)) {
- same_host_count++;
- }
-
- if ((*it)->url_request()->priority() < net::LOW) {
- const net::HttpServerProperties& http_server_properties =
- *(*it)->url_request()->context()->http_server_properties();
-
- if (!http_server_properties.SupportsSpdy(host_port_pair)) {
- ++total_delayable_count;
- }
- }
- }
- *total_delayable = total_delayable_count;
- *total_for_active_host = same_host_count;
-}
-
-// ShouldStartRequest is the main scheduling algorithm.
-//
-// Requests are categorized into two categories:
-//
-// 1. Immediately issued requests, which are:
-//
-// * Higher priority requests (>= net::LOW).
-// * Synchronous requests.
-// * Requests to SPDY-capable origin servers.
-// * Non-HTTP[S] requests.
-//
-// 2. The remainder are delayable requests, which follow these rules:
-//
-// * If no high priority requests are in flight, start loading low priority
-// requests.
-// * Once the renderer has a <body>, start loading delayable requests.
-// * Never exceed 10 delayable requests in flight per client.
-// * Never exceed 6 delayable requests for a given host.
-// * Prior to <body>, allow one delayable request to load at a time.
-ResourceScheduler::ShouldStartReqResult ResourceScheduler::ShouldStartRequest(
- ScheduledResourceRequest* request,
- Client* client) const {
- const net::URLRequest& url_request = *request->url_request();
-
- // TODO(simonjam): This may end up causing disk contention. We should
- // experiment with throttling if that happens.
- if (!url_request.url().SchemeIsHTTPOrHTTPS()) {
- return START_REQUEST;
- }
-
- if (client->using_spdy_proxy && url_request.url().SchemeIs("http")) {
- return START_REQUEST;
- }
-
- const net::HttpServerProperties& http_server_properties =
- *url_request.context()->http_server_properties();
-
- if (url_request.priority() >= net::LOW ||
- !ResourceRequestInfo::ForRequest(&url_request)->IsAsync()) {
- return START_REQUEST;
- }
-
- net::HostPortPair host_port_pair =
- net::HostPortPair::FromURL(url_request.url());
-
- // TODO(willchan): We should really improve this algorithm as described in
- // crbug.com/164101. Also, theoretically we should not count a SPDY request
- // against the delayable requests limit.
- if (http_server_properties.SupportsSpdy(host_port_pair)) {
- return START_REQUEST;
- }
-
- size_t num_delayable_requests_in_flight = 0;
- size_t num_requests_in_flight_for_host = 0;
- GetNumDelayableRequestsInFlight(client, host_port_pair,
- &num_delayable_requests_in_flight,
- &num_requests_in_flight_for_host);
-
- if (num_delayable_requests_in_flight >= kMaxNumDelayableRequestsPerClient) {
- return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
- }
-
- if (num_requests_in_flight_for_host >= kMaxNumDelayableRequestsPerHost) {
- // There may be other requests for other hosts we'd allow, so keep checking.
- return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
- }
-
- bool have_immediate_requests_in_flight =
- client->in_flight_requests.size() > num_delayable_requests_in_flight;
- if (have_immediate_requests_in_flight && !client->has_body &&
- num_delayable_requests_in_flight != 0) {
- return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
- }
-
- return START_REQUEST;
+ client->ReprioritizeRequest(
+ request, old_priority_params, new_priority_params);
}
ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
diff --git a/content/browser/loader/resource_scheduler.h b/content/browser/loader/resource_scheduler.h
index cd8f054..0e918f1 100644
--- a/content/browser/loader/resource_scheduler.h
+++ b/content/browser/loader/resource_scheduler.h
@@ -92,7 +92,7 @@ class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
bool operator()(const ScheduledResourceRequest* a,
const ScheduledResourceRequest* b) const;
};
- struct Client;
+ class Client;
typedef int64 ClientId;
typedef std::map<ClientId, Client*> ClientMap;
@@ -101,9 +101,6 @@ class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
// Called when a ScheduledResourceRequest is destroyed.
void RemoveRequest(ScheduledResourceRequest* request);
- // Unthrottles the |request| and adds it to |client|.
- void StartRequest(ScheduledResourceRequest* request, Client* client);
-
// Update the queue position for |request|, possibly causing it to start
// loading.
//
@@ -114,29 +111,6 @@ class CONTENT_EXPORT ResourceScheduler : public base::NonThreadSafe {
net::RequestPriority new_priority,
int intra_priority_value);
- // Attempts to load any pending requests in |client|, based on the
- // results of ShouldStartRequest().
- void LoadAnyStartablePendingRequests(Client* client);
-
- // Returns the number of requests with priority < LOW that are currently in
- // flight.
- void GetNumDelayableRequestsInFlight(
- Client* client,
- const net::HostPortPair& active_request_host,
- size_t* total_delayable,
- size_t* total_for_active_host) const;
-
- enum ShouldStartReqResult {
- DO_NOT_START_REQUEST_AND_STOP_SEARCHING = -2,
- DO_NOT_START_REQUEST_AND_KEEP_SEARCHING = -1,
- START_REQUEST = 1,
- };
-
- // Returns true if the request should start. This is the core scheduling
- // algorithm.
- ShouldStartReqResult ShouldStartRequest(ScheduledResourceRequest* request,
- Client* client) const;
-
// Returns the client ID for the given |child_id| and |route_id| combo.
ClientId MakeClientId(int child_id, int route_id);
diff --git a/content/browser/loader/resource_scheduler_unittest.cc b/content/browser/loader/resource_scheduler_unittest.cc
index e677f8f..7fba2a5 100644
--- a/content/browser/loader/resource_scheduler_unittest.cc
+++ b/content/browser/loader/resource_scheduler_unittest.cc
@@ -502,6 +502,37 @@ TEST_F(ResourceSchedulerTest, SpdyProxySchedulesImmediately) {
EXPECT_TRUE(after->started());
}
+TEST_F(ResourceSchedulerTest, NewSpdyHostInDelayableRequests) {
+ scheduler_.OnWillInsertBody(kChildId, kRouteId);
+ const int kMaxNumDelayableRequestsPerClient = 10; // Should match the .cc.
+
+ scoped_ptr<TestRequest> low1_spdy(
+ NewRequest("http://spdyhost1:8080/low", net::LOWEST));
+ // Cancel a request after we learn the server supports SPDY.
+ ScopedVector<TestRequest> lows;
+ for (int i = 0; i < kMaxNumDelayableRequestsPerClient - 1; ++i) {
+ string url = "http://host" + base::IntToString(i) + "/low";
+ lows.push_back(NewRequest(url.c_str(), net::LOWEST));
+ }
+ scoped_ptr<TestRequest> low1(NewRequest("http://host/low", net::LOWEST));
+ EXPECT_FALSE(low1->started());
+ http_server_properties_.SetSupportsSpdy(
+ net::HostPortPair("spdyhost1", 8080), true);
+ low1_spdy.reset();
+ EXPECT_TRUE(low1->started());
+
+ low1.reset();
+ scoped_ptr<TestRequest> low2_spdy(
+ NewRequest("http://spdyhost2:8080/low", net::IDLE));
+ // Reprioritize a request after we learn the server supports SPDY.
+ EXPECT_TRUE(low2_spdy->started());
+ http_server_properties_.SetSupportsSpdy(
+ net::HostPortPair("spdyhost2", 8080), true);
+ ChangeRequestPriority(low2_spdy.get(), net::LOWEST);
+ scoped_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ EXPECT_TRUE(low2->started());
+}
+
} // unnamed namespace
} // namespace content