From: Timo Sirainen Date: Fri, 30 Jul 2021 12:04:58 +0000 (+0300) Subject: doveadm: Change per-server command request queue to be global X-Git-Tag: 2.4.0~4765 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7dcde3b9221a591fa4827c2c8ea918cbc33030ea;p=thirdparty%2Fdovecot%2Fcore.git doveadm: Change per-server command request queue to be global The queue behavior isn't quite as efficient as it could be in this commit, but that will be fixed by the following commit. --- diff --git a/src/doveadm/doveadm-dsync.c b/src/doveadm/doveadm-dsync.c index 84b6c122df..1fb1dea54c 100644 --- a/src/doveadm/doveadm-dsync.c +++ b/src/doveadm/doveadm-dsync.c @@ -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(); diff --git a/src/doveadm/doveadm-mail-server.c b/src/doveadm/doveadm-mail-server.c index ecfcb96d64..ee73c0536b 100644 --- a/src/doveadm/doveadm-mail-server.c +++ b/src/doveadm/doveadm-mail-server.c @@ -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; diff --git a/src/doveadm/doveadm-server.h b/src/doveadm/doveadm-server.h index 5f41bb1ad5..0bc07c3c40 100644 --- a/src/doveadm/doveadm-server.h +++ b/src/doveadm/doveadm-server.h @@ -24,7 +24,6 @@ struct doveadm_server { struct ssl_iostream_context *ssl_ctx; struct connection_list *connections; - ARRAY_TYPE(string) queue; }; #endif