bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen#include "lib.h"
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen#include "array.h"
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen#include "llist.h"
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen#include "ioloop.h"
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen#include "sql-api-private.h"
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen#include <time.h>
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen#define QUERY_TIMEOUT_SECS 6
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstruct sqlpool_host {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen char *connect_string;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int connection_count;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen};
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstruct sqlpool_connection {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_db *db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int host_idx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen};
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstruct sqlpool_db {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_db api;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen pool_t pool;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sql_db *driver;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int connection_limit;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct sqlpool_host) hosts;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* all connections from all hosts */
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct sqlpool_connection) all_connections;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* index of last connection in all_connections that was used to
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen send a query. */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int last_query_conn_idx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* queued requests */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_request *requests_head, *requests_tail;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct timeout *request_to;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen};
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstruct sqlpool_request {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_request *prev, *next;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_db *db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen time_t created;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int host_idx;
cc4087c4d7b1b6188dc731e783cee361f1e9c185Timo Sirainen unsigned int retry_count;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* requests are a) queries */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen char *query;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sql_query_callback_t *callback;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen void *context;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* b) transaction waiters */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_transaction_context *trans;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen};
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstruct sqlpool_transaction_context {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_transaction_context ctx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sql_commit_callback_t *callback;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen void *context;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen pool_t query_pool;
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen struct sqlpool_request *commit_request;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen};
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenextern struct sql_db driver_sqlpool_db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainenstatic struct sqlpool_connection *
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainensqlpool_add_connection(struct sqlpool_db *db, struct sqlpool_host *host,
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen unsigned int host_idx);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_query_callback(struct sql_result *result,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_request *request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainendriver_sqlpool_commit_callback(const struct sql_commit_result *result,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_transaction_context *ctx);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic struct sqlpool_request * ATTR_NULL(2)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainensqlpool_request_new(struct sqlpool_db *db, const char *query)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_request *request;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request = i_new(struct sqlpool_request, 1);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->db = db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->created = time(NULL);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->query = i_strdup(query);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return request;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainensqlpool_request_free(struct sqlpool_request **_request)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_request *request = *_request;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *_request = NULL;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_assert(request->prev == NULL && request->next == NULL);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_free(request->query);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_free(request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainensqlpool_request_abort(struct sqlpool_request **_request)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_request *request = *_request;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *_request = NULL;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (request->callback != NULL)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->callback(&sql_not_connected_result, request->context);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_assert(request->prev != NULL ||
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->db->requests_head == request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen DLLIST2_REMOVE(&request->db->requests_head,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen &request->db->requests_tail, request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sqlpool_request_free(&request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainenstatic struct sql_transaction_context *
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_new_conn_trans(struct sqlpool_transaction_context *trans,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_db *conndb)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen struct sql_transaction_context *conn_trans;
191eb75dd8c688dc1669492b842233decaf9caccTimo Sirainen struct sql_transaction_query *query;
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen conn_trans = sql_transaction_begin(conndb);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* backend will use our queries list (we might still append more
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen queries to the list) */
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen conn_trans->head = trans->ctx.head;
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen conn_trans->tail = trans->ctx.tail;
191eb75dd8c688dc1669492b842233decaf9caccTimo Sirainen for (query = conn_trans->head; query != NULL; query = query->next)
191eb75dd8c688dc1669492b842233decaf9caccTimo Sirainen query->trans = conn_trans;
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen return conn_trans;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainensqlpool_request_handle_transaction(struct sql_db *conndb,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_transaction_context *trans)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen struct sql_transaction_context *conn_trans;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sqlpool_request_free(&trans->commit_request);
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen conn_trans = driver_sqlpool_new_conn_trans(trans, conndb);
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen sql_transaction_commit(&conn_trans,
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen driver_sqlpool_commit_callback, trans);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainensqlpool_request_send_next(struct sqlpool_db *db, struct sql_db *conndb)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_request *request;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->requests_head == NULL || !SQL_DB_IS_READY(conndb))
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request = db->requests_head;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen DLLIST2_REMOVE(&db->requests_head, &db->requests_tail, request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen timeout_reset(db->request_to);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (request->query != NULL) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sql_query(conndb, request->query,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_query_callback, request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen } else if (request->trans != NULL) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sqlpool_request_handle_transaction(conndb, request->trans);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen } else {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_unreached();
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void sqlpool_reconnect(struct sql_db *conndb)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen timeout_remove(&conndb->to_reconnect);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen (void)sql_connect(conndb);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic struct sqlpool_host *
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainensqlpool_find_host_with_least_connections(struct sqlpool_db *db,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int *host_idx_r)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_host *hosts, *min = NULL;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int i, count;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen hosts = array_get_modifiable(&db->hosts, &count);
902acc26200957a1f04da3cc947211f0b9ffce05Timo Sirainen i_assert(count > 0);
902acc26200957a1f04da3cc947211f0b9ffce05Timo Sirainen
902acc26200957a1f04da3cc947211f0b9ffce05Timo Sirainen min = &hosts[0];
902acc26200957a1f04da3cc947211f0b9ffce05Timo Sirainen *host_idx_r = 0;
902acc26200957a1f04da3cc947211f0b9ffce05Timo Sirainen
902acc26200957a1f04da3cc947211f0b9ffce05Timo Sirainen for (i = 1; i < count; i++) {
902acc26200957a1f04da3cc947211f0b9ffce05Timo Sirainen if (min->connection_count > hosts[i].connection_count) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen min = &hosts[i];
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *host_idx_r = i;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return min;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainenstatic bool sqlpool_have_successful_connections(struct sqlpool_db *db)
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen{
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen const struct sqlpool_connection *conn;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen array_foreach(&db->all_connections, conn) {
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen if (conn->db->state >= SQL_DB_STATE_IDLE)
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen return TRUE;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen }
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen return FALSE;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen}
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainenstatic void
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainensqlpool_handle_connect_failed(struct sqlpool_db *db, struct sql_db *conndb)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_host *host;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int host_idx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen if (conndb->connect_failure_count > 0) {
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen /* increase delay between reconnections to this
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen server */
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen conndb->connect_delay *= 5;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen if (conndb->connect_delay > SQL_CONNECT_MAX_DELAY)
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen conndb->connect_delay = SQL_CONNECT_MAX_DELAY;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen }
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen conndb->connect_failure_count++;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen /* reconnect after the delay */
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&conndb->to_reconnect);
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen conndb->to_reconnect = timeout_add(conndb->connect_delay * 1000,
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen sqlpool_reconnect, conndb);
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen /* if we have zero successful hosts and there still are hosts
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen without connections, connect to one of them. */
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen if (!sqlpool_have_successful_connections(db)) {
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen host = sqlpool_find_host_with_least_connections(db, &host_idx);
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen if (host->connection_count == 0)
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen (void)sqlpool_add_connection(db, host, host_idx);
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen }
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen}
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainenstatic void
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainensqlpool_state_changed(struct sql_db *conndb, enum sql_db_state prev_state,
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen void *context)
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen{
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen struct sqlpool_db *db = context;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen if (conndb->state == SQL_DB_STATE_IDLE) {
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen conndb->connect_failure_count = 0;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen conndb->connect_delay = SQL_CONNECT_MIN_DELAY;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen sqlpool_request_send_next(db, conndb);
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen }
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen if (prev_state == SQL_DB_STATE_CONNECTING &&
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen conndb->state == SQL_DB_STATE_DISCONNECTED &&
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen !conndb->no_reconnect)
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen sqlpool_handle_connect_failed(db, conndb);
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen}
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainenstatic struct sqlpool_connection *
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainensqlpool_add_connection(struct sqlpool_db *db, struct sqlpool_host *host,
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen unsigned int host_idx)
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen{
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen struct sql_db *conndb;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen struct sqlpool_connection *conn;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen host->connection_count++;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conndb = db->driver->v.init(host->connect_string);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_array_init(&conndb->module_contexts, 5);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conndb->state_change_callback = sqlpool_state_changed;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conndb->state_change_context = db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conndb->connect_delay = SQL_CONNECT_MIN_DELAY;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conn = array_append_space(&db->all_connections);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conn->host_idx = host_idx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conn->db = conndb;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return conn;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainenstatic struct sqlpool_connection *
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainensqlpool_add_new_connection(struct sqlpool_db *db)
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen{
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen struct sqlpool_host *host;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen unsigned int host_idx;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen host = sqlpool_find_host_with_least_connections(db, &host_idx);
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen if (host->connection_count >= db->connection_limit)
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen return NULL;
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen else
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen return sqlpool_add_connection(db, host, host_idx);
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen}
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic const struct sqlpool_connection *
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainensqlpool_find_available_connection(struct sqlpool_db *db,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int unwanted_host_idx,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen bool *all_disconnected_r)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sqlpool_connection *conns;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int i, count;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *all_disconnected_r = TRUE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conns = array_get(&db->all_connections, &count);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen for (i = 0; i < count; i++) {
35de8ec2dbdb8d772593289093e4244c88aef94cTimo Sirainen unsigned int idx = (i + db->last_query_conn_idx + 1) % count;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_db *conndb = conns[idx].db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (conns[idx].host_idx == unwanted_host_idx)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen continue;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
bbac309a80df5ca3cc656b08905f53b3d45c3914Timo Sirainen if (!SQL_DB_IS_READY(conndb) && conndb->to_reconnect == NULL) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* see if we could reconnect to it immediately */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen (void)sql_connect(conndb);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (SQL_DB_IS_READY(conndb)) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->last_query_conn_idx = idx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *all_disconnected_r = FALSE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return &conns[idx];
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (conndb->state != SQL_DB_STATE_DISCONNECTED)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *all_disconnected_r = FALSE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return NULL;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic bool
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_get_connection(struct sqlpool_db *db,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int unwanted_host_idx,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sqlpool_connection **conn_r)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sqlpool_connection *conn, *conns;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int i, count;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen bool all_disconnected;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conn = sqlpool_find_available_connection(db, unwanted_host_idx,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen &all_disconnected);
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (conn == NULL && unwanted_host_idx != UINT_MAX) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* maybe there are no wanted hosts. use any of them. */
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen conn = sqlpool_find_available_connection(db, UINT_MAX,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen &all_disconnected);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (conn == NULL && all_disconnected) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* no connected connections. connect_delays may have gotten too
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen high, reset all of them to see if some are still alive. */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conns = array_get(&db->all_connections, &count);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen for (i = 0; i < count; i++) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_db *conndb = conns[i].db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (conndb->connect_delay > SQL_CONNECT_RESET_DELAY)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conndb->connect_delay = SQL_CONNECT_RESET_DELAY;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen conn = sqlpool_find_available_connection(db, UINT_MAX,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen &all_disconnected);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (conn == NULL) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* still nothing. try creating new connections */
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen conn = sqlpool_add_new_connection(db);
2a70702978902669803cf8c7eed287cb006d2c48Timo Sirainen if (conn != NULL)
2a70702978902669803cf8c7eed287cb006d2c48Timo Sirainen (void)sql_connect(conn->db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (conn == NULL || !SQL_DB_IS_READY(conn->db))
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return FALSE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *conn_r = conn;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return TRUE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic bool
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_get_sync_connection(struct sqlpool_db *db,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sqlpool_connection **conn_r)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sqlpool_connection *conns;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int i, count;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (driver_sqlpool_get_connection(db, UINT_MAX, conn_r))
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return TRUE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* no idling connections, but maybe we can find one that's trying to
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen connect to server, and we can use it once it's finished */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conns = array_get(&db->all_connections, &count);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen for (i = 0; i < count; i++) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (conns[i].db->state == SQL_DB_STATE_CONNECTING) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *conn_r = &conns[i];
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return TRUE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return FALSE;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_parse_hosts(struct sqlpool_db *db, const char *connect_string)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const char *const *args, *key, *value, *const *hostnamep;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_host *host;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ARRAY_TYPE(const_string) hostnames, connect_args;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen t_array_init(&hostnames, 8);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen t_array_init(&connect_args, 32);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* connect string is a space separated list. it may contain
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen backend-specific strings which we'll pass as-is. we'll only care
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen about our own settings, plus the host settings. */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen args = t_strsplit_spaces(connect_string, " ");
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen for (; *args != NULL; args++) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen value = strchr(*args, '=');
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (value == NULL) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen key = *args;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen value = "";
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen } else {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen key = t_strdup_until(*args, value);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen value++;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (strcmp(key, "maxconns") == 0) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (str_to_uint(value, &db->connection_limit) < 0) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_fatal("Invalid value for maxconns: %s",
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen value);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen } else if (strcmp(key, "host") == 0) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_append(&hostnames, &value, 1);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen } else {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_append(&connect_args, args, 1);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* build a new connect string without our settings or hosts */
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&connect_args);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen connect_string = t_strarray_join(array_idx(&connect_args, 0), " ");
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (array_count(&hostnames) == 0) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* no hosts specified. create a default one. */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen host = array_append_space(&db->hosts);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen host->connect_string = i_strdup(connect_string);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen } else {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (*connect_string == '\0')
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen connect_string = NULL;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_foreach(&hostnames, hostnamep) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen host = array_append_space(&db->hosts);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen host->connect_string =
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_strconcat("host=", *hostnamep, " ",
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen connect_string, NULL);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->connection_limit == 0)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->connection_limit = SQL_DEFAULT_CONNECTION_LIMIT;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainenstatic void sqlpool_add_all_once(struct sqlpool_db *db)
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen{
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen struct sqlpool_host *host;
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen unsigned int host_idx;
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen for (;;) {
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen host = sqlpool_find_host_with_least_connections(db, &host_idx);
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen if (host->connection_count > 0)
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen break;
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen (void)sqlpool_add_connection(db, host, host_idx);
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen }
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen}
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstruct sql_db *
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_init(const char *connect_string, const struct sql_db *driver)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_db *db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_assert(connect_string != NULL);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db = i_new(struct sqlpool_db, 1);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->driver = driver;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->api = driver_sqlpool_db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->api.flags = driver->flags;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_array_init(&db->hosts, 8);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen T_BEGIN {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_parse_hosts(db, connect_string);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen } T_END;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_array_init(&db->all_connections, 16);
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen /* connect to all databases so we can do load balancing immediately */
bf17de7e2a802ec596150125d1acccbdb19f45d0Timo Sirainen sqlpool_add_all_once(db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return &db->api;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainenstatic void driver_sqlpool_abort_requests(struct sqlpool_db *db)
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen{
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen while (db->requests_head != NULL) {
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen struct sqlpool_request *request = db->requests_head;
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen sqlpool_request_abort(&request);
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen }
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&db->request_to);
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen}
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void driver_sqlpool_deinit(struct sql_db *_db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_host *host;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_connection *conn;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_foreach_modifiable(&db->all_connections, conn)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sql_deinit(&conn->db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_clear(&db->all_connections);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen driver_sqlpool_abort_requests(db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_foreach_modifiable(&db->hosts, host)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_free(host->connect_string);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_assert(array_count(&db->all_connections) == 0);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_free(&db->hosts);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_free(&db->all_connections);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_free(&_db->module_contexts);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_free(db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic int driver_sqlpool_connect(struct sql_db *_db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sqlpool_connection *conn;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen int ret = -1, ret2;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_foreach(&db->all_connections, conn) {
bbac309a80df5ca3cc656b08905f53b3d45c3914Timo Sirainen ret2 = conn->db->to_reconnect != NULL ? -1 :
bbac309a80df5ca3cc656b08905f53b3d45c3914Timo Sirainen sql_connect(conn->db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (ret2 > 0)
35de8ec2dbdb8d772593289093e4244c88aef94cTimo Sirainen ret = 1;
35de8ec2dbdb8d772593289093e4244c88aef94cTimo Sirainen else if (ret2 == 0 && ret < 0)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ret = 0;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return ret;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void driver_sqlpool_disconnect(struct sql_db *_db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sqlpool_connection *conn;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen array_foreach(&db->all_connections, conn)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sql_disconnect(conn->db);
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen driver_sqlpool_abort_requests(db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic const char *
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_escape_string(struct sql_db *_db, const char *string)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
2d20d46069fa0d4b98790779552dd778d1749d1cTimo Sirainen const struct sqlpool_connection *conns;
2d20d46069fa0d4b98790779552dd778d1749d1cTimo Sirainen unsigned int i, count;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
2d20d46069fa0d4b98790779552dd778d1749d1cTimo Sirainen /* use the first ready connection */
2d20d46069fa0d4b98790779552dd778d1749d1cTimo Sirainen conns = array_get(&db->all_connections, &count);
2d20d46069fa0d4b98790779552dd778d1749d1cTimo Sirainen for (i = 0; i < count; i++) {
2d20d46069fa0d4b98790779552dd778d1749d1cTimo Sirainen if (SQL_DB_IS_READY(conns[i].db))
2d20d46069fa0d4b98790779552dd778d1749d1cTimo Sirainen return sql_escape_string(conns[i].db, string);
2d20d46069fa0d4b98790779552dd778d1749d1cTimo Sirainen }
2d20d46069fa0d4b98790779552dd778d1749d1cTimo Sirainen /* no ready connections. just use the first one (we're guaranteed
2d20d46069fa0d4b98790779552dd778d1749d1cTimo Sirainen to always have one) */
2d20d46069fa0d4b98790779552dd778d1749d1cTimo Sirainen return sql_escape_string(conns[0].db, string);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void driver_sqlpool_timeout(struct sqlpool_db *db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen while (db->requests_head != NULL) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_request *request = db->requests_head;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (request->created + SQL_QUERY_TIMEOUT_SECS > ioloop_time)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen break;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_error("%s: Query timed out "
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen "(no free connections for %u secs): %s",
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->driver->name,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen (unsigned int)(ioloop_time - request->created),
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->query != NULL ? request->query :
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen "<transaction>");
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sqlpool_request_abort(&request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->requests_head == NULL)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen timeout_remove(&db->request_to);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_prepend_request(struct sqlpool_db *db,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_request *request)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen DLLIST2_PREPEND(&db->requests_head, &db->requests_tail, request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->request_to == NULL) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->request_to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_timeout, db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_append_request(struct sqlpool_db *db,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_request *request)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen DLLIST2_APPEND(&db->requests_head, &db->requests_tail, request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (db->request_to == NULL) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->request_to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_timeout, db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_query_callback(struct sql_result *result,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_request *request)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_db *db = request->db;
cc4087c4d7b1b6188dc731e783cee361f1e9c185Timo Sirainen const struct sqlpool_connection *conn = NULL;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_db *conndb;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
cc4087c4d7b1b6188dc731e783cee361f1e9c185Timo Sirainen if (result->failed_try_retry &&
cc4087c4d7b1b6188dc731e783cee361f1e9c185Timo Sirainen request->retry_count < array_count(&db->hosts)) {
dd7abc30ee4f7f5321e65bea93b2b0b409ac53f2Timo Sirainen i_warning("%s: Query failed, retrying: %s",
dd7abc30ee4f7f5321e65bea93b2b0b409ac53f2Timo Sirainen db->driver->name, sql_result_get_error(result));
cc4087c4d7b1b6188dc731e783cee361f1e9c185Timo Sirainen request->retry_count++;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_prepend_request(db, request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (driver_sqlpool_get_connection(request->db,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->host_idx, &conn)) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->host_idx = conn->host_idx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sqlpool_request_send_next(db, conn->db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen } else {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (result->failed) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_error("%s: Query failed, aborting: %s",
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->driver->name, request->query);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conndb = result->db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (request->callback != NULL)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->callback(result, request->context);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sqlpool_request_free(&request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sqlpool_request_send_next(db, conndb);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic void ATTR_NULL(3, 4)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainendriver_sqlpool_query(struct sql_db *_db, const char *query,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen sql_query_callback_t *callback, void *context)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_request *request;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sqlpool_connection *conn;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request = sqlpool_request_new(db, query);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->callback = callback;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->context = context;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (!driver_sqlpool_get_connection(db, UINT_MAX, &conn))
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_append_request(db, request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen else {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->host_idx = conn->host_idx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sql_query(conn->db, query, driver_sqlpool_query_callback,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void driver_sqlpool_exec(struct sql_db *_db, const char *query)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_query(_db, query, NULL, NULL);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic struct sql_result *
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_query_s(struct sql_db *_db, const char *query)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sqlpool_connection *conn;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_result *result;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (!driver_sqlpool_get_sync_connection(db, &conn)) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sql_not_connected_result.refcount++;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return &sql_not_connected_result;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen result = sql_query_s(conn->db, query);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (result->failed_try_retry) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (!driver_sqlpool_get_sync_connection(db, &conn))
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return result;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sql_result_unref(result);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen result = sql_query_s(conn->db, query);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return result;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic struct sql_transaction_context *
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_transaction_begin(struct sql_db *_db)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_transaction_context *ctx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ctx = i_new(struct sqlpool_transaction_context, 1);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ctx->ctx.db = _db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen /* queue changes until commit. even if we did have a free connection
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen now, don't use it or multiple open transactions could tie up all
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen connections. */
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen ctx->query_pool = pool_alloconly_create("sqlpool transaction", 1024);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return &ctx->ctx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_transaction_free(struct sqlpool_transaction_context *ctx)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (ctx->commit_request != NULL)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sqlpool_request_abort(&ctx->commit_request);
c69a177207ed18d0f0210347430a60957136bd6cJosef 'Jeff' Sipek pool_unref(&ctx->query_pool);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_free(ctx);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainendriver_sqlpool_commit_callback(const struct sql_commit_result *result,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_transaction_context *ctx)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
bb2b3656ef7635acc374f7fc19b25aeeb454ae95Timo Sirainen ctx->callback(result, ctx->context);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_transaction_free(ctx);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_transaction_commit(struct sql_transaction_context *_ctx,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen sql_commit_callback_t *callback,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen void *context)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_transaction_context *ctx =
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen (struct sqlpool_transaction_context *)_ctx;
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_ctx->db;
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen const struct sqlpool_connection *conn;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ctx->callback = callback;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ctx->context = context;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen ctx->commit_request = sqlpool_request_new(db, NULL);
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen ctx->commit_request->trans = ctx;
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen if (driver_sqlpool_get_connection(db, UINT_MAX, &conn))
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen sqlpool_request_handle_transaction(conn->db, ctx);
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen else
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen driver_sqlpool_append_request(db, ctx->commit_request);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic int
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_transaction_commit_s(struct sql_transaction_context *_ctx,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const char **error_r)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_transaction_context *ctx =
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen (struct sqlpool_transaction_context *)_ctx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_ctx->db;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sqlpool_connection *conn;
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen struct sql_transaction_context *conn_trans;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen int ret;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen *error_r = NULL;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen if (!driver_sqlpool_get_sync_connection(db, &conn)) {
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen *error_r = SQL_ERRSTR_NOT_CONNECTED;
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen driver_sqlpool_transaction_free(ctx);
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen return -1;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen conn_trans = driver_sqlpool_new_conn_trans(ctx, conn->db);
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen ret = sql_transaction_commit_s(&conn_trans, error_r);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_transaction_free(ctx);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return ret;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_transaction_rollback(struct sql_transaction_context *_ctx)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_transaction_context *ctx =
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen (struct sqlpool_transaction_context *)_ctx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_transaction_free(ctx);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_update(struct sql_transaction_context *_ctx, const char *query,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int *affected_rows)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_transaction_context *ctx =
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen (struct sqlpool_transaction_context *)_ctx;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen /* we didn't get a connection for transaction immediately.
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen queue updates until commit transfers all of these */
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen sql_transaction_add_query(&ctx->ctx, ctx->query_pool,
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen query, affected_rows);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainenstatic const char *
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainendriver_sqlpool_escape_blob(struct sql_db *_db,
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen const unsigned char *data, size_t size)
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen{
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen const struct sqlpool_connection *conns;
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen unsigned int i, count;
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen /* use the first ready connection */
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen conns = array_get(&db->all_connections, &count);
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen for (i = 0; i < count; i++) {
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen if (SQL_DB_IS_READY(conns[i].db))
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen return sql_escape_blob(conns[i].db, data, size);
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen }
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen /* no ready connections. just use the first one (we're guaranteed
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen to always have one) */
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen return sql_escape_blob(conns[0].db, data, size);
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen}
b87761f9bbef949f31dae297e619ac3f5e9c2b2eTimo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstruct sql_db driver_sqlpool_db = {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen "",
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen .v = {
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .deinit = driver_sqlpool_deinit,
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .connect = driver_sqlpool_connect,
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .disconnect = driver_sqlpool_disconnect,
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .escape_string = driver_sqlpool_escape_string,
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .exec = driver_sqlpool_exec,
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .query = driver_sqlpool_query,
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .query_s = driver_sqlpool_query_s,
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .transaction_begin = driver_sqlpool_transaction_begin,
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .transaction_commit = driver_sqlpool_transaction_commit,
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .transaction_commit_s = driver_sqlpool_transaction_commit_s,
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .transaction_rollback = driver_sqlpool_transaction_rollback,
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .update = driver_sqlpool_update,
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen
ef597c4619eb021563f659b886c67762fce7a817Timo Sirainen .escape_blob = driver_sqlpool_escape_blob,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen};