From 5e698ef509231a1a264cacde6acb669c9c17da88 Mon Sep 17 00:00:00 2001 From: willy tarreau Date: Tue, 2 May 2006 14:51:00 +0200 Subject: [PATCH] [MEDIUM] slightly optimize the scheduler for non-expirable tasks. The non-expirable tasks are now sent to a dedicated wait-queue so that they do not pollute the other ones anymore. This is a temporary dirty hack which will go away with the new O(log(n)) scheduler. --- haproxy.c | 52 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/haproxy.c b/haproxy.c index 10cb6e5d8..5a3f1cb23 100644 --- a/haproxy.c +++ b/haproxy.c @@ -733,9 +733,15 @@ void **pool_session = NULL, struct proxy *proxy = NULL; /* list of all existing proxies */ struct fdtab *fdtab = NULL; /* array of all the file descriptors */ struct task *rq = NULL; /* global run queue */ -struct task wait_queue = { /* global wait queue */ - prev:LIST_HEAD(wait_queue), - next:LIST_HEAD(wait_queue) +struct task wait_queue[2] = { /* global wait queue */ + { + prev:LIST_HEAD(wait_queue[0]), /* expirable tasks */ + next:LIST_HEAD(wait_queue[0]), + }, + { + prev:LIST_HEAD(wait_queue[1]), /* non-expirable tasks */ + next:LIST_HEAD(wait_queue[1]), + }, }; static int totalconn = 0; /* total # of terminated sessions */ @@ -1695,7 +1701,31 @@ struct task *task_queue(struct task *task) { struct task *list = task->wq; struct task *start_from; - /* first, test if the task was already in a list */ + /* This is a very dirty hack to queue non-expirable tasks in another queue + * in order to avoid pulluting the tail of the standard queue. This will go + * away with the new O(log(n)) scheduler anyway. + */ + if (tv_iseternity(&task->expire)) { + /* if the task was queued in the standard wait queue, we must dequeue it */ + if (task->prev) { + if (task->wq == LIST_HEAD(wait_queue[1])) + return task; + else { + task_delete(task); + task->prev = NULL; + } + } + list = task->wq = LIST_HEAD(wait_queue[1]); + } else { + /* if the task was queued in the eternity queue, we must dequeue it */ + if (task->prev && (task->wq == LIST_HEAD(wait_queue[1]))) { + task_delete(task); + task->prev = NULL; + list = task->wq = LIST_HEAD(wait_queue[0]); + } + } + + /* next, test if the task was already in a list */ if (task->prev == NULL) { // start_from = list; start_from = list->prev; @@ -3085,7 +3115,7 @@ int event_accept(int fd) { setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one)); t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */ - t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */ + t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */ t->state = TASK_IDLE; t->process = process_session; t->context = s; @@ -5973,8 +6003,8 @@ int process_runnable_tasks() { /* look for expired tasks and add them to the run queue. */ - tnext = ((struct task *)LIST_HEAD(wait_queue))->next; - while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */ + tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next; + while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */ tnext = t->next; if (t->state & TASK_RUNNING) continue; @@ -6735,8 +6765,8 @@ void dump(int sig) { struct task *t, *tnext; struct session *s; - tnext = ((struct task *)LIST_HEAD(wait_queue))->next; - while ((t = tnext) != LIST_HEAD(wait_queue)) { /* we haven't looped ? */ + tnext = ((struct task *)LIST_HEAD(wait_queue[0]))->next; + while ((t = tnext) != LIST_HEAD(wait_queue[0])) { /* we haven't looped ? */ tnext = t->next; s = t->context; qfprintf(stderr,"[dump] wq: task %p, still %ld ms, " @@ -8532,7 +8562,7 @@ int readcfgfile(char *file) { } t->next = t->prev = t->rqnext = NULL; /* task not in run queue yet */ - t->wq = LIST_HEAD(wait_queue); /* but already has a wait queue assigned */ + t->wq = LIST_HEAD(wait_queue[0]); /* but already has a wait queue assigned */ t->state = TASK_IDLE; t->process = process_chk; t->context = newsrv; @@ -9351,7 +9381,7 @@ static int appsession_task_init(void) if ((t = pool_alloc(task)) == NULL) return -1; t->next = t->prev = t->rqnext = NULL; - t->wq = LIST_HEAD(wait_queue); + t->wq = LIST_HEAD(wait_queue[0]); t->state = TASK_IDLE; t->context = NULL; tv_delayfrom(&t->expire, &now, TBLCHKINT);