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

Side by Side Diff: net/socket/client_socket_pool_base.cc

Issue 151118: Refactor ConnectJob and TCPConnectJob. (Closed)
Patch Set: Add comments. Created 11 years, 5 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
« no previous file with comments | « net/socket/client_socket_pool_base.h ('k') | net/socket/client_socket_pool_base_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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 "net/socket/client_socket_pool_base.h" 5 #include "net/socket/client_socket_pool_base.h"
6 6
7 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "base/stl_util-inl.h" 9 #include "base/stl_util-inl.h"
10 #include "base/time.h" 10 #include "base/time.h"
(...skipping 12 matching lines...) Expand all
23 // some conditions. See http://crbug.com/4606. 23 // some conditions. See http://crbug.com/4606.
24 const int kCleanupInterval = 10; // DO NOT INCREASE THIS TIMEOUT. 24 const int kCleanupInterval = 10; // DO NOT INCREASE THIS TIMEOUT.
25 25
26 // The maximum duration, in seconds, to keep idle persistent sockets alive. 26 // The maximum duration, in seconds, to keep idle persistent sockets alive.
27 const int kIdleTimeout = 300; // 5 minutes. 27 const int kIdleTimeout = 300; // 5 minutes.
28 28
29 } // namespace 29 } // namespace
30 30
31 namespace net { 31 namespace net {
32 32
33 ConnectJob::ConnectJob(const std::string& group_name,
34 const ClientSocketHandle* key_handle,
35 Delegate* delegate)
36 : group_name_(group_name),
37 key_handle_(key_handle),
38 delegate_(delegate),
39 load_state_(LOAD_STATE_IDLE) {
40 DCHECK(!group_name.empty());
41 DCHECK(key_handle);
42 DCHECK(delegate);
43 }
44
45 ConnectJob::~ConnectJob() {}
46
33 ClientSocketPoolBase::ClientSocketPoolBase( 47 ClientSocketPoolBase::ClientSocketPoolBase(
34 int max_sockets_per_group, 48 int max_sockets_per_group,
35 ConnectJobFactory* connect_job_factory) 49 ConnectJobFactory* connect_job_factory)
36 : idle_socket_count_(0), 50 : idle_socket_count_(0),
37 max_sockets_per_group_(max_sockets_per_group), 51 max_sockets_per_group_(max_sockets_per_group),
38 connect_job_factory_(connect_job_factory) {} 52 connect_job_factory_(connect_job_factory) {}
39 53
40 ClientSocketPoolBase::~ClientSocketPoolBase() { 54 ClientSocketPoolBase::~ClientSocketPoolBase() {
41 // Clean up any idle sockets. Assert that we have no remaining active 55 // Clean up any idle sockets. Assert that we have no remaining active
42 // sockets or pending requests. They should have all been cleaned up prior 56 // sockets or pending requests. They should have all been cleaned up prior
(...skipping 20 matching lines...) Expand all
63 const std::string& group_name, 77 const std::string& group_name,
64 const HostResolver::RequestInfo& resolve_info, 78 const HostResolver::RequestInfo& resolve_info,
65 int priority, 79 int priority,
66 ClientSocketHandle* handle, 80 ClientSocketHandle* handle,
67 CompletionCallback* callback) { 81 CompletionCallback* callback) {
68 DCHECK(!resolve_info.hostname().empty()); 82 DCHECK(!resolve_info.hostname().empty());
69 DCHECK_GE(priority, 0); 83 DCHECK_GE(priority, 0);
70 DCHECK(callback); 84 DCHECK(callback);
71 Group& group = group_map_[group_name]; 85 Group& group = group_map_[group_name];
72 86
73 CheckSocketCounts(group);
74
75 // Can we make another active socket now? 87 // Can we make another active socket now?
76 if (group.active_socket_count == max_sockets_per_group_) { 88 if (!group.HasAvailableSocketSlot(max_sockets_per_group_)) {
77 CHECK(callback); 89 CHECK(callback);
78 Request r(handle, callback, priority, resolve_info); 90 Request r(handle, callback, priority, resolve_info);
79 InsertRequestIntoQueue(r, &group.pending_requests); 91 InsertRequestIntoQueue(r, &group.pending_requests);
80 return ERR_IO_PENDING; 92 return ERR_IO_PENDING;
81 } 93 }
82 94
83 // OK, we are going to activate one.
84 group.active_socket_count++;
85
86 while (!group.idle_sockets.empty()) { 95 while (!group.idle_sockets.empty()) {
87 IdleSocket idle_socket = group.idle_sockets.back(); 96 IdleSocket idle_socket = group.idle_sockets.back();
88 group.idle_sockets.pop_back(); 97 group.idle_sockets.pop_back();
89 DecrementIdleCount(); 98 DecrementIdleCount();
90 if (idle_socket.socket->IsConnectedAndIdle()) { 99 if (idle_socket.socket->IsConnectedAndIdle()) {
91 // We found one we can reuse! 100 // We found one we can reuse!
92 handle->set_socket(idle_socket.socket); 101 HandOutSocket(idle_socket.socket, true /* reuse */, handle, &group);
93 handle->set_is_reused(true);
94 group.sockets_handed_out_count++;
95 CheckSocketCounts(group);
96 return OK; 102 return OK;
97 } 103 }
98 delete idle_socket.socket; 104 delete idle_socket.socket;
99 } 105 }
100 106
101 // We couldn't find a socket to reuse, so allocate and connect a new one. 107 // We couldn't find a socket to reuse, so allocate and connect a new one.
102 108
103 CHECK(callback); 109 CHECK(callback);
104 Request r(handle, callback, priority, resolve_info); 110 Request r(handle, callback, priority, resolve_info);
105 group.connecting_requests[handle] = r; 111 scoped_ptr<ConnectJob> connect_job(
112 connect_job_factory_->NewConnectJob(group_name, r, this));
106 113
107 CHECK(!ContainsKey(connect_job_map_, handle)); 114 int rv = connect_job->Connect();
115 if (rv == OK) {
116 HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
117 handle, &group);
118 } else if (rv == ERR_IO_PENDING) {
119 group.connecting_requests[handle] = r;
120 CHECK(!ContainsKey(connect_job_map_, handle));
121 connect_job_map_[handle] = connect_job.release();
122 } else {
123 if (group.IsEmpty())
124 group_map_.erase(group_name);
125 }
108 126
109 ConnectJob* connect_job = 127 return rv;
110 connect_job_factory_->NewConnectJob(group_name, r, this);
111 connect_job_map_[handle] = connect_job;
112 return connect_job->Connect();
113 } 128 }
114 129
115 void ClientSocketPoolBase::CancelRequest(const std::string& group_name, 130 void ClientSocketPoolBase::CancelRequest(const std::string& group_name,
116 const ClientSocketHandle* handle) { 131 const ClientSocketHandle* handle) {
117 CHECK(ContainsKey(group_map_, group_name)); 132 CHECK(ContainsKey(group_map_, group_name));
118 133
119 Group& group = group_map_[group_name]; 134 Group& group = group_map_[group_name];
120 135
121 CheckSocketCounts(group);
122
123 // Search pending_requests for matching handle. 136 // Search pending_requests for matching handle.
124 RequestQueue::iterator it = group.pending_requests.begin(); 137 RequestQueue::iterator it = group.pending_requests.begin();
125 for (; it != group.pending_requests.end(); ++it) { 138 for (; it != group.pending_requests.end(); ++it) {
126 if (it->handle == handle) { 139 if (it->handle == handle) {
127 group.pending_requests.erase(it); 140 group.pending_requests.erase(it);
128 return; 141 return;
129 } 142 }
130 } 143 }
131 144
132 // It's invalid to cancel a non-existent request. 145 // It's invalid to cancel a non-existent request.
133 CHECK(ContainsKey(group.connecting_requests, handle)); 146 CHECK(ContainsKey(group.connecting_requests, handle));
134 147
135 RequestMap::iterator map_it = group.connecting_requests.find(handle); 148 RequestMap::iterator map_it = group.connecting_requests.find(handle);
136 if (map_it != group.connecting_requests.end()) { 149 if (map_it != group.connecting_requests.end()) {
137 RemoveConnectJob(handle); 150 RemoveConnectJob(handle);
138 group.connecting_requests.erase(map_it); 151 group.connecting_requests.erase(map_it);
139 RemoveActiveSocket(group_name, &group); 152 OnAvailableSocketSlot(group_name, &group);
140 } 153 }
141 } 154 }
142 155
143 void ClientSocketPoolBase::ReleaseSocket(const std::string& group_name, 156 void ClientSocketPoolBase::ReleaseSocket(const std::string& group_name,
144 ClientSocket* socket) { 157 ClientSocket* socket) {
145 // Run this asynchronously to allow the caller to finish before we let 158 // Run this asynchronously to allow the caller to finish before we let
146 // another to begin doing work. This also avoids nasty recursion issues. 159 // another to begin doing work. This also avoids nasty recursion issues.
147 // NOTE: We cannot refer to the handle argument after this method returns. 160 // NOTE: We cannot refer to the handle argument after this method returns.
148 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 161 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
149 this, &ClientSocketPoolBase::DoReleaseSocket, group_name, socket)); 162 this, &ClientSocketPoolBase::DoReleaseSocket, group_name, socket));
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 if (force || j->ShouldCleanup(now)) { 235 if (force || j->ShouldCleanup(now)) {
223 delete j->socket; 236 delete j->socket;
224 j = group.idle_sockets.erase(j); 237 j = group.idle_sockets.erase(j);
225 DecrementIdleCount(); 238 DecrementIdleCount();
226 } else { 239 } else {
227 ++j; 240 ++j;
228 } 241 }
229 } 242 }
230 243
231 // Delete group if no longer needed. 244 // Delete group if no longer needed.
232 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { 245 if (group.IsEmpty()) {
233 CHECK(group.pending_requests.empty()); 246 CHECK(group.pending_requests.empty());
234 CHECK(group.connecting_requests.empty());
235 group_map_.erase(i++); 247 group_map_.erase(i++);
236 } else { 248 } else {
237 ++i; 249 ++i;
238 } 250 }
239 } 251 }
240 } 252 }
241 253
242 void ClientSocketPoolBase::IncrementIdleCount() { 254 void ClientSocketPoolBase::IncrementIdleCount() {
243 if (++idle_socket_count_ == 1) 255 if (++idle_socket_count_ == 1)
244 timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this, 256 timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this,
245 &ClientSocketPoolBase::OnCleanupTimerFired); 257 &ClientSocketPoolBase::OnCleanupTimerFired);
246 } 258 }
247 259
248 void ClientSocketPoolBase::DecrementIdleCount() { 260 void ClientSocketPoolBase::DecrementIdleCount() {
249 if (--idle_socket_count_ == 0) 261 if (--idle_socket_count_ == 0)
250 timer_.Stop(); 262 timer_.Stop();
251 } 263 }
252 264
253 void ClientSocketPoolBase::DoReleaseSocket(const std::string& group_name, 265 void ClientSocketPoolBase::DoReleaseSocket(const std::string& group_name,
254 ClientSocket* socket) { 266 ClientSocket* socket) {
255 GroupMap::iterator i = group_map_.find(group_name); 267 GroupMap::iterator i = group_map_.find(group_name);
256 CHECK(i != group_map_.end()); 268 CHECK(i != group_map_.end());
257 269
258 Group& group = i->second; 270 Group& group = i->second;
259 271
260 CHECK(group.active_socket_count > 0); 272 CHECK(group.active_socket_count > 0);
261 CheckSocketCounts(group); 273 group.active_socket_count--;
262
263 group.sockets_handed_out_count--;
264 274
265 const bool can_reuse = socket->IsConnectedAndIdle(); 275 const bool can_reuse = socket->IsConnectedAndIdle();
266 if (can_reuse) { 276 if (can_reuse) {
267 IdleSocket idle_socket; 277 IdleSocket idle_socket;
268 idle_socket.socket = socket; 278 idle_socket.socket = socket;
269 idle_socket.start_time = base::TimeTicks::Now(); 279 idle_socket.start_time = base::TimeTicks::Now();
270 280
271 group.idle_sockets.push_back(idle_socket); 281 group.idle_sockets.push_back(idle_socket);
272 IncrementIdleCount(); 282 IncrementIdleCount();
273 } else { 283 } else {
274 delete socket; 284 delete socket;
275 } 285 }
276 286
277 RemoveActiveSocket(group_name, &group); 287 OnAvailableSocketSlot(group_name, &group);
278 } 288 }
279 289
280 void ClientSocketPoolBase::OnConnectJobComplete( 290 void ClientSocketPoolBase::OnConnectJobComplete(int result, ConnectJob* job) {
281 const std::string& group_name, 291 DCHECK_NE(ERR_IO_PENDING, result);
282 const ClientSocketHandle* key_handle, 292 const std::string group_name = job->group_name();
283 ClientSocket* socket,
284 int result,
285 bool was_async) {
286 GroupMap::iterator group_it = group_map_.find(group_name); 293 GroupMap::iterator group_it = group_map_.find(group_name);
287 CHECK(group_it != group_map_.end()); 294 CHECK(group_it != group_map_.end());
288 Group& group = group_it->second; 295 Group& group = group_it->second;
289 296
290 CheckSocketCounts(group);
291
292 RequestMap* request_map = &group.connecting_requests; 297 RequestMap* request_map = &group.connecting_requests;
293 298
294 RequestMap::iterator it = request_map->find(key_handle); 299 RequestMap::iterator it = request_map->find(job->key_handle());
295 CHECK(it != request_map->end()); 300 CHECK(it != request_map->end());
296 Request request = it->second; 301 ClientSocketHandle* const handle = it->second.handle;
302 CompletionCallback* const callback = it->second.callback;
297 request_map->erase(it); 303 request_map->erase(it);
298 DCHECK_EQ(request.handle, key_handle); 304 DCHECK_EQ(handle, job->key_handle());
299 305
300 if (!socket) { 306 ClientSocket* const socket = job->ReleaseSocket();
301 RemoveActiveSocket(group_name, &group); 307 RemoveConnectJob(job->key_handle());
308
309 if (result != OK) {
310 callback->Run(result); // |group| is not necessarily valid after this.
311 // |group| may be invalid after the callback, we need to search
312 // |group_map_| again.
313 MaybeOnAvailableSocketSlot(group_name);
302 } else { 314 } else {
303 request.handle->set_socket(socket); 315 HandOutSocket(socket, false /* not reused */, handle, &group);
304 request.handle->set_is_reused(false); 316 callback->Run(result);
305 group.sockets_handed_out_count++;
306
307 CheckSocketCounts(group);
308 } 317 }
309
310 RemoveConnectJob(request.handle);
311
312 if (was_async)
313 request.callback->Run(result);
314 }
315
316 // static
317 void ClientSocketPoolBase::CheckSocketCounts(const Group& group) {
318 CHECK(group.active_socket_count ==
319 group.sockets_handed_out_count +
320 static_cast<int>(group.connecting_requests.size()))
321 << "[active_socket_count: " << group.active_socket_count
322 << " ] [sockets_handed_out_count: " << group.sockets_handed_out_count
323 << " ] [connecting_requests size: " << group.connecting_requests.size();
324 } 318 }
325 319
326 void ClientSocketPoolBase::RemoveConnectJob( 320 void ClientSocketPoolBase::RemoveConnectJob(
327 const ClientSocketHandle* handle) { 321 const ClientSocketHandle* handle) {
328 ConnectJobMap::iterator it = connect_job_map_.find(handle); 322 ConnectJobMap::iterator it = connect_job_map_.find(handle);
329 CHECK(it != connect_job_map_.end()); 323 CHECK(it != connect_job_map_.end());
330 delete it->second; 324 delete it->second;
331 connect_job_map_.erase(it); 325 connect_job_map_.erase(it);
332 } 326 }
333 327
334 void ClientSocketPoolBase::RemoveActiveSocket(const std::string& group_name, 328 void ClientSocketPoolBase::MaybeOnAvailableSocketSlot(
335 Group* group) { 329 const std::string& group_name) {
336 group->active_socket_count--; 330 GroupMap::iterator it = group_map_.find(group_name);
331 if (it != group_map_.end()) {
332 Group& group = it->second;
333 if (group.HasAvailableSocketSlot(max_sockets_per_group_))
334 OnAvailableSocketSlot(group_name, &group);
335 }
336 }
337 337
338 void ClientSocketPoolBase::OnAvailableSocketSlot(const std::string& group_name,
339 Group* group) {
338 if (!group->pending_requests.empty()) { 340 if (!group->pending_requests.empty()) {
339 ProcessPendingRequest(group_name, group); 341 ProcessPendingRequest(group_name, group);
340 // |group| may no longer be valid after this point. Be careful not to 342 // |group| may no longer be valid after this point. Be careful not to
341 // access it again. 343 // access it again.
342 } else if (group->active_socket_count == 0 && group->idle_sockets.empty()) { 344 } else if (group->IsEmpty()) {
343 // Delete |group| if no longer needed. |group| will no longer be valid. 345 // Delete |group| if no longer needed. |group| will no longer be valid.
344 DCHECK(group->connecting_requests.empty());
345 group_map_.erase(group_name); 346 group_map_.erase(group_name);
346 } else {
347 CheckSocketCounts(*group);
348 } 347 }
349 } 348 }
350 349
351 void ClientSocketPoolBase::ProcessPendingRequest(const std::string& group_name, 350 void ClientSocketPoolBase::ProcessPendingRequest(const std::string& group_name,
352 Group* group) { 351 Group* group) {
353 Request r = group->pending_requests.front(); 352 Request r = group->pending_requests.front();
354 group->pending_requests.pop_front(); 353 group->pending_requests.pop_front();
355 354
356 int rv = RequestSocket( 355 int rv = RequestSocket(
357 group_name, r.resolve_info, r.priority, r.handle, r.callback); 356 group_name, r.resolve_info, r.priority, r.handle, r.callback);
358 357
359 // |group| may be invalid after RequestSocket. 358 if (rv != ERR_IO_PENDING) {
359 r.callback->Run(rv);
360 if (rv != OK) {
361 // |group| may be invalid after the callback, we need to search
362 // |group_map_| again.
363 MaybeOnAvailableSocketSlot(group_name);
364 }
365 }
366 }
360 367
361 if (rv != ERR_IO_PENDING) 368 void ClientSocketPoolBase::HandOutSocket(
362 r.callback->Run(rv); 369 ClientSocket* socket,
370 bool reused,
371 ClientSocketHandle* handle,
372 Group* group) {
373 DCHECK(socket);
374 handle->set_socket(socket);
375 handle->set_is_reused(reused);
376 group->active_socket_count++;
363 } 377 }
364 378
365 } // namespace net 379 } // namespace net
OLDNEW
« no previous file with comments | « net/socket/client_socket_pool_base.h ('k') | net/socket/client_socket_pool_base_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698