]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: check: implement check deletion for dynamic servers
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 29 Jul 2021 13:51:45 +0000 (15:51 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 6 Aug 2021 09:09:48 +0000 (11:09 +0200)
Implement a mechanism to free a started check on runtime for dynamic
servers. A new function check_purge is created for this. The check task
will be marked for deletion and scheduled to properly close connection
elements and free the task/tasklet/buf_wait elements.

This function will be useful to delete a dynamic server wich checks.

include/haproxy/check-t.h
include/haproxy/check.h
src/check.c

index b78a9f9f5d338f4e437e93e1e7adabe604ac4c1b..084b15edabe9d77528e3756b734285b8bc02e9be 100644 (file)
@@ -53,6 +53,7 @@ enum chk_result {
 #define CHK_ST_IN_ALLOC         0x0040  /* check blocked waiting for input buffer allocation */
 #define CHK_ST_OUT_ALLOC        0x0080  /* check blocked waiting for output buffer allocation */
 #define CHK_ST_CLOSE_CONN       0x0100  /* check is waiting that the connection gets closed */
+#define CHK_ST_PURGE            0x0200  /* check must be freed */
 
 /* check status */
 enum healthcheck_status {
index 228f9d64dc0098b16bdde3c4da0a82559016f763..fdc447150d12ef0ea2d580d5e3e0030b7da666ec 100644 (file)
@@ -79,6 +79,7 @@ struct buffer *check_get_buf(struct check *check, struct buffer *bptr);
 void check_release_buf(struct check *check, struct buffer *bptr);
 const char *init_check(struct check *check, int type);
 void free_check(struct check *check);
+void check_purge(struct check *check);
 
 int init_srv_check(struct server *srv);
 int init_srv_agent_check(struct server *srv);
index c2ab8e830a983333168d6d6bb8ab317b44f67322..c40a47ddfe0bce804f4767dddd5d6ec2f22ceac7 100644 (file)
@@ -1102,7 +1102,10 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state)
        if (check->server)
                HA_SPIN_LOCK(SERVER_LOCK, &check->server->lock);
 
-       if (!(check->state & CHK_ST_INPROGRESS)) {
+       if (unlikely(check->state & CHK_ST_PURGE)) {
+               TRACE_STATE("health-check state to purge", CHK_EV_TASK_WAKE, check);
+       }
+       else if (!(check->state & (CHK_ST_INPROGRESS))) {
                /* no check currently running */
                if (!expired) /* woke up too early */ {
                        TRACE_STATE("health-check wake up too early", CHK_EV_TASK_WAKE, check);
@@ -1139,7 +1142,7 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state)
         * First, let's check whether there was an uncaught error,
         * which can happen on connect timeout or error.
         */
-       if (check->result == CHK_RES_UNKNOWN) {
+       if (check->result == CHK_RES_UNKNOWN && likely(!(check->state & CHK_ST_PURGE))) {
                /* Here the connection must be defined. Otherwise the
                 * error would have already been detected
                 */
@@ -1197,7 +1200,7 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state)
                check->sess = NULL;
        }
 
-       if (check->server) {
+       if (check->server && likely(!(check->state & CHK_ST_PURGE))) {
                if (check->result == CHK_RES_FAILED) {
                        /* a failure or timeout detected */
                        TRACE_DEVEL("report failure", CHK_EV_TASK_WAKE|CHK_EV_HCHK_END|CHK_EV_HCHK_ERR, check);
@@ -1236,6 +1239,23 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state)
                HA_SPIN_UNLOCK(SERVER_LOCK, &check->server->lock);
 
        TRACE_LEAVE(CHK_EV_TASK_WAKE, check);
+
+       /* Free the check if set to PURGE. After this, the check instance may be
+        * freed via the free_server invocation, so it must not be accessed
+        * after this point.
+        */
+       if (unlikely(check->state & CHK_ST_PURGE)) {
+               /* buf_wait */
+               LIST_DELETE(&check->buf_wait.list);
+               /* tasklet */
+               pool_free(pool_head_tasklet, check->wait_list.tasklet);
+               /* task */
+               task_destroy(check->task);
+               t = NULL;
+
+               free_server(check->server);
+       }
+
        return t;
 }
 
@@ -1314,6 +1334,11 @@ const char *init_check(struct check *check, int type)
        return NULL;
 }
 
+/* Liberates the resources allocated for a check.
+ *
+ * This function must only be used at startup when it is known that the check
+ * has never been executed.
+ */
 void free_check(struct check *check)
 {
        task_destroy(check->task);
@@ -1329,6 +1354,18 @@ void free_check(struct check *check)
        }
 }
 
+/* This function must be used in order to free a started check. The check will
+ * be scheduled for a next execution in order to properly close and free all
+ * check elements.
+ *
+ * Non thread-safe.
+ */
+void check_purge(struct check *check)
+{
+       check->state = CHK_ST_PURGE;
+       task_wakeup(check->task, TASK_WOKEN_OTHER);
+}
+
 /* manages a server health-check. Returns the time the task accepts to wait, or
  * TIME_ETERNITY for infinity.
  */