summaryrefslogtreecommitdiff
path: root/src/exchangedb
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-03-12 11:33:10 +0100
committerChristian Grothoff <christian@grothoff.org>2018-03-12 11:33:10 +0100
commita166ca7fece8bbe3c66dcf0217cc81d20d185ab0 (patch)
treeb9cf10b1034e3f1d4d9c367ef2faa7e6bd206404 /src/exchangedb
parent1ae2ba3d0a035734e4a28432e3246e58338fe9e8 (diff)
downloadexchange-a166ca7fece8bbe3c66dcf0217cc81d20d185ab0.tar.gz
exchange-a166ca7fece8bbe3c66dcf0217cc81d20d185ab0.tar.bz2
exchange-a166ca7fece8bbe3c66dcf0217cc81d20d185ab0.zip
fix #5281 for exchange: do preflight check that an old transaction is no longer running by accident
Diffstat (limited to 'src/exchangedb')
-rw-r--r--src/exchangedb/perf_taler_exchangedb_interpreter.c3
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c62
-rw-r--r--src/exchangedb/test_exchangedb.c21
3 files changed, 75 insertions, 11 deletions
diff --git a/src/exchangedb/perf_taler_exchangedb_interpreter.c b/src/exchangedb/perf_taler_exchangedb_interpreter.c
index b9bf9c32e..8a81befdb 100644
--- a/src/exchangedb/perf_taler_exchangedb_interpreter.c
+++ b/src/exchangedb/perf_taler_exchangedb_interpreter.c
@@ -1159,7 +1159,8 @@ interpret (struct PERF_TALER_EXCHANGEDB_interpreter_state *state)
case PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION:
GNUNET_break (GNUNET_OK ==
state->plugin->start (state->plugin->cls,
- state->session));
+ state->session,
+ "perf-interpreter"));
break;
case PERF_TALER_EXCHANGEDB_CMD_COMMIT_TRANSACTION:
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index a4f32cdc4..d6a9b2838 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015, 2016, 2017 GNUnet e.V.
+ Copyright (C) 2014, 2015, 2016, 2017, 2018 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -60,6 +60,11 @@ struct TALER_EXCHANGEDB_Session
*/
PGconn *conn;
+ /**
+ * Name of the current transaction, for debugging.
+ */
+ const char *transaction_name;
+
};
@@ -1533,11 +1538,14 @@ postgres_get_session (void *cls)
*
* @param cls the `struct PostgresClosure` with the plugin-specific state
* @param session the database connection
+ * @param name unique name identifying the transaction (for debugging)
+ * must point to a constant
* @return #GNUNET_OK on success
*/
static int
postgres_start (void *cls,
- struct TALER_EXCHANGEDB_Session *session)
+ struct TALER_EXCHANGEDB_Session *session,
+ const char *name)
{
PGresult *result;
ExecStatusType ex;
@@ -1552,9 +1560,11 @@ postgres_start (void *cls,
PQerrorMessage (session->conn));
GNUNET_break (0);
PQclear (result);
+ session->transaction_name = NULL;
return GNUNET_SYSERR;
}
PQclear (result);
+ session->transaction_name = name;
return GNUNET_OK;
}
@@ -1577,6 +1587,7 @@ postgres_rollback (void *cls,
GNUNET_break (PGRES_COMMAND_OK ==
PQresultStatus (result));
PQclear (result);
+ session->transaction_name = NULL;
}
@@ -1594,10 +1605,50 @@ postgres_commit (void *cls,
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_end
};
+ enum GNUNET_DB_QueryStatus qs;
- return GNUNET_PQ_eval_prepared_non_select (session->conn,
- "do_commit",
- params);
+ qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
+ "do_commit",
+ params);
+ session->transaction_name = NULL;
+ return qs;
+}
+
+
+/**
+ * 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
+ * @param session the database connection
+ */
+static void
+postgres_preflight (void *cls,
+ struct TALER_EXCHANGEDB_Session *session)
+{
+ PGresult *result;
+ ExecStatusType status;
+
+ if (NULL == session->transaction_name)
+ return; /* all good */
+ result = PQexec (session->conn,
+ "COMMIT");
+ status = PQresultStatus (result);
+ if (PGRES_COMMAND_OK == status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "BUG: Preflight check committed transaction `%s'!\n",
+ session->transaction_name);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "BUG: Preflight check failed to commit transaction `%s'!\n",
+ session->transaction_name);
+ }
+ session->transaction_name = NULL;
+ PQclear (result);
}
@@ -6363,6 +6414,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
plugin->create_tables = &postgres_create_tables;
plugin->start = &postgres_start;
plugin->commit = &postgres_commit;
+ plugin->preflight = &postgres_preflight;
plugin->rollback = &postgres_rollback;
plugin->insert_denomination_info = &postgres_insert_denomination_info;
plugin->get_denomination_info = &postgres_get_denomination_info;
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index a0eb50f08..36f0cce4e 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -1545,7 +1545,8 @@ run (void *cls)
FAILIF (GNUNET_OK !=
plugin->start (plugin->cls,
- session));
+ session,
+ "test-1"));
/* test DB is empty */
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
@@ -1909,7 +1910,8 @@ run (void *cls)
session));
FAILIF (GNUNET_OK !=
plugin->start (plugin->cls,
- session));
+ session,
+ "test-2"));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->mark_deposit_tiny (plugin->cls,
session,
@@ -1928,7 +1930,8 @@ run (void *cls)
&deposit));
FAILIF (GNUNET_OK !=
plugin->start (plugin->cls,
- session));
+ session,
+ "test-3"));
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->test_deposit_done (plugin->cls,
session,
@@ -1992,9 +1995,12 @@ run (void *cls)
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->commit (plugin->cls,
session));
+ plugin->preflight (plugin->cls,
+ session);
FAILIF (GNUNET_OK !=
plugin->start (plugin->cls,
- session));
+ session,
+ "test-4"));
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->insert_denomination_revocation (plugin->cls,
session,
@@ -2002,9 +2008,12 @@ run (void *cls)
&master_sig));
plugin->rollback (plugin->cls,
session);
+ plugin->preflight (plugin->cls,
+ session);
FAILIF (GNUNET_OK !=
plugin->start (plugin->cls,
- session));
+ session,
+ "test-5"));
{
struct TALER_MasterSignatureP msig;
uint64_t rev_rowid;
@@ -2164,6 +2173,8 @@ run (void *cls)
FAILIF (GNUNET_OK !=
test_wire_fees (session));
+ plugin->preflight (plugin->cls,
+ session);
result = 0;