From 73bc59c2a56ff351ae7c4d9f52de76b1b0173995 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Wed, 17 Nov 2010 16:55:44 +0000 Subject: [PATCH] lib-sql: Connect earlier to fallback host when using multiple hosts and primary fails. --- src/lib-sql/driver-sqlpool.c | 121 +++++++++++++++++++++++------------ 1 file changed, 80 insertions(+), 41 deletions(-) diff --git a/src/lib-sql/driver-sqlpool.c b/src/lib-sql/driver-sqlpool.c index 7bd2af90bb..2372708152 100644 --- a/src/lib-sql/driver-sqlpool.c +++ b/src/lib-sql/driver-sqlpool.c @@ -70,6 +70,9 @@ struct sqlpool_transaction_context { extern struct sql_db driver_sqlpool_db; +static struct sqlpool_connection * +sqlpool_add_connection(struct sqlpool_db *db, struct sqlpool_host *host, + unsigned int host_idx); static void driver_sqlpool_query_callback(struct sql_result *result, struct sqlpool_request *request); @@ -172,39 +175,6 @@ static void sqlpool_reconnect(struct sql_db *conndb) (void)sql_connect(conndb); } -static void -sqlpool_state_changed(struct sql_db *conndb, enum sql_db_state prev_state, - void *context) -{ - struct sqlpool_db *db = context; - - if (conndb->state == SQL_DB_STATE_IDLE) { - conndb->connect_failure_count = 0; - conndb->connect_delay = SQL_CONNECT_MIN_DELAY; - sqlpool_request_send_next(db, conndb); - } - - if (prev_state == SQL_DB_STATE_CONNECTING && - conndb->state == SQL_DB_STATE_DISCONNECTED && - !conndb->no_reconnect) { - /* connect failed */ - if (conndb->connect_failure_count > 0) { - /* increase delay between reconnections to this - server */ - conndb->connect_delay *= 5; - if (conndb->connect_delay > SQL_CONNECT_MAX_DELAY) - conndb->connect_delay = SQL_CONNECT_MAX_DELAY; - } - conndb->connect_failure_count++; - - /* reconnect after the delay */ - if (conndb->to_reconnect != NULL) - timeout_remove(&conndb->to_reconnect); - conndb->to_reconnect = timeout_add(conndb->connect_delay * 1000, - sqlpool_reconnect, conndb); - } -} - static struct sqlpool_host * sqlpool_find_host_with_least_connections(struct sqlpool_db *db, unsigned int *host_idx_r) @@ -227,16 +197,72 @@ sqlpool_find_host_with_least_connections(struct sqlpool_db *db, return min; } -static struct sqlpool_connection *sqlpool_add_connection(struct sqlpool_db *db) +static bool sqlpool_have_successful_connections(struct sqlpool_db *db) +{ + const struct sqlpool_connection *conn; + + array_foreach(&db->all_connections, conn) { + if (conn->db->state >= SQL_DB_STATE_IDLE) + return TRUE; + } + return FALSE; +} + +static void +sqlpool_handle_connect_failed(struct sqlpool_db *db, struct sql_db *conndb) { - struct sql_db *conndb; struct sqlpool_host *host; - struct sqlpool_connection *conn; unsigned int host_idx; - host = sqlpool_find_host_with_least_connections(db, &host_idx); - if (host->connection_count >= db->connection_limit) - return NULL; + if (conndb->connect_failure_count > 0) { + /* increase delay between reconnections to this + server */ + conndb->connect_delay *= 5; + if (conndb->connect_delay > SQL_CONNECT_MAX_DELAY) + conndb->connect_delay = SQL_CONNECT_MAX_DELAY; + } + conndb->connect_failure_count++; + + /* reconnect after the delay */ + if (conndb->to_reconnect != NULL) + timeout_remove(&conndb->to_reconnect); + conndb->to_reconnect = timeout_add(conndb->connect_delay * 1000, + sqlpool_reconnect, conndb); + + /* if we have zero successful hosts and there still are hosts + without connections, connect to one of them. */ + if (!sqlpool_have_successful_connections(db)) { + host = sqlpool_find_host_with_least_connections(db, &host_idx); + if (host->connection_count == 0) + (void)sqlpool_add_connection(db, host, host_idx); + } +} + +static void +sqlpool_state_changed(struct sql_db *conndb, enum sql_db_state prev_state, + void *context) +{ + struct sqlpool_db *db = context; + + if (conndb->state == SQL_DB_STATE_IDLE) { + conndb->connect_failure_count = 0; + conndb->connect_delay = SQL_CONNECT_MIN_DELAY; + sqlpool_request_send_next(db, conndb); + } + + if (prev_state == SQL_DB_STATE_CONNECTING && + conndb->state == SQL_DB_STATE_DISCONNECTED && + !conndb->no_reconnect) + sqlpool_handle_connect_failed(db, conndb); +} + +static struct sqlpool_connection * +sqlpool_add_connection(struct sqlpool_db *db, struct sqlpool_host *host, + unsigned int host_idx) +{ + struct sql_db *conndb; + struct sqlpool_connection *conn; + host->connection_count++; conndb = db->driver->v.init(host->connect_string); @@ -252,6 +278,19 @@ static struct sqlpool_connection *sqlpool_add_connection(struct sqlpool_db *db) return conn; } +static struct sqlpool_connection * +sqlpool_add_new_connection(struct sqlpool_db *db) +{ + struct sqlpool_host *host; + unsigned int host_idx; + + host = sqlpool_find_host_with_least_connections(db, &host_idx); + if (host->connection_count >= db->connection_limit) + return NULL; + else + return sqlpool_add_connection(db, host, host_idx); +} + static const struct sqlpool_connection * sqlpool_find_available_connection(struct sqlpool_db *db, unsigned int unwanted_host_idx, @@ -316,7 +355,7 @@ driver_sqlpool_get_connection(struct sqlpool_db *db, } if (conn == NULL) { /* still nothing. try creating new connections */ - conn = sqlpool_add_connection(db); + conn = sqlpool_add_new_connection(db); if (conn == NULL || !SQL_DB_IS_READY(conn->db)) return FALSE; } @@ -425,7 +464,7 @@ driver_sqlpool_init(const char *connect_string, const struct sql_db *driver) i_array_init(&db->all_connections, 16); /* always have at least one backend connection initialized */ - (void)sqlpool_add_connection(db); + (void)sqlpool_add_new_connection(db); return &db->api; } -- 2.47.3