]> git.ipfire.org Git - zone-sync.git/commitdiff
main: Add the option to run multiple zones at the same time master
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 21 May 2026 16:21:52 +0000 (16:21 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 21 May 2026 16:21:52 +0000 (16:21 +0000)
By default, zone-sync is parsing one zone, then updating it, and so on.
The main reason is that loading following zones could block the event
loop which means that an ongoing transfer can time out for no aparent
reason.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
main.c

diff --git a/main.c b/main.c
index 02a4db22e1c422312ecfcc3285256e2e54b5ceb0..38c6991fdca4423159b5cab1a5f140e87ce16abb 100644 (file)
--- a/main.c
+++ b/main.c
@@ -22,6 +22,7 @@
 #include <netdb.h>
 #include <stdio.h>
 #include <syslog.h>
+#include <string.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 
@@ -60,6 +61,9 @@ typedef struct ctx {
        // Path
        const char* path;
 
+       // Parallel
+       unsigned long parallel;
+
        // Flags
        enum {
                SECURE = (1 << 0),
@@ -81,7 +85,8 @@ typedef struct ctx {
        unsigned int num_zones;
 
        // How many transfers are running?
-       unsigned int running;
+       unsigned long running;
+       unsigned long processed;
 
        // Memory Context
        isc_mem_t* memctx;
@@ -111,6 +116,7 @@ typedef struct ctx {
 // Create the context
 static ctx_t ctx = {
        .log_level = LOG_INFO,
+       .parallel  = 1,
        .path      = DEFAULT_PATH,
        .transport = DNS_TRANSPORT_NONE,
 };
@@ -239,6 +245,8 @@ static zone_ctx* find_zone(dns_zone_t* z) {
        return NULL;
 }
 
+static int do_work(void);
+
 static void maybe_shutdown(void) {
        // Don't shut down if there is something left running
        if (ctx.running)
@@ -269,6 +277,9 @@ static void zone_done(dns_zone_t* z) {
        // Decrement the number of running zones
        ctx.running--;
 
+       // Launch some more work
+       do_work();
+
        // Terminate if we are all done
        maybe_shutdown();
 }
@@ -479,6 +490,22 @@ ERROR:
        zone_done(zone->zone);
 }
 
+/*
+       Called to start some more work to do
+*/
+static int do_work(void) {
+       while (!ctx.parallel || (ctx.running < ctx.parallel)) {
+               // We are done if all zones have been processed
+               if (ctx.processed >= ctx.num_zones)
+                       break;
+
+               // Launch the next zone
+               do_zone(&ctx.zones[ctx.processed++]);
+       }
+
+       return 0;
+}
+
 static int configure_transports(void) {
        dns_transport_type_t type = DNS_TRANSPORT_TCP;
        dns_name_t* name = NULL;
@@ -546,9 +573,8 @@ static void run_loop(void* data) {
                goto ERROR;
        }
 
-       // Process all zones
-       for (unsigned int i = 0; i < ctx.num_zones; i++)
-               do_zone(&ctx.zones[i]);
+       // Do some work
+       do_work();
 
 ERROR:
        // Potentially shut down if there is nothing to do
@@ -585,19 +611,21 @@ const char* argp_program_version = PACKAGE_VERSION;
 static const char* args_doc = "ZONE [ZONE...]";
 
 enum {
-       OPT_DEBUG   = 1,
-       OPT_QUIET   = 2,
-       OPT_PATH    = 3,
-       OPT_PRIMARY = 4,
-       OPT_SECURE  = 5,
+       OPT_DEBUG    = 1,
+       OPT_QUIET    = 2,
+       OPT_PATH     = 3,
+       OPT_PARALLEL = 4,
+       OPT_PRIMARY  = 5,
+       OPT_SECURE   = 6,
 };
 
 static struct argp_option options[] = {
-       { "debug",   OPT_DEBUG,   NULL,       0, "Run in debug mode", 0 },
-       { "quiet",   OPT_QUIET,   NULL,       0, "Run in quiet mode", 0 },
-       { "path",    OPT_PATH,    "PATH",     1, "Path where to store the zones", 0 },
-       { "primary", OPT_PRIMARY, "HOSTNAME", 1, "The hostname of the primary to fetch from", 0 },
-       { "secure",  OPT_SECURE , NULL,       0, "Use a secure transport to transfer the zone", 0 },
+       { "debug",    OPT_DEBUG,    NULL,       0, "Run in debug mode", 0 },
+       { "quiet",    OPT_QUIET,    NULL,       0, "Run in quiet mode", 0 },
+       { "path",     OPT_PATH,     "PATH",     1, "Path where to store the zones", 0 },
+       { "parallel", OPT_PARALLEL, "N",        1, "How many zones to process simultaneously", 0 },
+       { "primary",  OPT_PRIMARY,  "HOSTNAME", 1, "The hostname of the primary to fetch from", 0 },
+       { "secure",   OPT_SECURE ,  NULL,       0, "Use a secure transport to transfer the zone", 0 },
        { NULL },
 };
 
@@ -644,6 +672,7 @@ ERROR:
 }
 
 static error_t parse(int key, char* arg, struct argp_state* state) {
+       char* e = NULL;
        int r;
 
        switch (key) {
@@ -663,6 +692,17 @@ static error_t parse(int key, char* arg, struct argp_state* state) {
                        ctx.primary = arg;
                        break;
 
+               case OPT_PARALLEL:
+                       // Parse the number
+                       ctx.parallel = strtoul(arg, &e, 10);
+
+                       // Check if we could parse the number
+                       if ((e && *e) || (ctx.parallel == ULONG_MAX)) {
+                               argp_failure(state, EXIT_FAILURE, 0, "Could not parse number: %s", arg);
+                               return ARGP_ERR_UNKNOWN;
+                       }
+                       break;
+
                case OPT_SECURE:
                        ctx.flags |= SECURE;
                        break;