dovecot-2.0: pgsql: Fixes for errors handling with synchronous s...

dovecot at dovecot.org dovecot at dovecot.org
Tue Jun 29 20:29:22 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/2167bea550e1
changeset: 11654:2167bea550e1
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Jun 29 18:29:18 2010 +0100
description:
pgsql: Fixes for errors handling with synchronous sql queries.

diffstat:

 src/lib-sql/driver-pgsql.c |  45 +++++++++++++++++++++++++++++++++++++--------
 1 files changed, 37 insertions(+), 8 deletions(-)

diffs (149 lines):

diff -r 8c52ebde02a6 -r 2167bea550e1 src/lib-sql/driver-pgsql.c
--- a/src/lib-sql/driver-pgsql.c	Tue Jun 29 14:44:32 2010 +0000
+++ b/src/lib-sql/driver-pgsql.c	Tue Jun 29 18:29:18 2010 +0100
@@ -14,6 +14,7 @@
 
 	pool_t pool;
 	char *connect_string;
+	char *host;
 	PGconn *pg;
 
 	struct io *io;
@@ -21,7 +22,7 @@
 	enum io_condition io_dir;
 
 	struct pgsql_result *cur_result;
-	struct ioloop *ioloop;
+	struct ioloop *ioloop, *orig_ioloop;
 	struct sql_result *sync_result;
 
 	char *error;
@@ -72,6 +73,17 @@
 
 static void result_finish(struct pgsql_result *result);
 
+static void driver_pgsql_set_state(struct pgsql_db *db, enum sql_db_state state)
+{
+	/* switch back to original ioloop in case the caller wants to
+	   add/remove timeouts */
+	if (db->ioloop != NULL)
+		current_ioloop = db->orig_ioloop;
+	sql_db_set_state(&db->api, state);
+	if (db->ioloop != NULL)
+		current_ioloop = db->ioloop;
+}
+
 static void driver_pgsql_close(struct pgsql_db *db)
 {
 	db->io_dir = 0;
@@ -88,7 +100,7 @@
 	if (db->to_connect != NULL)
 		timeout_remove(&db->to_connect);
 
-	sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED);
+	driver_pgsql_set_state(db, SQL_DB_STATE_DISCONNECTED);
 
 	if (db->ioloop != NULL) {
 		/* running a sync query, stop it */
@@ -147,7 +159,7 @@
 		i_info("pgsql: Connected to %s", PQdb(db->pg));
 		if (db->to_connect != NULL)
 			timeout_remove(&db->to_connect);
-		sql_db_set_state(&db->api, SQL_DB_STATE_IDLE);
+		driver_pgsql_set_state(db, SQL_DB_STATE_IDLE);
 		if (db->ioloop != NULL) {
 			/* driver_pgsql_sync_init() waiting for connection to
 			   finish */
@@ -158,10 +170,11 @@
 
 static void driver_pgsql_connect_timeout(struct pgsql_db *db)
 {
+	const char *dbname = PQdb(db->pg);
 	unsigned int secs = ioloop_time - db->api.last_connect_try;
 
 	i_error("pgsql: Connect failed to %s: Timeout after %u seconds",
-		PQdb(db->pg), secs);
+		dbname != NULL ? dbname : db->host, secs);
 	driver_pgsql_close(db);
 }
 
@@ -185,11 +198,12 @@
 	/* nonblocking connecting begins. */
 	if (PQsetnonblocking(db->pg, 1) < 0)
 		i_error("pgsql: PQsetnonblocking() failed");
+	i_assert(db->to_connect == NULL);
 	db->to_connect = timeout_add(SQL_CONNECT_TIMEOUT_SECS * 1000,
 				     driver_pgsql_connect_timeout, db);
 	db->io = io_add(PQsocket(db->pg), IO_WRITE, connect_callback, db);
 	db->io_dir = IO_WRITE;
-	sql_db_set_state(&db->api, SQL_DB_STATE_CONNECTING);
+	driver_pgsql_set_state(db, SQL_DB_STATE_CONNECTING);
 	return 0;
 }
 
@@ -209,6 +223,15 @@
 	db = i_new(struct pgsql_db, 1);
 	db->connect_string = i_strdup(connect_string);
 	db->api = driver_pgsql_db;
+
+	T_BEGIN {
+		const char *const *arg = t_strsplit(connect_string, " ");
+
+		for (; *arg != NULL; arg++) {
+			if (strncmp(*arg, "host=", 5) == 0)
+				db->host = i_strdup(*arg + 5);
+		}
+	} T_END;
 	return &db->api;
 }
 
@@ -221,6 +244,7 @@
 
 	_db->no_reconnect = TRUE;
         driver_pgsql_close(db);
+	i_free(db->host);
 	i_free(db->error);
 	i_free(db->connect_string);
 	array_free(&_db->module_contexts);
@@ -234,7 +258,7 @@
 	if (db->fatal_error)
 		driver_pgsql_close(db);
 	else
-		sql_db_set_state(&db->api, SQL_DB_STATE_IDLE);
+		driver_pgsql_set_state(db, SQL_DB_STATE_IDLE);
 }
 
 static void consume_results(struct pgsql_db *db)
@@ -414,7 +438,7 @@
 		return;
 	}
 
-	sql_db_set_state(&db->api, SQL_DB_STATE_BUSY);
+	driver_pgsql_set_state(db, SQL_DB_STATE_BUSY);
 	if (ret > 0) {
 		/* write blocks */
 		db->io = io_add(PQsocket(db->pg), IO_WRITE,
@@ -493,6 +517,7 @@
 
 static void driver_pgsql_sync_init(struct pgsql_db *db)
 {
+	db->orig_ioloop = current_ioloop;
 	if (db->io == NULL) {
 		db->ioloop = io_loop_create();
 		return;
@@ -500,10 +525,14 @@
 
 	i_assert(db->api.state == SQL_DB_STATE_CONNECTING);
 
-	/* have to move our existing I/O handler to new I/O loop */
+	/* have to move our existing I/O and timeout handlers to new I/O loop */
 	io_remove(&db->io);
+	if (db->to_connect != NULL)
+		timeout_remove(&db->to_connect);
 
 	db->ioloop = io_loop_create();
+	db->to_connect = timeout_add(SQL_CONNECT_TIMEOUT_SECS * 1000,
+				     driver_pgsql_connect_timeout, db);
 	db->io = io_add(PQsocket(db->pg), db->io_dir, connect_callback, db);
 	/* wait for connecting to finish */
 	io_loop_run(db->ioloop);


More information about the dovecot-cvs mailing list