dovecot-1.2: pgsql: If query failed because connection was lost,...

dovecot at dovecot.org dovecot at dovecot.org
Mon Jan 12 20:26:40 EET 2009


details:   http://hg.dovecot.org/dovecot-1.2/rev/e3fd1a6467f2
changeset: 8617:e3fd1a6467f2
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Jan 12 13:26:24 2009 -0500
description:
pgsql: If query failed because connection was lost, retry it automatically.

diffstat:

1 file changed, 64 insertions(+), 20 deletions(-)
src/lib-sql/driver-pgsql.c |   84 +++++++++++++++++++++++++++++++++-----------

diffs (186 lines):

diff -r e50c8c44ab28 -r e3fd1a6467f2 src/lib-sql/driver-pgsql.c
--- a/src/lib-sql/driver-pgsql.c	Mon Jan 12 12:23:19 2009 -0500
+++ b/src/lib-sql/driver-pgsql.c	Mon Jan 12 13:26:24 2009 -0500
@@ -46,6 +46,7 @@ struct pgsql_result {
 	struct sql_result api;
 	PGresult *pgres;
 
+	char *query;
 	unsigned int rownum, rows;
 	unsigned int fields_count;
 	const char **fields;
@@ -55,6 +56,8 @@ struct pgsql_result {
 
 	sql_query_callback_t *callback;
 	void *context;
+
+	unsigned int retry_query:1;
 };
 
 struct pgsql_queue {
@@ -80,6 +83,10 @@ extern struct sql_db driver_pgsql_db;
 extern struct sql_db driver_pgsql_db;
 extern struct sql_result driver_pgsql_result;
 
+static void
+driver_pgsql_query_full(struct sql_db *db, const char *query,
+			sql_query_callback_t *callback, void *context,
+			bool retry_query);
 static void queue_send_next(struct pgsql_db *db);
 static void result_finish(struct pgsql_result *result);
 
@@ -280,6 +287,7 @@ static void driver_pgsql_result_free(str
 
 	i_free(result->fields);
 	i_free(result->values);
+	i_free(result->query);
 	i_free(result);
 
 	if (db->queue != NULL && !db->querying && db->connected)
@@ -289,9 +297,15 @@ static void result_finish(struct pgsql_r
 static void result_finish(struct pgsql_result *result)
 {
 	struct pgsql_db *db = (struct pgsql_db *)result->api.db;
-	bool free_result = TRUE;
-
-	if (result->callback != NULL) {
+	bool free_result = TRUE, retry = FALSE;
+	bool disconnected;
+
+	disconnected = PQstatus(db->pg) == CONNECTION_BAD;
+	if (disconnected && result->pgres == NULL && result->retry_query) {
+		/* retry the query */
+		i_error("pgsql: Query failed, retrying: %s", last_error(db));
+		retry = TRUE;
+	} else if (result->callback != NULL) {
 		result->api.callback = TRUE;
 		T_BEGIN {
 			result->callback(&result->api, result->context);
@@ -299,13 +313,20 @@ static void result_finish(struct pgsql_r
 		result->api.callback = FALSE;
 		free_result = db->sync_result != &result->api;
 	}
+
+	if (disconnected) {
+		/* disconnected */
+		driver_pgsql_close(db);
+
+		if (retry) {
+			/* retry the query */
+			driver_pgsql_query_full(&db->api, result->query,
+						result->callback,
+						result->context, FALSE);
+		}
+	}
 	if (free_result)
 		driver_pgsql_result_free(&result->api);
-
-	if (PQstatus(db->pg) == CONNECTION_BAD) {
-		/* disconnected */
-		driver_pgsql_close(db);
-	}
 }
 
 static void get_result(struct pgsql_result *result)
@@ -495,10 +516,10 @@ static void do_query(struct pgsql_result
 	}
 }
 
-static void exec_callback(struct sql_result *result,
+static void exec_callback(struct sql_result *_result,
 			  void *context ATTR_UNUSED)
 {
-        struct pgsql_db *db = (struct pgsql_db *)result->db;
+	struct pgsql_db *db = (struct pgsql_db *)_result->db;
 
 	i_error("pgsql: sql_exec() failed: %s", last_error(db));
 }
@@ -525,7 +546,8 @@ driver_pgsql_escape_string(struct sql_db
 	return to;
 }
 
-static void driver_pgsql_exec(struct sql_db *db, const char *query)
+static void driver_pgsql_exec_full(struct sql_db *db, const char *query,
+				   bool retry_query)
 {
 	struct pgsql_result *result;
 
@@ -533,12 +555,22 @@ static void driver_pgsql_exec(struct sql
 	result->api = driver_pgsql_result;
 	result->api.db = db;
 	result->callback = exec_callback;
-
+	if (retry_query) {
+		result->query = i_strdup(query);
+		result->retry_query = TRUE;
+	}
 	do_query(result, query);
 }
 
-static void driver_pgsql_query(struct sql_db *db, const char *query,
-			       sql_query_callback_t *callback, void *context)
+static void driver_pgsql_exec(struct sql_db *db, const char *query)
+{
+	driver_pgsql_exec_full(db, query, TRUE);
+}
+
+static void
+driver_pgsql_query_full(struct sql_db *db, const char *query,
+			sql_query_callback_t *callback, void *context,
+			bool retry_query)
 {
 	struct pgsql_result *result;
 
@@ -547,8 +579,17 @@ static void driver_pgsql_query(struct sq
 	result->api.db = db;
 	result->callback = callback;
 	result->context = context;
-
+	if (retry_query) {
+		result->query = i_strdup(query);
+		result->retry_query = TRUE;
+	}
 	do_query(result, query);
+}
+
+static void driver_pgsql_query(struct sql_db *db, const char *query,
+			       sql_query_callback_t *callback, void *context)
+{
+	driver_pgsql_query_full(db, query, callback, context, TRUE);
 }
 
 static void pgsql_query_s_callback(struct sql_result *result, void *context)
@@ -840,7 +881,8 @@ driver_pgsql_transaction_commit(struct s
 	ctx->callback = callback;
 	ctx->context = context;
 
-	sql_query(_ctx->db, "COMMIT", transaction_commit_callback, ctx);
+	driver_pgsql_query_full(_ctx->db, "COMMIT",
+				transaction_commit_callback, ctx, FALSE);
 }
 
 static int
@@ -884,9 +926,10 @@ driver_pgsql_transaction_rollback(struct
 }
 
 static void
-transaction_update_callback(struct sql_result *result,
-			    struct pgsql_transaction_context *ctx)
-{
+transaction_update_callback(struct sql_result *result, void *context)
+{
+	struct pgsql_transaction_context *ctx = context;
+
 	if (sql_result_next_row(result) < 0) {
 		ctx->failed = TRUE;
 		ctx->error = sql_result_get_error(result);
@@ -907,7 +950,8 @@ driver_pgsql_update(struct sql_transacti
 		sql_query(_ctx->db, "BEGIN", transaction_update_callback, ctx);
 	}
 
-	sql_query(_ctx->db, query, transaction_update_callback, ctx);
+	driver_pgsql_query_full(_ctx->db, query,
+				transaction_update_callback, ctx, FALSE);
 }
 
 struct sql_db driver_pgsql_db = {


More information about the dovecot-cvs mailing list