]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm: Change per-server command request queue to be global
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Fri, 30 Jul 2021 12:04:58 +0000 (15:04 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Mon, 17 Jan 2022 11:52:09 +0000 (13:52 +0200)
The queue behavior isn't quite as efficient as it could be in this commit,
but that will be fixed by the following commit.

src/doveadm/doveadm-dsync.c
src/doveadm/doveadm-mail-server.c
src/doveadm/doveadm-server.h

index 84b6c122dfc6bc8b8e87e812cb9da6361f5d09c5..1fb1dea54cd53d7e7de616622fe115ca59309a85 100644 (file)
@@ -926,7 +926,6 @@ dsync_connect_tcp(struct dsync_cmd_context *ctx,
                                    ctx->ctx.set->doveadm_username);
        server->password = p_strdup(ctx->ctx.pool,
                                    ctx->ctx.set->doveadm_password);
-       p_array_init(&server->queue, ctx->ctx.pool, 1);
 
        prev_ioloop = current_ioloop;
        ioloop = io_loop_create();
index ecfcb96d647a85f657efbcd9d84e8cb7394174d6..ee73c0536b3c5477b30ba44e2102fd6dfff5aeaf 100644 (file)
@@ -44,17 +44,29 @@ struct doveadm_mail_server_cmd {
        bool streaming;
 };
 
+struct doveadm_server_request {
+       struct doveadm_server *server;
+       char *username;
+};
+
 static HASH_TABLE(char *, struct doveadm_server *) servers;
 static pool_t server_pool;
 static struct doveadm_mail_cmd_context *cmd_ctx;
 static bool internal_failure = FALSE;
+static ARRAY(struct doveadm_server_request) doveadm_server_request_queue;
 
+static struct doveadm_server *doveadm_server_find_used(void);
 static void doveadm_cmd_callback(const struct doveadm_server_reply *reply,
                                 void *context);
 static void doveadm_mail_server_handle(struct doveadm_server *server,
                                       struct server_connection *conn,
                                       const char *username);
 
+static void doveadm_server_request_free(struct doveadm_server_request *request)
+{
+       i_free(request->username);
+}
+
 static struct doveadm_server *doveadm_server_get(const char *name)
 {
        struct doveadm_server *server;
@@ -64,6 +76,10 @@ static struct doveadm_server *doveadm_server_get(const char *name)
        if (!hash_table_is_created(servers)) {
                server_pool = pool_alloconly_create("doveadm servers", 1024*16);
                hash_table_create(&servers, server_pool, 0, str_hash, strcmp);
+
+               i_assert(!array_is_created(&doveadm_server_request_queue));
+               i_array_init(&doveadm_server_request_queue,
+                            DOVEADM_SERVER_QUEUE_MAX);
        }
        server = hash_table_lookup(servers, name);
        if (server == NULL) {
@@ -77,8 +93,6 @@ static struct doveadm_server *doveadm_server_get(const char *name)
                server->hostname = p == NULL ? server->name :
                        p_strdup_until(server_pool, server->name, p);
 
-               p_array_init(&server->queue, server_pool,
-                            DOVEADM_SERVER_QUEUE_MAX);
                hash_table_insert(servers, dup_name, server);
        }
        return server;
@@ -425,6 +439,7 @@ static void doveadm_cmd_callback(const struct doveadm_server_reply *reply,
        struct doveadm_mail_server_cmd *servercmd = context;
        struct server_connection *conn = servercmd->conn;
        struct doveadm_server *server = servercmd->server;
+       struct doveadm_server_request *request;
 
        switch (reply->exit_code) {
        case 0:
@@ -457,15 +472,23 @@ static void doveadm_cmd_callback(const struct doveadm_server_reply *reply,
        }
        doveadm_mail_server_cmd_free(&servercmd);
 
-       if (array_count(&server->queue) > 0) {
-               char *const *usernamep = array_front(&server->queue);
-               char *username = *usernamep;
+       /* See if there are any more requests queued for this same server.
+          If we can continue it here, we can reuse the same doveadm
+          connection. */
+       array_foreach_modifiable(&doveadm_server_request_queue, request) {
+               if (request->server == server) {
+                       struct doveadm_server_request request_copy = *request;
+                       unsigned int idx =
+                               array_foreach_idx(&doveadm_server_request_queue,
+                                                 request);
+                       array_delete(&doveadm_server_request_queue, idx, 1);
 
-               array_pop_front(&server->queue);
-               doveadm_mail_server_handle(server, conn, username);
-               i_free(username);
+                       doveadm_mail_server_handle(server, conn,
+                                                  request_copy.username);
+                       doveadm_server_request_free(&request_copy);
+                       break;
+               }
        }
-
        io_loop_stop(current_ioloop);
 }
 
@@ -510,17 +533,34 @@ static void doveadm_mail_server_handle(struct doveadm_server *server,
                              doveadm_cmd_callback, servercmd);
 }
 
-static void doveadm_server_flush_one(struct doveadm_server *server)
+static void
+doveadm_server_flush_one(struct doveadm_server *server)
 {
-       unsigned int count = array_count(&server->queue);
-
        do {
                io_loop_run(current_ioloop);
-       } while (array_count(&server->queue) == count &&
-                doveadm_server_have_used_connections(server) &&
+       } while (doveadm_server_have_used_connections(server) &&
                 !DOVEADM_MAIL_SERVER_FAILED());
 }
 
+static int doveadm_mail_server_request_queue_handle_next(const char **error_r)
+{
+       struct doveadm_server_request *request, request_copy;
+       struct server_connection *conn;
+
+       request = array_front_modifiable(&doveadm_server_request_queue);
+       request_copy = *request;
+       array_pop_front(&doveadm_server_request_queue);
+
+       if (server_connection_create(request_copy.server, &conn, error_r) < 0) {
+               internal_failure = TRUE;
+               return -1;
+       }
+       doveadm_mail_server_handle(request_copy.server, conn,
+                                  request_copy.username);
+       doveadm_server_request_free(&request_copy);
+       return 0;
+}
+
 static int
 doveadm_mail_server_user_get_host(struct doveadm_mail_cmd_context *ctx,
                                  struct auth_proxy_settings *proxy_set_r,
@@ -605,9 +645,9 @@ int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx,
 {
        struct doveadm_server *server;
        struct server_connection *conn;
+       struct doveadm_server_request *request;
        struct auth_proxy_settings proxy_set;
        const char *server_name, *socket_path, *referral;
-       char *username_dup;
        int ret;
 
        i_assert(cmd_ctx == ctx || cmd_ctx == NULL);
@@ -646,6 +686,21 @@ int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx,
        server->ip = proxy_set.host_ip;
        server->ssl_flags = proxy_set.ssl_flags;
        server->port = proxy_set.port;
+
+       if (array_count(&doveadm_server_request_queue) >= DOVEADM_SERVER_QUEUE_MAX) {
+               /* flush one request */
+               struct doveadm_server *pending_server =
+                       doveadm_server_find_used();
+               i_assert(pending_server != NULL);
+               doveadm_server_flush_one(pending_server);
+               /* The flush may or may not have eaten a request from the
+                  queue. If not, there's room for one new connection. */
+               if (array_count(&doveadm_server_request_queue) >= DOVEADM_SERVER_QUEUE_MAX) {
+                       if (doveadm_mail_server_request_queue_handle_next(error_r) < 0)
+                               return -1;
+               }
+       }
+
        if (server->connections == NULL ||
            server->connections->connections_count <
                        I_MAX(ctx->set->doveadm_worker_count, 1)) {
@@ -657,11 +712,9 @@ int doveadm_mail_server_user(struct doveadm_mail_cmd_context *ctx,
                                                   proxy_set.username);
                }
        } else {
-               if (array_count(&server->queue) >= DOVEADM_SERVER_QUEUE_MAX)
-                       doveadm_server_flush_one(server);
-
-               username_dup = i_strdup(proxy_set.username);
-               array_push_back(&server->queue, &username_dup);
+               request = array_append_space(&doveadm_server_request_queue);
+               request->username = i_strdup(proxy_set.username);
+               request->server = server;
        }
        *error_r = "doveadm server failure";
        return DOVEADM_MAIL_SERVER_FAILED() ? -1 : 1;
@@ -702,15 +755,28 @@ static void doveadm_servers_destroy_all_connections(void)
 void doveadm_mail_server_flush(void)
 {
        struct doveadm_server *server;
+       struct doveadm_server_request *request;
+       const char *error;
 
        if (!hash_table_is_created(servers)) {
                cmd_ctx = NULL;
                return;
        }
 
-       while ((server = doveadm_server_find_used()) != NULL &&
-              !DOVEADM_MAIL_SERVER_FAILED())
-               doveadm_server_flush_one(server);
+       while (!DOVEADM_MAIL_SERVER_FAILED()) {
+               server = doveadm_server_find_used();
+               if (server != NULL) {
+                       doveadm_server_flush_one(server);
+                       continue;
+               }
+
+               if (array_count(&doveadm_server_request_queue) == 0)
+                       break;
+               if (doveadm_mail_server_request_queue_handle_next(&error) < 0) {
+                       i_error("%s", error);
+                       break;
+               }
+       }
 
        doveadm_servers_destroy_all_connections();
        if (master_service_is_killed(master_service))
@@ -718,6 +784,10 @@ void doveadm_mail_server_flush(void)
        if (DOVEADM_MAIL_SERVER_FAILED())
                doveadm_mail_failed_error(cmd_ctx, MAIL_ERROR_TEMP);
 
+       /* queue may not be empty if something failed */
+       array_foreach_modifiable(&doveadm_server_request_queue, request)
+               doveadm_server_request_free(request);
+       array_free(&doveadm_server_request_queue);
        hash_table_destroy(&servers);
        pool_unref(&server_pool);
        cmd_ctx = NULL;
index 5f41bb1ad58ec75ab920c948ea42f2410fe38209..0bc07c3c40f76fdd231dd544e21e2eb3cd9deb91 100644 (file)
@@ -24,7 +24,6 @@ struct doveadm_server {
        struct ssl_iostream_context *ssl_ctx;
 
        struct connection_list *connections;
-       ARRAY_TYPE(string) queue;
 };
 
 #endif