[MEDIUM] listeners: queue proxy-bound listeners at the proxy's

All listeners that are limited by a proxy-specific resource are now
queued at the proxy's and not globally. This allows finer-grained
wakeups when releasing resource.
This commit is contained in:
Willy Tarreau 2011-07-24 23:55:06 +02:00
parent 08ceb1012b
commit 07687c171e
5 changed files with 27 additions and 7 deletions

View File

@ -301,6 +301,7 @@ struct proxy {
struct pxcounters be_counters; /* backend statistics counters */
struct pxcounters fe_counters; /* frontend statistics counters */
struct list listener_queue; /* list of the temporarily limited listeners because of lack of a proxy resource */
struct stktable table; /* table for storing sticking sessions */
int grace; /* grace time after stop request */

View File

@ -1041,6 +1041,7 @@ static void init_new_proxy(struct proxy *p)
LIST_INIT(&p->tcp_req.l4_rules);
LIST_INIT(&p->req_add);
LIST_INIT(&p->rsp_add);
LIST_INIT(&p->listener_queue);
/* Timeouts are defined as -1 */
proxy_reset_timeouts(p);

View File

@ -499,6 +499,10 @@ void maintain_proxies(int *next)
goto do_block;
}
/* The proxy is not limited so we can re-enable any waiting listener */
if (!LIST_ISEMPTY(&p->listener_queue))
dequeue_all_listeners(&p->listener_queue);
/* OK we have no reason to block, so let's unblock if we were blocking */
if (p->state == PR_STIDLE) {
for (l = p->listen; l != NULL; l = l->next)

View File

@ -2096,6 +2096,9 @@ struct task *process_session(struct task *t)
if (!LIST_ISEMPTY(&global_listener_queue))
dequeue_all_listeners(&global_listener_queue);
if (!LIST_ISEMPTY(&s->fe->listener_queue))
dequeue_all_listeners(&s->fe->listener_queue);
if (unlikely((global.mode & MODE_DEBUG) &&
(!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
int len;

View File

@ -1192,7 +1192,6 @@ int stream_sock_accept(int fd)
int max_accept = global.tune.maxaccept;
int cfd;
int ret;
int loops = 0;
if (unlikely(l->nbconn >= l->maxconn)) {
listener_full(l);
@ -1201,15 +1200,31 @@ int stream_sock_accept(int fd)
if (p && p->fe_sps_lim) {
int max = freq_ctr_remain(&p->fe_sess_per_sec, p->fe_sps_lim, 0);
if (unlikely(!max)) {
/* frontend accept rate limit was reached */
limit_listener(l, &p->listener_queue);
return 0;
}
if (max_accept > max)
max_accept = max;
}
while ((!p || p->feconn < p->maxconn) && actconn < global.maxconn && max_accept--) {
while (max_accept--) {
struct sockaddr_storage addr;
socklen_t laddr = sizeof(addr);
loops++;
if (unlikely(actconn >= global.maxconn)) {
limit_listener(l, &global_listener_queue);
return 0;
}
if (unlikely(p && p->feconn >= p->maxconn)) {
limit_listener(l, &p->listener_queue);
return 0;
}
cfd = accept(fd, (struct sockaddr *)&addr, &laddr);
if (unlikely(cfd == -1)) {
switch (errno) {
@ -1287,10 +1302,6 @@ int stream_sock_accept(int fd)
} /* end of while (p->feconn < p->maxconn) */
/* if we did not even enter the loop, we've reached resource limits */
if (!loops && max_accept)
limit_listener(l, &global_listener_queue);
return 0;
}