driver-sqlpool.c revision 191eb75dd8c688dc1669492b842233decaf9cacc
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2010-2015 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "array.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "llist.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "ioloop.h"
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen#include "sql-api-private.h"
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <time.h>
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define QUERY_TIMEOUT_SECS 6
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e9594e86dc601b72c1636f2b901dcfbf4ffaf47fAki Tuomistruct sqlpool_host {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen char *connect_string;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int connection_count;
ab1e5b156d1b5480d36ed6e8e06197339d803038Timo Sirainen};
ab1e5b156d1b5480d36ed6e8e06197339d803038Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct sqlpool_connection {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sql_db *db;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int host_idx;
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen};
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct sqlpool_db {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sql_db api;
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen pool_t pool;
fafa6393128960c70a9979af1c23cea41027fdd1Josef 'Jeff' Sipek const struct sql_db *driver;
0b2c958d1cdcbeb46c2ce7ada0917b304ad89dc1Timo Sirainen unsigned int connection_limit;
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen ARRAY(struct sqlpool_host) hosts;
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen /* all connections from all hosts */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ARRAY(struct sqlpool_connection) all_connections;
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen /* index of last connection in all_connections that was used to
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen send a query. */
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen unsigned int last_query_conn_idx;
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen /* queued requests */
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen struct sqlpool_request *requests_head, *requests_tail;
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen struct timeout *request_to;
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen};
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainenstruct sqlpool_request {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sqlpool_request *prev, *next;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen struct sqlpool_db *db;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen time_t created;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen unsigned int host_idx;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen unsigned int retry_count;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* requests are a) queries */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen char *query;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sql_query_callback_t *callback;
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi void *context;
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi /* b) transaction waiters */
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi struct sqlpool_transaction_context *trans;
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi};
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomistruct sqlpool_transaction_context {
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi struct sql_transaction_context ctx;
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi sql_commit_callback_t *callback;
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi void *context;
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi pool_t query_pool;
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi struct sqlpool_request *commit_request;
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi};
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomiextern struct sql_db driver_sqlpool_db;
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomistatic struct sqlpool_connection *
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomisqlpool_add_connection(struct sqlpool_db *db, struct sqlpool_host *host,
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomi unsigned int host_idx);
846624bdec0d5deec6cf22071158221391ec5f2dAki Tuomistatic void
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainendriver_sqlpool_query_callback(struct sql_result *result,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sqlpool_request *request);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainendriver_sqlpool_commit_callback(const char *error,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sqlpool_transaction_context *ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct sqlpool_request * ATTR_NULL(2)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainensqlpool_request_new(struct sqlpool_db *db, const char *query)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen{
5bd1c1d4fe3265d5e6b6054044fd6d78e42c9d0aTimo Sirainen struct sqlpool_request *request;
5bd1c1d4fe3265d5e6b6054044fd6d78e42c9d0aTimo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen request = i_new(struct sqlpool_request, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen request->db = db;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen request->created = time(NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen request->query = i_strdup(query);
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen return request;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenstatic void
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainensqlpool_request_free(struct sqlpool_request **_request)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sqlpool_request *request = *_request;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *_request = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(request->prev == NULL && request->next == NULL);
f330b7d9e14255fc06bc82908d9bc5a12cccb424Timo Sirainen i_free(request->query);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(request);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainenstatic void
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainensqlpool_request_abort(struct sqlpool_request **_request)
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen{
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen struct sqlpool_request *request = *_request;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen *_request = NULL;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen if (request->callback != NULL)
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen request->callback(&sql_not_connected_result, request->context);
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen i_assert(request->prev != NULL ||
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen request->db->requests_head == request);
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen DLLIST2_REMOVE(&request->db->requests_head,
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen &request->db->requests_tail, request);
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen sqlpool_request_free(&request);
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen}
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainenstatic struct sql_transaction_context *
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainendriver_sqlpool_new_conn_trans(struct sqlpool_transaction_context *trans,
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen struct sql_db *conndb)
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen{
f330b7d9e14255fc06bc82908d9bc5a12cccb424Timo Sirainen struct sql_transaction_context *conn_trans;
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen struct sql_transaction_query *query;
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen conn_trans = sql_transaction_begin(conndb);
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen /* backend will use our queries list (we might still append more
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen queries to the list) */
f330b7d9e14255fc06bc82908d9bc5a12cccb424Timo Sirainen conn_trans->head = trans->ctx.head;
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen conn_trans->tail = trans->ctx.tail;
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen for (query = conn_trans->head; query != NULL; query = query->next)
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen query->trans = conn_trans;
f330b7d9e14255fc06bc82908d9bc5a12cccb424Timo Sirainen return conn_trans;
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen}
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainenstatic void
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainensqlpool_request_handle_transaction(struct sql_db *conndb,
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen struct sqlpool_transaction_context *trans)
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen{
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen struct sql_transaction_context *conn_trans;
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen sqlpool_request_free(&trans->commit_request);
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen conn_trans = driver_sqlpool_new_conn_trans(trans, conndb);
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen sql_transaction_commit(&conn_trans,
f330b7d9e14255fc06bc82908d9bc5a12cccb424Timo Sirainen driver_sqlpool_commit_callback, trans);
f330b7d9e14255fc06bc82908d9bc5a12cccb424Timo Sirainen}
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen
f330b7d9e14255fc06bc82908d9bc5a12cccb424Timo Sirainenstatic void
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainensqlpool_request_send_next(struct sqlpool_db *db, struct sql_db *conndb)
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen{
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen struct sqlpool_request *request;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen if (db->requests_head == NULL || !SQL_DB_IS_READY(conndb))
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen return;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen request = db->requests_head;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen DLLIST2_REMOVE(&db->requests_head, &db->requests_tail, request);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen timeout_reset(db->request_to);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen if (request->query != NULL) {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen sql_query(conndb, request->query,
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen driver_sqlpool_query_callback, request);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen } else if (request->trans != NULL) {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen sqlpool_request_handle_transaction(conndb, request->trans);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen } else {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen i_unreached();
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen }
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen}
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainenstatic void sqlpool_reconnect(struct sql_db *conndb)
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen{
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen timeout_remove(&conndb->to_reconnect);
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen (void)sql_connect(conndb);
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen}
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainenstatic struct sqlpool_host *
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainensqlpool_find_host_with_least_connections(struct sqlpool_db *db,
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen unsigned int *host_idx_r)
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen{
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen struct sqlpool_host *hosts, *min = NULL;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen unsigned int i, count;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen hosts = array_get_modifiable(&db->hosts, &count);
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen i_assert(count > 0);
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen min = &hosts[0];
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen *host_idx_r = 0;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen for (i = 1; i < count; i++) {
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen if (min->connection_count > hosts[i].connection_count) {
85da8c055280cd45553b6b335e9fb226d6e2801eTimo Sirainen min = &hosts[i];
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen *host_idx_r = i;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen }
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen }
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen return min;
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen}
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainenstatic bool sqlpool_have_successful_connections(struct sqlpool_db *db)
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen{
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen const struct sqlpool_connection *conn;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen array_foreach(&db->all_connections, conn) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (conn->db->state >= SQL_DB_STATE_IDLE)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return FALSE;
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen}
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainensqlpool_handle_connect_failed(struct sqlpool_db *db, struct sql_db *conndb)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct sqlpool_host *host;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen unsigned int host_idx;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (conndb->connect_failure_count > 0) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* increase delay between reconnections to this
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen server */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen conndb->connect_delay *= 5;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (conndb->connect_delay > SQL_CONNECT_MAX_DELAY)
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen conndb->connect_delay = SQL_CONNECT_MAX_DELAY;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen conndb->connect_failure_count++;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* reconnect after the delay */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (conndb->to_reconnect != NULL)
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen timeout_remove(&conndb->to_reconnect);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen conndb->to_reconnect = timeout_add(conndb->connect_delay * 1000,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sqlpool_reconnect, conndb);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen /* if we have zero successful hosts and there still are hosts
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen without connections, connect to one of them. */
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen if (!sqlpool_have_successful_connections(db)) {
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen host = sqlpool_find_host_with_least_connections(db, &host_idx);
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen if (host->connection_count == 0)
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen (void)sqlpool_add_connection(db, host, host_idx);
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen }
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen}
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainen
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainenstatic void
620b5ed41650da63b0ba15c489f9f312231d5d9bTimo Sirainensqlpool_state_changed(struct sql_db *conndb, enum sql_db_state prev_state,
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen void *context)
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen{
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen struct sqlpool_db *db = context;
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen if (conndb->state == SQL_DB_STATE_IDLE) {
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen conndb->connect_failure_count = 0;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen conndb->connect_delay = SQL_CONNECT_MIN_DELAY;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen sqlpool_request_send_next(db, conndb);
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen }
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen if (prev_state == SQL_DB_STATE_CONNECTING &&
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen conndb->state == SQL_DB_STATE_DISCONNECTED &&
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen !conndb->no_reconnect)
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen sqlpool_handle_connect_failed(db, conndb);
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen}
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainenstatic struct sqlpool_connection *
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainensqlpool_add_connection(struct sqlpool_db *db, struct sqlpool_host *host,
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen unsigned int host_idx)
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen{
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen struct sql_db *conndb;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen struct sqlpool_connection *conn;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen host->connection_count++;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen conndb = db->driver->v.init(host->connect_string);
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen i_array_init(&conndb->module_contexts, 5);
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen conndb->state_change_callback = sqlpool_state_changed;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen conndb->state_change_context = db;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen conndb->connect_delay = SQL_CONNECT_MIN_DELAY;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen conn = array_append_space(&db->all_connections);
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen conn->host_idx = host_idx;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen conn->db = conndb;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen return conn;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen}
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainenstatic struct sqlpool_connection *
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainensqlpool_add_new_connection(struct sqlpool_db *db)
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen{
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen struct sqlpool_host *host;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen unsigned int host_idx;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen host = sqlpool_find_host_with_least_connections(db, &host_idx);
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen if (host->connection_count >= db->connection_limit)
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen return NULL;
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen else
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen return sqlpool_add_connection(db, host, host_idx);
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen}
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainen
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainenstatic const struct sqlpool_connection *
f0ff961282e618945dfe997dc45ff95d656e5790Timo Sirainensqlpool_find_available_connection(struct sqlpool_db *db,
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen unsigned int unwanted_host_idx,
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen bool *all_disconnected_r)
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen{
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen const struct sqlpool_connection *conns;
8ac66221e8fdc2c5523cff1893e0d1c5de25fa49Timo Sirainen unsigned int i, count;
8ac66221e8fdc2c5523cff1893e0d1c5de25fa49Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *all_disconnected_r = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen conns = array_get(&db->all_connections, &count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < count; i++) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen unsigned int idx = (i + db->last_query_conn_idx + 1) % count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sql_db *conndb = conns[idx].db;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
920b9f0fdfa5a5d7763e05736601a31bcb291a53Timo Sirainen if (conns[idx].host_idx == unwanted_host_idx)
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen continue;
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen if (!SQL_DB_IS_READY(conndb) && conndb->to_reconnect == NULL) {
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen /* see if we could reconnect to it immediately */
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainen (void)sql_connect(conndb);
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainen }
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen if (SQL_DB_IS_READY(conndb)) {
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainen db->last_query_conn_idx = idx;
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen *all_disconnected_r = FALSE;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen return &conns[idx];
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen }
c4877db8b6559846f4b58be8e42422dc734c193fTimo Sirainen if (conndb->state != SQL_DB_STATE_DISCONNECTED)
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen *all_disconnected_r = FALSE;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return NULL;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen}
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainenstatic bool
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainendriver_sqlpool_get_connection(struct sqlpool_db *db,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen unsigned int unwanted_host_idx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct sqlpool_connection **conn_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen const struct sqlpool_connection *conn, *conns;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen unsigned int i, count;
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen bool all_disconnected;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen conn = sqlpool_find_available_connection(db, unwanted_host_idx,
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen &all_disconnected);
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen if (conn == NULL && unwanted_host_idx != UINT_MAX) {
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen /* maybe there are no wanted hosts. use any of them. */
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen conn = sqlpool_find_available_connection(db, UINT_MAX,
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen &all_disconnected);
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen }
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen if (conn == NULL && all_disconnected) {
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen /* no connected connections. connect_delays may have gotten too
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen high, reset all of them to see if some are still alive. */
9af06b76539445d2d84d6e1bcb91685b6abeb4e0Timo Sirainen conns = array_get(&db->all_connections, &count);
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen for (i = 0; i < count; i++) {
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen struct sql_db *conndb = conns[i].db;
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen if (conndb->connect_delay > SQL_CONNECT_RESET_DELAY)
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen conndb->connect_delay = SQL_CONNECT_RESET_DELAY;
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen }
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen conn = sqlpool_find_available_connection(db, UINT_MAX,
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen &all_disconnected);
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen }
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen if (conn == NULL) {
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen /* still nothing. try creating new connections */
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen conn = sqlpool_add_new_connection(db);
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen if (conn != NULL)
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen (void)sql_connect(conn->db);
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen if (conn == NULL || !SQL_DB_IS_READY(conn->db))
9af06b76539445d2d84d6e1bcb91685b6abeb4e0Timo Sirainen return FALSE;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen }
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen *conn_r = conn;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen return TRUE;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen}
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainenstatic bool
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainendriver_sqlpool_get_sync_connection(struct sqlpool_db *db,
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen const struct sqlpool_connection **conn_r)
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct sqlpool_connection *conns;
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen unsigned int i, count;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (driver_sqlpool_get_connection(db, UINT_MAX, conn_r))
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return TRUE;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen /* no idling connections, but maybe we can find one that's trying to
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen connect to server, and we can use it once it's finished */
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen conns = array_get(&db->all_connections, &count);
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen for (i = 0; i < count; i++) {
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen if (conns[i].db->state == SQL_DB_STATE_CONNECTING) {
bb86f8f22f2561438ce710d2113f04a4d0082b50Timo Sirainen *conn_r = &conns[i];
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen return TRUE;
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen }
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen }
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen return FALSE;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen}
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen
ab1e5b156d1b5480d36ed6e8e06197339d803038Timo Sirainenstatic void
ab1e5b156d1b5480d36ed6e8e06197339d803038Timo Sirainendriver_sqlpool_parse_hosts(struct sqlpool_db *db, const char *connect_string)
ab1e5b156d1b5480d36ed6e8e06197339d803038Timo Sirainen{
ab1e5b156d1b5480d36ed6e8e06197339d803038Timo Sirainen const char *const *args, *key, *value, *const *hostnamep;
ab1e5b156d1b5480d36ed6e8e06197339d803038Timo Sirainen struct sqlpool_host *host;
ab1e5b156d1b5480d36ed6e8e06197339d803038Timo Sirainen ARRAY_TYPE(const_string) hostnames, connect_args;
ab1e5b156d1b5480d36ed6e8e06197339d803038Timo Sirainen
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen t_array_init(&hostnames, 8);
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen t_array_init(&connect_args, 32);
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen /* connect string is a space separated list. it may contain
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen backend-specific strings which we'll pass as-is. we'll only care
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen about our own settings, plus the host settings. */
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen args = t_strsplit_spaces(connect_string, " ");
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen for (; *args != NULL; args++) {
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen value = strchr(*args, '=');
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen if (value == NULL) {
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen key = *args;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen value = "";
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen } else {
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen key = t_strdup_until(*args, value);
dad1d7b721e80a7e6c0282ace93aef86312fa579Timo Sirainen value++;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen }
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen if (strcmp(key, "maxconns") == 0) {
dad1d7b721e80a7e6c0282ace93aef86312fa579Timo Sirainen if (str_to_uint(value, &db->connection_limit) < 0) {
dad1d7b721e80a7e6c0282ace93aef86312fa579Timo Sirainen i_fatal("Invalid value for maxconns: %s",
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen value);
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen }
82ed69779f49bd71ef1b570ce8aca67d357dbee8Timo Sirainen } else if (strcmp(key, "host") == 0) {
82ed69779f49bd71ef1b570ce8aca67d357dbee8Timo Sirainen array_append(&hostnames, &value, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen array_append(&connect_args, args, 1);
82ed69779f49bd71ef1b570ce8aca67d357dbee8Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* build a new connect string without our settings or hosts */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen array_append_zero(&connect_args);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen connect_string = t_strarray_join(array_idx(&connect_args, 0), " ");
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen if (array_count(&hostnames) == 0) {
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen /* no hosts specified. create a default one. */
97144a346898fb62f9fae44fa5c076986553c66bTimo Sirainen host = array_append_space(&db->hosts);
97144a346898fb62f9fae44fa5c076986553c66bTimo Sirainen host->connect_string = i_strdup(connect_string);
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen } else {
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen if (*connect_string == '\0')
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen connect_string = NULL;
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen array_foreach(&hostnames, hostnamep) {
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen host = array_append_space(&db->hosts);
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen host->connect_string =
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen i_strconcat("host=", *hostnamep, " ",
97144a346898fb62f9fae44fa5c076986553c66bTimo Sirainen connect_string, NULL);
97144a346898fb62f9fae44fa5c076986553c66bTimo Sirainen }
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen }
9bd08aa09ea0cbd7b221aae9fc0534eb762d3de6Timo Sirainen
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen if (db->connection_limit == 0)
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen db->connection_limit = SQL_DEFAULT_CONNECTION_LIMIT;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen}
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenstatic void sqlpool_add_all_once(struct sqlpool_db *db)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen{
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen struct sqlpool_host *host;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen unsigned int host_idx;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen for (;;) {
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen host = sqlpool_find_host_with_least_connections(db, &host_idx);
211c638d81d382517d196ad47565e0d85012c927klemens if (host->connection_count > 0)
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen break;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen (void)sqlpool_add_connection(db, host, host_idx);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen}
9af06b76539445d2d84d6e1bcb91685b6abeb4e0Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenstruct sql_db *
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainendriver_sqlpool_init(const char *connect_string, const struct sql_db *driver)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen{
8ac66221e8fdc2c5523cff1893e0d1c5de25fa49Timo Sirainen struct sqlpool_db *db;
8ac66221e8fdc2c5523cff1893e0d1c5de25fa49Timo Sirainen
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen i_assert(connect_string != NULL);
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen
9af06b76539445d2d84d6e1bcb91685b6abeb4e0Timo Sirainen db = i_new(struct sqlpool_db, 1);
9af06b76539445d2d84d6e1bcb91685b6abeb4e0Timo Sirainen db->driver = driver;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen db->api = driver_sqlpool_db;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen db->api.flags = driver->flags;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_array_init(&db->hosts, 8);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen T_BEGIN {
de9b2ee7878a73346ba0eee34798abb22ffcfcb6Timo Sirainen driver_sqlpool_parse_hosts(db, connect_string);
82ed69779f49bd71ef1b570ce8aca67d357dbee8Timo Sirainen } T_END;
82ed69779f49bd71ef1b570ce8aca67d357dbee8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_array_init(&db->all_connections, 16);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* connect to all databases so we can do load balancing immediately */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sqlpool_add_all_once(db);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return &db->api;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenstatic void driver_sqlpool_abort_requests(struct sqlpool_db *db)
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen{
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen while (db->requests_head != NULL) {
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen struct sqlpool_request *request = db->requests_head;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen sqlpool_request_abort(&request);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (db->request_to != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen timeout_remove(&db->request_to);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void driver_sqlpool_deinit(struct sql_db *_db)
5bd1c1d4fe3265d5e6b6054044fd6d78e42c9d0aTimo Sirainen{
5bd1c1d4fe3265d5e6b6054044fd6d78e42c9d0aTimo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sqlpool_host *host;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct sqlpool_connection *conn;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_foreach_modifiable(&db->all_connections, conn)
e9594e86dc601b72c1636f2b901dcfbf4ffaf47fAki Tuomi sql_deinit(&conn->db);
e9594e86dc601b72c1636f2b901dcfbf4ffaf47fAki Tuomi array_clear(&db->all_connections);
e9594e86dc601b72c1636f2b901dcfbf4ffaf47fAki Tuomi
e9594e86dc601b72c1636f2b901dcfbf4ffaf47fAki Tuomi driver_sqlpool_abort_requests(db);
e9594e86dc601b72c1636f2b901dcfbf4ffaf47fAki Tuomi
7707c4b35b868eda75b585c863d97726ff23f80fMartti Rannanjärvi array_foreach_modifiable(&db->hosts, host)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(host->connect_string);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen i_assert(array_count(&db->all_connections) == 0);
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen array_free(&db->hosts);
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen array_free(&db->all_connections);
f81801789c71f64a2fc3c44d09f9864bbc68cd45Timo Sirainen array_free(&_db->module_contexts);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(db);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainenstatic int driver_sqlpool_connect(struct sql_db *_db)
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen{
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
46d91e9ea8bf41e56c5436c064372171c5876d81Timo Sirainen const struct sqlpool_connection *conn;
46d91e9ea8bf41e56c5436c064372171c5876d81Timo Sirainen int ret = -1, ret2;
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen array_foreach(&db->all_connections, conn) {
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen ret2 = conn->db->to_reconnect != NULL ? -1 :
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen sql_connect(conn->db);
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen if (ret2 > 0)
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen ret = 1;
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen else if (ret2 == 0 && ret < 0)
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen ret = 0;
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void driver_sqlpool_disconnect(struct sql_db *_db)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct sqlpool_connection *conn;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_foreach(&db->all_connections, conn)
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen sql_disconnect(conn->db);
a835194f9a9dae88528367a791cbc282589f6c01Timo Sirainen driver_sqlpool_abort_requests(db);
0b878c6a17c608fcd8b52a5762ed2c6a5cf4700aTimo Sirainen}
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainenstatic const char *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainendriver_sqlpool_escape_string(struct sql_db *_db, const char *string)
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen{
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen const struct sqlpool_connection *conns;
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen unsigned int i, count;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen /* use the first ready connection */
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen conns = array_get(&db->all_connections, &count);
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen for (i = 0; i < count; i++) {
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen if (SQL_DB_IS_READY(conns[i].db))
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen return sql_escape_string(conns[i].db, string);
17018da24e7dbb419c5047c316caadcb2fc5364aTimo Sirainen }
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen /* no ready connections. just use the first one (we're guaranteed
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen to always have one) */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return sql_escape_string(conns[0].db, string);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenstatic void driver_sqlpool_timeout(struct sqlpool_db *db)
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen{
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen while (db->requests_head != NULL) {
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen struct sqlpool_request *request = db->requests_head;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (request->created + SQL_QUERY_TIMEOUT_SECS > ioloop_time)
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen break;
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen i_error("%s: Query timed out "
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen "(no free connections for %u secs): %s",
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen db->driver->name,
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen (unsigned int)(ioloop_time - request->created),
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen request->query != NULL ? request->query :
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen "<transaction>");
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen sqlpool_request_abort(&request);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (db->requests_head == NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen timeout_remove(&db->request_to);
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen}
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenstatic void
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainendriver_sqlpool_prepend_request(struct sqlpool_db *db,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sqlpool_request *request)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
6307d76096764e66bddc63d4a3e5a1aa19cc528fJosef 'Jeff' Sipek DLLIST2_PREPEND(&db->requests_head, &db->requests_tail, request);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen if (db->request_to == NULL) {
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen db->request_to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000,
0cea9b1f4fa0495a48f5f097e40492517d67e1baTimo Sirainen driver_sqlpool_timeout, db);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
0cea9b1f4fa0495a48f5f097e40492517d67e1baTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainendriver_sqlpool_append_request(struct sqlpool_db *db,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sqlpool_request *request)
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen{
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen DLLIST2_APPEND(&db->requests_head, &db->requests_tail, request);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen if (db->request_to == NULL) {
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen db->request_to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000,
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen driver_sqlpool_timeout, db);
763f83d3cc47bce05cbc396419c4db2b71dd8e68Timo Sirainen }
763f83d3cc47bce05cbc396419c4db2b71dd8e68Timo Sirainen}
763f83d3cc47bce05cbc396419c4db2b71dd8e68Timo Sirainen
763f83d3cc47bce05cbc396419c4db2b71dd8e68Timo Sirainenstatic void
763f83d3cc47bce05cbc396419c4db2b71dd8e68Timo Sirainendriver_sqlpool_query_callback(struct sql_result *result,
763f83d3cc47bce05cbc396419c4db2b71dd8e68Timo Sirainen struct sqlpool_request *request)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen{
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen struct sqlpool_db *db = request->db;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen const struct sqlpool_connection *conn = NULL;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen struct sql_db *conndb;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen if (result->failed_try_retry &&
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen request->retry_count < array_count(&db->hosts)) {
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen i_warning("%s: Query failed, retrying: %s",
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen db->driver->name, sql_result_get_error(result));
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen request->retry_count++;
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen driver_sqlpool_prepend_request(db, request);
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen if (driver_sqlpool_get_connection(request->db,
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen request->host_idx, &conn)) {
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen request->host_idx = conn->host_idx;
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen sqlpool_request_send_next(db, conn->db);
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen }
4aae8acbcfa9cac96b4af39bfabcbe569e804827Timo Sirainen } else {
5bdad39213d28ab35e615a7f4ea1712ab25b6a80Timo Sirainen if (result->failed) {
5bdad39213d28ab35e615a7f4ea1712ab25b6a80Timo Sirainen i_error("%s: Query failed, aborting: %s",
5bdad39213d28ab35e615a7f4ea1712ab25b6a80Timo Sirainen db->driver->name, request->query);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen }
763f83d3cc47bce05cbc396419c4db2b71dd8e68Timo Sirainen conndb = result->db;
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen
4aae8acbcfa9cac96b4af39bfabcbe569e804827Timo Sirainen if (request->callback != NULL)
4aae8acbcfa9cac96b4af39bfabcbe569e804827Timo Sirainen request->callback(result, request->context);
4aae8acbcfa9cac96b4af39bfabcbe569e804827Timo Sirainen sqlpool_request_free(&request);
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen sqlpool_request_send_next(db, conndb);
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen }
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen}
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen
51b979b6414b940f04677a7e2d064be119345954Timo Sirainenstatic void ATTR_NULL(3, 4)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainendriver_sqlpool_query(struct sql_db *_db, const char *query,
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen sql_query_callback_t *callback, void *context)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen{
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen struct sqlpool_request *request;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen const struct sqlpool_connection *conn;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
6cb2c6ecddcdbeac9e6c73a292244747e12a793eTimo Sirainen request = sqlpool_request_new(db, query);
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen request->callback = callback;
2af769daebd83719ac696a440e06f6020471cec0Timo Sirainen request->context = context;
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen if (!driver_sqlpool_get_connection(db, UINT_MAX, &conn))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen driver_sqlpool_append_request(db, request);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen else {
82ed69779f49bd71ef1b570ce8aca67d357dbee8Timo Sirainen request->host_idx = conn->host_idx;
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen sql_query(conn->db, query, driver_sqlpool_query_callback,
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen request);
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void driver_sqlpool_exec(struct sql_db *_db, const char *query)
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen{
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen driver_sqlpool_query(_db, query, NULL, NULL);
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen}
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen
1c0590b2729567ad60dafde4d2c5f19635755a3dTimo Sirainenstatic struct sql_result *
1c0590b2729567ad60dafde4d2c5f19635755a3dTimo Sirainendriver_sqlpool_query_s(struct sql_db *_db, const char *query)
ba482d3624ca4f1b3d638e6e8470ba5134f21493Timo Sirainen{
ba482d3624ca4f1b3d638e6e8470ba5134f21493Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen const struct sqlpool_connection *conn;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen struct sql_result *result;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen if (!driver_sqlpool_get_sync_connection(db, &conn)) {
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen sql_not_connected_result.refcount++;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen return &sql_not_connected_result;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
84da9c6d6e162b064608cbfa9a47e0d60553c593Timo Sirainen
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen result = sql_query_s(conn->db, query);
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen if (result->failed_try_retry) {
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen if (!driver_sqlpool_get_sync_connection(db, &conn))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return result;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen sql_result_unref(result);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen result = sql_query_s(conn->db, query);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen }
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen return result;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen}
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainenstatic struct sql_transaction_context *
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainendriver_sqlpool_transaction_begin(struct sql_db *_db)
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen{
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen struct sqlpool_transaction_context *ctx;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen ctx = i_new(struct sqlpool_transaction_context, 1);
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen ctx->ctx.db = _db;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen
425cbcea60cf689b0069698c83f8bdc474d70693Timo Sirainen /* queue changes until commit. even if we did have a free connection
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen now, don't use it or multiple open transactions could tie up all
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen connections. */
114a0f74e0f825c6bd8aeadfafb248a030762a1fTimo Sirainen ctx->query_pool = pool_alloconly_create("sqlpool transaction", 1024);
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen return &ctx->ctx;
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen}
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen
6fdf8b5e4e71a69f5974f59eec2b8c19bc421fe2Timo Sirainenstatic void
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainendriver_sqlpool_transaction_free(struct sqlpool_transaction_context *ctx)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen{
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen if (ctx->commit_request != NULL)
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen sqlpool_request_abort(&ctx->commit_request);
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen if (ctx->query_pool != NULL)
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen pool_unref(&ctx->query_pool);
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen i_free(ctx);
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen}
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainenstatic void
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainendriver_sqlpool_commit_callback(const char *error,
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen struct sqlpool_transaction_context *ctx)
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen{
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen ctx->callback(error, ctx->context);
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen driver_sqlpool_transaction_free(ctx);
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen}
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainenstatic void
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainendriver_sqlpool_transaction_commit(struct sql_transaction_context *_ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sql_commit_callback_t *callback,
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen void *context)
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen{
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen struct sqlpool_transaction_context *ctx =
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen (struct sqlpool_transaction_context *)_ctx;
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_ctx->db;
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen const struct sqlpool_connection *conn;
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen
ab70f55bb8d824ca1ed7c74196f2f502edd29cc7Timo Sirainen ctx->callback = callback;
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen ctx->context = context;
d0bbbc7057aa33b52ee378196dee7d773437468fTimo Sirainen
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen ctx->commit_request = sqlpool_request_new(db, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->commit_request->trans = ctx;
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen if (driver_sqlpool_get_connection(db, UINT_MAX, &conn))
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen sqlpool_request_handle_transaction(conn->db, ctx);
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen else
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen driver_sqlpool_append_request(db, ctx->commit_request);
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen}
4bbee99b3aef449a9a2a11a5b5cf1ca486915c49Timo Sirainen
62cfc346eb7b0a4fd9e1ab6edd63b98711161229Timo Sirainenstatic int
62cfc346eb7b0a4fd9e1ab6edd63b98711161229Timo Sirainendriver_sqlpool_transaction_commit_s(struct sql_transaction_context *_ctx,
62cfc346eb7b0a4fd9e1ab6edd63b98711161229Timo Sirainen const char **error_r)
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen{
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen struct sqlpool_transaction_context *ctx =
62cfc346eb7b0a4fd9e1ab6edd63b98711161229Timo Sirainen (struct sqlpool_transaction_context *)_ctx;
62cfc346eb7b0a4fd9e1ab6edd63b98711161229Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_ctx->db;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const struct sqlpool_connection *conn;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen struct sql_transaction_context *conn_trans;
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen int ret;
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen *error_r = NULL;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (!driver_sqlpool_get_sync_connection(db, &conn)) {
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen *error_r = SQL_ERRSTR_NOT_CONNECTED;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen driver_sqlpool_transaction_free(ctx);
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen return -1;
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen }
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen conn_trans = driver_sqlpool_new_conn_trans(ctx, conn->db);
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen ret = sql_transaction_commit_s(&conn_trans, error_r);
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen driver_sqlpool_transaction_free(ctx);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen return ret;
a817fdcc43aedf423e2134091d5f83f91d64bcc9Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainendriver_sqlpool_transaction_rollback(struct sql_transaction_context *_ctx)
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen{
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen struct sqlpool_transaction_context *ctx =
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen (struct sqlpool_transaction_context *)_ctx;
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen driver_sqlpool_transaction_free(ctx);
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen}
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainenstatic void
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainendriver_sqlpool_update(struct sql_transaction_context *_ctx, const char *query,
8ac66221e8fdc2c5523cff1893e0d1c5de25fa49Timo Sirainen unsigned int *affected_rows)
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen{
bba52ecbb0cfb6585f1a4ff29695dd2d27af98d2Timo Sirainen struct sqlpool_transaction_context *ctx =
bba52ecbb0cfb6585f1a4ff29695dd2d27af98d2Timo Sirainen (struct sqlpool_transaction_context *)_ctx;
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen /* we didn't get a connection for transaction immediately.
dbd9604da561399cc6255289d5b6f6f662ab2d00Timo Sirainen queue updates until commit transfers all of these */
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen sql_transaction_add_query(&ctx->ctx, ctx->query_pool,
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen query, affected_rows);
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen}
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainenstatic const char *
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainendriver_sqlpool_escape_blob(struct sql_db *_db,
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen const unsigned char *data, size_t size)
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen{
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen struct sqlpool_db *db = (struct sqlpool_db *)_db;
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen const struct sqlpool_connection *conns;
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen unsigned int i, count;
044b0557e92ae0bb3b25af49d5468bad3d17db43Timo Sirainen
044b0557e92ae0bb3b25af49d5468bad3d17db43Timo Sirainen /* use the first ready connection */
044b0557e92ae0bb3b25af49d5468bad3d17db43Timo Sirainen conns = array_get(&db->all_connections, &count);
044b0557e92ae0bb3b25af49d5468bad3d17db43Timo Sirainen for (i = 0; i < count; i++) {
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen if (SQL_DB_IS_READY(conns[i].db))
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen return sql_escape_blob(conns[i].db, data, size);
044b0557e92ae0bb3b25af49d5468bad3d17db43Timo Sirainen }
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen /* no ready connections. just use the first one (we're guaranteed
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen to always have one) */
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen return sql_escape_blob(conns[0].db, data, size);
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen}
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainenstruct sql_db driver_sqlpool_db = {
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen "",
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen .v = {
131b073bdc3650083b00616dc778dd3017c2bbb5Timo Sirainen NULL,
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen driver_sqlpool_deinit,
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen driver_sqlpool_connect,
289064eb21595d3e4460439eccdc48232d13f5e1Timo Sirainen driver_sqlpool_disconnect,
f3976df875193529127d584cb713983e8160bdcfTimo Sirainen driver_sqlpool_escape_string,
f3976df875193529127d584cb713983e8160bdcfTimo Sirainen driver_sqlpool_exec,
f3976df875193529127d584cb713983e8160bdcfTimo Sirainen driver_sqlpool_query,
f3976df875193529127d584cb713983e8160bdcfTimo Sirainen driver_sqlpool_query_s,
f3976df875193529127d584cb713983e8160bdcfTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen driver_sqlpool_transaction_begin,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen driver_sqlpool_transaction_commit,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen driver_sqlpool_transaction_commit_s,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen driver_sqlpool_transaction_rollback,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen driver_sqlpool_update,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen driver_sqlpool_escape_blob
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen};
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen