summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/anastasis_database_plugin.h7
-rw-r--r--src/stasis/anastasis-dbinit.c46
-rw-r--r--src/stasis/plugin_anastasis_postgres.c78
3 files changed, 119 insertions, 12 deletions
diff --git a/src/include/anastasis_database_plugin.h b/src/include/anastasis_database_plugin.h
index bc4b0e6..7bf91a2 100644
--- a/src/include/anastasis_database_plugin.h
+++ b/src/include/anastasis_database_plugin.h
@@ -232,9 +232,12 @@ struct ANASTASIS_DatabasePlugin
* 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
*/
- void
- (*preflight) (void *cls);
+ enum GNUNET_GenericReturnValue
+ (*preflight)(void *cls);
/**
* Check that the database connection is still up.
diff --git a/src/stasis/anastasis-dbinit.c b/src/stasis/anastasis-dbinit.c
index 17b3c56..a0e17db 100644
--- a/src/stasis/anastasis-dbinit.c
+++ b/src/stasis/anastasis-dbinit.c
@@ -34,6 +34,11 @@ static int global_ret;
static int reset_db;
/**
+ * -g option: do garbate collection
+ */
+static int gc_db;
+
+/**
* Main function that will be run.
*
* @param cls closure
@@ -54,21 +59,49 @@ run (void *cls,
{
fprintf (stderr,
"Failed to initialize database plugin.\n");
- global_ret = EXIT_FAILURE;
+ global_ret = EXIT_NOTINSTALLED;
return;
}
if (reset_db)
{
- (void) plugin->drop_tables (plugin->cls);
- ANASTASIS_DB_plugin_unload (plugin);
- plugin = ANASTASIS_DB_plugin_load (cfg);
+ if (GNUNET_OK != plugin->drop_tables (plugin->cls))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not drop tables as requested. Either database was not yet initialized, or permission denied. Consult the logs. Will still try to create new tables.\n");
+ }
}
if (GNUNET_OK !=
plugin->create_tables (plugin->cls))
{
global_ret = EXIT_FAILURE;
+ ANASTASIS_DB_plugin_unload (plugin);
return;
}
+ if (gc_db)
+ {
+ struct GNUNET_TIME_Absolute expire_backups;
+ struct GNUNET_TIME_Absolute expire_payments;
+ struct GNUNET_TIME_Absolute now;
+
+ now = GNUNET_TIME_absolute_get ();
+ expire_backups = GNUNET_TIME_absolute_subtract (
+ now,
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_MONTHS,
+ 6));
+ expire_payments = GNUNET_TIME_absolute_subtract (
+ now,
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_YEARS,
+ 10));
+ if (0 > plugin->gc (plugin->cls,
+ expire_backups,
+ expire_payments))
+ {
+ fprintf (stderr,
+ "Garbage collection failed!\n");
+ }
+ }
ANASTASIS_DB_plugin_unload (plugin);
}
@@ -86,7 +119,10 @@ main (int argc,
char *const *argv)
{
struct GNUNET_GETOPT_CommandLineOption options[] = {
-
+ GNUNET_GETOPT_option_flag ('g',
+ "garbagecollect",
+ "remove state data from database",
+ &gc_db),
GNUNET_GETOPT_option_flag ('r',
"reset",
"reset database (DANGEROUS: all existing data is lost!)",
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;
}