2008-09-08 00:20:55 +00:00
|
|
|
|
2008-11-16 20:33:53 +00:00
|
|
|
#include <lighttpd/base.h>
|
2008-09-08 00:20:55 +00:00
|
|
|
|
2009-10-03 15:15:44 +00:00
|
|
|
#include <lighttpd/plugin_core.h>
|
2013-05-21 15:16:44 +00:00
|
|
|
#include <lighttpd/throttle.h>
|
2009-10-03 15:15:44 +00:00
|
|
|
|
2009-07-08 19:06:07 +00:00
|
|
|
static liConnection* worker_con_get(liWorker *wrk);
|
2008-09-08 00:20:55 +00:00
|
|
|
|
|
|
|
/* closing sockets - wait for proper shutdown */
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_worker_add_closing_socket(liWorker *wrk, int fd) {
|
2009-09-28 22:24:37 +00:00
|
|
|
liServerState state = g_atomic_int_get(&wrk->srv->state);
|
2008-09-08 00:20:55 +00:00
|
|
|
|
2013-05-22 15:26:33 +00:00
|
|
|
if (-1 == fd) return;
|
|
|
|
|
2009-09-28 22:24:37 +00:00
|
|
|
if (LI_SERVER_RUNNING != state && LI_SERVER_WARMUP != state) {
|
2013-05-18 13:27:59 +00:00
|
|
|
shutdown(fd, SHUT_WR);
|
2008-09-09 16:09:20 +00:00
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
}
|
2008-09-08 00:20:55 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_add_closing_socket(&wrk->loop, fd);
|
2008-09-08 00:20:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Keep alive */
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_worker_check_keepalive(liWorker *wrk) {
|
2013-05-18 13:27:59 +00:00
|
|
|
li_tstamp now = li_cur_ts(wrk);
|
2008-09-08 00:20:55 +00:00
|
|
|
|
|
|
|
if (0 == wrk->keep_alive_queue.length) {
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_stop(&wrk->keep_alive_timer);
|
2008-09-08 00:20:55 +00:00
|
|
|
} else {
|
2013-05-18 13:27:59 +00:00
|
|
|
li_tstamp timeout = ((liConnection*)g_queue_peek_head(&wrk->keep_alive_queue))->keep_alive_data.timeout - now + 1;
|
|
|
|
li_event_timer_once(&wrk->keep_alive_timer, timeout);
|
2008-09-08 00:20:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
static void worker_keepalive_cb(liEventBase *watcher, int events) {
|
|
|
|
liWorker *wrk = LI_CONTAINER_OF(li_event_timer_from(watcher), liWorker, keep_alive_timer);
|
2013-05-25 12:37:09 +00:00
|
|
|
li_tstamp now = li_cur_ts(wrk);
|
2008-09-08 00:20:55 +00:00
|
|
|
GQueue *q = &wrk->keep_alive_queue;
|
|
|
|
GList *l;
|
2009-07-08 19:06:07 +00:00
|
|
|
liConnection *con;
|
2008-09-08 00:20:55 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
UNUSED(events);
|
2008-09-08 00:20:55 +00:00
|
|
|
|
|
|
|
while ( NULL != (l = g_queue_peek_head_link(q)) &&
|
2009-07-08 19:06:07 +00:00
|
|
|
(con = (liConnection*) l->data)->keep_alive_data.timeout <= now ) {
|
2013-05-25 12:37:09 +00:00
|
|
|
li_tstamp remaining = con->keep_alive_data.max_idle - wrk->srv->keep_alive_queue_timeout - (now - con->keep_alive_data.timeout);
|
2008-09-08 00:20:55 +00:00
|
|
|
if (remaining > 0) {
|
|
|
|
g_queue_delete_link(q, l);
|
|
|
|
con->keep_alive_data.link = NULL;
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_timer_once(&con->keep_alive_data.watcher, remaining);
|
2008-09-08 00:20:55 +00:00
|
|
|
} else {
|
|
|
|
/* close it */
|
2013-05-22 15:26:33 +00:00
|
|
|
li_connection_reset(con);
|
2008-09-08 00:20:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NULL == l) {
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_stop(&wrk->keep_alive_timer);
|
2008-09-08 00:20:55 +00:00
|
|
|
} else {
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_timer_once(&wrk->keep_alive_timer, con->keep_alive_data.timeout - now + 1);
|
2008-09-08 00:20:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-10 14:39:03 +00:00
|
|
|
/* check for timeouted connections */
|
2010-09-12 12:19:25 +00:00
|
|
|
static void worker_io_timeout_cb(liWaitQueue *wq, gpointer data) {
|
|
|
|
liWorker *wrk = data;
|
2009-07-08 19:06:07 +00:00
|
|
|
liConnection *con;
|
|
|
|
liWaitQueueElem *wqe;
|
2013-05-25 12:37:09 +00:00
|
|
|
li_tstamp now = li_cur_ts(wrk);
|
2008-11-10 14:39:03 +00:00
|
|
|
|
2010-09-12 12:19:25 +00:00
|
|
|
while ((wqe = li_waitqueue_pop(wq)) != NULL) {
|
2009-10-03 15:14:56 +00:00
|
|
|
liVRequest *vr;
|
2008-11-12 01:09:52 +00:00
|
|
|
/* connection has timed out */
|
|
|
|
con = wqe->data;
|
2009-10-03 15:14:56 +00:00
|
|
|
vr = con->mainvr;
|
|
|
|
if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
|
2010-07-31 12:44:45 +00:00
|
|
|
VR_DEBUG(vr, "connection io-timeout from %s after %.2f seconds", con->info.remote_addr_str->str, now - wqe->ts);
|
2009-10-03 15:14:56 +00:00
|
|
|
}
|
2009-07-09 20:17:24 +00:00
|
|
|
li_plugins_handle_close(con);
|
2013-05-25 17:14:02 +00:00
|
|
|
li_connection_reset(con);
|
2008-11-10 14:39:03 +00:00
|
|
|
}
|
2008-11-12 01:09:52 +00:00
|
|
|
|
2010-09-12 12:19:25 +00:00
|
|
|
li_waitqueue_update(wq);
|
2008-11-10 14:39:03 +00:00
|
|
|
}
|
|
|
|
|
2013-05-31 16:03:14 +00:00
|
|
|
static void worker_close_idle_connections(liWorker *wrk) {
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
for (i = wrk->connections_active; i-- > 0;) {
|
|
|
|
liConnection *con = g_array_index(wrk->connections, liConnection*, i);
|
|
|
|
switch (con->state) {
|
|
|
|
case LI_CON_STATE_KEEP_ALIVE:
|
|
|
|
li_connection_reset(con);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* update if wrk->wait_for_stop_connections.active changed */
|
|
|
|
li_connection_update_io_wait(con);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
li_worker_check_keepalive(wrk);
|
|
|
|
}
|
|
|
|
|
2008-09-08 00:20:55 +00:00
|
|
|
/* cache timestamp */
|
2009-07-17 11:04:01 +00:00
|
|
|
GString *li_worker_current_timestamp(liWorker *wrk, liTimeFunc timefunc, guint format_ndx) {
|
2009-01-07 19:59:51 +00:00
|
|
|
gsize len;
|
2009-01-07 22:36:17 +00:00
|
|
|
struct tm tm;
|
2009-07-17 11:04:01 +00:00
|
|
|
liWorkerTS *wts;
|
2013-05-18 13:27:59 +00:00
|
|
|
time_t now = (time_t)li_cur_ts(wrk);
|
2010-05-08 07:15:38 +00:00
|
|
|
GArray *a;
|
2008-09-08 00:20:55 +00:00
|
|
|
|
2010-05-08 07:15:38 +00:00
|
|
|
if (timefunc == LI_GMTIME) {
|
|
|
|
a = wrk->timestamps_gmt;
|
|
|
|
} else {
|
|
|
|
a = wrk->timestamps_local;
|
|
|
|
}
|
|
|
|
|
|
|
|
wts = &g_array_index(a, liWorkerTS, format_ndx);
|
|
|
|
|
2009-01-07 19:59:51 +00:00
|
|
|
/* cache hit */
|
2009-01-09 20:32:49 +00:00
|
|
|
if (now == wts->last_generated)
|
2009-01-07 19:59:51 +00:00
|
|
|
return wts->str;
|
2008-09-08 00:20:55 +00:00
|
|
|
|
2009-07-17 11:04:01 +00:00
|
|
|
if (timefunc == LI_GMTIME) {
|
|
|
|
if (!gmtime_r(&now, &tm))
|
|
|
|
return NULL;
|
|
|
|
} else if (!localtime_r(&now, &tm))
|
2009-01-07 22:36:17 +00:00
|
|
|
return NULL;
|
2009-07-17 11:04:01 +00:00
|
|
|
|
|
|
|
g_string_set_size(wts->str, 255);
|
|
|
|
|
2009-01-07 22:36:17 +00:00
|
|
|
len = strftime(wts->str->str, wts->str->allocated_len, g_array_index(wrk->srv->ts_formats, GString*, format_ndx)->str, &tm);
|
2009-07-17 11:04:01 +00:00
|
|
|
|
2009-01-07 19:59:51 +00:00
|
|
|
if (len == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
g_string_set_size(wts->str, len);
|
|
|
|
wts->last_generated = now;
|
2009-07-17 11:04:01 +00:00
|
|
|
|
2009-01-07 19:59:51 +00:00
|
|
|
return wts->str;
|
2008-09-08 00:20:55 +00:00
|
|
|
}
|
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
static void li_worker_prepare_cb(liEventBase *watcher, int events) {
|
|
|
|
liWorker *wrk = LI_CONTAINER_OF(li_event_prepare_from(watcher), liWorker, loop_prepare);
|
2010-08-29 10:24:30 +00:00
|
|
|
liServer *srv = wrk->srv;
|
2013-05-18 13:27:59 +00:00
|
|
|
UNUSED(events);
|
2010-08-29 10:24:30 +00:00
|
|
|
|
|
|
|
/* are there pending log entries? */
|
2012-03-16 12:24:17 +00:00
|
|
|
if (g_queue_get_length(&wrk->logs.log_queue)) {
|
2010-08-29 10:24:30 +00:00
|
|
|
/* take log entries from local queue, insert into global queue and notify log thread */
|
|
|
|
g_static_mutex_lock(&srv->logs.write_queue_mutex);
|
|
|
|
|
2012-03-16 12:24:17 +00:00
|
|
|
li_g_queue_merge(&srv->logs.write_queue, &wrk->logs.log_queue);
|
2010-08-29 10:24:30 +00:00
|
|
|
|
|
|
|
g_static_mutex_unlock(&srv->logs.write_queue_mutex);
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_async_send(&srv->logs.watcher);
|
2010-08-29 10:24:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-09 00:22:21 +00:00
|
|
|
/* stop worker watcher */
|
2013-05-18 13:27:59 +00:00
|
|
|
static void li_worker_stop_cb(liEventBase *watcher, int events) {
|
|
|
|
liWorker *wrk = LI_CONTAINER_OF(li_event_async_from(watcher), liWorker, worker_stop_watcher);
|
|
|
|
UNUSED(events);
|
2009-01-01 15:44:42 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
li_worker_stop(wrk, wrk);
|
2008-09-09 00:22:21 +00:00
|
|
|
}
|
|
|
|
|
2010-09-21 12:33:32 +00:00
|
|
|
/* stopping worker watcher */
|
2013-05-18 13:27:59 +00:00
|
|
|
static void li_worker_stopping_cb(liEventBase *watcher, int events) {
|
|
|
|
liWorker *wrk = LI_CONTAINER_OF(li_event_async_from(watcher), liWorker, worker_stopping_watcher);
|
|
|
|
UNUSED(events);
|
2010-09-21 12:33:32 +00:00
|
|
|
|
|
|
|
li_worker_stopping(wrk, wrk);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* suspend worker watcher */
|
2013-05-18 13:27:59 +00:00
|
|
|
static void li_worker_suspend_cb(liEventBase *watcher, int events) {
|
|
|
|
liWorker *wrk = LI_CONTAINER_OF(li_event_async_from(watcher), liWorker, worker_suspend_watcher);
|
|
|
|
UNUSED(events);
|
2009-08-30 18:43:13 +00:00
|
|
|
|
|
|
|
li_worker_suspend(wrk, wrk);
|
|
|
|
}
|
|
|
|
|
2008-09-09 00:22:21 +00:00
|
|
|
/* exit worker watcher */
|
2013-05-18 13:27:59 +00:00
|
|
|
static void li_worker_exit_cb(liEventBase *watcher, int events) {
|
|
|
|
liWorker *wrk = LI_CONTAINER_OF(li_event_async_from(watcher), liWorker, worker_exit_watcher);
|
|
|
|
UNUSED(events);
|
2009-01-01 15:44:42 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
li_worker_exit(wrk, wrk);
|
2008-09-09 00:22:21 +00:00
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
typedef struct li_worker_new_con_data li_worker_new_con_data;
|
|
|
|
struct li_worker_new_con_data {
|
2009-07-08 19:06:07 +00:00
|
|
|
liSocketAddress remote_addr;
|
2008-09-24 16:59:49 +00:00
|
|
|
int s;
|
2009-07-08 19:06:07 +00:00
|
|
|
liServerSocket *srv_sock;
|
2008-09-24 16:59:49 +00:00
|
|
|
};
|
|
|
|
|
2008-09-09 00:22:21 +00:00
|
|
|
/* new con watcher */
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_worker_new_con(liWorker *ctx, liWorker *wrk, liSocketAddress remote_addr, int s, liServerSocket *srv_sock) {
|
2008-09-24 16:59:49 +00:00
|
|
|
if (ctx == wrk) {
|
2009-07-08 19:06:07 +00:00
|
|
|
liConnection *con = worker_con_get(wrk);
|
2008-09-24 16:59:49 +00:00
|
|
|
|
2010-08-02 14:32:20 +00:00
|
|
|
li_connection_start(con, remote_addr, s, srv_sock);
|
2008-09-09 00:22:21 +00:00
|
|
|
} else {
|
2009-07-09 20:17:24 +00:00
|
|
|
li_worker_new_con_data *d = g_slice_new(li_worker_new_con_data);
|
2009-04-03 12:29:55 +00:00
|
|
|
d->remote_addr = remote_addr;
|
2008-09-24 16:59:49 +00:00
|
|
|
d->s = s;
|
2009-04-03 12:29:55 +00:00
|
|
|
d->srv_sock = srv_sock;
|
2008-09-24 16:59:49 +00:00
|
|
|
g_async_queue_push(wrk->new_con_queue, d);
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_async_send(&wrk->new_con_watcher);
|
2008-09-09 00:22:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
static void li_worker_new_con_cb(liEventBase *watcher, int events) {
|
|
|
|
liWorker *wrk = LI_CONTAINER_OF(li_event_async_from(watcher), liWorker, new_con_watcher);
|
2009-07-09 20:17:24 +00:00
|
|
|
li_worker_new_con_data *d;
|
2013-05-18 13:27:59 +00:00
|
|
|
UNUSED(events);
|
2008-09-09 00:22:21 +00:00
|
|
|
|
2008-09-24 16:59:49 +00:00
|
|
|
while (NULL != (d = g_async_queue_try_pop(wrk->new_con_queue))) {
|
2009-07-09 20:17:24 +00:00
|
|
|
li_worker_new_con(wrk, wrk, d->remote_addr, d->s, d->srv_sock);
|
|
|
|
g_slice_free(li_worker_new_con_data, d);
|
2008-09-09 00:22:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-03 14:18:46 +00:00
|
|
|
/* stats watcher */
|
2013-05-18 13:27:59 +00:00
|
|
|
static void worker_stats_watcher_cb(liEventBase *watcher, int events) {
|
|
|
|
liWorker *wrk = LI_CONTAINER_OF(li_event_timer_from(watcher), liWorker, stats_watcher);
|
2013-05-25 12:37:09 +00:00
|
|
|
li_tstamp now = li_cur_ts(wrk);
|
2013-05-18 13:27:59 +00:00
|
|
|
UNUSED(events);
|
2008-09-25 20:49:32 +00:00
|
|
|
|
|
|
|
if (wrk->stats.last_update && now != wrk->stats.last_update) {
|
|
|
|
wrk->stats.requests_per_sec =
|
|
|
|
(wrk->stats.requests - wrk->stats.last_requests) / (now - wrk->stats.last_update);
|
2009-10-02 10:13:37 +00:00
|
|
|
#if 0
|
|
|
|
if (wrk->stats.requests_per_sec > 0)
|
2008-12-30 13:24:33 +00:00
|
|
|
DEBUG(wrk->srv, "worker %u: %.2f requests per second", wrk->ndx, wrk->stats.requests_per_sec);
|
2009-10-02 10:13:37 +00:00
|
|
|
#endif
|
2008-09-25 20:49:32 +00:00
|
|
|
}
|
|
|
|
|
2009-11-07 14:42:03 +00:00
|
|
|
/* 5s averages and peak values */
|
2008-11-03 14:18:46 +00:00
|
|
|
if ((now - wrk->stats.last_avg) > 5) {
|
|
|
|
/* bytes in */
|
|
|
|
wrk->stats.bytes_in_5s_diff = wrk->stats.bytes_in - wrk->stats.bytes_in_5s;
|
|
|
|
wrk->stats.bytes_in_5s = wrk->stats.bytes_in;
|
2009-11-07 14:42:03 +00:00
|
|
|
wrk->stats.peak.bytes_in = MAX(wrk->stats.peak.bytes_in, wrk->stats.bytes_in_5s_diff / 5);
|
2008-11-03 14:18:46 +00:00
|
|
|
|
|
|
|
/* bytes out */
|
|
|
|
wrk->stats.bytes_out_5s_diff = wrk->stats.bytes_out - wrk->stats.bytes_out_5s;
|
|
|
|
wrk->stats.bytes_out_5s = wrk->stats.bytes_out;
|
2009-11-07 14:42:03 +00:00
|
|
|
wrk->stats.peak.bytes_out = MAX(wrk->stats.peak.bytes_out, wrk->stats.bytes_out_5s_diff / 5);
|
2008-11-03 14:18:46 +00:00
|
|
|
|
|
|
|
/* requests */
|
|
|
|
wrk->stats.requests_5s_diff = wrk->stats.requests - wrk->stats.requests_5s;
|
|
|
|
wrk->stats.requests_5s = wrk->stats.requests;
|
2009-11-07 14:42:03 +00:00
|
|
|
wrk->stats.peak.requests = MAX(wrk->stats.peak.requests, wrk->stats.requests_5s_diff / 5);
|
2008-11-03 14:18:46 +00:00
|
|
|
|
|
|
|
/* active connections */
|
|
|
|
wrk->stats.active_cons_5s = wrk->connections_active;
|
2009-11-07 14:42:03 +00:00
|
|
|
wrk->stats.peak.active_cons = MAX(wrk->stats.peak.active_cons, wrk->connections_active);
|
2008-11-03 14:18:46 +00:00
|
|
|
|
|
|
|
wrk->stats.last_avg = now;
|
|
|
|
}
|
|
|
|
|
|
|
|
wrk->stats.active_cons_cum += wrk->connections_active;
|
|
|
|
|
2008-09-25 20:49:32 +00:00
|
|
|
wrk->stats.last_requests = wrk->stats.requests;
|
|
|
|
wrk->stats.last_update = now;
|
2013-05-18 13:27:59 +00:00
|
|
|
|
|
|
|
/* and run again next second */
|
|
|
|
li_event_timer_once(&wrk->stats_watcher, 1);
|
2008-09-25 20:49:32 +00:00
|
|
|
}
|
|
|
|
|
2008-09-08 00:20:55 +00:00
|
|
|
/* init */
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
liWorker* li_worker_new(liServer *srv, struct ev_loop *loop) {
|
2009-07-08 19:06:07 +00:00
|
|
|
liWorker *wrk = g_slice_new0(liWorker);
|
2008-09-08 00:20:55 +00:00
|
|
|
wrk->srv = srv;
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_loop_init(&wrk->loop, loop);
|
2008-09-08 00:20:55 +00:00
|
|
|
|
2013-05-04 11:11:25 +00:00
|
|
|
li_lua_init(&wrk->LL, srv, wrk);
|
2009-11-01 14:43:12 +00:00
|
|
|
|
2008-09-08 00:20:55 +00:00
|
|
|
g_queue_init(&wrk->keep_alive_queue);
|
2015-01-17 14:13:54 +00:00
|
|
|
li_event_timer_init(&wrk->loop, "worker connection keep-alive", &wrk->keep_alive_timer, worker_keepalive_cb);
|
2008-09-08 00:20:55 +00:00
|
|
|
|
2008-09-24 16:59:49 +00:00
|
|
|
wrk->connections_active = 0;
|
2009-07-08 19:06:07 +00:00
|
|
|
wrk->connections = g_array_new(FALSE, TRUE, sizeof(liConnection*));
|
2008-09-24 16:59:49 +00:00
|
|
|
|
2008-09-08 00:20:55 +00:00
|
|
|
wrk->tmp_str = g_string_sized_new(255);
|
|
|
|
|
2009-07-17 11:04:01 +00:00
|
|
|
wrk->timestamps_gmt = g_array_sized_new(FALSE, TRUE, sizeof(liWorkerTS), srv->ts_formats->len);
|
|
|
|
g_array_set_size(wrk->timestamps_gmt, srv->ts_formats->len);
|
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
for (i = 0; i < srv->ts_formats->len; i++)
|
|
|
|
g_array_index(wrk->timestamps_gmt, liWorkerTS, i).str = g_string_sized_new(255);
|
|
|
|
}
|
|
|
|
wrk->timestamps_local = g_array_sized_new(FALSE, TRUE, sizeof(liWorkerTS), srv->ts_formats->len);
|
|
|
|
g_array_set_size(wrk->timestamps_local, srv->ts_formats->len);
|
2009-01-07 19:59:51 +00:00
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
for (i = 0; i < srv->ts_formats->len; i++)
|
2009-07-17 11:04:01 +00:00
|
|
|
g_array_index(wrk->timestamps_local, liWorkerTS, i).str = g_string_sized_new(255);
|
2009-01-07 19:59:51 +00:00
|
|
|
}
|
2008-09-08 00:20:55 +00:00
|
|
|
|
2015-01-17 14:13:54 +00:00
|
|
|
li_event_prepare_init(&wrk->loop, "worker flush logs", &wrk->loop_prepare, li_worker_prepare_cb);
|
|
|
|
li_event_async_init(&wrk->loop, "worker stop", &wrk->worker_stop_watcher, li_worker_stop_cb);
|
|
|
|
li_event_async_init(&wrk->loop, "worker stopping", &wrk->worker_stopping_watcher, li_worker_stopping_cb);
|
|
|
|
li_event_async_init(&wrk->loop, "worker exit", &wrk->worker_exit_watcher, li_worker_exit_cb);
|
|
|
|
li_event_async_init(&wrk->loop, "worker suspend", &wrk->worker_suspend_watcher, li_worker_suspend_cb);
|
2008-09-09 00:22:21 +00:00
|
|
|
|
2015-01-17 14:13:54 +00:00
|
|
|
li_event_async_init(&wrk->loop, "worker new connection", &wrk->new_con_watcher, li_worker_new_con_cb);
|
2008-09-09 00:22:21 +00:00
|
|
|
wrk->new_con_queue = g_async_queue_new();
|
|
|
|
|
2015-01-17 14:13:54 +00:00
|
|
|
li_event_timer_init(&wrk->loop, "worker stats update", &wrk->stats_watcher, worker_stats_watcher_cb);
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_set_keep_loop_alive(&wrk->stats_watcher, FALSE);
|
|
|
|
li_event_timer_once(&wrk->stats_watcher, 1);
|
2008-09-25 20:49:32 +00:00
|
|
|
|
2015-01-17 14:13:54 +00:00
|
|
|
li_event_async_init(&wrk->loop, "worker collect", &wrk->collect_watcher, li_collect_watcher_cb);
|
2008-09-26 08:36:36 +00:00
|
|
|
wrk->collect_queue = g_async_queue_new();
|
|
|
|
|
2008-11-12 01:09:52 +00:00
|
|
|
/* io timeout timer */
|
2015-08-09 08:12:21 +00:00
|
|
|
li_waitqueue_init(&wrk->io_timeout_queue, &wrk->loop, "io timeout queue", worker_io_timeout_cb, srv->io_timeout, wrk);
|
2008-11-10 14:39:03 +00:00
|
|
|
|
2008-11-12 21:16:52 +00:00
|
|
|
/* throttling */
|
2015-08-09 08:12:21 +00:00
|
|
|
li_waitqueue_init(&wrk->throttle_queue, &wrk->loop, "throttle queue", li_throttle_waitqueue_cb, ((gdouble)LI_THROTTLE_GRANULARITY) / 1000, wrk);
|
2008-11-12 21:16:52 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
wrk->tasklets = li_tasklet_pool_new(&wrk->loop, srv->tasklet_pool_threads);
|
2010-08-25 16:05:23 +00:00
|
|
|
|
2011-11-18 18:04:42 +00:00
|
|
|
wrk->network_read_buf = NULL;
|
2009-11-22 17:50:11 +00:00
|
|
|
|
2008-09-08 00:20:55 +00:00
|
|
|
return wrk;
|
|
|
|
}
|
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
struct ev_loop* li_worker_free(liWorker *wrk) {
|
|
|
|
struct ev_loop* evloop;
|
|
|
|
|
|
|
|
if (!wrk) return NULL;
|
2008-09-08 00:20:55 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
li_job_queue_clear(&wrk->loop.jobqueue);
|
2010-09-05 11:21:42 +00:00
|
|
|
|
2008-09-24 16:59:49 +00:00
|
|
|
{ /* close connections */
|
|
|
|
guint i;
|
|
|
|
if (wrk->connections_active > 0) {
|
|
|
|
ERROR(wrk->srv, "Server shutdown with unclosed connections: %u", wrk->connections_active);
|
|
|
|
for (i = wrk->connections_active; i-- > 0;) {
|
2009-07-08 19:06:07 +00:00
|
|
|
liConnection *con = g_array_index(wrk->connections, liConnection*, i);
|
2009-07-09 20:17:24 +00:00
|
|
|
li_connection_error(con);
|
2008-09-24 16:59:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < wrk->connections->len; i++) {
|
2013-05-22 15:26:33 +00:00
|
|
|
liConnection *con = g_array_index(wrk->connections, liConnection*, i);
|
|
|
|
li_connection_reset(con);
|
|
|
|
li_connection_free(con);
|
2008-09-24 16:59:49 +00:00
|
|
|
}
|
|
|
|
g_array_free(wrk->connections, TRUE);
|
|
|
|
}
|
|
|
|
|
2009-01-07 19:59:51 +00:00
|
|
|
{ /* free timestamps */
|
|
|
|
guint i;
|
2009-07-17 11:04:01 +00:00
|
|
|
for (i = 0; i < wrk->timestamps_gmt->len; i++) {
|
|
|
|
g_string_free(g_array_index(wrk->timestamps_gmt, liWorkerTS, i).str, TRUE);
|
|
|
|
g_string_free(g_array_index(wrk->timestamps_local, liWorkerTS, i).str, TRUE);
|
|
|
|
}
|
|
|
|
g_array_free(wrk->timestamps_gmt, TRUE);
|
|
|
|
g_array_free(wrk->timestamps_local, TRUE);
|
2009-01-07 19:59:51 +00:00
|
|
|
}
|
2008-09-08 00:20:55 +00:00
|
|
|
|
2013-05-22 15:26:33 +00:00
|
|
|
li_waitqueue_stop(&wrk->io_timeout_queue);
|
|
|
|
li_waitqueue_stop(&wrk->throttle_queue);
|
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_clear(&wrk->worker_stop_watcher);
|
|
|
|
li_event_clear(&wrk->worker_stopping_watcher);
|
|
|
|
li_event_clear(&wrk->worker_suspend_watcher);
|
|
|
|
li_event_clear(&wrk->worker_exit_watcher);
|
2009-04-14 16:18:25 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_clear(&wrk->new_con_watcher);
|
2008-09-24 18:02:47 +00:00
|
|
|
g_async_queue_unref(wrk->new_con_queue);
|
2013-05-18 13:27:59 +00:00
|
|
|
wrk->new_con_queue = NULL;
|
2008-09-24 18:02:47 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_clear(&wrk->stats_watcher);
|
2008-09-25 20:49:32 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
li_collect_watcher_cb(&wrk->collect_watcher.base, 0);
|
|
|
|
li_event_clear(&wrk->collect_watcher);
|
2008-09-26 08:36:36 +00:00
|
|
|
g_async_queue_unref(wrk->collect_queue);
|
2013-05-18 13:27:59 +00:00
|
|
|
wrk->collect_queue = NULL;
|
2008-09-26 08:36:36 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_clear(&wrk->loop_prepare);
|
2010-09-05 12:19:27 +00:00
|
|
|
|
2009-01-07 20:11:06 +00:00
|
|
|
g_string_free(wrk->tmp_str, TRUE);
|
|
|
|
|
2009-10-09 13:38:12 +00:00
|
|
|
li_stat_cache_free(wrk->stat_cache);
|
2009-03-01 20:16:58 +00:00
|
|
|
|
2010-08-25 16:05:23 +00:00
|
|
|
li_tasklet_pool_free(wrk->tasklets);
|
|
|
|
|
2013-05-04 11:11:25 +00:00
|
|
|
li_lua_clear(&wrk->LL);
|
2009-11-01 14:43:12 +00:00
|
|
|
|
2011-11-18 18:04:42 +00:00
|
|
|
li_buffer_release(wrk->network_read_buf);
|
2009-11-22 17:50:11 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
evloop = li_event_loop_clear(&wrk->loop);
|
|
|
|
|
2009-07-08 19:06:07 +00:00
|
|
|
g_slice_free(liWorker, wrk);
|
2013-05-18 13:27:59 +00:00
|
|
|
|
|
|
|
return evloop;
|
2008-09-08 00:20:55 +00:00
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_worker_run(liWorker *wrk) {
|
2010-05-10 19:47:57 +00:00
|
|
|
/* update and start io timeout queue since first worker is allocated before srv->io_timeout is set */
|
|
|
|
li_waitqueue_set_delay(&wrk->io_timeout_queue, wrk->srv->io_timeout);
|
|
|
|
li_waitqueue_update(&wrk->io_timeout_queue);
|
|
|
|
|
2010-06-30 07:56:13 +00:00
|
|
|
/* initialize timestamp caches for new ones that have been added by modules */
|
|
|
|
if (wrk->srv->ts_formats->len > wrk->timestamps_gmt->len) {
|
|
|
|
guint i = wrk->timestamps_gmt->len;
|
|
|
|
g_array_set_size(wrk->timestamps_gmt, wrk->srv->ts_formats->len);
|
|
|
|
g_array_set_size(wrk->timestamps_local, wrk->srv->ts_formats->len);
|
|
|
|
for (; i < wrk->srv->ts_formats->len; i++) {
|
|
|
|
g_array_index(wrk->timestamps_gmt, liWorkerTS, i).last_generated = 0;
|
|
|
|
g_array_index(wrk->timestamps_gmt, liWorkerTS, i).str = g_string_sized_new(255);
|
|
|
|
g_array_index(wrk->timestamps_local, liWorkerTS, i).last_generated = 0;
|
|
|
|
g_array_index(wrk->timestamps_local, liWorkerTS, i).str = g_string_sized_new(255);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-18 11:53:07 +00:00
|
|
|
/* setup stat cache if necessary */
|
|
|
|
if (wrk->srv->stat_cache_ttl && !wrk->stat_cache)
|
2010-08-25 16:05:23 +00:00
|
|
|
wrk->stat_cache = li_stat_cache_new(wrk, wrk->srv->stat_cache_ttl);
|
2010-07-18 11:53:07 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_loop_run(&wrk->loop);
|
2008-09-08 00:20:55 +00:00
|
|
|
}
|
2008-09-09 00:22:21 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_worker_stop(liWorker *context, liWorker *wrk) {
|
2008-09-09 00:22:21 +00:00
|
|
|
if (context == wrk) {
|
|
|
|
guint i;
|
|
|
|
|
2010-05-07 18:54:50 +00:00
|
|
|
li_plugins_worker_stop(wrk);
|
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_stop(&wrk->worker_stop_watcher);
|
|
|
|
li_event_stop(&wrk->worker_stopping_watcher);
|
|
|
|
li_event_stop(&wrk->worker_suspend_watcher);
|
|
|
|
|
|
|
|
li_event_stop(&wrk->new_con_watcher);
|
|
|
|
|
2010-07-18 11:53:07 +00:00
|
|
|
if (wrk->stat_cache)
|
|
|
|
li_waitqueue_stop(&wrk->stat_cache->delete_queue);
|
2013-05-31 16:03:14 +00:00
|
|
|
/* handle remaining new connections. there shouldn't be any, we'll kill them soon anyway */
|
|
|
|
li_worker_new_con_cb(&wrk->new_con_watcher.base, 0);
|
2008-09-09 00:22:21 +00:00
|
|
|
|
2013-05-31 16:03:14 +00:00
|
|
|
/* connections should already be done on "normal" shutdowns. otherwise force it now */
|
2008-09-24 16:59:49 +00:00
|
|
|
for (i = wrk->connections_active; i-- > 0;) {
|
2009-07-08 19:06:07 +00:00
|
|
|
liConnection *con = g_array_index(wrk->connections, liConnection*, i);
|
2013-05-31 16:03:14 +00:00
|
|
|
li_connection_reset(con);
|
2008-09-09 00:22:21 +00:00
|
|
|
}
|
2008-09-24 16:59:49 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
li_worker_check_keepalive(wrk);
|
2008-09-09 00:22:21 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_loop_end(&wrk->loop);
|
2008-09-09 00:22:21 +00:00
|
|
|
} else {
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_async_send(&wrk->worker_stop_watcher);
|
2008-09-09 00:22:21 +00:00
|
|
|
}
|
|
|
|
}
|
2009-08-30 18:43:13 +00:00
|
|
|
|
2010-09-21 12:33:32 +00:00
|
|
|
void li_worker_stopping(liWorker *context, liWorker *wrk) {
|
|
|
|
liServer *srv = context->srv;
|
|
|
|
|
|
|
|
if (context == srv->main_worker) {
|
|
|
|
li_server_state_wait(srv, &wrk->wait_for_stop_connections);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context == wrk) {
|
|
|
|
/* li_plugins_worker_stopping(wrk); ??? */
|
|
|
|
|
2013-05-31 16:03:14 +00:00
|
|
|
/* connections are killed after 3 seconds without IO */
|
|
|
|
li_waitqueue_set_delay(&wrk->io_timeout_queue, 3);
|
2010-09-21 12:33:32 +00:00
|
|
|
|
2013-05-31 16:03:14 +00:00
|
|
|
worker_close_idle_connections(wrk);
|
2010-09-21 12:33:32 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
li_worker_new_con_cb(&wrk->new_con_watcher.base, 0); /* handle remaining new connections */
|
2013-05-31 16:03:14 +00:00
|
|
|
|
|
|
|
li_event_loop_force_close_sockets(&wrk->loop);
|
|
|
|
|
2010-09-21 12:33:32 +00:00
|
|
|
if (0 == g_atomic_int_get(&wrk->connection_load) && wrk->wait_for_stop_connections.active) {
|
|
|
|
li_server_state_ready(srv, &wrk->wait_for_stop_connections);
|
|
|
|
}
|
|
|
|
} else {
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_async_send(&wrk->worker_stopping_watcher);
|
2010-09-21 12:33:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-30 18:43:13 +00:00
|
|
|
void li_worker_suspend(liWorker *context, liWorker *wrk) {
|
|
|
|
if (context == wrk) {
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
/* close keep alive connections */
|
|
|
|
for (i = wrk->connections_active; i-- > 0;) {
|
|
|
|
liConnection *con = g_array_index(wrk->connections, liConnection*, i);
|
2009-10-03 14:48:35 +00:00
|
|
|
if (con->state == LI_CON_STATE_KEEP_ALIVE) {
|
2013-05-25 17:14:02 +00:00
|
|
|
li_connection_reset(con);
|
2009-10-03 14:48:35 +00:00
|
|
|
}
|
2009-08-30 18:43:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
li_worker_check_keepalive(wrk);
|
2009-09-28 22:24:37 +00:00
|
|
|
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_loop_force_close_sockets(&wrk->loop);
|
2009-09-28 22:24:37 +00:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
ERROR(wrk->srv, "%i connections still active", (int) wrk->connections_active);
|
|
|
|
for (i = wrk->connections_active; i-- > 0;) {
|
|
|
|
liConnection *con = g_array_index(wrk->connections, liConnection*, i);
|
|
|
|
ERROR(wrk->srv, "%i state: %s, %i", i, li_connection_state_str(con->state), con->mainvr->state);
|
|
|
|
}
|
|
|
|
#endif
|
2009-08-30 18:43:13 +00:00
|
|
|
} else {
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_async_send(&wrk->worker_suspend_watcher);
|
2009-08-30 18:43:13 +00:00
|
|
|
}
|
|
|
|
}
|
2008-09-09 00:22:21 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_worker_exit(liWorker *context, liWorker *wrk) {
|
2008-09-09 00:22:21 +00:00
|
|
|
if (context == wrk) {
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_loop_exit(&wrk->loop);
|
2008-09-09 00:22:21 +00:00
|
|
|
} else {
|
2013-05-18 13:27:59 +00:00
|
|
|
li_event_async_send(&wrk->worker_exit_watcher);
|
2008-09-09 00:22:21 +00:00
|
|
|
}
|
|
|
|
}
|
2008-09-24 16:59:49 +00:00
|
|
|
|
|
|
|
|
2009-07-08 19:06:07 +00:00
|
|
|
static liConnection* worker_con_get(liWorker *wrk) {
|
|
|
|
liConnection *con;
|
2008-09-24 16:59:49 +00:00
|
|
|
|
|
|
|
if (wrk->connections_active >= wrk->connections->len) {
|
2009-07-09 20:17:24 +00:00
|
|
|
con = li_connection_new(wrk);
|
2008-09-24 16:59:49 +00:00
|
|
|
con->idx = wrk->connections_active;
|
|
|
|
g_array_append_val(wrk->connections, con);
|
|
|
|
} else {
|
2009-07-08 19:06:07 +00:00
|
|
|
con = g_array_index(wrk->connections, liConnection*, wrk->connections_active);
|
2013-05-22 15:26:33 +00:00
|
|
|
con->idx = wrk->connections_active;
|
2008-09-24 16:59:49 +00:00
|
|
|
}
|
2011-11-17 17:59:09 +00:00
|
|
|
|
2008-09-24 16:59:49 +00:00
|
|
|
g_atomic_int_inc((gint*) &wrk->connections_active);
|
2011-11-17 17:59:09 +00:00
|
|
|
|
|
|
|
if (wrk->connections_active > wrk->connections_active_max_5min)
|
|
|
|
wrk->connections_active_max_5min = wrk->connections_active;
|
|
|
|
|
2008-09-24 16:59:49 +00:00
|
|
|
return con;
|
|
|
|
}
|
|
|
|
|
2009-10-09 13:38:12 +00:00
|
|
|
void li_worker_con_put(liConnection *con) {
|
2009-07-08 19:06:07 +00:00
|
|
|
liWorker *wrk = con->wrk;
|
2013-05-25 12:37:09 +00:00
|
|
|
li_tstamp now = li_cur_ts(wrk);
|
2010-07-18 11:53:07 +00:00
|
|
|
|
2013-05-22 15:26:33 +00:00
|
|
|
if (-1 == (gint) con->idx)
|
|
|
|
/* already inactive connection */
|
2008-11-23 17:21:45 +00:00
|
|
|
return;
|
2008-09-24 16:59:49 +00:00
|
|
|
|
2009-10-04 12:25:59 +00:00
|
|
|
g_atomic_int_add((gint*) &wrk->srv->connection_load, -1);
|
2008-09-24 16:59:49 +00:00
|
|
|
g_atomic_int_add((gint*) &wrk->connection_load, -1);
|
|
|
|
g_atomic_int_add((gint*) &wrk->connections_active, -1);
|
2009-03-28 02:37:41 +00:00
|
|
|
|
2008-09-24 16:59:49 +00:00
|
|
|
if (con->idx != wrk->connections_active) {
|
|
|
|
/* Swap [con->idx] and [wrk->connections_active] */
|
2009-07-08 19:06:07 +00:00
|
|
|
liConnection *tmp;
|
2014-04-10 16:08:59 +00:00
|
|
|
LI_FORCE_ASSERT(con->idx < wrk->connections_active); /* con must be an active connection */
|
2009-07-08 19:06:07 +00:00
|
|
|
tmp = g_array_index(wrk->connections, liConnection*, wrk->connections_active);
|
2008-09-24 16:59:49 +00:00
|
|
|
tmp->idx = con->idx;
|
2013-05-22 15:26:33 +00:00
|
|
|
con->idx = -1;
|
|
|
|
g_array_index(wrk->connections, liConnection*, wrk->connections_active) = con;
|
2009-07-08 19:06:07 +00:00
|
|
|
g_array_index(wrk->connections, liConnection*, tmp->idx) = tmp;
|
2008-09-24 16:59:49 +00:00
|
|
|
}
|
2009-03-28 02:37:41 +00:00
|
|
|
|
2011-11-17 17:59:09 +00:00
|
|
|
/* free unused connections. we keep max(connections_active) for the past 5min allocated */
|
2011-11-17 18:18:17 +00:00
|
|
|
if ((now - wrk->connections_gc_ts) > 300.0) {
|
2011-11-17 17:59:09 +00:00
|
|
|
guint i;
|
|
|
|
|
|
|
|
for (i = wrk->connections->len; i > wrk->connections_active_max_5min; i--) {
|
|
|
|
li_connection_free(g_array_index(wrk->connections, liConnection*, i-1));
|
|
|
|
g_array_index(wrk->connections, liConnection*, i-1) = NULL;
|
2009-03-28 02:37:41 +00:00
|
|
|
}
|
2011-11-17 17:59:09 +00:00
|
|
|
|
|
|
|
wrk->connections->len = wrk->connections_active_max_5min;
|
|
|
|
wrk->connections_active_max_5min = wrk->connections_active;
|
2009-03-28 02:37:41 +00:00
|
|
|
wrk->connections_gc_ts = now;
|
|
|
|
}
|
2010-09-21 12:33:32 +00:00
|
|
|
|
2011-11-17 17:59:09 +00:00
|
|
|
|
2010-09-21 12:33:32 +00:00
|
|
|
if (wrk->wait_for_stop_connections.active && 0 == g_atomic_int_get((gint*) &wrk->connection_load)) {
|
|
|
|
li_server_state_ready(wrk->srv, &wrk->wait_for_stop_connections);
|
|
|
|
}
|
2008-09-24 16:59:49 +00:00
|
|
|
}
|