summaryrefslogtreecommitdiff
path: root/src/stasis/plugin_anastasis_postgres.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stasis/plugin_anastasis_postgres.c')
-rw-r--r--src/stasis/plugin_anastasis_postgres.c78
1 files changed, 73 insertions, 5 deletions
diff --git a/src/stasis/plugin_anastasis_postgres.c b/src/stasis/plugin_anastasis_postgres.c
index b78dbdb..b1be081 100644
--- a/src/stasis/plugin_anastasis_postgres.c
+++ b/src/stasis/plugin_anastasis_postgres.c
@@ -72,6 +72,10 @@ struct PostgresClosure
*/
char *currency;
+ /**
+ * Prepared statements have been initialized.
+ */
+ bool init;
};
@@ -524,38 +528,102 @@ check_connection (void *cls)
/**
+ * Connect to the database if the connection does not exist yet.
+ *
+ * @param pg the plugin-specific state
+ * @param skip_prepare true if we should skip prepared statement setup
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+internal_setup (struct PostgresClosure *pg,
+ bool skip_prepare)
+{
+ if (NULL == pg->conn)
+ {
+#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_EXECUTE_STATEMENT_END
+ };
+#else
+ struct GNUNET_PQ_ExecuteStatement *es = NULL;
+#endif
+ struct GNUNET_PQ_Context *db_conn;
+
+ db_conn = GNUNET_PQ_connect_with_cfg (pg->cfg,
+ "exchangedb-postgres",
+ NULL,
+ es,
+ NULL);
+ if (NULL == db_conn)
+ return GNUNET_SYSERR;
+ pg->conn = db_conn;
+ }
+ if (NULL == pg->transaction_name)
+ GNUNET_PQ_reconnect_if_down (pg->conn);
+ if (pg->init)
+ return GNUNET_OK;
+ if (skip_prepare)
+ return GNUNET_OK;
+ return postgres_connect (pg);
+}
+
+
+/**
* Do a pre-flight check that we are not in an uncommitted transaction.
* If we are, try to commit the previous transaction and output a warning.
* Does not return anything, as we will continue regardless of the outcome.
*
* @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @return #GNUNET_OK if everything is fine
+ * #GNUNET_NO if a transaction was rolled back
+ * #GNUNET_SYSERR on hard errors
*/
-static void
+static enum GNUNET_GenericReturnValue
postgres_preflight (void *cls)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_make_execute ("COMMIT"),
+ GNUNET_PQ_make_execute ("ROLLBACK"),
GNUNET_PQ_EXECUTE_STATEMENT_END
};
+ if (! pg->init)
+ {
+ if (GNUNET_OK !=
+ internal_setup (pg,
+ false))
+ return GNUNET_SYSERR;
+ }
if (NULL == pg->transaction_name)
- return; /* all good */
+ return GNUNET_OK; /* all good */
if (GNUNET_OK ==
GNUNET_PQ_exec_statements (pg->conn,
es))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "BUG: Preflight check committed transaction `%s'!\n",
+ "BUG: Preflight check rolled back transaction `%s'!\n",
pg->transaction_name);
}
else
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "BUG: Preflight check failed to commit transaction `%s'!\n",
+ "BUG: Preflight check failed to rollback transaction `%s'!\n",
pg->transaction_name);
}
pg->transaction_name = NULL;
+ return GNUNET_NO;
}