00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <ngx_config.h>
00024 #include <ngx_core.h>
00025 #include <ngx_http.h>
00026 #include <nginx.h>
00027 #include <ngx_log.h>
00028
00029 #include "ngx_connection_pool.h"
00030
00031 #if (NGX_THREADS)
00032 #error "This module is not thread safe"
00033 #endif
00034
00035 ngx_atomic_t connecton_pool_pcounter = 1;
00036 ngx_atomic_t *ngx_connecton_pool_pcounter = &connecton_pool_pcounter;
00037
00038
00039 ngx_connection_pool_t*
00040 ngx_connection_pool_create(ngx_log_t *_log, struct sockaddr_in *_sockaddr,
00041 ngx_uint_t _sockaddr_size, ngx_uint_t _stored_connections_limit)
00042 {
00043 ngx_connection_pool_t *connection_pool;
00044 ngx_pool_t *pool;
00045 char _name[256];
00046
00047 pool = ngx_create_pool(1024, _log);
00048 connection_pool = ngx_pcalloc(pool, sizeof(ngx_connection_pool_t));
00049
00050
00051 connection_pool->pool = pool;
00052 connection_pool->log = _log;
00053 connection_pool->sockaddr = _sockaddr;
00054 connection_pool->sockaddr_size = _sockaddr_size;
00055 connection_pool->stored_connections_limit = _stored_connections_limit;
00056 connection_pool->stored_connections = 0;
00057 connection_pool->returned_connections = 0;
00058
00059 connection_pool->first_connection = 0;
00060 connection_pool->last_connection = 0;
00061
00062
00063
00064 ngx_snprintf( (u_char*)_name, sizeof(_name)/sizeof(_name[0]),
00065 "connection_from_pool_%d",
00066 ngx_atomic_fetch_add(ngx_connecton_pool_pcounter, 1));
00067 connection_pool->name.len = strlen(_name);
00068 connection_pool->name.data = ngx_pcalloc(pool, connection_pool->name.len);
00069 ngx_memcpy(connection_pool->name.data, _name, connection_pool->name.len);
00070
00071
00072 return connection_pool;
00073 }
00074
00075 static void
00076 ngx_connection_pool_strip_broken(ngx_connection_pool_t *pool)
00077 {
00078 ngx_err_t err;
00079 ngx_int_t rc;
00080 ngx_pooled_connection_t *current;
00081 #define testbufflen 5
00082 u_char testbuff[testbufflen];
00083
00084 while (pool->first_connection != 0) {
00085 current = pool->first_connection;
00086 rc = read(current->fd, testbuff, testbufflen);
00087 err = ngx_errno;
00088 ngx_log_debug2(NGX_LOG_DEBUG, pool->log, errno,
00089 "[ngx_connection_pool_strip_broken] FD = %d, RET = %d",
00090 current->fd, rc);
00091
00092 if (rc == -1 || rc == 0) {
00093
00094 if (rc == -1 && err == EAGAIN) {
00095 break;
00096 } else {
00097
00098 pool->first_connection = current->next;
00099 if (pool->first_connection != 0) {
00100 pool->first_connection->previous = 0;
00101 } else if (pool->last_connection == current) {
00102 pool->last_connection = 0;
00103 }
00104
00105
00106
00107
00108
00109 if (ngx_close_socket(current->fd) == -1) {
00110 ngx_log_debug1(NGX_LOG_DEBUG, pool->log, ngx_errno,
00111 "[ngx_connection_pool_strip_broken] %d failed", current->fd);
00112 }
00113
00114 ngx_destroy_pool(current->pool);
00115
00116 pool->stored_connections--;
00117 if(rc == -1) {
00118 ngx_log_debug0(NGX_LOG_DEBUG, pool->log, err,
00119 "[ngx_connection_pool_strip_broken] Free failed connection");
00120 } else {
00121 ngx_log_debug0(NGX_LOG_DEBUG, pool->log, 0,
00122 "[ngx_connection_pool_strip_broken] Free connection, closed by foreign host");
00123 }
00124 }
00125 } else {
00126 break;
00127 }
00128 }
00129 }
00130
00131 static ngx_int_t
00132 ngx_connection_pool_get_new(ngx_connection_pool_t* pool,
00133 ngx_pooled_connection_t** new_connection)
00134 {
00135 ngx_peer_connection_t peer;
00136 ngx_pool_t *allocator_pool;
00137 ngx_int_t rc;
00138 ngx_err_t err;
00139
00140 if(pool->stored_connections >= pool->stored_connections_limit) {
00141 ngx_log_error(NGX_LOG_ERR, pool->log, 0, "[ngx_connection_pool_get_new] Connection limit hit. Consider increasing it.");
00142 return NGX_ERROR;
00143 }
00144
00145
00146
00147 peer.sockaddr = (struct sockaddr*) pool->sockaddr;
00148 peer.socklen = pool->sockaddr_size;
00149 peer.name = &pool->name;
00150 peer.get = ngx_event_get_peer;
00151 peer.log = pool->log;
00152 peer.log_error = NGX_ERROR_ERR;
00153
00154 rc = ngx_event_connect_peer(&peer);
00155
00156 if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
00157
00158 if(rc == NGX_ERROR) {
00159 err = ngx_errno;
00160 } else {
00161 err = 0;
00162 }
00163 ngx_log_error(NGX_LOG_ERR, pool->log, err,
00164 "[ngx_connection_pool_get_new] Connect failed, error was %d", rc);
00165 if (peer.connection != NULL && peer.connection->fd != -1) {
00166 ngx_close_connection(peer.connection);
00167 }
00168
00169 if (rc == NGX_ERROR) {
00170 return NGX_ERROR;
00171 } else {
00172 return NGX_AGAIN;
00173 }
00174 }
00175
00176 allocator_pool = ngx_create_pool(256, pool->log);
00177 (*new_connection) = ngx_pcalloc(allocator_pool, sizeof(ngx_pooled_connection_t));
00178
00179 (*new_connection)->fd = peer.connection->fd;
00180 (*new_connection)->connection = peer.connection;
00181
00182 (*new_connection)->owner_pool = pool;
00183 (*new_connection)->pool = allocator_pool;
00184 (*new_connection)->next = 0;
00185 (*new_connection)->previous = 0;
00186
00187 (*new_connection)->connection->data = *new_connection;
00188 (*new_connection)->data = 0;
00189
00190 pool->stored_connections++;
00191 pool->returned_connections++;
00192
00193 ngx_log_debug1(NGX_LOG_DEBUG, pool->log, 0,
00194 "[ngx_connection_pool_get_new] Success, FD = %d",
00195 (*new_connection)->connection->fd);
00196 return NGX_OK;
00197 }
00198
00199 ngx_int_t
00200 ngx_connection_pool_get(ngx_connection_pool_t* pool,
00201 ngx_pooled_connection_t** new_connection, ngx_int_t force_new)
00202 {
00203 ngx_int_t event;
00204 ngx_socket_t s;
00205 ngx_event_t *rev, *wev;
00206 ngx_connection_t *c;
00207
00208 if (force_new == 1) {
00209 return ngx_connection_pool_get_new(pool, new_connection);
00210 }
00211
00212 ngx_connection_pool_strip_broken(pool);
00213
00214
00215 if (pool->first_connection != NULL) {
00216
00217 (*new_connection) = pool->first_connection;
00218 pool->first_connection = (*new_connection)->next;
00219 if (pool->first_connection != 0) {
00220 pool->first_connection->previous = 0;
00221 } else if (pool->last_connection == (*new_connection)) {
00222 pool->last_connection = 0;
00223 }
00224 (*new_connection)->next = 0;
00225 (*new_connection)->previous = 0;
00226
00227
00228 s = (*new_connection)->fd;
00229
00230 c = ngx_get_connection(s, pool->log);
00231 if (c == NULL) {
00232 if (ngx_close_socket(s) == -1) {
00233 ngx_log_error(NGX_LOG_ERR, pool->log, ngx_socket_errno,
00234 "[ngx_connection_pool_get] ngx_close_socket_n failed");
00235 }
00236 ngx_log_debug3(NGX_LOG_DEBUG, pool->log, 0,
00237 "[ngx_connection_pool_get] Return old, get_connection failed.\
00238 Could hit nginx used connections limit! FD = %d, PoolCount = %d %d",
00239 s, pool->stored_connections, pool->returned_connections);
00240
00241
00242
00243 ngx_destroy_pool((*new_connection)->pool);
00244
00245 pool->returned_connections--;
00246 pool->stored_connections--;
00247 ngx_log_debug3(NGX_LOG_DEBUG,pool->log,0,"[ngx_connection_pool_release] Connection forcefully released, FD = %d, PoolCount = %d %d", s, pool->stored_connections, pool->returned_connections);
00248
00249 return NGX_ERROR;
00250 }
00251
00252 c->recv = ngx_recv;
00253 c->send = ngx_send;
00254 c->recv_chain = ngx_recv_chain;
00255 c->send_chain = ngx_send_chain;
00256
00257 c->sendfile = 1;
00258
00259 c->log_error = NGX_ERROR_ERR;
00260
00261 if (((struct sockaddr*)pool->sockaddr)->sa_family != AF_INET) {
00262 c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
00263 c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
00264
00265 #if (NGX_SOLARIS)
00266 c->sendfile = 0;
00267 #endif
00268 }
00269
00270 rev = c->read;
00271 wev = c->write;
00272
00273 rev->log = pool->log;
00274 wev->log = pool->log;
00275
00276 (*new_connection)->connection = c;
00277
00278 if (ngx_add_conn) {
00279 if (ngx_add_conn(c) == NGX_ERROR) {
00280 ngx_log_error(NGX_LOG_ERR, pool->log, 0,
00281 "[ngx_connection_pool_release] ngx_add_conn(c) failed, FD = %d, PoolCount = %d %d",
00282 s, pool->stored_connections, pool->returned_connections);
00283 ngx_connection_pool_release(*new_connection);
00284 return NGX_ERROR;
00285 }
00286 }
00287
00288 if (ngx_add_conn) {
00289 wev->ready = 1;
00290 } else if (ngx_event_flags & NGX_USE_AIO_EVENT) {
00291 rev->ready = 1;
00292 wev->ready = 1;
00293 } else {
00294 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
00295 event = NGX_CLEAR_EVENT;
00296 } else {
00297 event = NGX_LEVEL_EVENT;
00298 }
00299
00300 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
00301
00302 ngx_log_error(NGX_LOG_ERR, pool->log, 0,
00303 "[ngx_connection_pool_release] ngx_add_event(rev, NGX_READ_EVENT, event) failed, FD = %d, PoolCount = %d %d",
00304 s, pool->stored_connections, pool->returned_connections);
00305 ngx_connection_pool_release(*new_connection);
00306 return NGX_ERROR;
00307 }
00308
00309 wev->ready = 1;
00310 }
00311
00312 (*new_connection)->connection->data = *new_connection;
00313 pool->returned_connections++;
00314 ngx_log_debug3(NGX_LOG_DEBUG,pool->log, 0,
00315 "[ngx_connection_pool_get] Return old, FD = %d, PoolCount = %d %d",
00316 (*new_connection)->connection->fd, pool->stored_connections, pool->returned_connections);
00317 return NGX_OK;
00318 }
00319
00320
00321
00322 ngx_log_debug2(NGX_LOG_DEBUG, pool->log, 0,
00323 "[ngx_connection_pool_get] Allocate new, PoolCount = %d %d",
00324 pool->stored_connections, pool->returned_connections);
00325 return ngx_connection_pool_get_new(pool, new_connection);
00326 }
00327
00328 void
00329 ngx_connection_pool_return(ngx_pooled_connection_t *connection_context)
00330 {
00331 ngx_connection_t *connection;
00332 ngx_connection_pool_t *pool;
00333 ngx_uint_t log_error;
00334 ngx_socket_t fd;
00335
00336 connection = connection_context->connection;
00337 connection_context->data = 0;
00338
00339
00340 pool = connection_context->owner_pool;
00341
00342
00343
00344 fd = connection_context->connection->fd;
00345 if (fd != connection_context->fd) {
00346 ngx_log_error(NGX_LOG_ERR, connection->log, 0,
00347 "[ngx_connection_pool_return] Invalid FD %d != %d", fd,
00348 connection_context->fd);
00349 }
00350
00351 if (fd == -1) {
00352 ngx_connection_pool_release(connection_context);
00353 return;
00354 }
00355
00356 if (connection->read->timer_set) {
00357 ngx_del_timer(connection->read);
00358 }
00359
00360 if (connection->write->timer_set) {
00361 ngx_del_timer(connection->write);
00362 }
00363
00364 if (ngx_del_conn) {
00365
00366 ngx_del_conn(connection, 0);
00367 } else {
00368 if (connection->read->active || connection->read->disabled) {
00369 ngx_del_event(connection->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
00370 }
00371
00372 if (connection->write->active || connection->write->disabled) {
00373 ngx_del_event(connection->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
00374 }
00375 }
00376
00377 #if (NGX_THREADS)
00378
00379 ngx_mutex_lock(ngx_posted_events_mutex);
00380
00381 if (connection->read->prev) {
00382 ngx_delete_posted_event(connection->read);
00383 }
00384
00385 if (connection->write->prev) {
00386 ngx_delete_posted_event(connection->write);
00387 }
00388
00389 connection->read->closed = 1;
00390 connection->write->closed = 1;
00391
00392 if (connection->single_connection) {
00393 ngx_unlock(&connection->lock);
00394 connection->read->locked = 0;
00395 connection->write->locked = 0;
00396 }
00397
00398 ngx_mutex_unlock(ngx_posted_events_mutex);
00399
00400 #else
00401
00402 if (connection->read->prev) {
00403 ngx_delete_posted_event(connection->read);
00404 }
00405
00406 if (connection->write->prev) {
00407 ngx_delete_posted_event(connection->write);
00408 }
00409
00410 connection->read->closed = 1;
00411 connection->write->closed = 1;
00412
00413 #endif
00414
00415 log_error = connection->log_error;
00416
00417 ngx_free_connection(connection);
00418
00419
00420 connection->fd = (ngx_socket_t) -1;
00421
00422
00423 connection_context->connection = NULL;
00424
00425 if (pool->first_connection == NULL) {
00426
00427 pool->first_connection = connection_context;
00428 pool->last_connection = connection_context;
00429
00430 connection_context->next = NULL;
00431 connection_context->previous = NULL;
00432 } else {
00433 connection_context->next = NULL;
00434 connection_context->previous = pool->last_connection;
00435 pool->last_connection->next = connection_context;
00436 pool->last_connection = connection_context;
00437 }
00438 pool->returned_connections--;
00439 ngx_log_debug3( NGX_LOG_DEBUG, pool->log, 0,
00440 "[ngx_connection_pool_return] Connection returned to pool, FD = %d, PoolCount = %d %d",
00441 connection_context->fd, pool->stored_connections,
00442 pool->returned_connections);
00443 }
00444
00445 void ngx_connection_pool_release(ngx_pooled_connection_t *connection_context)
00446 {
00447 ngx_connection_t *connection;
00448 ngx_connection_pool_t *pool;
00449
00450 connection = connection_context->connection;
00451
00452 pool = connection_context->owner_pool;
00453
00454
00455 ngx_close_connection(connection_context->connection);
00456 ngx_destroy_pool(connection_context->pool);
00457
00458 pool->returned_connections--;
00459 pool->stored_connections--;
00460 ngx_log_debug3( NGX_LOG_DEBUG, pool->log, 0,
00461 "[ngx_connection_pool_release] Connection forcefully released, FD = %d, PoolCount = %d %d",
00462 connection->fd, pool->stored_connections,
00463 pool->returned_connections);
00464 }