]> git.ipfire.org Git - fireperf.git/commitdiff
ctx: Build out worker allocation
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 19 Sep 2024 11:16:32 +0000 (11:16 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 19 Sep 2024 11:16:32 +0000 (11:16 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/ctx.c

index 5bfe813dbb54309054d343844776174803c1fbdd..f7a24af6b30c8a6717aaa0cf224c917dde573afe 100644 (file)
--- a/src/ctx.c
+++ b/src/ctx.c
@@ -286,6 +286,56 @@ void fireperf_ctx_free(struct fireperf_ctx* ctx) {
        free(ctx);
 }
 
+static struct fireperf_worker* fireperf_ctx_find_idle_worker(struct fireperf_ctx* ctx) {
+       const struct fireperf_stats* stats = NULL;
+
+       for (unsigned int i = 0; i < ctx->num_workers; i++) {
+               if (!ctx->workers[i])
+                       continue;
+
+               // Fetch the worker's stats
+               stats = fireperf_worker_get_stats(ctx->workers[i]);
+               if (!stats)
+                       continue;
+
+               printf("C %lu\n", stats->open_connections);
+
+               // If the worker has no open connections, we can use it
+               if (stats->open_connections == 0)
+                       return ctx->workers[i];
+       }
+
+       return NULL;
+}
+
+static struct fireperf_worker* fireperf_ctx_find_least_busy_worker(struct fireperf_ctx* ctx) {
+       const struct fireperf_stats* stats = NULL;
+
+       struct fireperf_worker* worker = NULL;
+       unsigned int open_connections = 0;
+
+       for (unsigned int i = 0; i < ctx->num_workers; i++) {
+               if (!ctx->workers[i])
+                       continue;
+
+               // Fetch the worker's stats
+               stats = fireperf_worker_get_stats(ctx->workers[i]);
+               if (!stats)
+                       continue;
+
+               // If we have not seen a worker, we will save the first one;
+               // or replace it if we found a better match
+               if (!worker || stats->open_connections < open_connections) {
+                       worker = ctx->workers[i];
+
+                       // Save the number of connections
+                       open_connections = stats->open_connections;
+               }
+       }
+
+       return worker;
+}
+
 /*
        This function returns a free worker
 */
@@ -293,33 +343,38 @@ struct fireperf_worker* fireperf_ctx_fetch_worker(struct fireperf_ctx* ctx) {
        struct fireperf_worker* worker = NULL;
        int r;
 
-       /*
-               XXX TODO
-               To keep things simple, we create a new worker for each call.
+       // Return the first idle worker if available
+       worker = fireperf_ctx_find_idle_worker(ctx);
+       if (worker)
+               return worker;
+
+       // If all current workers are busy and we have not reached our maximum,
+       // we create a new one.
+       if (ctx->num_workers < ctx->max_workers) {
+               // Create a new worker
+               r = fireperf_worker_create(&worker, ctx);
+               if (r < 0) {
+                       ERROR(ctx, "Could not create worker: %s\n", strerror(-r));
+                       goto ERROR;
+               }
 
-               This should be replaced by a method that searches for the worker with
-               the least amount of connections and start up to as many workers as we
-               have CPU cores.
-       */
+               // Launch the worker
+               r = fireperf_worker_launch(worker);
+               if (r < 0) {
+                       ERROR(ctx, "Could not launch worker: %s\n", strerror(-r));
+                       goto ERROR;
+               }
 
-       // Create a new worker
-       r = fireperf_worker_create(&worker, ctx);
-       if (r < 0) {
-               ERROR(ctx, "Could not create worker: %s\n", strerror(-r));
-               goto ERROR;
-       }
+               // Store a reference
+               ctx->workers[ctx->num_workers++] = worker;
 
-       // Launch the worker
-       r = fireperf_worker_launch(worker);
-       if (r < 0) {
-               ERROR(ctx, "Could not launch worker: %s\n", strerror(-r));
-               goto ERROR;
+               return worker;
        }
 
-       // Store a reference
-       ctx->workers[ctx->num_workers++] = worker;
-
-       return worker;
+       // Return the least busy worker
+       worker = fireperf_ctx_find_least_busy_worker(ctx);
+       if (worker)
+               return worker;
 
 ERROR:
        if (worker)