]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s3:rpc_server: distribute clients based on available association group slots
authorStefan Metzmacher <metze@samba.org>
Thu, 12 Oct 2023 13:39:38 +0000 (15:39 +0200)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 17 Oct 2023 19:20:38 +0000 (19:20 +0000)
The important factor to distribute connection to workers
should be the number of used association group slots instead
of the raw number of connections. If one worker has a lot of
association groups with just one connection each, but another
with few association groups, but multiple connections per
association group. The one with less association groups should
get the connection. Note each worker is only able to allocate
UINT16_MAX allocation groups, but the number of connections
is only limited by RAM.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source3/librpc/idl/rpc_host.idl
source3/rpc_server/rpc_host.c
source3/rpc_server/rpc_worker.c

index 129d9227a277d4e3241cc370e839362cefd78f33..9eb48d3eaa8af04e5cc81213b6282c51d1b76c6c 100644 (file)
@@ -72,9 +72,22 @@ interface rpc_host_msg
                 */
                uint32 worker_index;
 
+
+               /**
+                * @brief How many association groups this process serves right now
+                *
+                * @note while this is uint32, we currently only support 16-bit
+                * values, as we use the worker_index in the high 16-bits of
+                * so we only have 16-bit per worker in order to form the 32-bit
+                * association group id.
+                */
+               uint32 num_association_groups;
+
                /**
-                * @brief How many clients this process serves right now
+                * @brief How many client connections this process serves right now
+                *
+                * @note might be greater or equal to num_association_groups.
                 */
-               uint32 num_clients;
+               uint32 num_connections;
        } rpc_worker_status;
 }
index 4e74706fd480e28d15819dfbf12d5169576dc176..92222dd17d4324506cc19babddac30b57ade7175 100644 (file)
@@ -170,7 +170,8 @@ struct rpc_work_process {
         * MSG_RPC_HOST_WORKER_STATUS sent by workers whenever a
         * client exits.
         */
-       uint32_t num_clients;
+       uint32_t num_associations;
+       uint32_t num_connections;
 
        /*
         * Send SHUTDOWN to an idle child after a while
@@ -1177,7 +1178,7 @@ static struct rpc_work_process *rpc_host_find_worker(struct rpc_server *server)
                if (!worker->available) {
                        continue;
                }
-               if (worker->num_clients == 0) {
+               if (worker->num_associations == 0) {
                        /*
                         * We have an idle worker...
                         */
@@ -1191,13 +1192,28 @@ static struct rpc_work_process *rpc_host_find_worker(struct rpc_server *server)
                        best_worker = worker;
                        continue;
                }
-               if (worker->num_clients < best_worker->num_clients) {
+               if (worker->num_associations < best_worker->num_associations) {
                        /*
-                        * It's also busy, but has less clients
+                        * It's also busy, but has less association groups
+                        * (logical clients)
                         */
                        best_worker = worker;
                        continue;
                }
+               if (worker->num_associations > best_worker->num_associations) {
+                       /*
+                        * It's not better
+                        */
+                       continue;
+               }
+               /*
+                * Ok, with the same number of association groups
+                * we pick the one with the lowest number of connections
+                */
+               if (worker->num_connections < best_worker->num_connections) {
+                       best_worker = worker;
+                       continue;
+               }
        }
 
        if (perfect_worker != NULL) {
@@ -1242,7 +1258,7 @@ static struct rpc_work_process *rpc_host_find_idle_worker(
                if (!worker->available) {
                        continue;
                }
-               if (worker->num_clients == 0) {
+               if (worker->num_associations == 0) {
                        return &server->workers[i];
                }
        }
@@ -1374,11 +1390,13 @@ again:
                goto done;
        }
 
-       DBG_INFO("Sending %s client %s to %d with %"PRIu32" clients\n",
+       DBG_INFO("Sending %s client %s to %d with "
+                "%"PRIu32" associations and %"PRIu32" connections\n",
                 client_type,
                 server->rpc_server_exe,
                 worker->pid,
-                worker->num_clients);
+                worker->num_associations,
+                worker->num_connections);
 
        iov = (struct iovec) {
                .iov_base = blob.data, .iov_len = blob.length,
@@ -1404,7 +1422,10 @@ again:
                          nt_errstr(status));
                goto done;
        }
-       worker->num_clients += 1;
+       if (assoc_group_id == 0) {
+               worker->num_associations += 1;
+       }
+       worker->num_connections += 1;
        TALLOC_FREE(worker->exit_timer);
 
        TALLOC_FREE(server->host->np_helper_shutdown);
@@ -1850,7 +1871,7 @@ static void rpc_host_exit_worker(
                }
                w->exit_timer = NULL;
 
-               SMB_ASSERT(w->num_clients == 0);
+               SMB_ASSERT(w->num_associations == 0);
 
                status = messaging_send(
                        server->host->msg_ctx,
@@ -1930,9 +1951,10 @@ static void rpc_host_child_status_recv(
        }
 
        worker->available = true;
-       worker->num_clients = status_message.num_clients;
+       worker->num_associations = status_message.num_association_groups;
+       worker->num_connections = status_message.num_connections;
 
-       if (worker->num_clients != 0) {
+       if (worker->num_associations != 0) {
                TALLOC_FREE(worker->exit_timer);
        } else {
                worker->exit_timer = tevent_add_timer(
@@ -2333,10 +2355,11 @@ static bool rpc_host_dump_status_filter(
                        }
 
                        fprintf(f,
-                               " worker[%zu]: pid=%d, num_clients=%"PRIu32"\n",
+                               " worker[%zu]: pid=%d, num_associations=%"PRIu32", num_connections=%"PRIu32"\n",
                                j,
                                (int)w->pid,
-                               w->num_clients);
+                               w->num_associations,
+                               w->num_connections);
                }
        }
 
index 9a4c33780e792858d6f5c69f4e1a210acea8cba3..e923110940d10fd5dcda0ca47ad29bfcac4367e5 100644 (file)
@@ -95,11 +95,13 @@ static void rpc_worker_print_interface(
 
 static NTSTATUS rpc_worker_report_status(struct rpc_worker *worker)
 {
-       uint8_t buf[12];
+       uint8_t buf[16];
        DATA_BLOB blob = { .data = buf, .length = sizeof(buf), };
        enum ndr_err_code ndr_err;
        NTSTATUS status;
 
+       worker->status.num_association_groups = worker->dce_ctx->assoc_groups_num;
+
        if (DEBUGLEVEL >= 10) {
                NDR_PRINT_DEBUG(rpc_worker_status, &worker->status);
        }
@@ -129,7 +131,19 @@ static void rpc_worker_connection_terminated(
        NTSTATUS status;
        bool found = false;
 
-       SMB_ASSERT(worker->status.num_clients > 0);
+       /*
+        * We need to drop the association group reference
+        * explicitly here in order to avoid the order given
+        * by the destructors. rpc_worker_report_status() below,
+        * expects worker->dce_ctx->assoc_groups_num to be updated
+        * already.
+        */
+       if (conn->assoc_group != NULL) {
+               talloc_unlink(conn, conn->assoc_group);
+               conn->assoc_group = NULL;
+       }
+
+       SMB_ASSERT(worker->status.num_connections > 0);
 
        for (w = worker->conns; w != NULL; w = w->next) {
                if (w == ncacn_conn) {
@@ -141,7 +155,7 @@ static void rpc_worker_connection_terminated(
 
        DLIST_REMOVE(worker->conns, ncacn_conn);
 
-       worker->status.num_clients -= 1;
+       worker->status.num_connections -= 1;
 
        status = rpc_worker_report_status(worker);
        if (!NT_STATUS_IS_OK(status)) {
@@ -467,7 +481,7 @@ static void rpc_worker_new_client(
        TALLOC_FREE(client);
 
        DLIST_ADD(worker->conns, ncacn_conn);
-       worker->status.num_clients += 1;
+       worker->status.num_connections += 1;
 
        dcesrv_loop_next_packet(dcesrv_conn, pkt, buffer);