commit cb75aba77326901fbd06365887ff53b2f37a3e66
parent ece7efaa0fcfb3e2015a402a3fe2275fbc1a587d
Author: Christian Grothoff <christian@grothoff.org>
Date: Sat, 13 Jun 2026 21:00:08 +0200
refactor to use new more robust GNUNET_PQ_init() style to handle database connection drops better
Diffstat:
4 files changed, 103 insertions(+), 133 deletions(-)
diff --git a/src/donaudb/create_tables.c b/src/donaudb/create_tables.c
@@ -29,53 +29,46 @@
enum GNUNET_GenericReturnValue
DONAUDB_create_tables (struct DONAUDB_PostgresContext *ctx)
{
- struct GNUNET_PQ_Context *conn;
- enum GNUNET_GenericReturnValue ret = GNUNET_OK;
-
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_end
};
- struct GNUNET_PQ_PreparedStatement ps[] = {
- GNUNET_PQ_make_prepare ("create_tables",
- "CALL"
- " donau.do_create_tables"
- " ();"),
- GNUNET_PQ_PREPARED_STATEMENT_END
- };
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_try_execute ("SET search_path TO donau;"),
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
- conn = GNUNET_PQ_connect_with_cfg (ctx->cfg,
- "donaudb-postgres",
- "donau-",
- es,
- ps);
- if (NULL == conn)
+ if (GNUNET_SYSERR ==
+ GNUNET_PQ_load_versioning (ctx->conn))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_PQ_run_sql (ctx->conn,
+ "donau-"))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_PQ_exec_sql (ctx->conn,
+ "procedures"))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to connect to database\n");
+ "Failed to load stored procedures\n");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_PQ_prepare_anon (ctx->conn,
+ "CALL donau.do_create_tables();"))
+ {
+ GNUNET_break (0);
return GNUNET_SYSERR;
}
if (0 >
- GNUNET_PQ_eval_prepared_non_select (conn,
- "create_tables",
+ GNUNET_PQ_eval_prepared_non_select (ctx->conn,
+ "",
params))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to create tables\n");
- ret = GNUNET_SYSERR;
- }
- if (GNUNET_OK == ret)
- {
- ret = GNUNET_PQ_exec_sql (conn,
- "procedures");
- if (GNUNET_OK != ret)
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to load stored procedures: %d\n",
- ret);
+ return GNUNET_SYSERR;
}
- GNUNET_PQ_disconnect (conn);
- return ret;
+ return GNUNET_OK;
}
diff --git a/src/donaudb/drop_tables.c b/src/donaudb/drop_tables.c
@@ -26,32 +26,9 @@
#include "helper.h"
-/**
- * Drop all Taler tables. This should only be used by testcases.
- *
- * @param ctx the `struct DONAUDB_PostgresContext` with the plugin-specific state
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
enum GNUNET_GenericReturnValue
DONAUDB_drop_tables (struct DONAUDB_PostgresContext *ctx)
{
- struct GNUNET_PQ_Context *conn;
- enum GNUNET_GenericReturnValue ret;
-
- if (NULL != ctx->conn)
- {
- GNUNET_PQ_disconnect (ctx->conn);
- ctx->conn = NULL;
- }
- conn = GNUNET_PQ_connect_with_cfg (ctx->cfg,
- "donaudb-postgres",
- NULL,
- NULL,
- NULL);
- if (NULL == conn)
- return GNUNET_SYSERR;
- ret = GNUNET_PQ_exec_sql (conn,
- "drop");
- GNUNET_PQ_disconnect (conn);
- return ret;
+ return GNUNET_PQ_exec_sql (ctx->conn,
+ "drop");
}
diff --git a/src/donaudb/plugin_donaudb_postgres.c b/src/donaudb/plugin_donaudb_postgres.c
@@ -23,6 +23,9 @@
#include <poll.h>
#include <pthread.h>
#include <libpq-fe.h>
+struct DONAUDB_PostgresContext;
+#define GNUNET_PQ_RECONNECT_CALLBACK_CLOSURE \
+ struct DONAUDB_PostgresContext
#include "helper.h"
/**
@@ -34,21 +37,55 @@
/**
- * Log a really unexpected PQ error with all the details we can get hold of.
+ * Function called each time we connect or reconnect to the
+ * database. Gives the application a chance to run some
+ * per-connection initialization logic.
*
- * @param result PQ result object of the PQ operation that failed
- * @param conn SQL connection that was used
+ * @param pg database conntext in the donau
+ * @param pq database connection handle
*/
-#define BREAK_DB_ERR(result,conn) do { \
- GNUNET_break (0); \
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \
- "Database failure: %s/%s/%s/%s/%s", \
- PQresultErrorField (result, PG_DIAG_MESSAGE_PRIMARY), \
- PQresultErrorField (result, PG_DIAG_MESSAGE_DETAIL), \
- PQresultErrorMessage (result), \
- PQresStatus (PQresultStatus (result)), \
- PQerrorMessage (conn)); \
-} while (0)
+static void
+reconnect_cb (struct DONAUDB_PostgresContext *pg,
+ struct GNUNET_PQ_Context *pq)
+{
+#if AUTO_EXPLAIN
+ /* Enable verbose logging to see where queries do not
+ properly use indices */
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"),
+ GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"),
+ GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"),
+ GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"),
+ /* https://wiki.postgresql.org/wiki/Serializable suggests to really
+ force the default to 'serializable' if SSI is to be used. */
+ GNUNET_PQ_make_try_execute (
+ "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
+ GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
+ GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
+ GNUNET_PQ_make_try_execute ("SET search_path TO donau;"),
+ GNUNET_PQ_EXECUTE_STATEMENT_END
+ };
+#else
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_try_execute (
+ "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
+ GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
+ GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
+ GNUNET_PQ_make_try_execute ("SET autocommit=OFF;"),
+ GNUNET_PQ_make_try_execute ("SET search_path TO donau;"),
+ GNUNET_PQ_EXECUTE_STATEMENT_END
+ };
+#endif
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_exec_statements (pq,
+ es))
+ {
+ GNUNET_break (0);
+ return;
+ }
+ pg->prep_gen++;
+}
/**
@@ -57,54 +94,25 @@
* @param pg the plugin-specific state
* @return #GNUNET_OK on success
*/
-enum GNUNET_GenericReturnValue
-DONAUDB_internal_setup (struct DONAUDB_PostgresContext *pg)
+static enum GNUNET_GenericReturnValue
+internal_setup (struct DONAUDB_PostgresContext *pg)
{
- if (NULL == pg->conn)
+ struct GNUNET_PQ_Context *db_conn;
+
+ if (NULL != pg->conn)
+ return GNUNET_OK;
+ db_conn = GNUNET_PQ_init (pg->cfg,
+ "donaudb-postgres",
+ &reconnect_cb,
+ pg);
+ if (NULL == db_conn)
+ return GNUNET_SYSERR;
+ if (0 == pg->prep_gen)
{
-#if AUTO_EXPLAIN
- /* Enable verbose logging to see where queries do not
- properly use indices */
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_try_execute ("LOAD 'auto_explain';"),
- GNUNET_PQ_make_try_execute ("SET auto_explain.log_min_duration=50;"),
- GNUNET_PQ_make_try_execute ("SET auto_explain.log_timing=TRUE;"),
- GNUNET_PQ_make_try_execute ("SET auto_explain.log_analyze=TRUE;"),
- /* https://wiki.postgresql.org/wiki/Serializable suggests to really
- force the default to 'serializable' if SSI is to be used. */
- GNUNET_PQ_make_try_execute (
- "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
- GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
- GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
- GNUNET_PQ_make_try_execute ("SET search_path TO donau;"),
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
-#else
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_try_execute (
- "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"),
- GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"),
- GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"),
- GNUNET_PQ_make_try_execute ("SET autocommit=OFF;"),
- GNUNET_PQ_make_try_execute ("SET search_path TO donau;"),
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
-#endif
- struct GNUNET_PQ_Context *db_conn;
-
- db_conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
- "donaudb-postgres",
- NULL,
- es,
- NULL);
- if (NULL == db_conn)
- return GNUNET_SYSERR;
-
- pg->prep_gen++;
- pg->conn = db_conn;
+ GNUNET_PQ_disconnect (db_conn);
+ return GNUNET_SYSERR;
}
- if (NULL == pg->transaction_name)
- GNUNET_PQ_reconnect_if_down (pg->conn);
+ pg->conn = db_conn;
return GNUNET_OK;
}
@@ -125,27 +133,22 @@ DONAUDB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"donau",
"BASE_URL");
- GNUNET_free (pg);
- return NULL;
+ goto fail;
}
if (GNUNET_OK !=
TALER_config_get_currency (cfg,
"donau",
&pg->currency))
{
- GNUNET_free (pg->donau_url);
- GNUNET_free (pg);
- return NULL;
+ goto fail;
}
if (GNUNET_OK !=
- DONAUDB_internal_setup (pg))
- {
- GNUNET_free (pg->donau_url);
- GNUNET_free (pg->currency);
- GNUNET_free (pg);
- return NULL;
- }
+ internal_setup (pg))
+ goto fail;
return pg;
+fail:
+ DONAUDB_disconnect (pg);
+ return NULL;
}
diff --git a/src/donaudb/preflight.c b/src/donaudb/preflight.c
@@ -34,9 +34,6 @@ DONAUDB_preflight (struct DONAUDB_PostgresContext *ctx)
GNUNET_PQ_EXECUTE_STATEMENT_END
};
- if (GNUNET_OK !=
- DONAUDB_internal_setup (ctx))
- return GNUNET_SYSERR;
if (NULL == ctx->transaction_name)
return GNUNET_OK; /* all good */
if (GNUNET_OK ==