]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Do not lock workers when using -T transferslowly/transferstuck
authorArtem Boldariev <artem@boldariev.com>
Mon, 19 Feb 2024 18:02:38 +0000 (20:02 +0200)
committerArtem Boldariev <artem@boldariev.com>
Wed, 21 Feb 2024 22:09:04 +0000 (00:09 +0200)
This commit ensures that worker threads are not sleeping (by using
select()) when '-T transferslowly/transferstuck' test options are
used. This commit converts synchronous implementation of the code into
an asynchronous one based on timers.

lib/ns/xfrout.c

index 0e09ddcc227d67cad70126eda5837f5e364c6438..31db2f043c927930863985d643483948e1848ae2 100644 (file)
@@ -674,6 +674,9 @@ typedef struct {
        isc_nm_timer_t *maxtime_timer;
 
        uint64_t idletime; /*%< XFR idle timeout (in ms) */
+
+       /* Delayed send */
+       isc_nm_timer_t *delayed_send_timer;
 } xfrout_ctx_t;
 
 static void
@@ -712,6 +715,9 @@ static void
 xfrout_log(xfrout_ctx_t *xfr, int level, const char *fmt, ...)
        ISC_FORMAT_PRINTF(3, 4);
 
+static void
+xfrout_delayed_timeout(void *arg, isc_result_t result);
+
 /**************************************************************************/
 
 void
@@ -1248,6 +1254,9 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id,
        isc_nm_timer_create(xfr->client->handle, xfrout_client_timeout, xfr,
                            &xfr->maxtime_timer);
 
+       isc_nm_timer_create(xfr->client->handle, xfrout_delayed_timeout, xfr,
+                           &xfr->delayed_send_timer);
+
        /*
         * Allocate a temporary buffer for the uncompressed response
         * message data.  The buffer size must be 65535 bytes
@@ -1281,6 +1290,74 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id,
        *xfrp = xfr;
 }
 
+static void
+xfrout_send(xfrout_ctx_t *xfr) {
+       const bool is_tcp = ((xfr->client->attributes & NS_CLIENTATTR_TCP) !=
+                            0);
+
+       if (is_tcp) {
+               isc_region_t used;
+
+               isc_buffer_usedregion(&xfr->txbuf, &used);
+
+               isc_nmhandle_attach(xfr->client->handle,
+                                   &xfr->client->sendhandle);
+               if (xfr->idletime > 0) {
+                       isc_nmhandle_setwritetimeout(xfr->client->sendhandle,
+                                                    xfr->idletime);
+               }
+               isc_nm_send(xfr->client->sendhandle, &used, xfrout_senddone,
+                           xfr);
+               xfr->sends++;
+               xfr->cbytes = used.length;
+       } else {
+               ns_client_send(xfr->client);
+               xfr->stream->methods->pause(xfr->stream);
+               isc_nmhandle_detach(&xfr->client->reqhandle);
+               xfrout_ctx_destroy(&xfr);
+       }
+}
+
+static void
+xfrout_delayed_timeout(void *arg, isc_result_t result) {
+       xfrout_ctx_t *xfr = (xfrout_ctx_t *)arg;
+       UNUSED(result);
+
+       isc_nm_timer_stop(xfr->delayed_send_timer);
+       xfrout_send(xfr);
+}
+
+static void
+xfrout_enqueue_send(xfrout_ctx_t *xfr) {
+       uint64_t timeout = 0;
+
+       /*
+        * System test helper options to simulate network issues.
+        *
+        * Both "transferslowly" and "transferstuck" are not meant to be
+        * used together (and are not actually used this way).
+        */
+       if (ns_server_getoption(xfr->client->manager->sctx,
+                               NS_SERVER_TRANSFERSLOWLY))
+       {
+               /* Sleep for a bit over a second. */
+               timeout = 1000;
+       } else if (ns_server_getoption(xfr->client->manager->sctx,
+                                      NS_SERVER_TRANSFERSTUCK))
+       {
+               /* Sleep for a bit over a minute. */
+               timeout = 60 * 1000;
+       }
+
+       if (timeout == 0) {
+               xfrout_send(xfr);
+               return;
+       }
+
+       /* delay */
+       isc_nm_timer_start(xfr->delayed_send_timer, timeout);
+}
+
 /*
  * Arrange to send as much as we can of "stream" without blocking.
  *
@@ -1519,7 +1596,6 @@ sendstream(xfrout_ctx_t *xfr) {
        }
 
        if (is_tcp) {
-               isc_region_t used;
                dns_compress_init(&cctx, xfr->mctx,
                                  DNS_COMPRESS_CASE | DNS_COMPRESS_LARGE);
                cleanup_cctx = true;
@@ -1530,60 +1606,15 @@ sendstream(xfrout_ctx_t *xfr) {
                dns_compress_invalidate(&cctx);
                cleanup_cctx = false;
 
-               isc_buffer_usedregion(&xfr->txbuf, &used);
-
                xfrout_log(xfr, ISC_LOG_DEBUG(8),
-                          "sending TCP message of %d bytes", used.length);
-
-               /* System test helper options to simulate network issues. */
-               if (ns_server_getoption(xfr->client->manager->sctx,
-                                       NS_SERVER_TRANSFERSLOWLY))
-               {
-                       /* Sleep for a bit over a second. */
-                       select(0, NULL, NULL, NULL,
-                              &(struct timeval){ 1, 1000 });
-               }
-               if (ns_server_getoption(xfr->client->manager->sctx,
-                                       NS_SERVER_TRANSFERSTUCK))
-               {
-                       /* Sleep for a bit over a minute. */
-                       select(0, NULL, NULL, NULL,
-                              &(struct timeval){ 60, 1000 });
-               }
+                          "sending TCP message of %d bytes",
+                          isc_buffer_usedlength(&xfr->txbuf));
 
-               isc_nmhandle_attach(xfr->client->handle,
-                                   &xfr->client->sendhandle);
-               if (xfr->idletime > 0) {
-                       isc_nmhandle_setwritetimeout(xfr->client->sendhandle,
-                                                    xfr->idletime);
-               }
-               isc_nm_send(xfr->client->sendhandle, &used, xfrout_senddone,
-                           xfr);
-               xfr->sends++;
-               xfr->cbytes = used.length;
+               xfrout_enqueue_send(xfr);
        } else {
                xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response");
 
-               /* System test helper options to simulate network issues. */
-               if (ns_server_getoption(xfr->client->manager->sctx,
-                                       NS_SERVER_TRANSFERSLOWLY))
-               {
-                       /* Sleep for a bit over a second. */
-                       select(0, NULL, NULL, NULL,
-                              &(struct timeval){ 1, 1000 });
-               }
-               if (ns_server_getoption(xfr->client->manager->sctx,
-                                       NS_SERVER_TRANSFERSTUCK))
-               {
-                       /* Sleep for a bit over a minute. */
-                       select(0, NULL, NULL, NULL,
-                              &(struct timeval){ 60, 1000 });
-               }
-
-               ns_client_send(xfr->client);
-               xfr->stream->methods->pause(xfr->stream);
-               isc_nmhandle_detach(&xfr->client->reqhandle);
-               xfrout_ctx_destroy(&xfr);
+               xfrout_enqueue_send(xfr);
                return;
        }
 
@@ -1608,10 +1639,6 @@ failure:
                return;
        }
 
-       if (xfr->client->sendhandle != NULL) {
-               isc_nmhandle_detach(&xfr->client->sendhandle);
-       }
-
        xfrout_fail(xfr, result, "sending zone data");
 }
 
@@ -1622,6 +1649,9 @@ xfrout_ctx_destroy(xfrout_ctx_t **xfrp) {
 
        INSIST(xfr->sends == 0);
 
+       isc_nm_timer_stop(xfr->delayed_send_timer);
+       isc_nm_timer_detach(&xfr->delayed_send_timer);
+
        isc_nm_timer_stop(xfr->maxtime_timer);
        isc_nm_timer_detach(&xfr->maxtime_timer);