[core] change srv->conns to doubly-linked-list

avoids separate memory allocation for list of pointers
This commit is contained in:
Glenn Strauss 2021-07-28 04:35:54 -04:00
parent 5a58f6963c
commit 81a107b4e6
7 changed files with 33 additions and 49 deletions

View File

@ -21,7 +21,6 @@ struct connection {
h2con *h2;
int fd; /* the FD for this connection */
uint32_t ndx; /* reverse mapping to server->connection[ndx] */
fdnode *fdn; /* fdevent (fdnode *) object */
/* fd states */
@ -62,6 +61,7 @@ struct connection {
int keep_alive_idle; /* remember max_keep_alive_idle from config */
connection *next;
connection *prev;
};
typedef struct {
@ -153,7 +153,6 @@ struct server {
/* buffers */
buffer *tmp_buf;
connections conns;
connections joblist_A;
connections joblist_B;
connections fdwaitqueue;
@ -171,6 +170,7 @@ struct server {
int sockets_disabled;
uint32_t lim_conns;
connection *conns;
connection *conns_pool;
log_error_st *errh;

View File

@ -48,7 +48,6 @@ static connection *connection_init(server *srv);
static void connection_reset(connection *con);
static connection *connections_get_new_connection(server *srv) {
connections * const conns = &srv->conns;
connection *con;
--srv->lim_conns;
if (srv->conns_pool) {
@ -61,16 +60,22 @@ static connection *connections_get_new_connection(server *srv) {
if (srv->srvconf.h2proto)
request_pool_extend(srv, 8);
}
con->next = NULL;
return (conns->ptr[(con->ndx = conns->used++)] = con);
/*con->prev = NULL;*//*(already set)*/
if ((con->next = srv->conns))
con->next->prev = con;
return (srv->conns = con);
}
static void connection_del(server *srv, connection *con) {
if (con->next)
con->next->prev = con->prev;
if (con->prev)
con->prev->next = con->next;
else
srv->conns = con->next;
con->prev = NULL;
con->next = srv->conns_pool;
srv->conns_pool = con;
connections * const conns = &srv->conns;
if (con->ndx != --conns->used) /* not last element */
(conns->ptr[con->ndx] = conns->ptr[conns->used])->ndx = con->ndx;
++srv->lim_conns;
}
@ -555,18 +560,11 @@ void connections_pool_clear(server * const srv) {
void connections_free(server *srv) {
connections_pool_clear(srv);
connections * const conns = &srv->conns;
for (uint32_t i = 0; i < conns->used; ++i)
connection_free(conns->ptr[i]);
free(conns->ptr);
conns->ptr = NULL;
}
void connections_init(server *srv) {
connections * const conns = &srv->conns;
conns->size = srv->srvconf.max_conns;
conns->ptr = calloc(conns->size, sizeof(*conns->ptr));
force_assert(NULL != conns->ptr);
connection *con;
while ((con = srv->conns)) {
srv->conns = con->next;
connection_free(con);
}
}
@ -1566,18 +1564,17 @@ static void connection_check_timeout (connection * const con, const unix_time64_
void connection_periodic_maint (server * const srv, const unix_time64_t cur_ts) {
/* check all connections for timeouts */
connections * const conns = &srv->conns;
for (size_t ndx = 0; ndx < conns->used; ++ndx) {
connection_check_timeout(conns->ptr[ndx], cur_ts);
for (connection *con = srv->conns, *tc; con; con = tc) {
tc = con->next;
connection_check_timeout(con, cur_ts);
}
}
void connection_graceful_shutdown_maint (server *srv) {
connections * const conns = &srv->conns;
const int graceful_expire =
(srv->graceful_expire_ts && srv->graceful_expire_ts < log_monotonic_secs);
for (uint32_t ndx = 0; ndx < conns->used; ++ndx) {
connection * const con = conns->ptr[ndx];
for (connection *con = srv->conns, *tc; con; con = tc) {
tc = con->next;
int changed = 0;
request_st * const r = &con->request;

View File

@ -8,8 +8,6 @@ struct server_socket; /* declaration */
void connections_pool_clear(server *srv);
__attribute_cold__
void connections_init(server *srv);
__attribute_cold__
void connections_free(server *srv);

View File

@ -131,13 +131,11 @@ URIHANDLER_FUNC(mod_evasive_uri_handler) {
if (p->conf.max_conns == 0) return HANDLER_GO_ON;
sock_addr * const dst_addr = &r->con->dst_addr;
const connections * const conns = &r->con->srv->conns;
for (uint32_t i = 0, conns_by_ip = 0; i < conns->used; ++i) {
connection *c = conns->ptr[i];
uint32_t conns_by_ip = 0;
for (const connection *c = r->con->srv->conns; c; c = c->next) {
/* check if other connections are already actively serving data for the same IP
* we can only ban connections which are already behind the 'read request' state
* */
*/
if (c->request.state <= CON_STATE_REQUEST_END) continue;
if (!sock_addr_is_addr_eq(&c->dst_addr, dst_addr)) continue;

View File

@ -298,9 +298,7 @@ static void mod_status_html_rtable (request_st * const rq, const server * const
* (avoid write() per connection) */
buffer * const b = rq->tmp_buf;
buffer_clear(b);
connection * const * const cptr = srv->conns.ptr;
for (uint32_t i = 0, used = srv->conns.used; i < used; ++i) {
const connection * const con = cptr[i];
for (const connection *con = srv->conns; con; con = con->next) {
const request_st * const r = &con->request;
if (r->http_status <= HTTP_VERSION_1_1) {
if (buffer_string_space(b) < 4096) {
@ -547,8 +545,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, request_st *
buffer_append_string_len(b, CONST_STR_LEN(" connections</b>\n"));
int per_line = 50;
for (j = 0; j < srv->conns.used; ++j) {
connection *c = srv->conns.ptr[j];
for (const connection *c = srv->conns; c; c = c->next) {
const request_st * const cr = &c->request;
const char *state;
@ -635,8 +632,7 @@ static handler_t mod_status_handle_server_status_text(server *srv, request_st *
buffer_append_int(b, srv->lim_conns); /*(could omit)*/
buffer_append_string_len(b, CONST_STR_LEN("\nScoreboard: "));
for (uint32_t i = 0; i < srv->conns.used; ++i) {
connection *c = srv->conns.ptr[i];
for (const connection *c = srv->conns; c; c = c->next) {
const request_st * const cr = &c->request;
const char *state =
((c->h2 && 0 == c->h2->rused)
@ -894,11 +890,8 @@ TRIGGER_FUNC(mod_status_trigger) {
plugin_data *p = p_d;
/* check all connections */
for (uint32_t i = 0; i < srv->conns.used; ++i) {
connection *c = srv->conns.ptr[i];
for (const connection *c = srv->conns; c; c = c->next)
p->bytes_written += c->bytes_written_cur_second;
}
/* a sliding average */
p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;

View File

@ -592,8 +592,7 @@ TRIGGER_FUNC(mod_wstunnel_handle_trigger) {
gw_handle_trigger(srv, p_d);
for (uint32_t i = 0; i < srv->conns.used; ++i) {
connection *con = srv->conns.ptr[i];
for (connection *con = srv->conns; con; con = con->next) {
request_st * const r = &con->request;
handler_ctx *hctx = r->plugin_ctx[p->id];
if (NULL == hctx || r->handler_module != p->self)

View File

@ -1766,7 +1766,6 @@ static int server_main_setup (server * const srv, int argc, char **argv) {
/* or use the default: we really don't want to hit max-fds */
srv->lim_conns = srv->srvconf.max_conns = srv->max_fds/3;
}
connections_init(srv);
/* libev backend overwrites our SIGCHLD handler and calls waitpid on SIGCHLD; we want our own SIGCHLD handling. */
#ifdef HAVE_SIGACTION
@ -1969,7 +1968,7 @@ static void server_main_loop (server * const srv) {
if (graceful_shutdown) {
server_graceful_state(srv);
if (0 == srv->conns.used && graceful_shutdown) {
if (NULL == srv->conns && graceful_shutdown) {
/* we are in graceful shutdown phase and all connections are closed
* we are ready to terminate without harming anyone */
srv_shutdown = 1;
@ -2035,7 +2034,7 @@ int main (int argc, char **argv) {
server_graceful_state(srv);
}
if (0 == srv->conns.used) rc = 0;
if (NULL == srv->conns) rc = 0;
if (2 == graceful_shutdown) { /* value 2 indicates idle timeout */
log_error(srv->errh, __FILE__, __LINE__,
"server stopped after idle timeout");