driver-sqlpool.c revision 2a70702978902669803cf8c7eed287cb006d2c48
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen/* Copyright (c) 2010 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
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ARRAY_DEFINE(hosts, struct sqlpool_host);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* all connections from all hosts */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ARRAY_DEFINE(all_connections, struct sqlpool_connection);
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;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int retried:1;
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
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_commit_callback(const char *error,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_transaction_context *ctx);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic struct sqlpool_request *
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;
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;
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 */
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen if (conndb->to_reconnect != NULL)
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen 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++) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen unsigned int idx = (i + db->last_query_conn_idx) % 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
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (!SQL_DB_IS_READY(conndb)) {
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);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (conn == NULL && unwanted_host_idx != -1U) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* maybe there are no wanted hosts. use any of them. */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conn = sqlpool_find_available_connection(db, -1U,
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 }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conn = sqlpool_find_available_connection(db, -1U,
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
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (driver_sqlpool_get_connection(db, -1U, 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 */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen (void)array_append_space(&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
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);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* always have at least one backend connection initialized */
73bc59c2a56ff351ae7c4d9f52de76b1b0173995Timo Sirainen (void)sqlpool_add_new_connection(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 }
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen if (db->request_to != NULL)
9349a0afffad990e45d3ad33081e1d2d9e68a753Timo Sirainen 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) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ret2 = sql_connect(conn->db);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (ret2 > 0)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return 1;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (ret2 == 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;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sqlpool_connection *conn;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen /* we always have at least one connection */
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen conn = array_idx(&db->all_connections, 0);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen return sql_escape_string(conn->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;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen const struct sqlpool_connection *conn;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sql_db *conndb;
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (result->failed_try_retry && !request->retried) {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_error("%s: Query failed, retrying: %s",
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen db->driver->name, sql_result_get_error(result));
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen request->retried = TRUE;
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
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void driver_sqlpool_query(struct sql_db *_db, const char *query,
6b2738c39a868ff9291867138c55029fc40cf105Timo 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
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (!driver_sqlpool_get_connection(db, -1U, &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);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen if (ctx->query_pool != NULL)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen pool_unref(&ctx->query_pool);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen i_free(ctx);
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen}
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstatic void
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainendriver_sqlpool_commit_callback(const char *error,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen struct sqlpool_transaction_context *ctx)
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen{
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen ctx->callback(error, 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
75113e5fa7532ef628f273caac2feec6008992c6Timo Sirainen if (driver_sqlpool_get_connection(db, -1U, &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
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainenstruct sql_db driver_sqlpool_db = {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen "",
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen .v = {
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen NULL,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_deinit,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_connect,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_disconnect,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_escape_string,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_exec,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_query,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_query_s,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_transaction_begin,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_transaction_commit,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_transaction_commit_s,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_transaction_rollback,
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen driver_sqlpool_update
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen }
6b2738c39a868ff9291867138c55029fc40cf105Timo Sirainen};