diff options
Diffstat (limited to 'src/stasis/plugin_anastasis_postgres.c')
-rw-r--r-- | src/stasis/plugin_anastasis_postgres.c | 78 |
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; } |