summaryrefslogtreecommitdiff
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
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
-rw-r--r--src/auditor/taler-auditor.c11
-rw-r--r--src/auditor/taler-wire-auditor.c5
-rw-r--r--src/exchange/taler-exchange-aggregator.c19
-rw-r--r--src/exchange/taler-exchange-httpd_db.c7
-rw-r--r--src/exchange/taler-exchange-httpd_db.h4
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.c1
-rw-r--r--src/exchange/taler-exchange-httpd_keystate.c2
-rw-r--r--src/exchange/taler-exchange-httpd_payback.c1
-rw-r--r--src/exchange/taler-exchange-httpd_refresh_link.c1
-rw-r--r--src/exchange/taler-exchange-httpd_refresh_melt.c1
-rw-r--r--src/exchange/taler-exchange-httpd_refresh_reveal.c1
-rw-r--r--src/exchange/taler-exchange-httpd_refund.c1
-rw-r--r--src/exchange/taler-exchange-httpd_reserve_status.c3
-rw-r--r--src/exchange/taler-exchange-httpd_reserve_withdraw.c1
-rw-r--r--src/exchange/taler-exchange-httpd_track_transaction.c17
-rw-r--r--src/exchange/taler-exchange-httpd_track_transfer.c5
-rw-r--r--src/exchange/taler-exchange-wirewatch.c5
-rw-r--r--src/exchange/test_taler_exchange_aggregator.c6
-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
-rw-r--r--src/include/taler_exchangedb_plugin.h20
22 files changed, 157 insertions, 40 deletions
diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c
index e807378fe..b8f6c624c 100644
--- a/src/auditor/taler-auditor.c
+++ b/src/auditor/taler-auditor.c
@@ -1890,7 +1890,7 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Detected applicable deposit of %s\n",
TALER_amount2s (&amount_without_fee));
- deposit_fee = fee;
+ deposit_fee = fee;
}
/* Check that the fees given in the transaction list and in dki match */
TALER_amount_ntoh (&tmp,
@@ -2006,7 +2006,7 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
merchant_gain,
deposit_fee));
}
-
+
/* Calculate total balance change, i.e. expenditures minus refunds */
if (GNUNET_SYSERR ==
TALER_amount_subtract (&spent,
@@ -3906,8 +3906,11 @@ transact (Analysis analysis,
GNUNET_break (0);
return GNUNET_SYSERR;
}
+ edb->preflight (edb->cls,
+ esession);
ret = edb->start (edb->cls,
- esession);
+ esession,
+ "auditor");
if (GNUNET_OK != ret)
{
GNUNET_break (0);
@@ -3918,7 +3921,7 @@ transact (Analysis analysis,
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
{
qs = edb->commit (edb->cls,
- esession);
+ esession);
if (0 > qs)
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
diff --git a/src/auditor/taler-wire-auditor.c b/src/auditor/taler-wire-auditor.c
index 8ba38d39c..55a2a05fb 100644
--- a/src/auditor/taler-wire-auditor.c
+++ b/src/auditor/taler-wire-auditor.c
@@ -1412,8 +1412,11 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
+ edb->preflight (edb->cls,
+ esession);
ret = edb->start (edb->cls,
- esession);
+ esession,
+ "wire auditor");
if (GNUNET_OK != ret)
{
GNUNET_break (0);
diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c
index d5d43052d..49cbb2b93 100644
--- a/src/exchange/taler-exchange-aggregator.c
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -618,7 +618,7 @@ refund_by_coin_cb (void *cls,
}
return GNUNET_OK;
}
-
+
/**
* Function called with details about deposits that have been made,
@@ -675,7 +675,7 @@ deposit_cb (void *cls,
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
return qs;
}
-
+
GNUNET_assert (NULL == au->wire);
au->wire = json_incref ((json_t *) wire);
if (GNUNET_OK !=
@@ -810,7 +810,7 @@ aggregate_cb (void *cls,
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
return qs;
}
-
+
if (au->rows_offset >= aggregation_limit)
{
/* Bug: we asked for at most #aggregation_limit results! */
@@ -1203,9 +1203,12 @@ run_reserve_closures (void *cls)
GNUNET_SCHEDULER_shutdown ();
return;
}
+ db_plugin->preflight (db_plugin->cls,
+ session);
if (GNUNET_OK !=
db_plugin->start (db_plugin->cls,
- session))
+ session,
+ "aggregator reserve closures"))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to start database transaction!\n");
@@ -1413,7 +1416,8 @@ run_aggregation (void *cls)
transaction to mark all* of the selected deposits as minor! */
if (GNUNET_OK !=
db_plugin->start (db_plugin->cls,
- session))
+ session,
+ "aggregator mark tiny transactions"))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to start database transaction!\n");
@@ -1767,9 +1771,12 @@ run_transfers (void *cls)
GNUNET_SCHEDULER_shutdown ();
return;
}
+ db_plugin->preflight (db_plugin->cls,
+ session);
if (GNUNET_OK !=
db_plugin->start (db_plugin->cls,
- session))
+ session,
+ "aggregator run transfer"))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to start database transaction!\n");
diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c
index bd7777ce3..7817de990 100644
--- a/src/exchange/taler-exchange-httpd_db.c
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -41,6 +41,7 @@
* errors, generates an error message for @a connection.
*
* @param connection MHD connection to run @a cb for
+ * @param name name of the transaction (for debugging)
* @param[out] set to MHD response code, if transaction failed
* @param cb callback implementing transaction logic
* @param cb_cls closure for @a cb, must be read-only!
@@ -48,6 +49,7 @@
*/
int
TEH_DB_run_transaction (struct MHD_Connection *connection,
+ const char *name,
int *mhd_ret,
TEH_DB_TransactionCallback cb,
void *cb_cls)
@@ -64,13 +66,16 @@ TEH_DB_run_transaction (struct MHD_Connection *connection,
TALER_EC_DB_SETUP_FAILED);
return GNUNET_SYSERR;
}
+ TEH_plugin->preflight (TEH_plugin->cls,
+ session);
for (unsigned int retries = 0;retries < MAX_TRANSACTION_COMMIT_RETRIES; retries++)
{
enum GNUNET_DB_QueryStatus qs;
if (GNUNET_OK !=
TEH_plugin->start (TEH_plugin->cls,
- session))
+ session,
+ name))
{
GNUNET_break (0);
if (NULL != mhd_ret)
diff --git a/src/exchange/taler-exchange-httpd_db.h b/src/exchange/taler-exchange-httpd_db.h
index 7e342c842..2a42bcd85 100644
--- a/src/exchange/taler-exchange-httpd_db.h
+++ b/src/exchange/taler-exchange-httpd_db.h
@@ -52,8 +52,9 @@ typedef enum GNUNET_DB_QueryStatus
* attempts to commit the transaction. Upon soft failures,
* retries @a cb a few times. Upon hard or persistent soft
* errors, generates an error message for @a connection.
- *
+ *
* @param connection MHD connection to run @a cb for
+ * @param name name of the transaction (for debugging)
* @param[out] set to MHD response code, if transaction failed
* @param cb callback implementing transaction logic
* @param cb_cls closure for @a cb, must be read-only!
@@ -61,6 +62,7 @@ typedef enum GNUNET_DB_QueryStatus
*/
int
TEH_DB_run_transaction (struct MHD_Connection *connection,
+ const char *name,
int *mhd_ret,
TEH_DB_TransactionCallback cb,
void *cb_cls);
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c
index 542c56c9c..277430b2d 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -289,6 +289,7 @@ verify_and_execute_deposit (struct MHD_Connection *connection,
dc.deposit = deposit;
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
+ "execute deposit",
&mhd_ret,
&deposit_transaction,
&dc))
diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c
index 0428b1016..042773bf9 100644
--- a/src/exchange/taler-exchange-httpd_keystate.c
+++ b/src/exchange/taler-exchange-httpd_keystate.c
@@ -711,6 +711,7 @@ reload_keys_denom_iter (void *cls,
arc.revocation_master_sig = revocation_master_sig;
if (GNUNET_OK !=
TEH_DB_run_transaction (NULL,
+ "add denomination key revocations",
NULL,
&add_revocations_transaction,
&arc))
@@ -739,6 +740,7 @@ reload_keys_denom_iter (void *cls,
if (GNUNET_OK !=
TEH_DB_run_transaction (NULL,
+ "add denomination key",
NULL,
&add_denomination_transaction,
(void *) dki))
diff --git a/src/exchange/taler-exchange-httpd_payback.c b/src/exchange/taler-exchange-httpd_payback.c
index e6fade49e..6f910b55b 100644
--- a/src/exchange/taler-exchange-httpd_payback.c
+++ b/src/exchange/taler-exchange-httpd_payback.c
@@ -396,6 +396,7 @@ verify_and_execute_payback (struct MHD_Connection *connection,
pc.coin = coin;
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
+ "run payback",
&mhd_ret,
&payback_transaction,
&pc))
diff --git a/src/exchange/taler-exchange-httpd_refresh_link.c b/src/exchange/taler-exchange-httpd_refresh_link.c
index aee23369c..0ec505a84 100644
--- a/src/exchange/taler-exchange-httpd_refresh_link.c
+++ b/src/exchange/taler-exchange-httpd_refresh_link.c
@@ -203,6 +203,7 @@ TEH_REFRESH_handler_refresh_link (struct TEH_RequestHandler *rh,
ctx.mlist = json_array ();
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
+ "run link",
&mhd_ret,
&refresh_link_transaction,
&ctx))
diff --git a/src/exchange/taler-exchange-httpd_refresh_melt.c b/src/exchange/taler-exchange-httpd_refresh_melt.c
index 400d2bb8c..384589df1 100644
--- a/src/exchange/taler-exchange-httpd_refresh_melt.c
+++ b/src/exchange/taler-exchange-httpd_refresh_melt.c
@@ -364,6 +364,7 @@ handle_refresh_melt (struct MHD_Connection *connection,
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
+ "run melt",
&mhd_ret,
&refresh_melt_transaction,
rmc))
diff --git a/src/exchange/taler-exchange-httpd_refresh_reveal.c b/src/exchange/taler-exchange-httpd_refresh_reveal.c
index 4a7cd33db..b0451842d 100644
--- a/src/exchange/taler-exchange-httpd_refresh_reveal.c
+++ b/src/exchange/taler-exchange-httpd_refresh_reveal.c
@@ -587,6 +587,7 @@ handle_refresh_reveal_json (struct MHD_Connection *connection,
/* do transactional work */
if (GNUNET_OK ==
TEH_DB_run_transaction (connection,
+ "run reveal",
&res,
&refresh_reveal_transaction,
rctx))
diff --git a/src/exchange/taler-exchange-httpd_refund.c b/src/exchange/taler-exchange-httpd_refund.c
index 986c9d312..97cd9351f 100644
--- a/src/exchange/taler-exchange-httpd_refund.c
+++ b/src/exchange/taler-exchange-httpd_refund.c
@@ -452,6 +452,7 @@ verify_and_execute_refund (struct MHD_Connection *connection,
}
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
+ "run refund",
&mhd_ret,
&refund_transaction,
(void *) refund))
diff --git a/src/exchange/taler-exchange-httpd_reserve_status.c b/src/exchange/taler-exchange-httpd_reserve_status.c
index f87afa5ae..998460da7 100644
--- a/src/exchange/taler-exchange-httpd_reserve_status.c
+++ b/src/exchange/taler-exchange-httpd_reserve_status.c
@@ -78,7 +78,7 @@ struct ReserveStatusContext
/**
- * Function implementing /reserve/status transaction.
+ * Function implementing /reserve/status transaction.
* Execute a /reserve/status. Given the public key of a reserve,
* return the associated transaction history. Runs the
* transaction logic; IF it returns a non-error code, the transaction
@@ -144,6 +144,7 @@ TEH_RESERVE_handler_reserve_status (struct TEH_RequestHandler *rh,
rsc.rh = NULL;
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
+ "get reserve status",
&mhd_ret,
&reserve_status_transaction,
&rsc))
diff --git a/src/exchange/taler-exchange-httpd_reserve_withdraw.c b/src/exchange/taler-exchange-httpd_reserve_withdraw.c
index 11265b43c..3f2bc3173 100644
--- a/src/exchange/taler-exchange-httpd_reserve_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_reserve_withdraw.c
@@ -492,6 +492,7 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh,
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
+ "run reserve withdraw",
&mhd_ret,
&withdraw_transaction,
&wc))
diff --git a/src/exchange/taler-exchange-httpd_track_transaction.c b/src/exchange/taler-exchange-httpd_track_transaction.c
index 13a106621..fdda22b8d 100644
--- a/src/exchange/taler-exchange-httpd_track_transaction.c
+++ b/src/exchange/taler-exchange-httpd_track_transaction.c
@@ -120,25 +120,25 @@ struct DepositWtidContext
* Public key of the merchant.
*/
const struct TALER_MerchantPublicKeyP *merchant_pub;
-
+
/**
* Set by #handle_wtid data to the wire transfer ID.
- */
+ */
struct TALER_WireTransferIdentifierRawP wtid;
-
+
/**
* Set by #handle_wtid data to the coin's contribution to the wire transfer.
- */
+ */
struct TALER_Amount coin_contribution;
-
+
/**
* Set by #handle_wtid data to the fee charged to the coin.
- */
+ */
struct TALER_Amount coin_fee;
/**
* Set by #handle_wtid data to the wire transfer execution time.
- */
+ */
struct GNUNET_TIME_Absolute execution_time;
/**
@@ -289,9 +289,10 @@ check_and_handle_track_transaction_request (struct MHD_Connection *connection,
ctx.pending = GNUNET_NO;
ctx.tps = tps;
ctx.merchant_pub = merchant_pub;
-
+
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
+ "handle track transaction",
&mhd_ret,
&track_transaction_transaction,
&ctx))
diff --git a/src/exchange/taler-exchange-httpd_track_transfer.c b/src/exchange/taler-exchange-httpd_track_transfer.c
index 38c6c29e3..493febc21 100644
--- a/src/exchange/taler-exchange-httpd_track_transfer.c
+++ b/src/exchange/taler-exchange-httpd_track_transfer.c
@@ -141,7 +141,7 @@ reply_track_transfer_details (struct MHD_Connection *connection,
TALER_EC_EXCHANGE_BAD_CONFIGURATION,
"no keys");
}
-
+
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
@@ -327,7 +327,7 @@ handle_transaction_data (void *cls,
/**
* Execute a "/track/transfer". Returns the transaction information
* associated with the given wire transfer identifier.
- *
+ *
* If it returns a non-error code, the transaction logic MUST
* NOT queue a MHD response. IF it returns an hard error, the
* transaction logic MUST queue a MHD response and set @a mhd_ret. IF
@@ -474,6 +474,7 @@ TEH_TRACKING_handler_track_transfer (struct TEH_RequestHandler *rh,
return MHD_YES; /* parse error */
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
+ "run track transfer",
&mhd_ret,
&track_transfer_transaction,
&ctx))
diff --git a/src/exchange/taler-exchange-wirewatch.c b/src/exchange/taler-exchange-wirewatch.c
index 856a62019..e9f9276ca 100644
--- a/src/exchange/taler-exchange-wirewatch.c
+++ b/src/exchange/taler-exchange-wirewatch.c
@@ -422,9 +422,12 @@ find_transfers (void *cls)
GNUNET_SCHEDULER_shutdown ();
return;
}
+ db_plugin->preflight (db_plugin->cls,
+ session);
if (GNUNET_OK !=
db_plugin->start (db_plugin->cls,
- session))
+ session,
+ "wirewatch check for incoming wire transfers"))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to start database transaction!\n");
diff --git a/src/exchange/test_taler_exchange_aggregator.c b/src/exchange/test_taler_exchange_aggregator.c
index 3265bf2a1..0335bcd44 100644
--- a/src/exchange/test_taler_exchange_aggregator.c
+++ b/src/exchange/test_taler_exchange_aggregator.c
@@ -447,7 +447,8 @@ do_deposit (struct Command *cmd)
/* finally, actually perform the DB operation */
if ( (GNUNET_OK !=
plugin->start (plugin->cls,
- session)) ||
+ session,
+ "aggregator-test-1")) ||
(GNUNET_OK !=
plugin->insert_deposit (plugin->cls,
session,
@@ -1150,7 +1151,8 @@ run (void *cls)
&issue.properties.denom_hash);
if ( (GNUNET_OK !=
plugin->start (plugin->cls,
- session)) ||
+ session,
+ "aggregator-test-2")) ||
(GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_denomination_info (plugin->cls,
session,
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;
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index ae38856a3..33677559a 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -1152,11 +1152,14 @@ struct TALER_EXCHANGEDB_Plugin
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param session connection to use
+ * @param name unique name identifying the transaction (for debugging),
+ * must point to a constant
* @return #GNUNET_OK on success
*/
int
(*start) (void *cls,
- struct TALER_EXCHANGEDB_Session *session);
+ struct TALER_EXCHANGEDB_Session *session,
+ const char *name);
/**
@@ -1172,6 +1175,19 @@ struct TALER_EXCHANGEDB_Plugin
/**
+ * 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
+ */
+ void
+ (*preflight) (void *cls,
+ struct TALER_EXCHANGEDB_Session *session);
+
+
+ /**
* Abort/rollback a transaction.
*
* @param cls the @e cls of this struct with the plugin-specific state
@@ -1397,7 +1413,7 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_CoinSpendPublicKeyP *coin_pub,
TALER_EXCHANGEDB_RefundCoinCallback cb,
void *cb_cls);
-
+
/**
* Mark a deposit as tiny, thereby declaring that it cannot be