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

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: Handle duplicate RenderViewReady messages Created 8 years 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 namespace content {
15
16 namespace {
17
18 ResourceScheduler::ClientId MakeClientId(int child_id, int route_id) {
19 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
20 }
21
22 } // unnamed namespace
23
24 class ResourceScheduler::ScheduledResourceRequest : public ResourceThrottle {
25 public:
26 ScheduledResourceRequest(const ClientId& client_id,
27 const net::URLRequest& request,
28 ResourceScheduler* scheduler)
29 : client_id_(client_id),
30 request_(request),
31 ready_(false),
32 deferred_(false),
33 scheduler_(scheduler) {
34 }
35
36 virtual ~ScheduledResourceRequest() {
37 scheduler_->RemoveRequest(this);
38 }
39
40 void Start() {
41 ready_ = true;
42 if (deferred_) {
43 controller()->Resume();
44 }
45 }
46
47 const ClientId& client_id() const { return client_id_; }
48 const net::URLRequest& url_request() const { return request_; }
49
50 private:
51 virtual void WillStartRequest(bool* defer) OVERRIDE {
52 deferred_ = *defer = !ready_;
53 }
54
55 ClientId client_id_;
56 const net::URLRequest& request_;
57 bool ready_;
58 bool deferred_;
59 ResourceScheduler* scheduler_;
60
61 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest);
62 };
63
64 ResourceScheduler::ResourceScheduler() {
65 DetachFromThread(); // Construction happens on the main thread.
66 }
67
68 ResourceScheduler::~ResourceScheduler() {
69 DetachFromThread(); // Destruction happens on the main thread.
70 }
71
72 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
73 int child_id,
74 int route_id,
75 const net::URLRequest& url_request) {
76 DCHECK(CalledOnValidThread());
77 ClientId client_id = MakeClientId(child_id, route_id);
78 scoped_ptr<ScheduledResourceRequest> request(
79 new ScheduledResourceRequest(client_id, url_request, this));
80
81 if (route_id == 0 || !ContainsKey(client_map_, client_id)) {
82 // <a ping> requests don't belong to a specific page. Most tests don't call
83 // OnCreate et. al. as needed to register Clients either.
84 unowned_requests_.insert(request.get());
85 request->Start();
86 return request.PassAs<ResourceThrottle>();
87 }
88
89 Client* client = client_map_[client_id];
90 DCHECK(!client->has_closed);
91
92 // Treat synchronous requests as high priority.
93 bool is_low_priority = url_request.priority() < net::MEDIUM &&
94 !(url_request.load_flags() & net::LOAD_IGNORE_LIMITS);
95
96 if (is_low_priority && !client->in_flight_requests.empty() &&
97 !client->has_painted) {
98 client->pending_requests.push_back(request.get());
99 } else {
100 StartRequest(request.get(), client);
101 }
102 return request.PassAs<ResourceThrottle>();
103 }
104
105 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) {
106 DCHECK(CalledOnValidThread());
107 if (ContainsKey(unowned_requests_, request)) {
108 unowned_requests_.erase(request);
109 return;
110 }
111
112 DCHECK(ContainsKey(client_map_, request->client_id()));
113 Client* client = client_map_[request->client_id()];
114 RequestSet::iterator it = client->in_flight_requests.find(request);
115 if (it == client->in_flight_requests.end()) {
116 bool removed = false;
117 RequestQueue::iterator queue_it;
118 for (queue_it = client->pending_requests.begin();
119 queue_it != client->pending_requests.end(); ++queue_it) {
120 if (*queue_it == request) {
121 client->pending_requests.erase(queue_it);
122 removed = true;
123 break;
124 }
125 }
126 DCHECK(removed);
127 DCHECK(!ContainsKey(client->in_flight_requests, request));
128 } else {
129 size_t erased = client->in_flight_requests.erase(request);
130 DCHECK(erased);
131 }
132
133 if (client->has_closed) {
134 if (client->in_flight_requests.empty()
135 && client->pending_requests.empty()) {
136 delete client;
137 client_map_.erase(request->client_id());
138 }
139 } else if (client->in_flight_requests.empty()) {
140 LoadPendingRequests(client);
141 }
142 }
143
144 void ResourceScheduler::OnCreate(int child_id, int route_id) {
145 DCHECK(CalledOnValidThread());
146 ClientId client_id = MakeClientId(child_id, route_id);
147 if (!ContainsKey(client_map_, client_id)) {
148 client_map_[client_id] = new Client;
149 }
150 }
151
152 void ResourceScheduler::OnNavigate(int child_id, int route_id) {
153 DCHECK(CalledOnValidThread());
154 ClientId client_id = MakeClientId(child_id, route_id);
155 if (!ContainsKey(client_map_, client_id)) {
156 return;
darin (slow to review) 2012/12/18 21:09:56 nit: What happens if a navigation occurs before On
157 }
158
159 Client* client = client_map_[client_id];
160 client->has_painted = false;
161 }
162
163 void ResourceScheduler::OnFirstPaint(int child_id, int route_id) {
164 DCHECK(CalledOnValidThread());
165 ClientId client_id = MakeClientId(child_id, route_id);
166 if (!ContainsKey(client_map_, client_id)) {
167 return;
darin (slow to review) 2012/12/18 21:09:56 ditto
168 }
169
170 Client* client = client_map_[client_id];
171 if (!client->has_painted) {
172 client->has_painted = true;
173 LoadPendingRequests(client);
174 }
175 }
176
177 void ResourceScheduler::OnDestroy(int child_id, int route_id) {
178 DCHECK(CalledOnValidThread());
179 ClientId client_id = MakeClientId(child_id, route_id);
180 if (!ContainsKey(client_map_, client_id)) {
181 return;
darin (slow to review) 2012/12/18 21:09:56 ditto
182 }
183
184 Client* client = client_map_[client_id];
185 if (client->pending_requests.empty() && client->in_flight_requests.empty()) {
186 delete client;
187 client_map_.erase(client_id);
188 } else {
189 client->has_closed = true;
190 }
191 }
192
193 void ResourceScheduler::StartRequest(ScheduledResourceRequest* request,
194 Client* client) {
195 client->in_flight_requests.insert(request);
196 request->Start();
197 }
198
199 void ResourceScheduler::LoadPendingRequests(Client* client) {
200 RequestQueue::iterator it;
201 for (it = client->pending_requests.begin();
202 it != client->pending_requests.end(); ++it) {
203 StartRequest(*it, client);
204 }
205 client->pending_requests.clear();
206 }
207
208 ResourceScheduler::Client::Client()
209 : has_painted(false),
210 has_closed(false) {
211 }
212
213 ResourceScheduler::Client::~Client() {
214 }
215
216 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698