bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen#include "lib.h"
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen#include "ioloop.h"
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen#include "llist.h"
39d2cc2552e1cf52338c3add7db18a17fdc7b849Timo Sirainen#include "master-service.h"
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen#include "worker-connection.h"
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen#include "worker-pool.h"
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen#define MAX_WORKER_IDLE_SECS (60*5)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenstruct worker_connection_list {
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection_list *prev, *next;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection *conn;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen time_t last_use;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen};
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenstruct worker_pool {
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen char *socket_path;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen indexer_status_callback_t *callback;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen unsigned int connection_count;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection_list *busy_list, *idle_list;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen};
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenstatic void
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainenworker_connection_list_free(struct worker_pool *pool,
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen struct worker_connection_list *list);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenstruct worker_pool *
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenworker_pool_init(const char *socket_path, indexer_status_callback_t *callback)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen{
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_pool *pool;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen pool = i_new(struct worker_pool, 1);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen pool->socket_path = i_strdup(socket_path);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen pool->callback = callback;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen return pool;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen}
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenvoid worker_pool_deinit(struct worker_pool **_pool)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen{
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_pool *pool = *_pool;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen *_pool = NULL;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen while (pool->busy_list != NULL) {
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection_list *list = pool->busy_list;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen DLLIST_REMOVE(&pool->busy_list, list);
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen worker_connection_list_free(pool, list);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen }
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen while (pool->idle_list != NULL) {
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection_list *list = pool->idle_list;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen DLLIST_REMOVE(&pool->idle_list, list);
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen worker_connection_list_free(pool, list);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen }
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen i_free(pool->socket_path);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen i_free(pool);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen}
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
df26373d0aa3cb208da213fce32e2abc5d97f90bTimo Sirainenbool worker_pool_have_busy_connections(struct worker_pool *pool)
df26373d0aa3cb208da213fce32e2abc5d97f90bTimo Sirainen{
df26373d0aa3cb208da213fce32e2abc5d97f90bTimo Sirainen return pool->busy_list != NULL;
df26373d0aa3cb208da213fce32e2abc5d97f90bTimo Sirainen}
df26373d0aa3cb208da213fce32e2abc5d97f90bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenstatic int worker_pool_add_connection(struct worker_pool *pool)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen{
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection *conn;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection_list *list;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen conn = worker_connection_create(pool->socket_path, pool->callback);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen if (worker_connection_connect(conn) < 0) {
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen worker_connection_destroy(&conn);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen return -1;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen }
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen i_assert(pool->idle_list == NULL);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen list = i_new(struct worker_connection_list, 1);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen list->conn = conn;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen list->last_use = ioloop_time;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen pool->idle_list = list;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen pool->connection_count++;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen return 0;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen}
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenstatic void
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainenworker_connection_list_free(struct worker_pool *pool,
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen struct worker_connection_list *list)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen{
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen i_assert(pool->connection_count > 0);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen pool->connection_count--;
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen worker_connection_destroy(&list->conn);
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen i_free(list);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen}
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenstatic unsigned int worker_pool_find_max_connections(struct worker_pool *pool)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen{
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection_list *list;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen unsigned int limit;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen i_assert(pool->idle_list == NULL);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen if (pool->busy_list == NULL)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen return 1;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen for (list = pool->busy_list; list != NULL; list = list->next) {
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen if (worker_connection_get_process_limit(list->conn, &limit))
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen return limit;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen }
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen /* we have at least one connection that has already been created,
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen but without having handshaked yet. wait until it's finished. */
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen return 0;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen}
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenbool worker_pool_get_connection(struct worker_pool *pool,
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection **conn_r)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen{
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection_list *list;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen unsigned int max_connections;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen while (pool->idle_list != NULL &&
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen !worker_connection_is_connected(pool->idle_list->conn)) {
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen list = pool->idle_list;
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen DLLIST_REMOVE(&pool->idle_list, list);
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen worker_connection_list_free(pool, list);
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen }
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen if (pool->idle_list == NULL) {
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen max_connections = worker_pool_find_max_connections(pool);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen if (pool->connection_count >= max_connections)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen return FALSE;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen if (worker_pool_add_connection(pool) < 0)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen return FALSE;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen i_assert(pool->idle_list != NULL);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen }
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen list = pool->idle_list;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen DLLIST_REMOVE(&pool->idle_list, list);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen DLLIST_PREPEND(&pool->busy_list, list);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen *conn_r = list->conn;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen return TRUE;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen}
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenstatic void worker_pool_kill_idle_connections(struct worker_pool *pool)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen{
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection_list *list, *next;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen time_t kill_timestamp;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen kill_timestamp = ioloop_time - MAX_WORKER_IDLE_SECS;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen for (list = pool->idle_list; list != NULL; list = next) {
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen next = list->next;
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen if (list->last_use < kill_timestamp) {
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen DLLIST_REMOVE(&pool->idle_list, list);
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen worker_connection_list_free(pool, list);
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen }
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen }
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen}
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenvoid worker_pool_release_connection(struct worker_pool *pool,
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection *conn)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen{
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection_list *list;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen if (worker_connection_is_busy(conn)) {
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen /* not finished with all queued requests yet */
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen return;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen }
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen for (list = pool->busy_list; list != NULL; list = list->next) {
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen if (list->conn == conn)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen break;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen }
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen i_assert(list != NULL);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen DLLIST_REMOVE(&pool->busy_list, list);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen if (!worker_connection_is_connected(conn))
6f7b4a6773eee7216c1afdc808c3cfdc92ac1b40Timo Sirainen worker_connection_list_free(pool, list);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen else {
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen DLLIST_PREPEND(&pool->idle_list, list);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen list->last_use = ioloop_time;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen worker_pool_kill_idle_connections(pool);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen }
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen}
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenstruct worker_connection *
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainenworker_pool_find_username_connection(struct worker_pool *pool,
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen const char *username)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen{
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen struct worker_connection_list *list;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen const char *worker_user;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen for (list = pool->busy_list; list != NULL; list = list->next) {
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen worker_user = worker_connection_get_username(list->conn);
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen if (worker_user != NULL && strcmp(worker_user, username) == 0)
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen return list->conn;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen }
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen return NULL;
d9e404180ff26dbbaea68534a5f176765022b76bTimo Sirainen}