diff options
author | Christian Grothoff <christian@grothoff.org> | 2018-03-12 11:33:10 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2018-03-12 11:33:10 +0100 |
commit | a166ca7fece8bbe3c66dcf0217cc81d20d185ab0 (patch) | |
tree | b9cf10b1034e3f1d4d9c367ef2faa7e6bd206404 /src/exchangedb | |
parent | 1ae2ba3d0a035734e4a28432e3246e58338fe9e8 (diff) | |
download | exchange-a166ca7fece8bbe3c66dcf0217cc81d20d185ab0.tar.xz |
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.c | 3 | ||||
-rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 62 | ||||
-rw-r--r-- | src/exchangedb/test_exchangedb.c | 21 |
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; |