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

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

Issue 12600018: ResourceScheduler should use renderer notifications instead of MRUCache to track renderers. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Reverse destruction order Created 7 years, 9 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
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"
11 #include "content/public/browser/resource_throttle.h" 11 #include "content/public/browser/resource_throttle.h"
12 #include "ipc/ipc_message_macros.h" 12 #include "ipc/ipc_message_macros.h"
13 #include "net/base/load_flags.h" 13 #include "net/base/load_flags.h"
14 #include "net/base/request_priority.h" 14 #include "net/base/request_priority.h"
15 #include "net/url_request/url_request.h" 15 #include "net/url_request/url_request.h"
16 16
17 namespace content { 17 namespace content {
18 18
19 // TODO(simonjam): This is arbitrary. Experiment.
20 static const int kMaxNumNavigationsToTrack = 5;
21
22 class ResourceScheduler::ScheduledResourceRequest 19 class ResourceScheduler::ScheduledResourceRequest
23 : public ResourceMessageDelegate, 20 : public ResourceMessageDelegate,
24 public ResourceThrottle { 21 public ResourceThrottle {
25 public: 22 public:
26 ScheduledResourceRequest(const ClientId& client_id, 23 ScheduledResourceRequest(const ClientId& client_id,
27 net::URLRequest* request, 24 net::URLRequest* request,
28 ResourceScheduler* scheduler) 25 ResourceScheduler* scheduler)
29 : ResourceMessageDelegate(request), 26 : ResourceMessageDelegate(request),
30 client_id_(client_id), 27 client_id_(client_id),
31 request_(request), 28 request_(request),
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 73
77 ClientId client_id_; 74 ClientId client_id_;
78 net::URLRequest* request_; 75 net::URLRequest* request_;
79 bool ready_; 76 bool ready_;
80 bool deferred_; 77 bool deferred_;
81 ResourceScheduler* scheduler_; 78 ResourceScheduler* scheduler_;
82 79
83 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); 80 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest);
84 }; 81 };
85 82
86 ResourceScheduler::ResourceScheduler() 83 ResourceScheduler::ResourceScheduler() {
87 : client_map_(kMaxNumNavigationsToTrack) {
88 } 84 }
89 85
90 ResourceScheduler::~ResourceScheduler() { 86 ResourceScheduler::~ResourceScheduler() {
91 for (ClientMap::iterator it ALLOW_UNUSED = client_map_.begin(); 87 for (ClientMap::iterator it ALLOW_UNUSED = client_map_.begin();
92 it != client_map_.end(); ++it) { 88 it != client_map_.end(); ++it) {
93 DCHECK(it->second->pending_requests.empty()); 89 DCHECK(it->second->pending_requests.empty());
94 DCHECK(it->second->in_flight_requests.empty()); 90 DCHECK(it->second->in_flight_requests.empty());
95 } 91 }
96 DCHECK(unowned_requests_.empty()); 92 DCHECK(unowned_requests_.empty());
93 DCHECK(client_map_.empty());
97 } 94 }
98 95
99 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest( 96 scoped_ptr<ResourceThrottle> ResourceScheduler::ScheduleRequest(
100 int child_id, 97 int child_id,
101 int route_id, 98 int route_id,
102 net::URLRequest* url_request) { 99 net::URLRequest* url_request) {
103 DCHECK(CalledOnValidThread()); 100 DCHECK(CalledOnValidThread());
104 ClientId client_id = MakeClientId(child_id, route_id); 101 ClientId client_id = MakeClientId(child_id, route_id);
105 scoped_ptr<ScheduledResourceRequest> request( 102 scoped_ptr<ScheduledResourceRequest> request(
106 new ScheduledResourceRequest(client_id, url_request, this)); 103 new ScheduledResourceRequest(client_id, url_request, this));
107 104
108 ClientMap::iterator it = client_map_.Get(client_id); 105 ClientMap::iterator it = client_map_.find(client_id);
109 if (it == client_map_.end()) { 106 if (it == client_map_.end()) {
110 // There are several ways this could happen: 107 // There are several ways this could happen:
111 // 1. <a ping> requests don't have a route_id. 108 // 1. <a ping> requests don't have a route_id.
112 // 2. Most unittests don't send the IPCs needed to register Clients. 109 // 2. Most unittests don't send the IPCs needed to register Clients.
113 // 3. The tab is closed while a RequestResource IPC is in flight. 110 // 3. The tab is closed while a RequestResource IPC is in flight.
114 // 4. The tab hasn't navigated recently.
115 unowned_requests_.insert(request.get()); 111 unowned_requests_.insert(request.get());
116 request->Start(); 112 request->Start();
117 return request.PassAs<ResourceThrottle>(); 113 return request.PassAs<ResourceThrottle>();
118 } 114 }
119 115
120 Client* client = it->second; 116 Client* client = it->second;
121 117
122 bool is_synchronous = (url_request->load_flags() & net::LOAD_IGNORE_LIMITS) == 118 bool is_synchronous = (url_request->load_flags() & net::LOAD_IGNORE_LIMITS) ==
123 net::LOAD_IGNORE_LIMITS; 119 net::LOAD_IGNORE_LIMITS;
124 bool is_low_priority = 120 bool is_low_priority =
125 url_request->priority() < net::LOW && !is_synchronous; 121 url_request->priority() < net::LOW && !is_synchronous;
126 122
127 if (is_low_priority && !client->in_flight_requests.empty() && 123 if (is_low_priority && !client->in_flight_requests.empty() &&
128 !client->has_body) { 124 !client->has_body) {
129 client->pending_requests.push_back(request.get()); 125 client->pending_requests.push_back(request.get());
130 } else { 126 } else {
131 StartRequest(request.get(), client); 127 StartRequest(request.get(), client);
132 } 128 }
133 return request.PassAs<ResourceThrottle>(); 129 return request.PassAs<ResourceThrottle>();
134 } 130 }
135 131
136 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) { 132 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) {
137 DCHECK(CalledOnValidThread()); 133 DCHECK(CalledOnValidThread());
138 if (ContainsKey(unowned_requests_, request)) { 134 if (ContainsKey(unowned_requests_, request)) {
139 unowned_requests_.erase(request); 135 unowned_requests_.erase(request);
140 return; 136 return;
141 } 137 }
142 138
143 ClientMap::iterator client_it = client_map_.Get(request->client_id()); 139 ClientMap::iterator client_it = client_map_.find(request->client_id());
144 if (client_it == client_map_.end()) { 140 if (client_it == client_map_.end()) {
145 return; 141 return;
146 } 142 }
147 143
148 Client* client = client_it->second; 144 Client* client = client_it->second;
149 RequestSet::iterator request_it = client->in_flight_requests.find(request); 145 RequestSet::iterator request_it = client->in_flight_requests.find(request);
150 if (request_it == client->in_flight_requests.end()) { 146 if (request_it == client->in_flight_requests.end()) {
151 bool removed = false; 147 bool removed = false;
152 RequestQueue::iterator queue_it; 148 RequestQueue::iterator queue_it;
153 for (queue_it = client->pending_requests.begin(); 149 for (queue_it = client->pending_requests.begin();
(...skipping 11 matching lines...) Expand all
165 DCHECK(erased); 161 DCHECK(erased);
166 } 162 }
167 163
168 if (client->in_flight_requests.empty()) { 164 if (client->in_flight_requests.empty()) {
169 // Since the network is now idle, we may as well load some of the low 165 // Since the network is now idle, we may as well load some of the low
170 // priority requests. 166 // priority requests.
171 LoadPendingRequests(client); 167 LoadPendingRequests(client);
172 } 168 }
173 } 169 }
174 170
171 void ResourceScheduler::OnClientCreated(int child_id, int route_id) {
172 DCHECK(CalledOnValidThread());
173 ClientId client_id = MakeClientId(child_id, route_id);
174 DCHECK(!ContainsKey(client_map_, client_id));
175
176 client_map_[client_id] = new Client;
177 }
178
179 void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
180 DCHECK(CalledOnValidThread());
181 ClientId client_id = MakeClientId(child_id, route_id);
182 DCHECK(ContainsKey(client_map_, client_id));
183 ClientMap::iterator it = client_map_.find(client_id);
184 Client* client = it->second;
185
186 // FYI, ResourceDispatcherHost cancels all of the requests after this function
187 // is called. It should end up canceling all of the requests except for a
188 // cross-renderer navigation.
189 for (RequestSet::iterator it = client->in_flight_requests.begin();
190 it != client->in_flight_requests.end(); ++it) {
191 unowned_requests_.insert(*it);
192 }
193 client->in_flight_requests.clear();
194
195 delete client;
196 client_map_.erase(it);
197 }
198
175 void ResourceScheduler::OnNavigate(int child_id, int route_id) { 199 void ResourceScheduler::OnNavigate(int child_id, int route_id) {
176 DCHECK(CalledOnValidThread()); 200 DCHECK(CalledOnValidThread());
177 ClientId client_id = MakeClientId(child_id, route_id); 201 ClientId client_id = MakeClientId(child_id, route_id);
178 202
179 ClientMap::iterator it = client_map_.Get(client_id); 203 ClientMap::iterator it = client_map_.find(client_id);
180 if (it == client_map_.end()) { 204 if (it == client_map_.end()) {
181 it = client_map_.Put(client_id, new Client(this)); 205 // The client was likely deleted shortly before we received this IPC.
206 return;
182 } 207 }
183 208
184 Client* client = it->second; 209 Client* client = it->second;
185 client->has_body = false; 210 client->has_body = false;
186 } 211 }
187 212
188 void ResourceScheduler::OnWillInsertBody(int child_id, int route_id) { 213 void ResourceScheduler::OnWillInsertBody(int child_id, int route_id) {
189 DCHECK(CalledOnValidThread()); 214 DCHECK(CalledOnValidThread());
190 ClientId client_id = MakeClientId(child_id, route_id); 215 ClientId client_id = MakeClientId(child_id, route_id);
191 ClientMap::iterator it = client_map_.Get(client_id); 216
217 ClientMap::iterator it = client_map_.find(client_id);
192 if (it == client_map_.end()) { 218 if (it == client_map_.end()) {
219 // The client was likely deleted shortly before we received this IPC.
193 return; 220 return;
194 } 221 }
195 222
196 Client* client = it->second; 223 Client* client = it->second;
224 client->has_body = false;
197 if (!client->has_body) { 225 if (!client->has_body) {
198 client->has_body = true; 226 client->has_body = true;
199 LoadPendingRequests(client); 227 LoadPendingRequests(client);
200 } 228 }
201 } 229 }
202 230
203 void ResourceScheduler::StartRequest(ScheduledResourceRequest* request, 231 void ResourceScheduler::StartRequest(ScheduledResourceRequest* request,
204 Client* client) { 232 Client* client) {
205 client->in_flight_requests.insert(request); 233 client->in_flight_requests.insert(request);
206 request->Start(); 234 request->Start();
207 } 235 }
208 236
209 void ResourceScheduler::LoadPendingRequests(Client* client) { 237 void ResourceScheduler::LoadPendingRequests(Client* client) {
210 while (!client->pending_requests.empty()) { 238 while (!client->pending_requests.empty()) {
211 ScheduledResourceRequest* request = client->pending_requests.front(); 239 ScheduledResourceRequest* request = client->pending_requests.front();
212 client->pending_requests.erase(client->pending_requests.begin()); 240 client->pending_requests.erase(client->pending_requests.begin());
213 StartRequest(request, client); 241 StartRequest(request, client);
214 } 242 }
215 } 243 }
216 244
217 void ResourceScheduler::RemoveClient(Client* client) {
218 LoadPendingRequests(client);
219 for (RequestSet::iterator it = client->in_flight_requests.begin();
220 it != client->in_flight_requests.end(); ++it) {
221 unowned_requests_.insert(*it);
222 }
223 client->in_flight_requests.clear();
224 }
225
226 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 245 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
227 int child_id, int route_id) { 246 int child_id, int route_id) {
228 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 247 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
229 } 248 }
230 249
231 ResourceScheduler::Client::Client(ResourceScheduler* scheduler) 250 ResourceScheduler::Client::Client()
232 : has_body(false), 251 : has_body(false) {
233 scheduler_(scheduler) {
234 } 252 }
235 253
236 ResourceScheduler::Client::~Client() { 254 ResourceScheduler::Client::~Client() {
237 scheduler_->RemoveClient(this);
238 DCHECK(in_flight_requests.empty());
239 DCHECK(pending_requests.empty());
240 } 255 }
241 256
242 } // namespace content 257 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/loader/resource_scheduler.h ('k') | content/browser/loader/resource_scheduler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698