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

Side by Side Diff: content/browser/loader/resource_scheduler.cc

Issue 11270027: Add a ResourceScheduler to ResourceDispatcherHost. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix Win build Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/browser/loader/resource_scheduler.h"
6
7 #include "base/stl_util.h"
8 #include "content/public/browser/resource_controller.h"
9 #include "content/public/browser/resource_throttle.h"
10 #include "net/base/load_flags.h"
11 #include "net/base/request_priority.h"
12 #include "net/url_request/url_request.h"
13
14 // TODO(simonjam): This is arbitrary. Experiment.
15 static const int MAX_NUM_NAVIGATIONS_TO_TRACK = 5;
darin (slow to review) 2013/01/14 22:03:30 nit: constants use kConstantStyle. not required f
James Simonsen 2013/01/15 01:10:06 Done.
16
17 namespace content {
18
19 class ResourceScheduler::ScheduledResourceRequest : public ResourceThrottle {
20 public:
21 ScheduledResourceRequest(const ClientId& client_id,
22 const net::URLRequest& request,
23 ResourceScheduler* scheduler)
24 : client_id_(client_id),
25 request_(request),
26 ready_(false),
27 deferred_(false),
28 scheduler_(scheduler) {
29 }
30
31 virtual ~ScheduledResourceRequest() {
32 scheduler_->RemoveRequest(this);
darin (slow to review) 2013/01/14 22:56:22 how do you know that the scheduler_ is still a val
James Simonsen 2013/01/15 01:10:06 |this| is owned by the same ResourceDispatcher tha
33 }
34
35 void Start() {
36 ready_ = true;
37 if (deferred_ &&
38 request_.status().status() != net::URLRequestStatus::CANCELED) {
39 controller()->Resume();
40 }
41 }
42
43 const ClientId& client_id() const { return client_id_; }
44 const net::URLRequest& url_request() const { return request_; }
45
46 private:
47 virtual void WillStartRequest(bool* defer) OVERRIDE {
48 deferred_ = *defer = !ready_;
49 }
50
51 ClientId client_id_;
52 const net::URLRequest& request_;
53 bool ready_;
54 bool deferred_;
55 ResourceScheduler* scheduler_;
56
57 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest);
58 };
59
60 ResourceScheduler::ResourceScheduler()
61 : client_map_(MAX_NUM_NAVIGATIONS_TO_TRACK) {
62 DetachFromThread(); // Construction happens on the main thread.
63 }
64
65 ResourceScheduler::~ResourceScheduler() {
66 DetachFromThread(); // Destruction happens on the main thread.
67 }
darin (slow to review) 2013/01/14 22:56:22 Hmm, should you assert that the pending_requests l
James Simonsen 2013/01/15 01:10:06 Yeah, sounds good. Done.
68
69 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
70 int child_id,
71 int route_id,
72 const net::URLRequest& url_request) {
73 DCHECK(CalledOnValidThread());
74 ClientId client_id = MakeClientId(child_id, route_id);
75 scoped_ptr<ScheduledResourceRequest> request(
76 new ScheduledResourceRequest(client_id, url_request, this));
77
78 ClientMap::iterator it = client_map_.Get(client_id);
79 if (it == client_map_.end()) {
80 // There are several ways this could happen:
81 // 1. <a ping> requests don't have a route_id.
darin (slow to review) 2013/01/14 22:56:22 It seems like a bug that <a ping> requests don't h
James Simonsen 2013/01/15 01:10:06 That wouldn't be the only bug with <a ping>. Will
82 // 2. Most unittests don't send the IPCs needed to register Clients.
83 // 3. The tab is closed while a RequestResource IPC is in flight.
84 // 4. The tab hasn't navigated recently.
85 unowned_requests_.insert(request.get());
86 request->Start();
87 return request.PassAs<ResourceThrottle>();
88 }
89
90 Client* client = it->second;
91
92 bool is_synchronous = (url_request.load_flags() & net::LOAD_IGNORE_LIMITS) ==
93 net::LOAD_IGNORE_LIMITS;
94 bool is_low_priority =
95 url_request.priority() < net::MEDIUM && !is_synchronous;
96
97 if (is_low_priority && !client->in_flight_requests.empty() &&
98 !client->has_painted) {
99 client->pending_requests.push_back(request.get());
100 } else {
101 StartRequest(request.get(), client);
102 }
103 return request.PassAs<ResourceThrottle>();
104 }
105
106 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) {
107 DCHECK(CalledOnValidThread());
108 if (ContainsKey(unowned_requests_, request)) {
109 unowned_requests_.erase(request);
110 return;
111 }
112
113 ClientMap::iterator client_it = client_map_.Get(request->client_id());
114 if (client_it == client_map_.end()) {
115 return;
116 }
117
118 Client* client = client_it->second;
119 RequestSet::iterator request_it = client->in_flight_requests.find(request);
120 if (request_it == client->in_flight_requests.end()) {
121 bool removed = false;
122 RequestQueue::iterator queue_it;
123 for (queue_it = client->pending_requests.begin();
124 queue_it != client->pending_requests.end(); ++queue_it) {
125 if (*queue_it == request) {
126 client->pending_requests.erase(queue_it);
127 removed = true;
128 break;
129 }
130 }
131 DCHECK(removed);
132 DCHECK(!ContainsKey(client->in_flight_requests, request));
133 } else {
134 size_t erased = client->in_flight_requests.erase(request);
135 DCHECK(erased);
136 }
137
138 LoadPendingRequests(client);
darin (slow to review) 2013/01/14 22:56:22 I'm not sure I understand why you are calling Load
James Simonsen 2013/01/15 01:10:06 Good catch! It's only supposed to do that when tha
139 }
140
141 void ResourceScheduler::OnNavigate(int child_id, int route_id) {
142 DCHECK(CalledOnValidThread());
143 ClientId client_id = MakeClientId(child_id, route_id);
144
145 ClientMap::iterator it = client_map_.Get(client_id);
146 if (it == client_map_.end()) {
147 it = client_map_.Put(client_id, new Client(this));
148 }
149
150 Client* client = it->second;
151 client->has_painted = false;
152 }
153
154 void ResourceScheduler::OnFirstPaint(int child_id, int route_id) {
155 DCHECK(CalledOnValidThread());
156 ClientId client_id = MakeClientId(child_id, route_id);
157 ClientMap::iterator it = client_map_.Get(client_id);
158 if (it == client_map_.end()) {
159 return;
160 }
161
162 Client* client = it->second;
163 if (!client->has_painted) {
164 client->has_painted = true;
165 LoadPendingRequests(client);
166 }
167 }
168
169 void ResourceScheduler::StartRequest(ScheduledResourceRequest* request,
170 Client* client) {
171 client->in_flight_requests.insert(request);
172 request->Start();
173 }
174
175 void ResourceScheduler::LoadPendingRequests(Client* client) {
176 RequestQueue::iterator it;
177 for (it = client->pending_requests.begin();
darin (slow to review) 2013/01/14 22:56:22 it seems like you are asserting that client->has_p
James Simonsen 2013/01/15 01:10:06 Yeah, there are a couple of ways we might decide t
178 it != client->pending_requests.end(); ++it) {
179 StartRequest(*it, client);
180 }
181 client->pending_requests.clear();
182 }
183
184 void ResourceScheduler::RemoveClient(Client* client) {
185 LoadPendingRequests(client);
186 for (RequestSet::iterator it = client->in_flight_requests.begin();
187 it != client->in_flight_requests.end(); ++it) {
188 unowned_requests_.insert(*it);
189 }
190 client->in_flight_requests.clear();
191 }
192
193 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
194 int child_id, int route_id) {
195 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
196 }
197
198 ResourceScheduler::Client::Client(ResourceScheduler* scheduler)
199 : has_painted(false),
200 scheduler_(scheduler) {
201 }
202
203 ResourceScheduler::Client::~Client() {
204 scheduler_->RemoveClient(this);
205 DCHECK(in_flight_requests.empty());
206 DCHECK(pending_requests.empty());
207 }
208
209 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698