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;
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) {
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;
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:
}
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);
}
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,
{
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);
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)) {
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;
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))
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;