]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[BUG] scheduler: fix improper handling of duplicates __task_queue()
authorWilly Tarreau <w@1wt.eu>
Sat, 21 Mar 2009 11:51:40 +0000 (12:51 +0100)
committerWilly Tarreau <w@1wt.eu>
Sat, 21 Mar 2009 11:57:06 +0000 (12:57 +0100)
The top of a duplicate tree is not where bit == -1 but at the most
negative bit. This was causing tasks to be queued in reverse order
within duplicates. While this is not dramatic, it's incorrect and
might lead to longer than expected duplicate depths under some
circumstances.

include/proto/task.h
src/task.c

index 9d90b1737e8b3e6770fb3e4bf623ca9307e435cf..86a3c3d8151d712912a93f45f4f1070b93a7ef2d 100644 (file)
@@ -26,6 +26,7 @@
 #include <sys/time.h>
 
 #include <common/config.h>
+#include <common/eb32tree.h>
 #include <common/memory.h>
 #include <common/mini-clist.h>
 #include <common/standard.h>
@@ -80,7 +81,7 @@
 extern unsigned int run_queue;    /* run queue size */
 extern unsigned int niced_tasks;  /* number of niced tasks in the run queue */
 extern struct pool_head *pool2_task;
-extern struct task *last_timer;   /* optimization: last queued timer */
+extern struct eb32_node *last_timer;   /* optimization: last queued timer */
 
 /* return 0 if task is in run queue, otherwise non-zero */
 static inline int task_in_rq(struct task *t)
@@ -113,7 +114,7 @@ static inline struct task *task_wakeup(struct task *t, unsigned int f)
 static inline struct task *__task_unlink_wq(struct task *t)
 {
        eb32_delete(&t->wq);
-       if (last_timer == t)
+       if (last_timer == &t->wq)
                last_timer = NULL;
        return t;
 }
index b46420a4a3158fb2560508b2adb928a5ffb646b2..17d825e595fd1bfe4ec5e8133324e9438e96b237 100644 (file)
@@ -27,7 +27,7 @@ struct pool_head *pool2_task;
 
 unsigned int run_queue = 0;
 unsigned int niced_tasks = 0;      /* number of niced tasks in the run queue */
-struct task *last_timer = NULL;    /* optimization: last queued timer */
+struct eb32_node *last_timer = NULL;  /* optimization: last queued timer */
 
 static struct eb_root timers;      /* sorted timers tree */
 static struct eb_root rqueue;      /* tree constituting the run queue */
@@ -91,19 +91,22 @@ void __task_queue(struct task *task)
 #endif
 
        if (likely(last_timer &&
-                  last_timer->wq.key == task->wq.key &&
-                  last_timer->wq.node.bit == -1 &&
-                  last_timer->wq.node.node_p)) {
+                  last_timer->node.bit < 0 &&
+                  last_timer->key == task->wq.key &&
+                  last_timer->node.node_p)) {
                /* Most often, last queued timer has the same expiration date, so
                 * if it's not queued at the root, let's queue a dup directly there.
-                * Note that we can only use dups at the dup tree's root (bit==-1).
+                * Note that we can only use dups at the dup tree's root (most
+                * negative bit).
                 */
-               eb_insert_dup(&last_timer->wq.node, &task->wq.node);
+               eb_insert_dup(&last_timer->node, &task->wq.node);
+               if (task->wq.node.bit < last_timer->node.bit)
+                       last_timer = &task->wq;
                return;
        }
        eb32_insert(&timers, &task->wq);
-       if (task->wq.node.bit == -1)
-               last_timer = task; /* we only want a dup tree's root */
+       if (!last_timer || (task->wq.node.bit < last_timer->node.bit))
+               last_timer = &task->wq;
        return;
 }