[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.
diff --git a/haproxy.c b/haproxy.c
index 10cb6e5..5a3f1cb 100644
--- a/haproxy.c
+++ b/haproxy.c
@@ -733,9 +733,15 @@
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 *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 @@
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 @@
/* 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 @@
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 @@
}
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 @@
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);