From: Michael Tremer Date: Thu, 19 Sep 2024 11:16:32 +0000 (+0000) Subject: ctx: Build out worker allocation X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8c184c026847e6225772ccf3e529eb1d4094de37;p=fireperf.git ctx: Build out worker allocation Signed-off-by: Michael Tremer --- diff --git a/src/ctx.c b/src/ctx.c index 5bfe813..f7a24af 100644 --- 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)