dovecot-2.1: lib-sql: If mysql/pgsql commit fails due to server ...

dovecot at dovecot.org dovecot at dovecot.org
Thu Dec 8 07:02:12 EET 2011


details:   http://hg.dovecot.org/dovecot-2.1/rev/782f09d13ece
changeset: 13821:782f09d13ece
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Dec 08 07:02:03 2011 +0200
description:
lib-sql: If mysql/pgsql commit fails due to server disconnection, reconnect and retry.

diffstat:

 src/lib-sql/driver-mysql.c |  47 ++++++++++++++++++++++++++++++++++-----------
 src/lib-sql/driver-pgsql.c |  41 +++++++++++++++++++++++++++++----------
 2 files changed, 65 insertions(+), 23 deletions(-)

diffs (133 lines):

diff -r 3b70254e0596 -r 782f09d13ece src/lib-sql/driver-mysql.c
--- a/src/lib-sql/driver-mysql.c	Thu Dec 08 06:11:03 2011 +0200
+++ b/src/lib-sql/driver-mysql.c	Thu Dec 08 07:02:03 2011 +0200
@@ -506,31 +506,54 @@
 	return ret;
 }
 
+static int driver_mysql_try_commit_s(struct mysql_transaction_context *ctx)
+{
+	struct sql_transaction_context *_ctx = &ctx->ctx;
+
+	/* try to use a transaction in any case,
+	   even if it's not actually functional. */
+	if (transaction_send_query(ctx, "BEGIN", NULL) < 0) {
+		if (_ctx->db->state != SQL_DB_STATE_DISCONNECTED)
+			return -1;
+		/* we got disconnected, retry */
+		return 0;
+	}
+	while (_ctx->head != NULL) {
+		if (transaction_send_query(ctx, _ctx->head->query,
+					   _ctx->head->affected_rows) < 0)
+			return -1;
+		_ctx->head = _ctx->head->next;
+	}
+	if (transaction_send_query(ctx, "COMMIT", NULL) < 0)
+		return -1;
+	return 1;
+}
+
 static int
 driver_mysql_transaction_commit_s(struct sql_transaction_context *_ctx,
 				  const char **error_r)
 {
 	struct mysql_transaction_context *ctx =
 		(struct mysql_transaction_context *)_ctx;
-	int ret = 0;
+	struct mysql_db *db = (struct mysql_db *)_ctx->db;
+	int ret = 1;
 
 	*error_r = NULL;
 
 	if (_ctx->head != NULL) {
-		/* try to use a transaction in any case,
-		   even if it doesn't work. */
-		(void)transaction_send_query(ctx, "BEGIN", NULL);
-		while (_ctx->head != NULL) {
-			if (transaction_send_query(ctx, _ctx->head->query,
-						   _ctx->head->affected_rows) < 0)
-				break;
-			_ctx->head = _ctx->head->next;
+		ret = driver_mysql_try_commit_s(ctx);
+		*error_r = t_strdup(ctx->error);
+		if (ret == 0) {
+			i_info("%s: Disconnected from database, "
+			       "retrying commit", db->dbname);
+			if (sql_connect(_ctx->db) >= 0) {
+				ctx->failed = FALSE;
+				ret = driver_mysql_try_commit_s(ctx);
+			}
 		}
-		ret = transaction_send_query(ctx, "COMMIT", NULL);
-		*error_r = ctx->error;
 	}
 	sql_transaction_rollback(&_ctx);
-	return ret;
+	return ret <= 0 ? -1 : 0;
 }
 
 static void
diff -r 3b70254e0596 -r 782f09d13ece src/lib-sql/driver-pgsql.c
--- a/src/lib-sql/driver-pgsql.c	Thu Dec 08 06:11:03 2011 +0200
+++ b/src/lib-sql/driver-pgsql.c	Thu Dec 08 07:02:03 2011 +0200
@@ -956,22 +956,16 @@
 				       "ROLLBACK" : "COMMIT");
 }
 
-static int
-driver_pgsql_transaction_commit_s(struct sql_transaction_context *_ctx,
-				  const char **error_r)
+static void
+driver_pgsql_try_commit_s(struct pgsql_transaction_context *ctx,
+			  const char **error_r)
 {
-	struct pgsql_transaction_context *ctx =
-		(struct pgsql_transaction_context *)_ctx;
+	struct sql_transaction_context *_ctx = &ctx->ctx;
 	struct pgsql_db *db = (struct pgsql_db *)_ctx->db;
 	struct sql_transaction_query *single_query = NULL;
 	struct sql_result *result;
 
-	*error_r = NULL;
-
-	if (ctx->failed || _ctx->head == NULL) {
-		/* nothing to be done */
-		result = NULL;
-	} else if (_ctx->head->next == NULL) {
+	if (_ctx->head->next == NULL) {
 		/* just a single query, send it */
 		single_query = _ctx->head;
 		result = sql_query_s(_ctx->db, single_query->query);
@@ -999,6 +993,31 @@
 	}
 	if (result != NULL)
 		sql_result_unref(result);
+}
+
+static int
+driver_pgsql_transaction_commit_s(struct sql_transaction_context *_ctx,
+				  const char **error_r)
+{
+	struct pgsql_transaction_context *ctx =
+		(struct pgsql_transaction_context *)_ctx;
+	struct pgsql_db *db = (struct pgsql_db *)_ctx->db;
+
+	*error_r = NULL;
+
+	if (_ctx->head != NULL) {
+		driver_pgsql_try_commit_s(ctx, error_r);
+		if (_ctx->db->state == SQL_DB_STATE_DISCONNECTED) {
+			*error_r = t_strdup(*error_r);
+			i_info("%s: Disconnected from database, "
+			       "retrying commit", pgsql_prefix(db));
+			if (sql_connect(_ctx->db) >= 0) {
+				ctx->failed = FALSE;
+				*error_r = NULL;
+				driver_pgsql_try_commit_s(ctx, error_r);
+			}
+		}
+	}
 
 	i_assert(ctx->refcount == 1);
 	driver_pgsql_transaction_unref(ctx);


More information about the dovecot-cvs mailing list