From ee6ec1f55d1557101341ac7a02cf5985aaed63e1 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 21 Apr 2023 10:50:35 +0200 Subject: [PATCH 01/12] -fix bug in sync --- contrib/gana | 2 +- src/exchangedb/pg_insert_records_by_table.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/gana b/contrib/gana index 7adfb722a..1ec4596bf 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 7adfb722ac988170a31cdfd8132073eb7f2a6c43 +Subproject commit 1ec4596bf4925ee24fc06d3e74d2a553b8239870 diff --git a/src/exchangedb/pg_insert_records_by_table.c b/src/exchangedb/pg_insert_records_by_table.c index 73e6ccda1..5f6de25de 100644 --- a/src/exchangedb/pg_insert_records_by_table.c +++ b/src/exchangedb/pg_insert_records_by_table.c @@ -1407,7 +1407,7 @@ irbt_cb_table_purse_decision (struct PostgresClosure *pg, GNUNET_PQ_query_param_timestamp ( &td->details.purse_decision.action_timestamp), GNUNET_PQ_query_param_bool ( - &td->details.purse_decision.refunded), + td->details.purse_decision.refunded), GNUNET_PQ_query_param_end }; From 03deaeb1080289a9228e4eb39c2f4bb29980c89c Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 21 Apr 2023 10:54:50 +0200 Subject: [PATCH 02/12] -fix doxygen --- contrib/microhttpd.tag | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contrib/microhttpd.tag b/contrib/microhttpd.tag index d80405036..5156a1a3a 100644 --- a/contrib/microhttpd.tag +++ b/contrib/microhttpd.tag @@ -46,6 +46,12 @@ microhttpd.h + + #define + MHD_HTTP_CONTENT_TOO_LARGE + microhttpd.h + + #define MHD_HTTP_REQUEST_TIMEOUT From 5290453e3630fdca0a4c79806db6a3e0c04d4746 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 21 Apr 2023 22:30:37 +0200 Subject: [PATCH 03/12] clean up reserve_get logic --- contrib/gana | 2 +- .../taler-exchange-httpd_reserves_get.c | 315 ++++++++---------- src/exchangedb/pg_reserves_in_insert.c | 6 +- 3 files changed, 146 insertions(+), 177 deletions(-) diff --git a/contrib/gana b/contrib/gana index 1ec4596bf..bf43b20a0 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 1ec4596bf4925ee24fc06d3e74d2a553b8239870 +Subproject commit bf43b20a0362ac19bcf1bab9c33215e55d8d9f36 diff --git a/src/exchange/taler-exchange-httpd_reserves_get.c b/src/exchange/taler-exchange-httpd_reserves_get.c index 88f7aca9c..003db9260 100644 --- a/src/exchange/taler-exchange-httpd_reserves_get.c +++ b/src/exchange/taler-exchange-httpd_reserves_get.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -62,6 +62,16 @@ struct ReservePoller */ struct GNUNET_TIME_Absolute timeout; + /** + * Public key of the reserve the inquiry is about. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Balance of the reserve, set in the callback. + */ + struct TALER_Amount balance; + /** * True if we are still suspended. */ @@ -84,13 +94,10 @@ static struct ReservePoller *rp_tail; void TEH_reserves_get_cleanup () { - struct ReservePoller *rp; - - while (NULL != (rp = rp_head)) + for (struct ReservePoller *rp = rp_head; + NULL != rp; + rp = rp->next) { - GNUNET_CONTAINER_DLL_remove (rp_head, - rp_tail, - rp); if (rp->suspended) { rp->suspended = false; @@ -115,11 +122,14 @@ rp_cleanup (struct TEH_RequestContext *rc) if (NULL != rp->eh) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Cancelling DB event listening\n"); + "Cancelling DB event listening on cleanup (odd unless during shutdown)\n"); TEH_plugin->event_listen_cancel (TEH_plugin->cls, rp->eh); rp->eh = NULL; } + GNUNET_CONTAINER_DLL_remove (rp_head, + rp_tail, + rp); GNUNET_free (rp); } @@ -143,20 +153,14 @@ db_event_cb (void *cls, (void) extra; (void) extra_size; - if (NULL == rp) - return; /* event triggered while main transaction - was still running */ if (! rp->suspended) return; /* might get multiple wake-up events */ - rp->suspended = false; GNUNET_async_scope_enter (&rc->async_scope_id, &old_scope); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Resuming from long-polling on reserve\n"); TEH_check_invariants (); - GNUNET_CONTAINER_DLL_remove (rp_head, - rp_tail, - rp); + rp->suspended = false; MHD_resume_connection (rp->connection); TALER_MHD_daemon_trigger (); TEH_check_invariants (); @@ -164,191 +168,154 @@ db_event_cb (void *cls, } -/** - * Closure for #reserve_history_transaction. - */ -struct ReserveHistoryContext -{ - /** - * Public key of the reserve the inquiry is about. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Balance of the reserve, set in the callback. - */ - struct TALER_Amount balance; - - /** - * Set to true if we did not find the reserve. - */ - bool not_found; -}; - - -/** - * Function implementing /reserves/ GET transaction. - * Execute a /reserves/ GET. 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 - * 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 it returns the soft error code, the function MAY be called again - * to retry and MUST not queue a MHD response. - * - * @param cls a `struct ReserveHistoryContext *` - * @param connection MHD request which triggered the transaction - * @param[out] mhd_ret set to MHD response status for @a connection, - * if transaction failed (!) - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -reserve_balance_transaction (void *cls, - struct MHD_Connection *connection, - MHD_RESULT *mhd_ret) -{ - struct ReserveHistoryContext *rsc = cls; - enum GNUNET_DB_QueryStatus qs; - - qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls, - &rsc->reserve_pub, - &rsc->balance); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - GNUNET_break (0); - *mhd_ret - = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "get_reserve_balance"); - } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) - rsc->not_found = true; - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) - rsc->not_found = false; - return qs; -} - - MHD_RESULT TEH_handler_reserves_get (struct TEH_RequestContext *rc, const char *const args[1]) { - struct ReserveHistoryContext rsc; - struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_ZERO; - struct GNUNET_DB_EventHandler *eh = NULL; + struct ReservePoller *rp = rc->rh_ctx; - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (args[0], - strlen (args[0]), - &rsc.reserve_pub, - sizeof (rsc.reserve_pub))) + if (NULL == rp) { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_RESERVE_PUB_MALFORMED, - args[0]); - } - { - const char *long_poll_timeout_ms; + struct GNUNET_TIME_Relative timeout + = GNUNET_TIME_UNIT_ZERO; - long_poll_timeout_ms - = MHD_lookup_connection_value (rc->connection, - MHD_GET_ARGUMENT_KIND, - "timeout_ms"); - if (NULL != long_poll_timeout_ms) + rp = GNUNET_new (struct ReservePoller); + rp->connection = rc->connection; + rc->rh_ctx = rp; + rc->rh_cleaner = &rp_cleanup; + GNUNET_CONTAINER_DLL_insert (rp_head, + rp_tail, + rp); + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (args[0], + strlen (args[0]), + &rp->reserve_pub, + sizeof (rp->reserve_pub))) { - unsigned int timeout_ms; - char dummy; - - if (1 != sscanf (long_poll_timeout_ms, - "%u%c", - &timeout_ms, - &dummy)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "timeout_ms (must be non-negative number)"); - } - timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, - timeout_ms); + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_RESERVE_PUB_MALFORMED, + args[0]); } + { + const char *long_poll_timeout_ms; + + long_poll_timeout_ms + = MHD_lookup_connection_value (rc->connection, + MHD_GET_ARGUMENT_KIND, + "timeout_ms"); + if (NULL != long_poll_timeout_ms) + { + unsigned int timeout_ms; + char dummy; + + if (1 != sscanf (long_poll_timeout_ms, + "%u%c", + &timeout_ms, + &dummy)) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "timeout_ms (must be non-negative number)"); + } + timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + timeout_ms); + } + } + rp->timeout = GNUNET_TIME_relative_to_absolute (timeout); } - if ( (! GNUNET_TIME_relative_is_zero (timeout)) && - (NULL == rc->rh_ctx) ) + + if ( (GNUNET_TIME_absolute_is_future (rp->timeout)) && + (NULL == rp->eh) ) { struct TALER_ReserveEventP rep = { .header.size = htons (sizeof (rep)), .header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING), - .reserve_pub = rsc.reserve_pub + .reserve_pub = rp->reserve_pub }; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting DB event listening\n"); - eh = TEH_plugin->event_listen (TEH_plugin->cls, - timeout, - &rep.header, - &db_event_cb, - rc); + rp->eh = TEH_plugin->event_listen ( + TEH_plugin->cls, + GNUNET_TIME_absolute_get_remaining (rp->timeout), + &rep.header, + &db_event_cb, + rp); } { - MHD_RESULT mhd_ret; + enum GNUNET_DB_QueryStatus qs; - if (GNUNET_OK != - TEH_DB_run_transaction (rc->connection, - "get reserve balance", - TEH_MT_REQUEST_OTHER, - &mhd_ret, - &reserve_balance_transaction, - &rsc)) + qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls, + &rp->reserve_pub, + &rp->balance); + switch (qs) { - if (NULL != eh) + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); /* single-shot query should never have soft-errors */ + if (NULL != rp->eh) + { TEH_plugin->event_listen_cancel (TEH_plugin->cls, - eh); - return mhd_ret; - } - } - /* generate proper response */ - if (rsc.not_found) - { - struct ReservePoller *rp = rc->rh_ctx; - - if ( (NULL != rp) || - (GNUNET_TIME_relative_is_zero (timeout)) ) - { + rp->eh); + rp->eh = NULL; + } return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN, - args[0]); + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_SOFT_FAILURE, + "get_reserve_balance"); + case GNUNET_DB_STATUS_HARD_ERROR: + GNUNET_break (0); + if (NULL != rp->eh) + { + TEH_plugin->event_listen_cancel (TEH_plugin->cls, + rp->eh); + rp->eh = NULL; + } + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "get_reserve_balance"); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + if (NULL != rp->eh) + { + TEH_plugin->event_listen_cancel (TEH_plugin->cls, + rp->eh); + rp->eh = NULL; + } + return TALER_MHD_REPLY_JSON_PACK (rc->connection, + MHD_HTTP_OK, + TALER_JSON_pack_amount ("balance", + &rp->balance)); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + if ( (NULL != rp) || + (GNUNET_TIME_absolute_is_future (rp->timeout)) ) + { + if (NULL != rp->eh) + { + TEH_plugin->event_listen_cancel (TEH_plugin->cls, + rp->eh); + rp->eh = NULL; + } + return TALER_MHD_reply_with_error (rc->connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN, + args[0]); + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Long-polling on reserve for %s\n", + GNUNET_STRINGS_relative_time_to_string ( + GNUNET_TIME_absolute_get_remaining (rp->timeout), + true)); + rp->suspended = true; + MHD_suspend_connection (rc->connection); + return MHD_YES; } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Long-polling on reserve for %s\n", - GNUNET_STRINGS_relative_time_to_string (timeout, - GNUNET_YES)); - rp = GNUNET_new (struct ReservePoller); - rp->connection = rc->connection; - rp->timeout = GNUNET_TIME_relative_to_absolute (timeout); - rp->eh = eh; - rc->rh_ctx = rp; - rc->rh_cleaner = &rp_cleanup; - rp->suspended = true; - GNUNET_CONTAINER_DLL_insert (rp_head, - rp_tail, - rp); - MHD_suspend_connection (rc->connection); - return MHD_YES; } - if (NULL != eh) - TEH_plugin->event_listen_cancel (TEH_plugin->cls, - eh); - return TALER_MHD_REPLY_JSON_PACK ( - rc->connection, - MHD_HTTP_OK, - TALER_JSON_pack_amount ("balance", - &rsc.balance)); + GNUNET_break (0); + return MHD_NO; } diff --git a/src/exchangedb/pg_reserves_in_insert.c b/src/exchangedb/pg_reserves_in_insert.c index 71c57f844..876774de9 100644 --- a/src/exchangedb/pg_reserves_in_insert.c +++ b/src/exchangedb/pg_reserves_in_insert.c @@ -722,8 +722,6 @@ TEH_PG_reserves_in_insert ( &transaction_duplicate[i], &conflicts[i], &reserve_uuid[i]); - fprintf (stdout, "reserve uuid : %ld c :%d t:%d\n", reserve_uuid[i], - conflicts[i], transaction_duplicate[i]); if (qs2<0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -825,7 +823,11 @@ TEH_PG_reserves_in_insert ( cs = TEH_PG_commit (pg); if (cs < 0) + { + for (unsigned int i = 0; i Date: Sat, 22 Apr 2023 01:20:41 +0200 Subject: [PATCH 04/12] misc bugfixes in reserves_in batch logic --- .../taler-exchange-httpd_reserves_get.c | 40 +- .../exchange_do_reserves_in_insert.sql | 1349 ++++++++--------- src/exchangedb/pg_reserves_in_insert.c | 1018 +++++-------- src/testing/testing_api_cmd_exec_wirewatch.c | 1 - src/testing/testing_api_loop.c | 2 +- 5 files changed, 1082 insertions(+), 1328 deletions(-) diff --git a/src/exchange/taler-exchange-httpd_reserves_get.c b/src/exchange/taler-exchange-httpd_reserves_get.c index 003db9260..c22e62bf5 100644 --- a/src/exchange/taler-exchange-httpd_reserves_get.c +++ b/src/exchange/taler-exchange-httpd_reserves_get.c @@ -147,18 +147,13 @@ db_event_cb (void *cls, const void *extra, size_t extra_size) { - struct TEH_RequestContext *rc = cls; - struct ReservePoller *rp = rc->rh_ctx; + struct ReservePoller *rp = cls; struct GNUNET_AsyncScopeSave old_scope; (void) extra; (void) extra_size; if (! rp->suspended) return; /* might get multiple wake-up events */ - GNUNET_async_scope_enter (&rc->async_scope_id, - &old_scope); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Resuming from long-polling on reserve\n"); TEH_check_invariants (); rp->suspended = false; MHD_resume_connection (rp->connection); @@ -238,7 +233,8 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc, }; GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Starting DB event listening\n"); + "Starting DB event listening until %s\n", + GNUNET_TIME_absolute2s (rp->timeout)); rp->eh = TEH_plugin->event_listen ( TEH_plugin->cls, GNUNET_TIME_absolute_get_remaining (rp->timeout), @@ -256,49 +252,27 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc, { case GNUNET_DB_STATUS_SOFT_ERROR: GNUNET_break (0); /* single-shot query should never have soft-errors */ - if (NULL != rp->eh) - { - TEH_plugin->event_listen_cancel (TEH_plugin->cls, - rp->eh); - rp->eh = NULL; - } return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_SOFT_FAILURE, "get_reserve_balance"); case GNUNET_DB_STATUS_HARD_ERROR: GNUNET_break (0); - if (NULL != rp->eh) - { - TEH_plugin->event_listen_cancel (TEH_plugin->cls, - rp->eh); - rp->eh = NULL; - } return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_GENERIC_DB_FETCH_FAILED, "get_reserve_balance"); case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - if (NULL != rp->eh) - { - TEH_plugin->event_listen_cancel (TEH_plugin->cls, - rp->eh); - rp->eh = NULL; - } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Got reserve balance of %s\n", + TALER_amount2s (&rp->balance)); return TALER_MHD_REPLY_JSON_PACK (rc->connection, MHD_HTTP_OK, TALER_JSON_pack_amount ("balance", &rp->balance)); case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - if ( (NULL != rp) || - (GNUNET_TIME_absolute_is_future (rp->timeout)) ) + if (! GNUNET_TIME_absolute_is_future (rp->timeout)) { - if (NULL != rp->eh) - { - TEH_plugin->event_listen_cancel (TEH_plugin->cls, - rp->eh); - rp->eh = NULL; - } return TALER_MHD_reply_with_error (rc->connection, MHD_HTTP_NOT_FOUND, TALER_EC_EXCHANGE_RESERVES_STATUS_UNKNOWN, diff --git a/src/exchangedb/exchange_do_reserves_in_insert.sql b/src/exchangedb/exchange_do_reserves_in_insert.sql index 3a217accf..e7506dc85 100644 --- a/src/exchangedb/exchange_do_reserves_in_insert.sql +++ b/src/exchangedb/exchange_do_reserves_in_insert.sql @@ -23,12 +23,12 @@ CREATE OR REPLACE FUNCTION exchange_do_batch_reserves_in_insert( IN in_credit_frac INT4, IN in_exchange_account_name VARCHAR, IN in_execution_date INT8, - IN in_wire_source_h_payto BYTEA, ---h_payto + IN in_wire_source_h_payto BYTEA, IN in_payto_uri VARCHAR, - IN in_notify text, - OUT out_reserve_found BOOLEAN, - OUT transaction_duplicate BOOLEAN, - OUT ruuid INT8) + IN in_notify TEXT, + OUT out_reserve_found0 BOOLEAN, + OUT transaction_duplicate0 BOOLEAN, + OUT ruuid0 INT8) LANGUAGE plpgsql AS $$ DECLARE @@ -38,11 +38,10 @@ DECLARE DECLARE curs_trans refcursor; BEGIN - ruuid = 0; - out_reserve_found = TRUE; - transaction_duplicate = TRUE; + ruuid0 = 0; + out_reserve_found0 = TRUE; + transaction_duplicate0 = TRUE; ---SIMPLE INSERT ON CONFLICT DO NOTHING INSERT INTO wire_targets (wire_target_h_payto ,payto_uri) @@ -65,18 +64,16 @@ BEGIN ,in_credit_frac ,in_reserve_expiration ,in_gc_date) - ON CONFLICT DO NOTHING - RETURNING reserve_uuid, reserve_pub) - SELECT * FROM reserve_changes; + ON CONFLICT DO NOTHING + RETURNING reserve_uuid, reserve_pub) + SELECT reserve_uuid, reserve_pub FROM reserve_changes; + FETCH FROM curs INTO i; IF FOUND THEN -- We made a change, so the reserve did not previously exist. - IF in_reserve_pub = i.reserve_pub - THEN - out_reserve_found = FALSE; - ruuid = i.reserve_uuid; - END IF; + out_reserve_found0 = FALSE; + ruuid0 = i.reserve_uuid; END IF; CLOSE curs; @@ -100,56 +97,56 @@ BEGIN ,in_execution_date) ON CONFLICT DO NOTHING RETURNING reserve_pub) - SELECT * FROM reserve_transaction; + SELECT reserve_pub FROM reserve_transaction; + FETCH FROM curs_trans INTO i; IF FOUND THEN - IF i.reserve_pub = in_reserve_pub - THEN - -- HAPPY PATH THERE IS NO DUPLICATE TRANS - transaction_duplicate = FALSE; - EXECUTE FORMAT ( + transaction_duplicate0 = FALSE; + EXECUTE FORMAT ( 'NOTIFY %s' ,in_notify); - END IF; END IF; + CLOSE curs_trans; + RETURN; END $$; + CREATE OR REPLACE FUNCTION exchange_do_batch2_reserves_insert( IN in_gc_date INT8, IN in_reserve_expiration INT8, - IN in_reserve_pub BYTEA, - IN in_wire_ref INT8, - IN in_credit_val INT8, - IN in_credit_frac INT4, - IN in_exchange_account_name VARCHAR, - IN in_execution_date INT8, - IN in_wire_source_h_payto BYTEA, ---h_payto - IN in_payto_uri VARCHAR, - IN in_notify text, - IN in2_notify text, - IN in2_reserve_pub BYTEA, - IN in2_wire_ref INT8, - IN in2_credit_val INT8, - IN in2_credit_frac INT4, - IN in2_exchange_account_name VARCHAR, - IN in2_execution_date INT8, - IN in2_wire_source_h_payto BYTEA, ---h_payto - IN in2_payto_uri VARCHAR, - OUT out_reserve_found BOOLEAN, - OUT out_reserve_found2 BOOLEAN, - OUT transaction_duplicate BOOLEAN, - OUT transaction_duplicate2 BOOLEAN, - OUT ruuid INT8, - OUT ruuid2 INT8) + IN in0_reserve_pub BYTEA, + IN in0_wire_ref INT8, + IN in0_credit_val INT8, + IN in0_credit_frac INT4, + IN in0_exchange_account_name VARCHAR, + IN in0_execution_date INT8, + IN in0_wire_source_h_payto BYTEA, + IN in0_payto_uri VARCHAR, + IN in0_notify TEXT, + IN in1_reserve_pub BYTEA, + IN in1_wire_ref INT8, + IN in1_credit_val INT8, + IN in1_credit_frac INT4, + IN in1_exchange_account_name VARCHAR, + IN in1_execution_date INT8, + IN in1_wire_source_h_payto BYTEA, + IN in1_payto_uri VARCHAR, + IN in1_notify TEXT, + OUT out_reserve_found0 BOOLEAN, + OUT out_reserve_found1 BOOLEAN, + OUT transaction_duplicate0 BOOLEAN, + OUT transaction_duplicate1 BOOLEAN, + OUT ruuid0 INT8, + OUT ruuid1 INT8) LANGUAGE plpgsql AS $$ DECLARE curs_reserve_exist REFCURSOR; DECLARE - curs_transaction_exist refcursor; + curs_transaction_exist REFCURSOR; DECLARE i RECORD; DECLARE @@ -157,21 +154,21 @@ DECLARE DECLARE k INT8; BEGIN - transaction_duplicate=TRUE; - transaction_duplicate2=TRUE; - out_reserve_found = TRUE; - out_reserve_found2 = TRUE; - ruuid=0; - ruuid2=0; - k=0; + transaction_duplicate0 = TRUE; + transaction_duplicate1 = TRUE; + out_reserve_found0 = TRUE; + out_reserve_found1 = TRUE; + ruuid0=0; + ruuid1=0; + INSERT INTO wire_targets (wire_target_h_payto ,payto_uri) VALUES - (in_wire_source_h_payto - ,in_payto_uri), - (in2_wire_source_h_payto - ,in2_payto_uri) + (in0_wire_source_h_payto + ,in0_payto_uri), + (in1_wire_source_h_payto + ,in1_payto_uri) ON CONFLICT DO NOTHING; OPEN curs_reserve_exist FOR @@ -183,39 +180,51 @@ BEGIN ,expiration_date ,gc_date) VALUES - (in_reserve_pub - ,in_credit_val - ,in_credit_frac + (in0_reserve_pub + ,in0_credit_val + ,in0_credit_frac ,in_reserve_expiration ,in_gc_date), - (in2_reserve_pub - ,in2_credit_val - ,in2_credit_frac + (in1_reserve_pub + ,in1_credit_val + ,in1_credit_frac ,in_reserve_expiration ,in_gc_date) - ON CONFLICT DO NOTHING - RETURNING reserve_uuid,reserve_pub) - SELECT * FROM reserve_changes; - WHILE k < 2 LOOP + ON CONFLICT DO NOTHING + RETURNING reserve_uuid, reserve_pub) + SELECT reserve_uuid, reserve_pub FROM reserve_changes; + + k=0; + <> LOOP FETCH FROM curs_reserve_exist INTO i; - IF FOUND + IF NOT FOUND THEN - IF in_reserve_pub = i.reserve_pub - THEN - ruuid = i.reserve_uuid; - IF in_reserve_pub <> in2_reserve_pub - THEN - out_reserve_found = FALSE; - END IF; - END IF; - IF in2_reserve_pub = i.reserve_pub - THEN - out_reserve_found2 = FALSE; - ruuid2 = i.reserve_uuid; - END IF; + EXIT loop_reserve; END IF; - k=k+1; - END LOOP; + + <> LOOP + CASE k + WHEN 0 THEN + k = k + 1; + IF in0_reserve_pub = i.reserve_pub + THEN + ruuid0 = i.reserve_uuid; + out_reserve_found0 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 1 THEN + IF in1_reserve_pub = i.reserve_pub + THEN + ruuid1 = i.reserve_uuid; + out_reserve_found1 = FALSE; + EXIT loop_reserve; + END IF; + EXIT loop_k; + END CASE; + END LOOP loop_k; + END LOOP loop_reserve; + CLOSE curs_reserve_exist; OPEN curs_transaction_exist FOR @@ -229,160 +238,153 @@ BEGIN ,wire_source_h_payto ,execution_date) VALUES - (in_reserve_pub - ,in_wire_ref - ,in_credit_val - ,in_credit_frac - ,in_exchange_account_name - ,in_wire_source_h_payto - ,in_execution_date), - (in2_reserve_pub - ,in2_wire_ref - ,in2_credit_val - ,in2_credit_frac - ,in2_exchange_account_name - ,in2_wire_source_h_payto - ,in2_execution_date) + (in0_reserve_pub + ,in0_wire_ref + ,in0_credit_val + ,in0_credit_frac + ,in0_exchange_account_name + ,in0_wire_source_h_payto + ,in0_execution_date), + (in1_reserve_pub + ,in1_wire_ref + ,in1_credit_val + ,in1_credit_frac + ,in1_exchange_account_name + ,in1_wire_source_h_payto + ,in1_execution_date) ON CONFLICT DO NOTHING RETURNING reserve_pub) - SELECT * FROM reserve_in_exist; + SELECT reserve_pub FROM reserve_in_exist; + FETCH FROM curs_transaction_exist INTO r; - IF FOUND - THEN - IF in_reserve_pub = r.reserve_pub + + k=0; + <> LOOP + FETCH FROM curs_transaction_exist INTO i; + IF NOT FOUND THEN - transaction_duplicate = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in_notify); + EXIT loop_transaction; END IF; - IF in2_reserve_pub = r.reserve_pub - THEN - transaction_duplicate2 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in2_notify); - END IF; - FETCH FROM curs_transaction_exist INTO r; - IF FOUND - THEN - IF in_reserve_pub = r.reserve_pub - THEN - transaction_duplicate = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in_notify); - END IF; - IF in2_reserve_pub = r.reserve_pub - THEN - transaction_duplicate2 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in2_notify); - END IF; - END IF; - END IF; -/* IF transaction_duplicate - OR transaction_duplicate2 - THEN - CLOSE curs_transaction_exist; - ROLLBACK; - RETURN; - END IF;*/ + + <> LOOP + CASE k + WHEN 0 THEN + k = k + 1; + IF in0_reserve_pub = r.reserve_pub + THEN + transaction_duplicate0 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in0_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 1 THEN + IF in0_reserve_pub = r.reserve_pub + THEN + transaction_duplicate1 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in1_notify); + EXIT loop_transaction; + END IF; + END CASE; + END LOOP loop2_k; + END LOOP loop_transaction; + CLOSE curs_transaction_exist; + RETURN; END $$; + CREATE OR REPLACE FUNCTION exchange_do_batch4_reserves_insert( IN in_gc_date INT8, IN in_reserve_expiration INT8, - IN in_reserve_pub BYTEA, - IN in_wire_ref INT8, - IN in_credit_val INT8, - IN in_credit_frac INT4, - IN in_exchange_account_name VARCHAR, - IN in_execution_date INT8, - IN in_wire_source_h_payto BYTEA, ---h_payto - IN in_payto_uri VARCHAR, - IN in_notify text, - IN in2_notify text, - IN in3_notify text, - IN in4_notify text, + IN in0_reserve_pub BYTEA, + IN in0_wire_ref INT8, + IN in0_credit_val INT8, + IN in0_credit_frac INT4, + IN in0_exchange_account_name VARCHAR, + IN in0_execution_date INT8, + IN in0_wire_source_h_payto BYTEA, + IN in0_payto_uri VARCHAR, + IN in0_notify TEXT, + IN in1_reserve_pub BYTEA, + IN in1_wire_ref INT8, + IN in1_credit_val INT8, + IN in1_credit_frac INT4, + IN in1_exchange_account_name VARCHAR, + IN in1_execution_date INT8, + IN in1_wire_source_h_payto BYTEA, + IN in1_payto_uri VARCHAR, + IN in1_notify TEXT, IN in2_reserve_pub BYTEA, IN in2_wire_ref INT8, IN in2_credit_val INT8, IN in2_credit_frac INT4, IN in2_exchange_account_name VARCHAR, IN in2_execute_date INT8, - IN in2_wire_source_h_payto BYTEA, ---h_payto + IN in2_wire_source_h_payto BYTEA, IN in2_payto_uri VARCHAR, + IN in2_notify TEXT, IN in3_reserve_pub BYTEA, IN in3_wire_ref INT8, IN in3_credit_val INT8, IN in3_credit_frac INT4, IN in3_exchange_account_name VARCHAR, IN in3_execute_date INT8, - IN in3_wire_source_h_payto BYTEA, ---h_payto + IN in3_wire_source_h_payto BYTEA, IN in3_payto_uri VARCHAR, - IN in4_reserve_pub BYTEA, - IN in4_wire_ref INT8, - IN in4_credit_val INT8, - IN in4_credit_frac INT4, - IN in4_exchange_account_name VARCHAR, - IN in4_execution_date INT8, - IN in4_wire_source_h_payto BYTEA, ---h_payto - IN in4_payto_uri VARCHAR, - OUT out_reserve_found BOOLEAN, + IN in3_notify TEXT, + OUT out_reserve_found0 BOOLEAN, + OUT out_reserve_found1 BOOLEAN, OUT out_reserve_found2 BOOLEAN, OUT out_reserve_found3 BOOLEAN, - OUT out_reserve_found4 BOOLEAN, - OUT transaction_duplicate BOOLEAN, + OUT transaction_duplicate0 BOOLEAN, + OUT transaction_duplicate1 BOOLEAN, OUT transaction_duplicate2 BOOLEAN, OUT transaction_duplicate3 BOOLEAN, - OUT transaction_duplicate4 BOOLEAN, - OUT ruuid INT8, + OUT ruuid0 INT8, + OUT ruuid1 INT8, OUT ruuid2 INT8, - OUT ruuid3 INT8, - OUT ruuid4 INT8) + OUT ruuid3 INT8) LANGUAGE plpgsql AS $$ DECLARE - curs_reserve_exist refcursor; + curs_reserve_exist REFCURSOR; DECLARE k INT8; DECLARE - curs_transaction_exist refcursor; + curs_transaction_exist REFCURSOR; DECLARE i RECORD; - BEGIN ---INITIALIZATION - transaction_duplicate=TRUE; + transaction_duplicate0=TRUE; + transaction_duplicate1=TRUE; transaction_duplicate2=TRUE; transaction_duplicate3=TRUE; - transaction_duplicate4=TRUE; - out_reserve_found = TRUE; + out_reserve_found0 = TRUE; + out_reserve_found1 = TRUE; out_reserve_found2 = TRUE; out_reserve_found3 = TRUE; - out_reserve_found4 = TRUE; - ruuid=0; + ruuid0=0; + ruuid1=0; ruuid2=0; ruuid3=0; - ruuid4=0; - k=0; - --SIMPLE INSERT ON CONFLICT DO NOTHING + INSERT INTO wire_targets (wire_target_h_payto ,payto_uri) VALUES - (in_wire_source_h_payto - ,in_payto_uri), + (in0_wire_source_h_payto + ,in0_payto_uri), + (in1_wire_source_h_payto + ,in1_payto_uri), (in2_wire_source_h_payto ,in2_payto_uri), (in3_wire_source_h_payto - ,in3_payto_uri), - (in4_wire_source_h_payto - ,in4_payto_uri) + ,in3_payto_uri) ON CONFLICT DO NOTHING; OPEN curs_reserve_exist FOR @@ -394,9 +396,14 @@ BEGIN ,expiration_date ,gc_date) VALUES - (in_reserve_pub - ,in_credit_val - ,in_credit_frac + (in0_reserve_pub + ,in0_credit_val + ,in0_credit_frac + ,in_reserve_expiration + ,in_gc_date), + (in1_reserve_pub + ,in1_credit_val + ,in1_credit_frac ,in_reserve_expiration ,in_gc_date), (in2_reserve_pub @@ -408,310 +415,313 @@ BEGIN ,in3_credit_val ,in3_credit_frac ,in_reserve_expiration - ,in_gc_date), - (in4_reserve_pub - ,in4_credit_val - ,in4_credit_frac - ,in_reserve_expiration ,in_gc_date) - ON CONFLICT DO NOTHING - RETURNING reserve_uuid,reserve_pub) - SELECT * FROM reserve_changes; - - WHILE k < 4 LOOP - FETCH FROM curs_reserve_exist INTO i; - IF FOUND - THEN - IF in_reserve_pub = i.reserve_pub - THEN - ruuid = i.reserve_uuid; - IF in_reserve_pub - NOT IN (in2_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub) - THEN - out_reserve_found = FALSE; - END IF; - END IF; - IF in2_reserve_pub = i.reserve_pub - THEN - ruuid2 = i.reserve_uuid; - IF in2_reserve_pub - NOT IN (in_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub) - THEN - out_reserve_found2 = FALSE; - END IF; - END IF; - IF in3_reserve_pub = i.reserve_pub - THEN - ruuid3 = i.reserve_uuid; - IF in3_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in4_reserve_pub) - THEN - out_reserve_found3 = FALSE; - END IF; - END IF; - IF in4_reserve_pub = i.reserve_pub - THEN - ruuid4 = i.reserve_uuid; - IF in4_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in3_reserve_pub) - THEN - out_reserve_found4 = FALSE; - END IF; - END IF; - END IF; - k=k+1; - END LOOP; - CLOSE curs_reserve_exist; + ON CONFLICT DO NOTHING + RETURNING reserve_uuid,reserve_pub) + SELECT reserve_uuid, reserve_pub FROM reserve_changes; k=0; - OPEN curs_transaction_exist FOR - WITH reserve_in_changes AS ( - INSERT INTO reserves_in - (reserve_pub - ,wire_reference - ,credit_val - ,credit_frac - ,exchange_account_section - ,wire_source_h_payto - ,execution_date) - VALUES - (in_reserve_pub - ,in_wire_ref - ,in_credit_val - ,in_credit_frac - ,in_exchange_account_name - ,in_wire_source_h_payto - ,in_execution_date), - (in2_reserve_pub - ,in2_wire_ref - ,in2_credit_val - ,in2_credit_frac - ,in2_exchange_account_name - ,in2_wire_source_h_payto - ,in2_execution_date), - (in3_reserve_pub - ,in3_wire_ref - ,in3_credit_val - ,in3_credit_frac - ,in3_exchange_account_name - ,in3_wire_source_h_payto - ,in3_execution_date), - (in4_reserve_pub - ,in4_wire_ref - ,in4_credit_val - ,in4_credit_frac - ,in4_exchange_account_name - ,in4_wire_source_h_payto - ,in4_execution_date) - ON CONFLICT DO NOTHING - RETURNING reserve_pub) - SELECT * FROM reserve_in_changes; - WHILE k < 4 LOOP - FETCH FROM curs_transaction_exist INTO i; - IF FOUND + <> LOOP + FETCH FROM curs_reserve_exist INTO i; + IF NOT FOUND THEN - IF in_reserve_pub = i.reserve_pub - THEN - transaction_duplicate = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in_notify); - END IF; - IF in2_reserve_pub = i.reserve_pub - THEN - transaction_duplicate2 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in2_notify); - END IF; - IF in3_reserve_pub = i.reserve_pub - THEN - transaction_duplicate3 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in3_notify); - END IF; - IF in4_reserve_pub = i.reserve_pub - THEN - transaction_duplicate4 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in4_notify); - END IF; + EXIT loop_reserve; END IF; - k=k+1; - END LOOP; - /**ROLLBACK TRANSACTION IN SORTED PROCEDURE IS IT PROSSIBLE ?**/ - /*IF transaction_duplicate - OR transaction_duplicate2 - OR transaction_duplicate3 - OR transaction_duplicate4 - THEN - RAISE EXCEPTION 'Reserve did not exist, but INSERT into reserves_in gave conflict'; - ROLLBACK; - CLOSE curs_transaction_exist; - RETURN; - END IF;*/ - CLOSE curs_transaction_exist; - RETURN; + <> LOOP + CASE k + WHEN 0 THEN + k = k + 1; + IF in0_reserve_pub = i.reserve_pub + THEN + ruuid0 = i.reserve_uuid; + out_reserve_found0 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 1 THEN + k = k + 1; + IF in1_reserve_pub = i.reserve_pub + THEN + ruuid1 = i.reserve_uuid; + out_reserve_found1 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 2 THEN + k = k + 1; + IF in2_reserve_pub = i.reserve_pub + THEN + ruuid2 = i.reserve_uuid; + out_reserve_found2 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 3 THEN + IF in3_reserve_pub = i.reserve_pub + THEN + ruuid3 = i.reserve_uuid; + out_reserve_found3 = FALSE; + EXIT loop_reserve; + END IF; + EXIT loop_k; + END CASE; + END LOOP loop_k; + END LOOP loop_reserve; + + CLOSE curs_reserve_exist; + + OPEN curs_transaction_exist FOR + WITH reserve_changes AS ( + INSERT INTO reserves_in + (reserve_pub + ,wire_reference + ,credit_val + ,credit_frac + ,exchange_account_section + ,wire_source_h_payto + ,execution_date) + VALUES + (in0_reserve_pub + ,in0_wire_ref + ,in0_credit_val + ,in0_credit_frac + ,in0_exchange_account_name + ,in0_wire_source_h_payto + ,in0_execution_date), + (in1_reserve_pub + ,in1_wire_ref + ,in1_credit_val + ,in1_credit_frac + ,in1_exchange_account_name + ,in1_wire_source_h_payto + ,in1_execution_date), + (in2_reserve_pub + ,in2_wire_ref + ,in2_credit_val + ,in2_credit_frac + ,in2_exchange_account_name + ,in2_wire_source_h_payto + ,in2_execution_date), + (in3_reserve_pub + ,in3_wire_ref + ,in3_credit_val + ,in3_credit_frac + ,in3_exchange_account_name + ,in3_wire_source_h_payto + ,in3_execution_date) + ON CONFLICT DO NOTHING + RETURNING reserve_pub) + SELECT reserve_uuid, reserve_pub FROM reserve_changes; + + k=0; + <> LOOP + FETCH FROM curs_transaction_exist INTO i; + IF NOT FOUND + THEN + EXIT loop_transaction; + END IF; + + <> LOOP + CASE k + WHEN 0 THEN + k = k + 1; + IF in0_reserve_pub = r.reserve_pub + THEN + transaction_duplicate0 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in0_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 1 THEN + k = k + 1; + IF in1_reserve_pub = r.reserve_pub + THEN + transaction_duplicate1 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in1_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 2 THEN + k = k + 1; + IF in2_reserve_pub = r.reserve_pub + THEN + transaction_duplicate2 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in2_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 3 THEN + IF in3_reserve_pub = r.reserve_pub + THEN + transaction_duplicate3 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in3_notify); + EXIT loop_transaction; + END IF; + END CASE; + END LOOP loop2_k; + END LOOP loop_transaction; + + CLOSE curs_transaction_exist; + + RETURN; END $$; + CREATE OR REPLACE FUNCTION exchange_do_batch8_reserves_insert( IN in_gc_date INT8, IN in_reserve_expiration INT8, - IN in_reserve_pub BYTEA, - IN in_wire_ref INT8, - IN in_credit_val INT8, - IN in_credit_frac INT4, - IN in_exchange_account_name VARCHAR, - IN in_execution_date INT8, - IN in_wire_source_h_payto BYTEA, ---h_payto - IN in_payto_uri VARCHAR, - IN in_notify text, - IN in2_notify text, - IN in3_notify text, - IN in4_notify text, - IN in5_notify text, - IN in6_notify text, - IN in7_notify text, - IN in8_notify text, + IN in0_reserve_pub BYTEA, + IN in0_wire_ref INT8, + IN in0_credit_val INT8, + IN in0_credit_frac INT4, + IN in0_exchange_account_name VARCHAR, + IN in0_execution_date INT8, + IN in0_wire_source_h_payto BYTEA, + IN in0_payto_uri VARCHAR, + IN in0_notify TEXT, + IN in1_reserve_pub BYTEA, + IN in1_wire_ref INT8, + IN in1_credit_val INT8, + IN in1_credit_frac INT4, + IN in1_exchange_account_name VARCHAR, + IN in1_execution_date INT8, + IN in1_wire_source_h_payto BYTEA, + IN in1_payto_uri VARCHAR, + IN in1_notify TEXT, IN in2_reserve_pub BYTEA, IN in2_wire_ref INT8, IN in2_credit_val INT8, IN in2_credit_frac INT4, IN in2_exchange_account_name VARCHAR, IN in2_execution_date INT8, - IN in2_wire_source_h_payto BYTEA, ---h_payto + IN in2_wire_source_h_payto BYTEA, IN in2_payto_uri VARCHAR, + IN in2_notify TEXT, IN in3_reserve_pub BYTEA, IN in3_wire_ref INT8, IN in3_credit_val INT8, IN in3_credit_frac INT4, IN in3_exchange_account_name VARCHAR, IN in3_execution_date INT8, - IN in3_wire_source_h_payto BYTEA, ---h_payto + IN in3_wire_source_h_payto BYTEA, IN in3_payto_uri VARCHAR, + IN in3_notify TEXT, IN in4_reserve_pub BYTEA, IN in4_wire_ref INT8, IN in4_credit_val INT8, IN in4_credit_frac INT4, IN in4_exchange_account_name VARCHAR, IN in4_execution_date INT8, - IN in4_wire_source_h_payto BYTEA, ---h_payto + IN in4_wire_source_h_payto BYTEA, IN in4_payto_uri VARCHAR, + IN in4_notify TEXT, IN in5_reserve_pub BYTEA, IN in5_wire_ref INT8, IN in5_credit_val INT8, IN in5_credit_frac INT4, IN in5_exchange_account_name VARCHAR, IN in5_execution_date INT8, - IN in5_wire_source_h_payto BYTEA, ---h_payto + IN in5_wire_source_h_payto BYTEA, IN in5_payto_uri VARCHAR, + IN in5_notify TEXT, IN in6_reserve_pub BYTEA, IN in6_wire_ref INT8, IN in6_credit_val INT8, IN in6_credit_frac INT4, IN in6_exchange_account_name VARCHAR, IN in6_execution_date INT8, - IN in6_wire_source_h_payto BYTEA, ---h_payto + IN in6_wire_source_h_payto BYTEA, IN in6_payto_uri VARCHAR, + IN in6_notify TEXT, IN in7_reserve_pub BYTEA, IN in7_wire_ref INT8, IN in7_credit_val INT8, IN in7_credit_frac INT4, IN in7_exchange_account_name VARCHAR, IN in7_execution_date INT8, - IN in7_wire_source_h_payto BYTEA, ---h_payto + IN in7_wire_source_h_payto BYTEA, IN in7_payto_uri VARCHAR, - IN in8_reserve_pub BYTEA, - IN in8_wire_ref INT8, - IN in8_credit_val INT8, - IN in8_credit_frac INT4, - IN in8_exchange_account_name VARCHAR, - IN in8_execution_date INT8, - IN in8_wire_source_h_payto BYTEA, ---h_payto - IN in8_payto_uri VARCHAR, - OUT out_reserve_found BOOLEAN, + IN in7_notify TEXT, + OUT out_reserve_found0 BOOLEAN, + OUT out_reserve_found1 BOOLEAN, OUT out_reserve_found2 BOOLEAN, OUT out_reserve_found3 BOOLEAN, OUT out_reserve_found4 BOOLEAN, OUT out_reserve_found5 BOOLEAN, OUT out_reserve_found6 BOOLEAN, OUT out_reserve_found7 BOOLEAN, - OUT out_reserve_found8 BOOLEAN, - OUT transaction_duplicate BOOLEAN, + OUT transaction_duplicate0 BOOLEAN, + OUT transaction_duplicate1 BOOLEAN, OUT transaction_duplicate2 BOOLEAN, OUT transaction_duplicate3 BOOLEAN, OUT transaction_duplicate4 BOOLEAN, OUT transaction_duplicate5 BOOLEAN, OUT transaction_duplicate6 BOOLEAN, OUT transaction_duplicate7 BOOLEAN, - OUT transaction_duplicate8 BOOLEAN, - OUT ruuid INT8, + OUT ruuid0 INT8, + OUT ruuid1 INT8, OUT ruuid2 INT8, OUT ruuid3 INT8, OUT ruuid4 INT8, OUT ruuid5 INT8, OUT ruuid6 INT8, - OUT ruuid7 INT8, - OUT ruuid8 INT8) + OUT ruuid7 INT8) LANGUAGE plpgsql AS $$ DECLARE - curs_reserve_existed refcursor; + curs_reserve_exist REFCURSOR; DECLARE k INT8; DECLARE - curs_transaction_existed refcursor; + curs_transaction_exist REFCURSOR; DECLARE i RECORD; DECLARE r RECORD; BEGIN ---INITIALIZATION - transaction_duplicate=TRUE; + transaction_duplicate0=TRUE; + transaction_duplicate1=TRUE; transaction_duplicate2=TRUE; transaction_duplicate3=TRUE; transaction_duplicate4=TRUE; transaction_duplicate5=TRUE; transaction_duplicate6=TRUE; transaction_duplicate7=TRUE; - transaction_duplicate8=TRUE; - out_reserve_found = TRUE; + out_reserve_found0 = TRUE; + out_reserve_found1 = TRUE; out_reserve_found2 = TRUE; out_reserve_found3 = TRUE; out_reserve_found4 = TRUE; out_reserve_found5 = TRUE; out_reserve_found6 = TRUE; out_reserve_found7 = TRUE; - out_reserve_found8 = TRUE; - ruuid=0; + ruuid0=0; + ruuid1=0; ruuid2=0; ruuid3=0; ruuid4=0; ruuid5=0; ruuid6=0; ruuid7=0; - ruuid8=0; - k=0; - --SIMPLE INSERT ON CONFLICT DO NOTHING INSERT INTO wire_targets (wire_target_h_payto ,payto_uri) VALUES - (in_wire_source_h_payto - ,in_payto_uri), + (in0_wire_source_h_payto + ,in0_payto_uri), + (in1_wire_source_h_payto + ,in1_payto_uri), (in2_wire_source_h_payto ,in2_payto_uri), (in3_wire_source_h_payto @@ -723,12 +733,10 @@ BEGIN (in6_wire_source_h_payto ,in6_payto_uri), (in7_wire_source_h_payto - ,in7_payto_uri), - (in8_wire_source_h_payto - ,in8_payto_uri) + ,in7_payto_uri) ON CONFLICT DO NOTHING; - OPEN curs_reserve_existed FOR + OPEN curs_reserve_exist FOR WITH reserve_changes AS ( INSERT INTO reserves (reserve_pub @@ -737,9 +745,14 @@ BEGIN ,expiration_date ,gc_date) VALUES - (in_reserve_pub - ,in_credit_val - ,in_credit_frac + (in0_reserve_pub + ,in0_credit_val + ,in0_credit_frac + ,in_reserve_expiration + ,in_gc_date), + (in1_reserve_pub + ,in1_credit_val + ,in1_credit_frac ,in_reserve_expiration ,in_gc_date), (in2_reserve_pub @@ -771,295 +784,269 @@ BEGIN ,in7_credit_val ,in7_credit_frac ,in_reserve_expiration - ,in_gc_date), - (in8_reserve_pub - ,in8_credit_val - ,in8_credit_frac - ,in_reserve_expiration ,in_gc_date) - ON CONFLICT DO NOTHING - RETURNING reserve_uuid,reserve_pub) - SELECT * FROM reserve_changes; - - WHILE k < 8 LOOP - - FETCH FROM curs_reserve_existed INTO i; - IF FOUND - THEN - IF in_reserve_pub = i.reserve_pub - THEN - ruuid = i.reserve_uuid; - IF in_reserve_pub - NOT IN (in2_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub - ,in5_reserve_pub - ,in6_reserve_pub - ,in7_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found = FALSE; - END IF; - END IF; - IF in2_reserve_pub = i.reserve_pub - THEN - ruuid2 = i.reserve_uuid; - IF in2_reserve_pub - NOT IN (in_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub - ,in5_reserve_pub - ,in6_reserve_pub - ,in7_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found2 = FALSE; - END IF; - END IF; - IF in3_reserve_pub = i.reserve_pub - THEN - ruuid3 = i.reserve_uuid; - IF in3_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in4_reserve_pub - ,in5_reserve_pub - ,in6_reserve_pub - ,in7_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found3 = FALSE; - END IF; - END IF; - IF in4_reserve_pub = i.reserve_pub - THEN - ruuid4 = i.reserve_uuid; - IF in4_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in3_reserve_pub - ,in5_reserve_pub - ,in6_reserve_pub - ,in7_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found4 = FALSE; - END IF; - END IF; - IF in5_reserve_pub = i.reserve_pub - THEN - ruuid5 = i.reserve_uuid; - IF in5_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub - ,in6_reserve_pub - ,in7_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found5 = FALSE; - END IF; - END IF; - IF in6_reserve_pub = i.reserve_pub - THEN - ruuid6 = i.reserve_uuid; - IF in6_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub - ,in5_reserve_pub - ,in7_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found6 = FALSE; - END IF; - END IF; - IF in7_reserve_pub = i.reserve_pub - THEN - ruuid7 = i.reserve_uuid; - IF in7_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub - ,in5_reserve_pub - ,in6_reserve_pub - ,in8_reserve_pub) - THEN - out_reserve_found7 = FALSE; - END IF; - END IF; - IF in8_reserve_pub = i.reserve_pub - THEN - ruuid8 = i.reserve_uuid; - IF in8_reserve_pub - NOT IN (in_reserve_pub - ,in2_reserve_pub - ,in3_reserve_pub - ,in4_reserve_pub - ,in5_reserve_pub - ,in6_reserve_pub - ,in7_reserve_pub) - THEN - out_reserve_found8 = FALSE; - END IF; - END IF; - END IF; - k=k+1; - END LOOP; - - CLOSE curs_reserve_existed; + ON CONFLICT DO NOTHING + RETURNING reserve_uuid,reserve_pub) + SELECT reserve_uuid, reserve_pub FROM reserve_changes; k=0; - OPEN curs_transaction_existed FOR - WITH reserve_in_changes AS ( - INSERT INTO reserves_in - (reserve_pub - ,wire_reference - ,credit_val - ,credit_frac - ,exchange_account_section - ,wire_source_h_payto - ,execution_date) - VALUES - (in_reserve_pub - ,in_wire_ref - ,in_credit_val - ,in_credit_frac - ,in_exchange_account_name - ,in_wire_source_h_payto - ,in_execution_date), - (in2_reserve_pub - ,in2_wire_ref - ,in2_credit_val - ,in2_credit_frac - ,in2_exchange_account_name - ,in2_wire_source_h_payto - ,in2_execution_date), - (in3_reserve_pub - ,in3_wire_ref - ,in3_credit_val - ,in3_credit_frac - ,in3_exchange_account_name - ,in3_wire_source_h_payto - ,in3_execution_date), - (in4_reserve_pub - ,in4_wire_ref - ,in4_credit_val - ,in4_credit_frac - ,in4_exchange_account_name - ,in4_wire_source_h_payto - ,in4_execution_date), - (in5_reserve_pub - ,in5_wire_ref - ,in5_credit_val - ,in5_credit_frac - ,in5_exchange_account_name - ,in5_wire_source_h_payto - ,in5_execution_date), - (in6_reserve_pub - ,in6_wire_ref - ,in6_credit_val - ,in6_credit_frac - ,in6_exchange_account_name - ,in6_wire_source_h_payto - ,in6_execution_date), - (in7_reserve_pub - ,in7_wire_ref - ,in7_credit_val - ,in7_credit_frac - ,in7_exchange_account_name - ,in7_wire_source_h_payto - ,in7_execution_date), - (in8_reserve_pub - ,in8_wire_ref - ,in8_credit_val - ,in8_credit_frac - ,in8_exchange_account_name - ,in8_wire_source_h_payto - ,in8_execution_date) - ON CONFLICT DO NOTHING - RETURNING reserve_pub) - SELECT * FROM reserve_in_changes; - - WHILE k < 8 LOOP - FETCH FROM curs_transaction_existed INTO r; - IF FOUND + <> LOOP + FETCH FROM curs_reserve_exist INTO i; + IF NOT FOUND THEN - IF in_reserve_pub = r.reserve_pub - THEN - transaction_duplicate = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in_notify); - END IF; - IF in2_reserve_pub = r.reserve_pub - THEN - transaction_duplicate2 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in2_notify); - END IF; - IF in3_reserve_pub = r.reserve_pub - THEN - transaction_duplicate3 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in3_notify); - END IF; - IF in4_reserve_pub = r.reserve_pub - THEN - transaction_duplicate4 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in4_notify); - END IF; - IF in5_reserve_pub = r.reserve_pub - THEN - transaction_duplicate5 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in5_notify); - END IF; - IF in6_reserve_pub = r.reserve_pub - THEN - transaction_duplicate6 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in6_notify); - END IF; - IF in7_reserve_pub = r.reserve_pub - THEN - transaction_duplicate7 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in7_notify); - END IF; - IF in8_reserve_pub = r.reserve_pub - THEN - transaction_duplicate8 = FALSE; - EXECUTE FORMAT ( - 'NOTIFY %s' - ,in8_notify); - END IF; + EXIT loop_reserve; END IF; - k=k+1; - END LOOP; - /* IF transaction_duplicate - OR transaction_duplicate2 - OR transaction_duplicate3 - OR transaction_duplicate4 - OR transaction_duplicate5 - OR transaction_duplicate6 - OR transaction_duplicate7 - OR transaction_duplicate8 - THEN - CLOSE curs_transaction_existed; - ROLLBACK; - RETURN; - END IF;*/ - CLOSE curs_transaction_existed; + + <> LOOP + CASE k + WHEN 0 THEN + k = k + 1; + IF in0_reserve_pub = i.reserve_pub + THEN + ruuid0 = i.reserve_uuid; + out_reserve_found0 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 1 THEN + k = k + 1; + IF in1_reserve_pub = i.reserve_pub + THEN + ruuid1 = i.reserve_uuid; + out_reserve_found1 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 2 THEN + k = k + 1; + IF in2_reserve_pub = i.reserve_pub + THEN + ruuid2 = i.reserve_uuid; + out_reserve_found2 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 3 THEN + k = k + 1; + IF in3_reserve_pub = i.reserve_pub + THEN + ruuid3 = i.reserve_uuid; + out_reserve_found3 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 4 THEN + k = k + 1; + IF in4_reserve_pub = i.reserve_pub + THEN + ruuid4 = i.reserve_uuid; + out_reserve_found4 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 5 THEN + k = k + 1; + IF in5_reserve_pub = i.reserve_pub + THEN + ruuid5 = i.reserve_uuid; + out_reserve_found5 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 6 THEN + k = k + 1; + IF in6_reserve_pub = i.reserve_pub + THEN + ruuid6 = i.reserve_uuid; + out_reserve_found6 = FALSE; + CONTINUE loop_reserve; + END IF; + CONTINUE loop_k; + WHEN 7 THEN + IF in7_reserve_pub = i.reserve_pub + THEN + ruuid7 = i.reserve_uuid; + out_reserve_found7 = FALSE; + EXIT loop_reserve; + END IF; + EXIT loop_k; + END CASE; + END LOOP loop_k; + END LOOP loop_reserve; + + CLOSE curs_reserve_exist; + + OPEN curs_transaction_exist FOR + WITH reserve_changes AS ( + INSERT INTO reserves_in + (reserve_pub + ,wire_reference + ,credit_val + ,credit_frac + ,exchange_account_section + ,wire_source_h_payto + ,execution_date) + VALUES + (in0_reserve_pub + ,in0_wire_ref + ,in0_credit_val + ,in0_credit_frac + ,in0_exchange_account_name + ,in0_wire_source_h_payto + ,in0_execution_date), + (in1_reserve_pub + ,in1_wire_ref + ,in1_credit_val + ,in1_credit_frac + ,in1_exchange_account_name + ,in1_wire_source_h_payto + ,in1_execution_date), + (in2_reserve_pub + ,in2_wire_ref + ,in2_credit_val + ,in2_credit_frac + ,in2_exchange_account_name + ,in2_wire_source_h_payto + ,in2_execution_date), + (in3_reserve_pub + ,in3_wire_ref + ,in3_credit_val + ,in3_credit_frac + ,in3_exchange_account_name + ,in3_wire_source_h_payto + ,in3_execution_date), + (in4_reserve_pub + ,in4_wire_ref + ,in4_credit_val + ,in4_credit_frac + ,in4_exchange_account_name + ,in4_wire_source_h_payto + ,in4_execution_date), + (in5_reserve_pub + ,in5_wire_ref + ,in5_credit_val + ,in5_credit_frac + ,in5_exchange_account_name + ,in5_wire_source_h_payto + ,in5_execution_date), + (in6_reserve_pub + ,in6_wire_ref + ,in6_credit_val + ,in6_credit_frac + ,in6_exchange_account_name + ,in6_wire_source_h_payto + ,in6_execution_date), + (in7_reserve_pub + ,in7_wire_ref + ,in7_credit_val + ,in7_credit_frac + ,in7_exchange_account_name + ,in7_wire_source_h_payto + ,in7_execution_date) + ON CONFLICT DO NOTHING + RETURNING reserve_pub) + SELECT reserve_pub FROM reserve_changes; + + k=0; + <> LOOP + FETCH FROM curs_transaction_exist INTO i; + IF NOT FOUND + THEN + EXIT loop_transaction; + END IF; + + <> LOOP + CASE k + WHEN 0 THEN + k = k + 1; + IF in0_reserve_pub = r.reserve_pub + THEN + transaction_duplicate0 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in0_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 1 THEN + k = k + 1; + IF in1_reserve_pub = r.reserve_pub + THEN + transaction_duplicate1 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in1_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 2 THEN + k = k + 1; + IF in2_reserve_pub = r.reserve_pub + THEN + transaction_duplicate2 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in2_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 3 THEN + k = k + 1; + IF in3_reserve_pub = r.reserve_pub + THEN + transaction_duplicate3 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in3_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 4 THEN + k = k + 1; + IF in4_reserve_pub = r.reserve_pub + THEN + transaction_duplicate4 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in4_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 5 THEN + k = k + 1; + IF in5_reserve_pub = r.reserve_pub + THEN + transaction_duplicate2 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in5_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 6 THEN + k = k + 1; + IF in6_reserve_pub = r.reserve_pub + THEN + transaction_duplicate6 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in6_notify); + CONTINUE loop_transaction; + END IF; + CONTINUE loop2_k; + WHEN 7 THEN + IF in7_reserve_pub = r.reserve_pub + THEN + transaction_duplicate7 = FALSE; + EXECUTE FORMAT ( + 'NOTIFY %s' + ,in7_notify); + EXIT loop_transaction; + END IF; + END CASE; + END LOOP loop2_k; + END LOOP loop_transaction; + + CLOSE curs_transaction_exist; RETURN; END $$; diff --git a/src/exchangedb/pg_reserves_in_insert.c b/src/exchangedb/pg_reserves_in_insert.c index 876774de9..2e29a1857 100644 --- a/src/exchangedb/pg_reserves_in_insert.c +++ b/src/exchangedb/pg_reserves_in_insert.c @@ -55,53 +55,107 @@ compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub) } +/** + * Record we keep per reserve to process. + */ +struct ReserveRecord +{ + /** + * Details about reserve to insert (input). + */ + const struct TALER_EXCHANGEDB_ReserveInInfo *reserve; + + /** + * Hash of the payto URI in @e reserve. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Notification to trigger on the reserve (input). + */ + char *notify_s; + + /** + * Set to UUID of the reserve (output); + */ + uint64_t reserve_uuid; + + /** + * Set to true if the transaction was an exact duplicate (output). + */ + bool transaction_duplicate; + + /** + * Set to true if the transaction conflicted with an existing reserve (output) + * and needs to be re-done with an UPDATE. + */ + bool conflicts; +}; + + +/** + * Generate the SQL parameters to insert the record @a rr at + * index @a index + */ +#define RR_QUERY_PARAM(rr,index) \ + GNUNET_PQ_query_param_auto_from_type (rr[index].reserve->reserve_pub), \ + GNUNET_PQ_query_param_uint64 (&rr[index].reserve->wire_reference), \ + TALER_PQ_query_param_amount (rr[index].reserve->balance), \ + GNUNET_PQ_query_param_string (rr[index].reserve->exchange_account_name), \ + GNUNET_PQ_query_param_timestamp (&rr[index].reserve->execution_time), \ + GNUNET_PQ_query_param_auto_from_type (&rr[index].h_payto), \ + GNUNET_PQ_query_param_string (rr[index].reserve->sender_account_details), \ + GNUNET_PQ_query_param_string (rr[index].notify_s) + + +/** + * Generate the SQL parameters to obtain results for record @a rr at + * index @a index + */ +#define RR_RESULT_PARAM(rr,index) \ + GNUNET_PQ_result_spec_bool ("conflicted" TALER_S (index), \ + &rr[index].conflicts), \ + GNUNET_PQ_result_spec_bool ("transaction_duplicate" TALER_S (index), \ + &rr[index].transaction_duplicate), \ + GNUNET_PQ_result_spec_uint64 ("reserve_uuid" TALER_S (index), \ + &rr[index].reserve_uuid) + + +/** + * Insert 1 reserve record @a rr into the database. + * + * @param pg database context + * @param gc gc timestamp to use + * @param reserve_expiration expiration time to use + * @param[in,out] rr array of reserve details to use and update + * @return database transaction status + */ static enum GNUNET_DB_QueryStatus insert1 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[1], struct GNUNET_TIME_Timestamp gc, - char *const *notify_s, struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid) + struct ReserveRecord *rr) { enum GNUNET_DB_QueryStatus qs; - struct TALER_PaytoHashP h_payto0; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_timestamp (&gc), GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto0), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - - GNUNET_PQ_query_param_string (notify_s[0]), + RR_QUERY_PARAM (rr, 0), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), + RR_RESULT_PARAM (rr, 0), GNUNET_PQ_result_spec_end }; PREPARE (pg, "batch1_reserve_create", "SELECT " - " out_reserve_found AS conflicted" - ",transaction_duplicate" - ",ruuid AS reserve_uuid" + " out_reserve_found0 AS conflicted0" + ",transaction_duplicate0 AS transaction_duplicate0" + ",ruuid0 AS reserve_uuid0" " FROM exchange_do_batch_reserves_in_insert" " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);"); - TALER_payto_hash (reserves[0].sender_account_details, - &h_payto0); qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "batch1_reserve_create", params, @@ -114,7 +168,7 @@ insert1 (struct PostgresClosure *pg, return qs; } GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); - if ((! conflict[0]) && transaction_duplicate[0]) + if ((! rr[0].conflicts) && rr[0].transaction_duplicate) { GNUNET_break (0); TEH_PG_rollback (pg); @@ -124,438 +178,418 @@ insert1 (struct PostgresClosure *pg, } +/** + * Insert 2 reserve records @a rr into the database. + * + * @param pg database context + * @param gc gc timestamp to use + * @param reserve_expiration expiration time to use + * @param[in,out] rr array of reserve details to use and update + * @return database transaction status + */ static enum GNUNET_DB_QueryStatus insert2 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[2], struct GNUNET_TIME_Timestamp gc, - char *const*notify_s, struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid) + struct ReserveRecord *rr) { - enum GNUNET_DB_QueryStatus qs1; - struct TALER_PaytoHashP h_payto[2]; + enum GNUNET_DB_QueryStatus qs; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_timestamp (&gc), GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[0]), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_string (notify_s[1]), - - GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), - TALER_PQ_query_param_amount (reserves[1].balance), - GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[1]), - GNUNET_PQ_query_param_string (reserves[1].sender_account_details), + RR_QUERY_PARAM (rr, 0), + RR_QUERY_PARAM (rr, 1), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("conflicted2", - &conflict[1]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - &transaction_duplicate[1]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - &reserve_uuid[1]), + RR_RESULT_PARAM (rr, 0), + RR_RESULT_PARAM (rr, 1), GNUNET_PQ_result_spec_end }; PREPARE (pg, "batch2_reserve_create", - "SELECT " - "out_reserve_found AS conflicted" - ",out_reserve_found2 AS conflicted2" - ",transaction_duplicate" - ",transaction_duplicate2" - ",ruuid AS reserve_uuid" - ",ruuid2 AS reserve_uuid2" + "SELECT" + " out_reserve_found0 AS conflicted0" + ",out_reserve_found1 AS conflicted1" + ",transaction_duplicate0" + ",transaction_duplicate1" + ",ruuid0 AS reserve_uuid0" + ",ruuid1 AS reserve_uuid1" " FROM exchange_do_batch2_reserves_insert" " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20);"); - TALER_payto_hash (reserves[0].sender_account_details, - &h_payto[0]); - TALER_payto_hash (reserves[1].sender_account_details, - &h_payto[1]); - qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch2_reserve_create", - params, - rs); - if (qs1 < 0) + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch2_reserve_create", + params, + rs); + if (qs < 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to create reserves 2(%d)\n", - qs1); - return qs1; + qs); + return qs; } - - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); - if ( ((! conflict[0]) && (transaction_duplicate[0])) || - ((! conflict[1]) && (transaction_duplicate[1])) ) + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); + for (unsigned int i = 0; i<2; i++) { - GNUNET_break (0); - TEH_PG_rollback (pg); - return GNUNET_DB_STATUS_HARD_ERROR; + if ((! rr[i].conflicts) && (rr[i].transaction_duplicate)) + { + GNUNET_break (0); + TEH_PG_rollback (pg); + return GNUNET_DB_STATUS_HARD_ERROR; + } } - return qs1; + return qs; } +/** + * Insert 4 reserve records @a rr into the database. + * + * @param pg database context + * @param gc gc timestamp to use + * @param reserve_expiration expiration time to use + * @param[in,out] rr array of reserve details to use and update + * @return database transaction status + */ static enum GNUNET_DB_QueryStatus insert4 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[4], struct GNUNET_TIME_Timestamp gc, - char *const*notify_s, struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid) + struct ReserveRecord *rr) { - enum GNUNET_DB_QueryStatus qs3; - struct TALER_PaytoHashP h_payto[4]; + enum GNUNET_DB_QueryStatus qs; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_timestamp (&gc), GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[0]), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_string (notify_s[1]), - GNUNET_PQ_query_param_string (notify_s[2]), - GNUNET_PQ_query_param_string (notify_s[3]), - - GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), - TALER_PQ_query_param_amount (reserves[1].balance), - GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[1]), - GNUNET_PQ_query_param_string (reserves[1].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), - TALER_PQ_query_param_amount (reserves[2].balance), - GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[2]), - GNUNET_PQ_query_param_string (reserves[2].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), - TALER_PQ_query_param_amount (reserves[3].balance), - GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[3]), - GNUNET_PQ_query_param_string (reserves[3].sender_account_details), - + RR_QUERY_PARAM (rr, 0), + RR_QUERY_PARAM (rr, 1), + RR_QUERY_PARAM (rr, 2), + RR_QUERY_PARAM (rr, 3), GNUNET_PQ_query_param_end }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("conflicted2", - &conflict[1]), - GNUNET_PQ_result_spec_bool ("conflicted3", - &conflict[2]), - GNUNET_PQ_result_spec_bool ("conflicted4", - &conflict[3]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - &transaction_duplicate[1]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate3", - &transaction_duplicate[2]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate4", - &transaction_duplicate[3]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - &reserve_uuid[1]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", - &reserve_uuid[2]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", - &reserve_uuid[3]), + RR_RESULT_PARAM (rr, 0), + RR_RESULT_PARAM (rr, 1), + RR_RESULT_PARAM (rr, 2), + RR_RESULT_PARAM (rr, 3), GNUNET_PQ_result_spec_end }; PREPARE (pg, "batch4_reserve_create", - "SELECT " - "out_reserve_found AS conflicted" + "SELECT" + " out_reserve_found0 AS conflicted0" + ",out_reserve_found1 AS conflicted1" ",out_reserve_found2 AS conflicted2" ",out_reserve_found3 AS conflicted3" - ",out_reserve_found4 AS conflicted4" - ",transaction_duplicate" + ",transaction_duplicate0" + ",transaction_duplicate1" ",transaction_duplicate2" ",transaction_duplicate3" - ",transaction_duplicate4" - ",ruuid AS reserve_uuid" + ",ruuid0 AS reserve_uuid0" + ",ruuid1 AS reserve_uuid1" ",ruuid2 AS reserve_uuid2" ",ruuid3 AS reserve_uuid3" - ",ruuid4 AS reserve_uuid4" " FROM exchange_do_batch4_reserves_insert" " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38);"); - - for (unsigned int i = 0; i<4; i++) - TALER_payto_hash (reserves[i].sender_account_details, - &h_payto[i]); - qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch4_reserve_create", - params, - rs); - if (qs3 < 0) + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch4_reserve_create", + params, + rs); + if (qs < 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to create reserves4 (%d)\n", - qs3); - return qs3; + qs); + return qs; } - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); - - if ( - ((! conflict[0]) && (transaction_duplicate[0])) - || ((! conflict[1]) && (transaction_duplicate[1])) - || ((! conflict[2]) && (transaction_duplicate[2])) - || ((! conflict[3]) && (transaction_duplicate[3])) - ) + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); + for (unsigned int i = 0; i<4; i++) { - GNUNET_break (0); - TEH_PG_rollback (pg); - return GNUNET_DB_STATUS_HARD_ERROR; + if ((! rr[i].conflicts) && (rr[i].transaction_duplicate)) + { + GNUNET_break (0); + TEH_PG_rollback (pg); + return GNUNET_DB_STATUS_HARD_ERROR; + } } - return qs3; + return qs; } +/** + * Insert 8 reserve records @a rr into the database. + * + * @param pg database context + * @param gc gc timestamp to use + * @param reserve_expiration expiration time to use + * @param[in,out] rr array of reserve details to use and update + * @return database transaction status + */ static enum GNUNET_DB_QueryStatus insert8 (struct PostgresClosure *pg, - const struct TALER_EXCHANGEDB_ReserveInInfo reserves[8], struct GNUNET_TIME_Timestamp gc, - char *const*notify_s, struct GNUNET_TIME_Timestamp reserve_expiration, - bool *transaction_duplicate, - bool *conflict, - uint64_t *reserve_uuid) + struct ReserveRecord *rr) { - enum GNUNET_DB_QueryStatus qs3; - struct TALER_PaytoHashP h_payto[8]; + enum GNUNET_DB_QueryStatus qs; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_timestamp (&gc), GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), - TALER_PQ_query_param_amount (reserves[0].balance), - GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[0]), - GNUNET_PQ_query_param_string (reserves[0].sender_account_details), - - GNUNET_PQ_query_param_string (notify_s[0]), - GNUNET_PQ_query_param_string (notify_s[1]), - GNUNET_PQ_query_param_string (notify_s[2]), - GNUNET_PQ_query_param_string (notify_s[3]), - GNUNET_PQ_query_param_string (notify_s[4]), - GNUNET_PQ_query_param_string (notify_s[5]), - GNUNET_PQ_query_param_string (notify_s[6]), - GNUNET_PQ_query_param_string (notify_s[7]), - - GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), - TALER_PQ_query_param_amount (reserves[1].balance), - GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[1]), - GNUNET_PQ_query_param_string (reserves[1].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), - TALER_PQ_query_param_amount (reserves[2].balance), - GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[2]), - GNUNET_PQ_query_param_string (reserves[2].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), - TALER_PQ_query_param_amount (reserves[3].balance), - GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[3]), - GNUNET_PQ_query_param_string (reserves[3].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[4].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[4].wire_reference), - TALER_PQ_query_param_amount (reserves[4].balance), - GNUNET_PQ_query_param_string (reserves[4].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[4].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[4]), - GNUNET_PQ_query_param_string (reserves[4].sender_account_details), - GNUNET_PQ_query_param_timestamp (&reserve_expiration), - - GNUNET_PQ_query_param_auto_from_type (reserves[5].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[5].wire_reference), - TALER_PQ_query_param_amount (reserves[5].balance), - GNUNET_PQ_query_param_string (reserves[5].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[5].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[5]), - GNUNET_PQ_query_param_string (reserves[5].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[6].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[6].wire_reference), - TALER_PQ_query_param_amount (reserves[6].balance), - GNUNET_PQ_query_param_string (reserves[6].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[6].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[6]), - GNUNET_PQ_query_param_string (reserves[6].sender_account_details), - - GNUNET_PQ_query_param_auto_from_type (reserves[7].reserve_pub), - GNUNET_PQ_query_param_uint64 (&reserves[7].wire_reference), - TALER_PQ_query_param_amount (reserves[7].balance), - GNUNET_PQ_query_param_string (reserves[7].exchange_account_name), - GNUNET_PQ_query_param_timestamp (&reserves[7].execution_time), - GNUNET_PQ_query_param_auto_from_type (&h_payto[7]), - GNUNET_PQ_query_param_string (reserves[7].sender_account_details), - + RR_QUERY_PARAM (rr, 0), + RR_QUERY_PARAM (rr, 1), + RR_QUERY_PARAM (rr, 2), + RR_QUERY_PARAM (rr, 3), + RR_QUERY_PARAM (rr, 4), + RR_QUERY_PARAM (rr, 5), + RR_QUERY_PARAM (rr, 6), + RR_QUERY_PARAM (rr, 7), GNUNET_PQ_query_param_end }; - struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_bool ("conflicted", - &conflict[0]), - GNUNET_PQ_result_spec_bool ("conflicted2", - &conflict[1]), - GNUNET_PQ_result_spec_bool ("conflicted3", - &conflict[2]), - GNUNET_PQ_result_spec_bool ("conflicted4", - &conflict[3]), - GNUNET_PQ_result_spec_bool ("conflicted5", - &conflict[4]), - GNUNET_PQ_result_spec_bool ("conflicted6", - &conflict[5]), - GNUNET_PQ_result_spec_bool ("conflicted7", - &conflict[6]), - GNUNET_PQ_result_spec_bool ("conflicted8", - &conflict[7]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate", - &transaction_duplicate[0]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate2", - &transaction_duplicate[1]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate3", - &transaction_duplicate[2]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate4", - &transaction_duplicate[3]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate5", - &transaction_duplicate[4]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate6", - &transaction_duplicate[5]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate7", - &transaction_duplicate[6]), - GNUNET_PQ_result_spec_bool ("transaction_duplicate8", - &transaction_duplicate[7]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid", - &reserve_uuid[0]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", - &reserve_uuid[1]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", - &reserve_uuid[2]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", - &reserve_uuid[3]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid5", - &reserve_uuid[4]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid6", - &reserve_uuid[5]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid7", - &reserve_uuid[6]), - GNUNET_PQ_result_spec_uint64 ("reserve_uuid8", - &reserve_uuid[7]), + RR_RESULT_PARAM (rr, 0), + RR_RESULT_PARAM (rr, 1), + RR_RESULT_PARAM (rr, 2), + RR_RESULT_PARAM (rr, 3), + RR_RESULT_PARAM (rr, 4), + RR_RESULT_PARAM (rr, 5), + RR_RESULT_PARAM (rr, 6), + RR_RESULT_PARAM (rr, 7), GNUNET_PQ_result_spec_end }; PREPARE (pg, "batch8_reserve_create", "SELECT" - " out_reserve_found AS conflicted" + " out_reserve_found0 AS conflicted0" + ",out_reserve_found1 AS conflicted1" ",out_reserve_found2 AS conflicted2" ",out_reserve_found3 AS conflicted3" ",out_reserve_found4 AS conflicted4" ",out_reserve_found5 AS conflicted5" ",out_reserve_found6 AS conflicted6" ",out_reserve_found7 AS conflicted7" - ",out_reserve_found8 AS conflicted8" - ",transaction_duplicate" + ",transaction_duplicate0" + ",transaction_duplicate1" ",transaction_duplicate2" ",transaction_duplicate3" ",transaction_duplicate4" ",transaction_duplicate5" ",transaction_duplicate6" ",transaction_duplicate7" - ",transaction_duplicate8" - ",ruuid AS reserve_uuid" + ",ruuid0 AS reserve_uuid0" + ",ruuid1 AS reserve_uuid1" ",ruuid2 AS reserve_uuid2" ",ruuid3 AS reserve_uuid3" ",ruuid4 AS reserve_uuid4" ",ruuid5 AS reserve_uuid5" ",ruuid6 AS reserve_uuid6" ",ruuid7 AS reserve_uuid7" - ",ruuid8 AS reserve_uuid8" " FROM exchange_do_batch8_reserves_insert" " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$70,$71,$72,$73,$74);"); - for (unsigned int i = 0; i<8; i++) - TALER_payto_hash (reserves[i].sender_account_details, - &h_payto[i]); - qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "batch8_reserve_create", - params, - rs); - if (qs3 < 0) + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "batch8_reserve_create", + params, + rs); + if (qs < 0) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to create reserves8 (%d)\n", - qs3); - return qs3; + qs); + return qs; } - GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); - if ( - ((! conflict[0]) && (transaction_duplicate[0])) - || ((! conflict[1]) && (transaction_duplicate[1])) - || ((! conflict[2]) && (transaction_duplicate[2])) - || ((! conflict[3]) && (transaction_duplicate[3])) - || ((! conflict[4]) && (transaction_duplicate[4])) - || ((! conflict[5]) && (transaction_duplicate[5])) - || ((! conflict[6]) && (transaction_duplicate[6])) - || ((! conflict[7]) && (transaction_duplicate[7])) - ) + GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs); + for (unsigned int i = 0; i<8; i++) + { + if ((! rr[i].conflicts) && (rr[i].transaction_duplicate)) + { + GNUNET_break (0); + TEH_PG_rollback (pg); + return GNUNET_DB_STATUS_HARD_ERROR; + } + } + return qs; +} + + +static enum GNUNET_DB_QueryStatus +transact ( + struct PostgresClosure *pg, + struct ReserveRecord *rr, + unsigned int reserves_length, + unsigned int batch_size, + enum GNUNET_DB_QueryStatus *results) +{ + struct GNUNET_TIME_Timestamp reserve_expiration + = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); + struct GNUNET_TIME_Timestamp gc + = GNUNET_TIME_relative_to_timestamp (pg->legal_reserve_expiration_time); + bool need_update = false; + + if (GNUNET_OK != + TEH_PG_preflight (pg)) { GNUNET_break (0); - TEH_PG_rollback (pg); return GNUNET_DB_STATUS_HARD_ERROR; } - return qs3; + + if (GNUNET_OK != + TEH_PG_start_read_committed (pg, + "READ_COMMITED")) + { + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + { + unsigned int i = 0; + + while (i < reserves_length) + { + enum GNUNET_DB_QueryStatus qs; + enum GNUNET_DB_QueryStatus + (*fun)(struct PostgresClosure *pg, + struct GNUNET_TIME_Timestamp gc, + struct GNUNET_TIME_Timestamp reserve_expiration, + struct ReserveRecord *rr); + unsigned int lim; + unsigned int bs; + + bs = GNUNET_MIN (batch_size, + reserves_length - i); + switch (bs) + { + case 7: + case 6: + case 5: + case 4: + fun = &insert4; + lim = 4; + break; + case 3: + case 2: + fun = &insert2; + lim = 2; + break; + case 1: + fun = &insert1; + lim = 1; + break; + case 0: + GNUNET_assert (0); + break; + default: + fun = insert8; + lim = 8; + break; + } + + qs = fun (pg, + gc, + reserve_expiration, + &rr[i]); + if (qs < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to create reserve batch_%u (%d)\n", + lim, + qs); + results[i] = qs; + return qs; + } + for (unsigned int j = 0; jreserve_pub), + GNUNET_PQ_query_param_timestamp (&reserve_expiration), + GNUNET_PQ_query_param_uint64 (&rr[i].reserve->wire_reference), + TALER_PQ_query_param_amount (rr[i].reserve->balance), + GNUNET_PQ_query_param_string (rr[i].reserve->exchange_account_name), + GNUNET_PQ_query_param_auto_from_type (&rr[i].h_payto), + GNUNET_PQ_query_param_string (rr[i].notify_s), + GNUNET_PQ_query_param_end + }; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_bool ("duplicate", + &duplicate), + GNUNET_PQ_result_spec_end + }; + enum GNUNET_DB_QueryStatus qs; + + qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "reserves_update", + params, + rs); + if (qs < 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to update reserves (%d)\n", + qs); + results[i] = qs; + return qs; + } + results[i] = duplicate + ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS + : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + } + } + + { + enum GNUNET_DB_QueryStatus cs = TEH_PG_commit (pg); + + if (0 > cs) + return cs; + } + return reserves_length; } @@ -568,271 +602,31 @@ TEH_PG_reserves_in_insert ( enum GNUNET_DB_QueryStatus *results) { struct PostgresClosure *pg = cls; - enum GNUNET_DB_QueryStatus qs1; - enum GNUNET_DB_QueryStatus qs2; - enum GNUNET_DB_QueryStatus qs4; - enum GNUNET_DB_QueryStatus qs5; - uint64_t reserve_uuid[reserves_length]; - bool transaction_duplicate[reserves_length]; - bool need_update = false; - struct GNUNET_TIME_Timestamp reserve_expiration - = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); - struct GNUNET_TIME_Timestamp gc - = GNUNET_TIME_relative_to_timestamp (pg->legal_reserve_expiration_time); - bool conflicts[reserves_length]; - char *notify_s[reserves_length]; + struct ReserveRecord rrs[reserves_length]; + enum GNUNET_DB_QueryStatus qs; - if (GNUNET_OK != - TEH_PG_preflight (pg)) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating reserve %s with expiration in %s\n", - TALER_B2S (&(reserves->reserve_pub)), - GNUNET_STRINGS_relative_time_to_string ( - pg->idle_reserve_expiration_time, - GNUNET_NO)); - - if (GNUNET_OK != - TEH_PG_start_read_committed (pg, - "READ_COMMITED")) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - - /* Optimistically assume this is a new reserve, create balance for the first - time; we do this before adding the actual transaction to "reserves_in", - as for a new reserve it can't be a duplicate 'add' operation, and as - the 'add' operation needs the reserve entry as a foreign key. */ for (unsigned int i = 0; ireserve_pub); + rr->reserve = reserve; + TALER_payto_hash (reserves->sender_account_details, + &rr->h_payto); + rr->notify_s = compute_notify_on_reserve (reserve->reserve_pub); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating reserve %s with expiration in %s\n", + TALER_B2S (&reserve->reserve_pub), + GNUNET_STRINGS_relative_time_to_string ( + pg->idle_reserve_expiration_time, + false)); } - - unsigned int i = 0; - - while (i < reserves_length) - { - unsigned int bs = GNUNET_MIN (batch_size, - reserves_length - i); - if (bs >= 8) - { - qs1 = insert8 (pg, - &reserves[i], - gc, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i]); - - if (qs1<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_8 (%d)\n", - qs1); - results[i] = qs1; - return qs1; - } - need_update |= conflicts[i]; - need_update |= conflicts[i + 1]; - need_update |= conflicts[i + 2]; - need_update |= conflicts[i + 3]; - need_update |= conflicts[i + 4]; - need_update |= conflicts[i + 5]; - need_update |= conflicts[i + 6]; - need_update |= conflicts[i + 7]; - for (unsigned int j = 0; j<8; j++) - results[i + j] = transaction_duplicate[i + j] - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - i += 8; - continue; - } - switch (bs) - { - case 7: - case 6: - case 5: - case 4: - qs4 = insert4 (pg, - &reserves[i], - gc, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i]); - if (qs4<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_4 (%d)\n", - qs4); - results[i] = qs4; - return qs4; - } - need_update |= conflicts[i]; - need_update |= conflicts[i + 1]; - need_update |= conflicts[i + 2]; - need_update |= conflicts[i + 3]; - for (unsigned int j = 0; j<4; j++) - results[i + j] = transaction_duplicate[i + j] - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - i += 4; - break; - case 3: - case 2: - qs5 = insert2 (pg, - &reserves[i], - gc, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i]); - if (qs5<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_2 (%d)\n", - qs5); - results[i] = qs5; - return qs5; - } - need_update |= conflicts[i]; - need_update |= conflicts[i + 1]; - for (unsigned int j = 0; j<2; j++) - results[i + j] = transaction_duplicate[i + j] - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - i += 2; - break; - case 1: - qs2 = insert1 (pg, - &reserves[i], - gc, - ¬ify_s[i], - reserve_expiration, - &transaction_duplicate[i], - &conflicts[i], - &reserve_uuid[i]); - if (qs2<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to create reserve batch_1 (%d)\n)", - qs2); - results[i] = qs2; - return qs2; - } - need_update |= conflicts[i]; - results[i] = (transaction_duplicate[i]) - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - i += 1; - break; - case 0: - GNUNET_assert (0); - break; - } - } /* end while */ - // commit - { - enum GNUNET_DB_QueryStatus cs; - - cs = TEH_PG_commit (pg); - if (cs < 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to commit\n"); - return cs; - } - } - if (! need_update) - { - goto exit; - } - // begin serializable - { - if (GNUNET_OK != - TEH_PG_start (pg, - "reserve-insert-continued")) - { - GNUNET_break (0); - return GNUNET_DB_STATUS_HARD_ERROR; - } - } - - PREPARE (pg, - "reserves_update", - "SELECT" - " out_duplicate AS duplicate " - "FROM exchange_do_batch_reserves_update" - " ($1,$2,$3,$4,$5,$6,$7,$8);"); + qs = transact (pg, + rrs, + reserves_length, + batch_size, + results); for (unsigned int i = 0; iconn, - "reserves_update", - params, - rs); - if (qs3<0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to update reserves (%d)\n", - qs3); - results[i] = qs3; - return qs3; - } - results[i] = duplicate - ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS - : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; - } - } - - { - enum GNUNET_DB_QueryStatus cs; - - cs = TEH_PG_commit (pg); - if (cs < 0) - { - for (unsigned int i = 0; ilabel); is->child_death_task = NULL; From 53157062cb482824b4315aaa60bb548b2977ced2 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 22 Apr 2023 01:40:53 +0200 Subject: [PATCH 05/12] -misc bugs --- .../exchange_do_reserves_in_insert.sql | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/exchangedb/exchange_do_reserves_in_insert.sql b/src/exchangedb/exchange_do_reserves_in_insert.sql index e7506dc85..1c99f4fd1 100644 --- a/src/exchangedb/exchange_do_reserves_in_insert.sql +++ b/src/exchangedb/exchange_do_reserves_in_insert.sql @@ -32,11 +32,11 @@ CREATE OR REPLACE FUNCTION exchange_do_batch_reserves_in_insert( LANGUAGE plpgsql AS $$ DECLARE - curs refcursor; + curs REFCURSOR; DECLARE i RECORD; DECLARE - curs_trans refcursor; + curs_trans REFCURSOR; BEGIN ruuid0 = 0; out_reserve_found0 = TRUE; @@ -228,7 +228,7 @@ BEGIN CLOSE curs_reserve_exist; OPEN curs_transaction_exist FOR - WITH reserve_in_exist AS ( + WITH reserve_transaction AS ( INSERT INTO reserves_in (reserve_pub ,wire_reference @@ -254,7 +254,7 @@ BEGIN ,in1_execution_date) ON CONFLICT DO NOTHING RETURNING reserve_pub) - SELECT reserve_pub FROM reserve_in_exist; + SELECT reserve_pub FROM reserve_transaction; FETCH FROM curs_transaction_exist INTO r; @@ -270,7 +270,7 @@ BEGIN CASE k WHEN 0 THEN k = k + 1; - IF in0_reserve_pub = r.reserve_pub + IF in0_reserve_pub = i.reserve_pub THEN transaction_duplicate0 = FALSE; EXECUTE FORMAT ( @@ -280,7 +280,7 @@ BEGIN END IF; CONTINUE loop2_k; WHEN 1 THEN - IF in0_reserve_pub = r.reserve_pub + IF in0_reserve_pub = i.reserve_pub THEN transaction_duplicate1 = FALSE; EXECUTE FORMAT ( @@ -324,7 +324,7 @@ CREATE OR REPLACE FUNCTION exchange_do_batch4_reserves_insert( IN in2_credit_val INT8, IN in2_credit_frac INT4, IN in2_exchange_account_name VARCHAR, - IN in2_execute_date INT8, + IN in2_execution_date INT8, IN in2_wire_source_h_payto BYTEA, IN in2_payto_uri VARCHAR, IN in2_notify TEXT, @@ -333,7 +333,7 @@ CREATE OR REPLACE FUNCTION exchange_do_batch4_reserves_insert( IN in3_credit_val INT8, IN in3_credit_frac INT4, IN in3_exchange_account_name VARCHAR, - IN in3_execute_date INT8, + IN in3_execution_date INT8, IN in3_wire_source_h_payto BYTEA, IN in3_payto_uri VARCHAR, IN in3_notify TEXT, @@ -472,7 +472,7 @@ BEGIN CLOSE curs_reserve_exist; OPEN curs_transaction_exist FOR - WITH reserve_changes AS ( + WITH reserve_transaction AS ( INSERT INTO reserves_in (reserve_pub ,wire_reference @@ -512,7 +512,7 @@ BEGIN ,in3_execution_date) ON CONFLICT DO NOTHING RETURNING reserve_pub) - SELECT reserve_uuid, reserve_pub FROM reserve_changes; + SELECT reserve_pub FROM reserve_transaction; k=0; <> LOOP @@ -526,7 +526,7 @@ BEGIN CASE k WHEN 0 THEN k = k + 1; - IF in0_reserve_pub = r.reserve_pub + IF in0_reserve_pub = i.reserve_pub THEN transaction_duplicate0 = FALSE; EXECUTE FORMAT ( @@ -537,7 +537,7 @@ BEGIN CONTINUE loop2_k; WHEN 1 THEN k = k + 1; - IF in1_reserve_pub = r.reserve_pub + IF in1_reserve_pub = i.reserve_pub THEN transaction_duplicate1 = FALSE; EXECUTE FORMAT ( @@ -548,7 +548,7 @@ BEGIN CONTINUE loop2_k; WHEN 2 THEN k = k + 1; - IF in2_reserve_pub = r.reserve_pub + IF in2_reserve_pub = i.reserve_pub THEN transaction_duplicate2 = FALSE; EXECUTE FORMAT ( @@ -558,7 +558,7 @@ BEGIN END IF; CONTINUE loop2_k; WHEN 3 THEN - IF in3_reserve_pub = r.reserve_pub + IF in3_reserve_pub = i.reserve_pub THEN transaction_duplicate3 = FALSE; EXECUTE FORMAT ( @@ -877,7 +877,7 @@ BEGIN CLOSE curs_reserve_exist; OPEN curs_transaction_exist FOR - WITH reserve_changes AS ( + WITH reserve_transaction AS ( INSERT INTO reserves_in (reserve_pub ,wire_reference @@ -945,7 +945,7 @@ BEGIN ,in7_execution_date) ON CONFLICT DO NOTHING RETURNING reserve_pub) - SELECT reserve_pub FROM reserve_changes; + SELECT reserve_pub FROM reserve_transaction; k=0; <> LOOP @@ -959,7 +959,7 @@ BEGIN CASE k WHEN 0 THEN k = k + 1; - IF in0_reserve_pub = r.reserve_pub + IF in0_reserve_pub = i.reserve_pub THEN transaction_duplicate0 = FALSE; EXECUTE FORMAT ( @@ -970,7 +970,7 @@ BEGIN CONTINUE loop2_k; WHEN 1 THEN k = k + 1; - IF in1_reserve_pub = r.reserve_pub + IF in1_reserve_pub = i.reserve_pub THEN transaction_duplicate1 = FALSE; EXECUTE FORMAT ( @@ -981,7 +981,7 @@ BEGIN CONTINUE loop2_k; WHEN 2 THEN k = k + 1; - IF in2_reserve_pub = r.reserve_pub + IF in2_reserve_pub = i.reserve_pub THEN transaction_duplicate2 = FALSE; EXECUTE FORMAT ( @@ -992,7 +992,7 @@ BEGIN CONTINUE loop2_k; WHEN 3 THEN k = k + 1; - IF in3_reserve_pub = r.reserve_pub + IF in3_reserve_pub = i.reserve_pub THEN transaction_duplicate3 = FALSE; EXECUTE FORMAT ( @@ -1003,7 +1003,7 @@ BEGIN CONTINUE loop2_k; WHEN 4 THEN k = k + 1; - IF in4_reserve_pub = r.reserve_pub + IF in4_reserve_pub = i.reserve_pub THEN transaction_duplicate4 = FALSE; EXECUTE FORMAT ( @@ -1014,7 +1014,7 @@ BEGIN CONTINUE loop2_k; WHEN 5 THEN k = k + 1; - IF in5_reserve_pub = r.reserve_pub + IF in5_reserve_pub = i.reserve_pub THEN transaction_duplicate2 = FALSE; EXECUTE FORMAT ( @@ -1025,7 +1025,7 @@ BEGIN CONTINUE loop2_k; WHEN 6 THEN k = k + 1; - IF in6_reserve_pub = r.reserve_pub + IF in6_reserve_pub = i.reserve_pub THEN transaction_duplicate6 = FALSE; EXECUTE FORMAT ( @@ -1035,7 +1035,7 @@ BEGIN END IF; CONTINUE loop2_k; WHEN 7 THEN - IF in7_reserve_pub = r.reserve_pub + IF in7_reserve_pub = i.reserve_pub THEN transaction_duplicate7 = FALSE; EXECUTE FORMAT ( From 89c5a3eca927deb57dff2a093e1f0e27b279eb87 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 22 Apr 2023 01:53:41 +0200 Subject: [PATCH 06/12] -misc bugs --- src/exchangedb/exchange_do_reserves_in_insert.sql | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/exchangedb/exchange_do_reserves_in_insert.sql b/src/exchangedb/exchange_do_reserves_in_insert.sql index 1c99f4fd1..77672f012 100644 --- a/src/exchangedb/exchange_do_reserves_in_insert.sql +++ b/src/exchangedb/exchange_do_reserves_in_insert.sql @@ -786,8 +786,13 @@ BEGIN ,in_reserve_expiration ,in_gc_date) ON CONFLICT DO NOTHING - RETURNING reserve_uuid,reserve_pub) - SELECT reserve_uuid, reserve_pub FROM reserve_changes; + RETURNING + reserve_uuid + ,reserve_pub) + SELECT + reserve_uuid + ,reserve_pub + FROM reserve_changes; k=0; <> LOOP @@ -1016,7 +1021,7 @@ BEGIN k = k + 1; IF in5_reserve_pub = i.reserve_pub THEN - transaction_duplicate2 = FALSE; + transaction_duplicate5 = FALSE; EXECUTE FORMAT ( 'NOTIFY %s' ,in5_notify); From 9e61579c8b8c42d49fc60744782dbd71efbbda8a Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 22 Apr 2023 02:26:44 +0200 Subject: [PATCH 07/12] -misc fixes --- src/benchmark/bank-benchmark-cs.conf | 6 +++--- src/benchmark/taler-bank-benchmark.c | 2 ++ src/benchmark/taler-exchange-benchmark.c | 2 +- src/exchange/taler-exchange-wirewatch.c | 10 +++++++++- src/exchangedb/exchange_do_reserves_in_insert.sql | 6 +++--- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/benchmark/bank-benchmark-cs.conf b/src/benchmark/bank-benchmark-cs.conf index d012f0faa..e32370f89 100644 --- a/src/benchmark/bank-benchmark-cs.conf +++ b/src/benchmark/bank-benchmark-cs.conf @@ -28,7 +28,7 @@ DB = postgres # exchange (or the twister) is actually listening. base_url = "http://localhost:8081/" -WIREWATCH_IDLE_SLEEP_INTERVAL = 1500 ms +WIREWATCH_IDLE_SLEEP_INTERVAL = 500 ms [exchange-offline] MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv @@ -51,11 +51,11 @@ MAX_DEBT = EUR:100000000000.0 MAX_DEBT_BANK = EUR:1000000000000000.0 [benchmark] -USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42 +USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42?receiver-name=user42 [exchange-account-2] # What is the payto://-URL of the exchange (to generate wire response) -PAYTO_URI = "payto://x-taler-bank/localhost:8082/Exchange" +PAYTO_URI = "payto://x-taler-bank/localhost:8082/Exchange?receiver-name=Exchange" enable_debit = YES enable_credit = YES diff --git a/src/benchmark/taler-bank-benchmark.c b/src/benchmark/taler-bank-benchmark.c index b17bb9411..584df4896 100644 --- a/src/benchmark/taler-bank-benchmark.c +++ b/src/benchmark/taler-bank-benchmark.c @@ -689,6 +689,8 @@ parallel_benchmark (void) } /* But be extra sure we did finish all shards by doing one more */ + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Shard check phase\n"); wirewatch[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, NULL, NULL, NULL, "taler-exchange-wirewatch", diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 77ef94ebc..fd7553813 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2014-2020 Taler Systems SA + (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as diff --git a/src/exchange/taler-exchange-wirewatch.c b/src/exchange/taler-exchange-wirewatch.c index 9f954c27f..2bffc3b85 100644 --- a/src/exchange/taler-exchange-wirewatch.c +++ b/src/exchange/taler-exchange-wirewatch.c @@ -482,6 +482,10 @@ transaction_completed (void) latency = GNUNET_TIME_absolute_get_duration (hh_start_time); left = GNUNET_TIME_relative_subtract (longpoll_timeout, latency); +#if 1 + left = GNUNET_TIME_relative_min (left, + GNUNET_TIME_UNIT_SECONDS); +#endif delayed_until = GNUNET_TIME_relative_to_absolute (left); } if (test_mode) @@ -857,6 +861,10 @@ lock_shard (void *cls) job_name, GNUNET_STRINGS_relative_time_to_string (rdelay, true)); +#if 1 + rdelay = GNUNET_TIME_relative_min (rdelay, + GNUNET_TIME_UNIT_SECONDS); +#endif delayed_until = GNUNET_TIME_relative_to_absolute (rdelay); } GNUNET_assert (NULL == task); @@ -869,7 +877,7 @@ lock_shard (void *cls) job_name, GNUNET_STRINGS_relative_time_to_string ( wirewatch_idle_sleep_interval, - GNUNET_YES)); + true)); delayed_until = GNUNET_TIME_relative_to_absolute ( wirewatch_idle_sleep_interval); shard_open = false; diff --git a/src/exchangedb/exchange_do_reserves_in_insert.sql b/src/exchangedb/exchange_do_reserves_in_insert.sql index 77672f012..07ce3ec28 100644 --- a/src/exchangedb/exchange_do_reserves_in_insert.sql +++ b/src/exchangedb/exchange_do_reserves_in_insert.sql @@ -286,8 +286,8 @@ BEGIN EXECUTE FORMAT ( 'NOTIFY %s' ,in1_notify); - EXIT loop_transaction; END IF; + EXIT loop_transaction; END CASE; END LOOP loop2_k; END LOOP loop_transaction; @@ -564,8 +564,8 @@ BEGIN EXECUTE FORMAT ( 'NOTIFY %s' ,in3_notify); - EXIT loop_transaction; END IF; + EXIT loop_transaction; END CASE; END LOOP loop2_k; END LOOP loop_transaction; @@ -1046,8 +1046,8 @@ BEGIN EXECUTE FORMAT ( 'NOTIFY %s' ,in7_notify); - EXIT loop_transaction; END IF; + EXIT loop_transaction; END CASE; END LOOP loop2_k; END LOOP loop_transaction; From 0236caf3546acfc25dabe8f8f5763c64a6f55561 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 22 Apr 2023 02:30:02 +0200 Subject: [PATCH 08/12] -misc fixes --- src/exchangedb/exchange_do_reserves_in_insert.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/exchangedb/exchange_do_reserves_in_insert.sql b/src/exchangedb/exchange_do_reserves_in_insert.sql index 07ce3ec28..d68541f22 100644 --- a/src/exchangedb/exchange_do_reserves_in_insert.sql +++ b/src/exchangedb/exchange_do_reserves_in_insert.sql @@ -280,7 +280,7 @@ BEGIN END IF; CONTINUE loop2_k; WHEN 1 THEN - IF in0_reserve_pub = i.reserve_pub + IF in1_reserve_pub = i.reserve_pub THEN transaction_duplicate1 = FALSE; EXECUTE FORMAT ( From be1d8afaec27d7cda6fb858930557e5a9be5df15 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 22 Apr 2023 02:33:18 +0200 Subject: [PATCH 09/12] -misc fixes --- src/exchangedb/exchange_do_reserves_in_insert.sql | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/exchangedb/exchange_do_reserves_in_insert.sql b/src/exchangedb/exchange_do_reserves_in_insert.sql index d68541f22..dd202a2ae 100644 --- a/src/exchangedb/exchange_do_reserves_in_insert.sql +++ b/src/exchangedb/exchange_do_reserves_in_insert.sql @@ -218,9 +218,8 @@ BEGIN THEN ruuid1 = i.reserve_uuid; out_reserve_found1 = FALSE; - EXIT loop_reserve; END IF; - EXIT loop_k; + EXIT loop_reserve; END CASE; END LOOP loop_k; END LOOP loop_reserve; @@ -462,9 +461,8 @@ BEGIN THEN ruuid3 = i.reserve_uuid; out_reserve_found3 = FALSE; - EXIT loop_reserve; END IF; - EXIT loop_k; + EXIT loop_reserve; END CASE; END LOOP loop_k; END LOOP loop_reserve; @@ -872,9 +870,8 @@ BEGIN THEN ruuid7 = i.reserve_uuid; out_reserve_found7 = FALSE; - EXIT loop_reserve; END IF; - EXIT loop_k; + EXIT loop_reserve; END CASE; END LOOP loop_k; END LOOP loop_reserve; From 76b934b219b6ec82f58a7e95cbc6fff4f4ed0ebf Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 22 Apr 2023 02:54:55 +0200 Subject: [PATCH 10/12] -misc fixes --- .../exchange_do_reserves_in_insert.sql | 54 +++++++++---------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/src/exchangedb/exchange_do_reserves_in_insert.sql b/src/exchangedb/exchange_do_reserves_in_insert.sql index dd202a2ae..6cd5847df 100644 --- a/src/exchangedb/exchange_do_reserves_in_insert.sql +++ b/src/exchangedb/exchange_do_reserves_in_insert.sql @@ -145,14 +145,12 @@ LANGUAGE plpgsql AS $$ DECLARE curs_reserve_exist REFCURSOR; +DECLARE + k INT8; DECLARE curs_transaction_exist REFCURSOR; DECLARE i RECORD; -DECLARE - r RECORD; -DECLARE - k INT8; BEGIN transaction_duplicate0 = TRUE; transaction_duplicate1 = TRUE; @@ -228,35 +226,33 @@ BEGIN OPEN curs_transaction_exist FOR WITH reserve_transaction AS ( - INSERT INTO reserves_in - (reserve_pub - ,wire_reference - ,credit_val - ,credit_frac - ,exchange_account_section - ,wire_source_h_payto - ,execution_date) - VALUES - (in0_reserve_pub - ,in0_wire_ref - ,in0_credit_val - ,in0_credit_frac - ,in0_exchange_account_name - ,in0_wire_source_h_payto - ,in0_execution_date), - (in1_reserve_pub - ,in1_wire_ref - ,in1_credit_val - ,in1_credit_frac - ,in1_exchange_account_name - ,in1_wire_source_h_payto - ,in1_execution_date) + INSERT INTO reserves_in + (reserve_pub + ,wire_reference + ,credit_val + ,credit_frac + ,exchange_account_section + ,wire_source_h_payto + ,execution_date) + VALUES + (in0_reserve_pub + ,in0_wire_ref + ,in0_credit_val + ,in0_credit_frac + ,in0_exchange_account_name + ,in0_wire_source_h_payto + ,in0_execution_date), + (in1_reserve_pub + ,in1_wire_ref + ,in1_credit_val + ,in1_credit_frac + ,in1_exchange_account_name + ,in1_wire_source_h_payto + ,in1_execution_date) ON CONFLICT DO NOTHING RETURNING reserve_pub) SELECT reserve_pub FROM reserve_transaction; - FETCH FROM curs_transaction_exist INTO r; - k=0; <> LOOP FETCH FROM curs_transaction_exist INTO i; From c3fc8c5e558d4bcba0492c8d0e2d563ce7fb0519 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 22 Apr 2023 14:43:26 +0200 Subject: [PATCH 11/12] fix fakebank long polling --- src/bank-lib/fakebank.c | 691 +++++++++++++++--------- src/exchange/taler-exchange-wirewatch.c | 34 +- 2 files changed, 474 insertions(+), 251 deletions(-) diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c index 76e4db70a..60492e50f 100644 --- a/src/bank-lib/fakebank.c +++ b/src/bank-lib/fakebank.c @@ -400,6 +400,148 @@ struct Transaction }; +/** + * Function called to clean up context of a connection. + * + * @param ctx context to clean up + */ +typedef void +(*ConnectionCleaner)(void *ctx); + +/** + * Universal context we keep per connection. + */ +struct ConnectionContext +{ + /** + * Function we call upon completion to clean up. + */ + ConnectionCleaner ctx_cleaner; + + /** + * Request-handler specific context. + */ + void *ctx; +}; + + +/** + * This is the "base" structure for both the /history and the + * /history-range API calls. + */ +struct HistoryArgs +{ + + /** + * Bank account number of the requesting client. + */ + uint64_t account_number; + + /** + * Index of the starting transaction, exclusive (!). + */ + uint64_t start_idx; + + /** + * Requested number of results and order + * (positive: ascending, negative: descending) + */ + int64_t delta; + + /** + * Timeout for long polling. + */ + struct GNUNET_TIME_Relative lp_timeout; + + /** + * true if starting point was given. + */ + bool have_start; + +}; + + +/** + * Context we keep per history request. + */ +struct HistoryContext +{ + /** + * When does this request time out. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * Client arguments for this request. + */ + struct HistoryArgs ha; + + /** + * Account the request is about. + */ + struct Account *acc; + + /** + * Payto URI of the account. + */ + char *payto_uri; + + /** + * JSON object we are building to return. + */ + json_t *history; + +}; + + +/** + * Function called to clean up a history context. + * + * @param cls a `struct HistoryContext *` + */ +static void +history_cleanup (void *cls) +{ + struct HistoryContext *hc = cls; + + GNUNET_free (hc->payto_uri); + json_decref (hc->history); + GNUNET_free (hc); +} + + +/** + * Context we keep per get withdrawal operation request. + */ +struct WithdrawContext +{ + /** + * When does this request time out. + */ + struct GNUNET_TIME_Absolute timeout; + + /** + * The withdrawal operation this is about. + */ + struct WithdrawalOperation *wo; + +}; + + +/** + * Function called to clean up a withdraw context. + * + * @param cls a `struct WithdrawContext *` + */ +static void +withdraw_cleanup (void *cls) +{ + struct WithdrawContext *wc = cls; + + GNUNET_free (wc); +} + + /** * Handle for the fake bank. */ @@ -569,13 +711,6 @@ struct TALER_FAKEBANK_Handle }; -/** - * Special address "con_cls" can point to to indicate that the handler has - * been called more than once already (was previously suspended). - */ -static int special_ptr; - - /** * Task run whenever HTTP server operations are pending. * @@ -1583,15 +1718,14 @@ handle_mhd_completion_callback (void *cls, enum MHD_RequestTerminationCode toe) { /* struct TALER_FAKEBANK_Handle *h = cls; */ + struct ConnectionContext *cc = *con_cls; (void) cls; (void) connection; (void) toe; - if (NULL == *con_cls) + if (NULL == cc) return; - if (&special_ptr == *con_cls) - return; - GNUNET_JSON_post_parser_cleanup (*con_cls); - *con_cls = NULL; + cc->ctx_cleaner (cc->ctx); + GNUNET_free (cc); } @@ -1603,7 +1737,7 @@ handle_mhd_completion_callback (void *cls, * @param account account into which to deposit the funds (credit) * @param upload_data request data * @param upload_data_size size of @a upload_data in bytes - * @param con_cls closure for request (a `struct Buffer *`) + * @param con_cls closure for request (a `struct ConnectionContext *`) * @return MHD result code */ static MHD_RESULT @@ -1614,14 +1748,21 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h, size_t *upload_data_size, void **con_cls) { + struct ConnectionContext *cc = *con_cls; enum GNUNET_JSON_PostResult pr; json_t *json; uint64_t row_id; struct GNUNET_TIME_Timestamp timestamp; + if (NULL == cc) + { + cc = GNUNET_new (struct ConnectionContext); + cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup; + *con_cls = cc; + } pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, connection, - con_cls, + &cc->ctx, upload_data, upload_data_size, &json); @@ -1736,7 +1877,7 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h, * @param account account making the transfer * @param upload_data request data * @param upload_data_size size of @a upload_data in bytes - * @param con_cls closure for request (a `struct Buffer *`) + * @param con_cls closure for request (a `struct ConnectionContext *`) * @return MHD result code */ static MHD_RESULT @@ -1747,14 +1888,21 @@ handle_transfer (struct TALER_FAKEBANK_Handle *h, size_t *upload_data_size, void **con_cls) { + struct ConnectionContext *cc = *con_cls; enum GNUNET_JSON_PostResult pr; json_t *json; uint64_t row_id; struct GNUNET_TIME_Timestamp ts; + if (NULL == cc) + { + cc = GNUNET_new (struct ConnectionContext); + cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup; + *con_cls = cc; + } pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, connection, - con_cls, + &cc->ctx, upload_data, upload_data_size, &json); @@ -1895,42 +2043,6 @@ handle_home_page (struct TALER_FAKEBANK_Handle *h, } -/** - * This is the "base" structure for both the /history and the - * /history-range API calls. - */ -struct HistoryArgs -{ - - /** - * Bank account number of the requesting client. - */ - uint64_t account_number; - - /** - * Index of the starting transaction, exclusive (!). - */ - uint64_t start_idx; - - /** - * Requested number of results and order - * (positive: ascending, negative: descending) - */ - int64_t delta; - - /** - * Timeout for long polling. - */ - struct GNUNET_TIME_Relative lp_timeout; - - /** - * true if starting point was given. - */ - bool have_start; - -}; - - /** * Parse URL history arguments, of _both_ APIs: * /history/incoming and /history/outgoing. @@ -2176,7 +2288,7 @@ start_lp (struct TALER_FAKEBANK_Handle *h, * @param h the fakebank handle * @param connection the connection * @param account which account the request is about - * @param con_cls closure for request (NULL or &special_ptr) + * @param con_cls closure for request */ static MHD_RESULT handle_debit_history (struct TALER_FAKEBANK_Handle *h, @@ -2184,87 +2296,106 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, const char *account, void **con_cls) { - struct HistoryArgs ha; - struct Account *acc; + struct ConnectionContext *cc = *con_cls; + struct HistoryContext *hc; struct Transaction *pos; - json_t *history; - char *debit_payto; enum GNUNET_GenericReturnValue ret; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Handling /history/outgoing connection %p\n", - connection); - if (GNUNET_OK != - (ret = parse_history_common_args (h, - connection, - &ha))) + if (NULL == cc) { - GNUNET_break_op (0); - return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; - } - if (&special_ptr == *con_cls) - ha.lp_timeout = GNUNET_TIME_UNIT_ZERO; - acc = lookup_account (h, - account, - NULL); - if (NULL == acc) - { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_BANK_UNKNOWN_ACCOUNT, - account); - } - GNUNET_asprintf (&debit_payto, - "payto://x-taler-bank/localhost/%s?receiver-name=%s", - account, - acc->receiver_name); - history = json_array (); - if (NULL == history) - { - GNUNET_break (0); - GNUNET_free (debit_payto); - return MHD_NO; - } - GNUNET_assert (0 == - pthread_mutex_lock (&h->big_lock)); - if (! ha.have_start) - { - pos = (0 > ha.delta) - ? acc->out_tail - : acc->out_head; + cc = GNUNET_new (struct ConnectionContext); + cc->ctx_cleaner = &history_cleanup; + *con_cls = cc; + hc = GNUNET_new (struct HistoryContext); + cc->ctx = hc; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Handling /history/outgoing connection %p\n", + connection); + if (GNUNET_OK != + (ret = parse_history_common_args (h, + connection, + &hc->ha))) + { + GNUNET_break_op (0); + return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; + } + GNUNET_assert (0 == + pthread_mutex_lock (&h->big_lock)); + hc->acc = lookup_account (h, + account, + NULL); + if (NULL == hc->acc) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_BANK_UNKNOWN_ACCOUNT, + account); + } + GNUNET_asprintf (&hc->payto_uri, + "payto://x-taler-bank/localhost/%s?receiver-name=%s", + account, + hc->acc->receiver_name); + /* New invariant: */ + GNUNET_assert (0 == strcmp (hc->payto_uri, + hc->acc->payto_uri)); + hc->history = json_array (); + if (NULL == hc->history) + { + GNUNET_break (0); + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return MHD_NO; + } + hc->timeout = GNUNET_TIME_relative_to_absolute (hc->ha.lp_timeout); } else { - struct Transaction *t = h->transactions[ha.start_idx % h->ram_limit]; + hc = cc->ctx; + GNUNET_assert (0 == + pthread_mutex_lock (&h->big_lock)); + } + + if (! hc->ha.have_start) + { + pos = (0 > hc->ha.delta) + ? hc->acc->out_tail + : hc->acc->out_head; + } + else + { + struct Transaction *t = h->transactions[hc->ha.start_idx % h->ram_limit]; bool overflow; uint64_t dir; bool skip = true; - dir = (0 > ha.delta) ? (h->ram_limit - 1) : 1; - overflow = (t->row_id != ha.start_idx); + dir = (0 > hc->ha.delta) ? (h->ram_limit - 1) : 1; + overflow = (t->row_id != hc->ha.start_idx); /* If account does not match, linear scan for first matching account. */ while ( (! overflow) && - (NULL != t) && - (t->debit_account != acc) ) + (NULL != t) && + (t->debit_account != hc->acc) ) { skip = false; t = h->transactions[(t->row_id + dir) % h->ram_limit]; if ( (NULL != t) && - (t->row_id == ha.start_idx) ) + (t->row_id == hc->ha.start_idx) ) overflow = true; /* full circle, give up! */ } if ( (NULL == t) || overflow) { - if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) && - (0 < ha.delta)) + /* FIXME: these conditions are unclear to me. */ + if ( (GNUNET_TIME_relative_is_zero (hc->ha.lp_timeout)) && + (0 < hc->ha.delta)) { GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); if (overflow) { - GNUNET_free (debit_payto); return TALER_MHD_reply_with_ec ( connection, TALER_EC_BANK_ANCIENT_TRANSACTION_GONE, @@ -2272,35 +2403,36 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, } goto finish; } - *con_cls = &special_ptr; + if (h->in_shutdown) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + goto finish; + } start_lp (h, connection, - acc, - ha.lp_timeout, + hc->acc, + GNUNET_TIME_absolute_get_remaining (hc->timeout), LP_DEBIT, NULL); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); - json_decref (history); - GNUNET_free (debit_payto); return MHD_YES; } - if (t->debit_account != acc) + if (t->debit_account != hc->acc) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid start specified, transaction %llu not with account %s!\n", - (unsigned long long) ha.start_idx, + (unsigned long long) hc->ha.start_idx, account); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); - GNUNET_free (debit_payto); - json_decref (history); return MHD_NO; } if (skip) { /* range is exclusive, skip the matching entry */ - if (0 > ha.delta) + if (0 > hc->ha.delta) pos = t->prev_out; else pos = t->next_out; @@ -2313,9 +2445,9 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, if (NULL != pos) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Returning %lld debit transactions starting (inclusive) from %llu\n", - (long long) ha.delta, + (long long) hc->ha.delta, (unsigned long long) pos->row_id); - while ( (0 != ha.delta) && + while ( (0 != hc->ha.delta) && (NULL != pos) ) { json_t *trans; @@ -2327,9 +2459,9 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, "Unexpected CREDIT transaction #%llu for account `%s'\n", (unsigned long long) pos->row_id, account); - if (0 > ha.delta) + if (0 > hc->ha.delta) pos = pos->prev_in; - if (0 < ha.delta) + if (0 < hc->ha.delta) pos = pos->next_in; continue; } @@ -2348,7 +2480,7 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, GNUNET_JSON_pack_string ("credit_account", credit_payto), GNUNET_JSON_pack_string ("debit_account", - debit_payto), // FIXME #7275: inefficient to return this here always! + hc->payto_uri), // FIXME #7275: inefficient to return this here always! GNUNET_JSON_pack_string ("exchange_base_url", pos->subject.debit.exchange_base_url), GNUNET_JSON_pack_data_auto ("wtid", @@ -2356,51 +2488,55 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h, GNUNET_assert (NULL != trans); GNUNET_free (credit_payto); GNUNET_assert (0 == - json_array_append_new (history, + json_array_append_new (hc->history, trans)); - if (ha.delta > 0) - ha.delta--; + if (hc->ha.delta > 0) + hc->ha.delta--; else - ha.delta++; - if (0 > ha.delta) + hc->ha.delta++; + if (0 > hc->ha.delta) pos = pos->prev_out; - if (0 < ha.delta) + if (0 < hc->ha.delta) pos = pos->next_out; } - if ( (0 == json_array_size (history)) && - (! GNUNET_TIME_relative_is_zero (ha.lp_timeout)) && - (0 < ha.delta)) + if ( (0 == json_array_size (hc->history)) && + (! h->in_shutdown) && + (GNUNET_TIME_absolute_is_future (hc->timeout)) && + (0 < hc->ha.delta)) { - *con_cls = &special_ptr; start_lp (h, connection, - acc, - ha.lp_timeout, + hc->acc, + GNUNET_TIME_absolute_get_remaining (hc->timeout), LP_DEBIT, NULL); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); - json_decref (history); return MHD_YES; } GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); finish: - if (0 == json_array_size (history)) + if (0 == json_array_size (hc->history)) { - json_decref (history); + GNUNET_break (h->in_shutdown || + (! GNUNET_TIME_absolute_is_future (hc->timeout))); return TALER_MHD_reply_static (connection, MHD_HTTP_NO_CONTENT, NULL, NULL, 0); } - GNUNET_free (debit_payto); - return TALER_MHD_REPLY_JSON_PACK (connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_array_steal ( - "outgoing_transactions", - history)); + { + json_t *h = hc->history; + + hc->history = NULL; + return TALER_MHD_REPLY_JSON_PACK (connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_array_steal ( + "outgoing_transactions", + h)); + } } @@ -2419,77 +2555,101 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, const char *account, void **con_cls) { - struct HistoryArgs ha; - struct Account *acc; + struct ConnectionContext *cc = *con_cls; + struct HistoryContext *hc; const struct Transaction *pos; - json_t *history; - const char *credit_payto; enum GNUNET_GenericReturnValue ret; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Handling /history/incoming connection %p (%d)\n", - connection, - (*con_cls == &special_ptr)); - if (GNUNET_OK != - (ret = parse_history_common_args (h, - connection, - &ha))) + if (NULL == cc) { - GNUNET_break_op (0); - return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; - } - if (&special_ptr == *con_cls) - ha.lp_timeout = GNUNET_TIME_UNIT_ZERO; - *con_cls = &special_ptr; - acc = lookup_account (h, - account, - NULL); - if (NULL == acc) - { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_BANK_UNKNOWN_ACCOUNT, - account); - } - history = json_array (); - GNUNET_assert (NULL != history); - credit_payto = acc->payto_uri; - GNUNET_assert (0 == - pthread_mutex_lock (&h->big_lock)); - if (! ha.have_start) - { - pos = (0 > ha.delta) - ? acc->in_tail - : acc->in_head; + cc = GNUNET_new (struct ConnectionContext); + cc->ctx_cleaner = &history_cleanup; + *con_cls = cc; + hc = GNUNET_new (struct HistoryContext); + cc->ctx = hc; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Handling /history/incoming connection %p\n", + connection); + if (GNUNET_OK != + (ret = parse_history_common_args (h, + connection, + &hc->ha))) + { + GNUNET_break_op (0); + return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; + } + GNUNET_assert (0 == + pthread_mutex_lock (&h->big_lock)); + hc->acc = lookup_account (h, + account, + NULL); + if (NULL == hc->acc) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_BANK_UNKNOWN_ACCOUNT, + account); + } + /* FIXME: was simply: acc->payto_uri -- same!? */ + GNUNET_asprintf (&hc->payto_uri, + "payto://x-taler-bank/localhost/%s?receiver-name=%s", + account, + hc->acc->receiver_name); + GNUNET_assert (0 == strcmp (hc->payto_uri, + hc->acc->payto_uri)); + hc->history = json_array (); + if (NULL == hc->history) + { + GNUNET_break (0); + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return MHD_NO; + } + hc->timeout = GNUNET_TIME_relative_to_absolute (hc->ha.lp_timeout); } else { - struct Transaction *t = h->transactions[ha.start_idx % h->ram_limit]; + hc = cc->ctx; + GNUNET_assert (0 == + pthread_mutex_lock (&h->big_lock)); + } + + if (! hc->ha.have_start) + { + pos = (0 > hc->ha.delta) + ? hc->acc->in_tail + : hc->acc->in_head; + } + else + { + struct Transaction *t = h->transactions[hc->ha.start_idx % h->ram_limit]; bool overflow; uint64_t dir; bool skip = true; - overflow = ( (NULL != t) && (t->row_id != ha.start_idx) ); - dir = (0 > ha.delta) ? (h->ram_limit - 1) : 1; + overflow = ( (NULL != t) && (t->row_id != hc->ha.start_idx) ); + dir = (0 > hc->ha.delta) ? (h->ram_limit - 1) : 1; /* If account does not match, linear scan for first matching account. */ while ( (! overflow) && (NULL != t) && - (t->credit_account != acc) ) + (t->credit_account != hc->acc) ) { skip = false; t = h->transactions[(t->row_id + dir) % h->ram_limit]; if ( (NULL != t) && - (t->row_id == ha.start_idx) ) + (t->row_id == hc->ha.start_idx) ) overflow = true; /* full circle, give up! */ } if ( (NULL == t) || overflow) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "No transactions available, suspending request\n"); - if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) && - (0 < ha.delta)) + /* FIXME: these conditions are unclear to me. */ + if (GNUNET_TIME_relative_is_zero (hc->ha.lp_timeout) && + (0 < hc->ha.delta)) { GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); @@ -2500,23 +2660,27 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, NULL); goto finish; } - *con_cls = &special_ptr; + if (h->in_shutdown) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + goto finish; + } start_lp (h, connection, - acc, - ha.lp_timeout, + hc->acc, + GNUNET_TIME_absolute_get_remaining (hc->timeout), LP_CREDIT, NULL); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); - json_decref (history); return MHD_YES; } if (skip) { /* range from application is exclusive, skip the matching entry */ - if (0 > ha.delta) + if (0 > hc->ha.delta) pos = t->prev_in; else pos = t->next_in; @@ -2529,9 +2693,9 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, if (NULL != pos) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Returning %lld credit transactions starting (inclusive) from %llu\n", - (long long) ha.delta, + (long long) hc->ha.delta, (unsigned long long) pos->row_id); - while ( (0 != ha.delta) && + while ( (0 != hc->ha.delta) && (NULL != pos) ) { json_t *trans; @@ -2542,9 +2706,9 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, "Unexpected DEBIT transaction #%llu for account `%s'\n", (unsigned long long) pos->row_id, account); - if (0 > ha.delta) + if (0 > hc->ha.delta) pos = pos->prev_in; - if (0 < ha.delta) + if (0 < hc->ha.delta) pos = pos->next_in; continue; } @@ -2556,57 +2720,62 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h, TALER_JSON_pack_amount ("amount", &pos->amount), GNUNET_JSON_pack_string ("credit_account", - credit_payto), // FIXME #7275: inefficient to repeat this always here! + hc->payto_uri), // FIXME #7275: inefficient to repeat this always here! GNUNET_JSON_pack_string ("debit_account", pos->debit_account->payto_uri), GNUNET_JSON_pack_data_auto ("reserve_pub", &pos->subject.credit.reserve_pub)); GNUNET_assert (NULL != trans); GNUNET_assert (0 == - json_array_append_new (history, + json_array_append_new (hc->history, trans)); - if (ha.delta > 0) - ha.delta--; + if (hc->ha.delta > 0) + hc->ha.delta--; else - ha.delta++; - if (0 > ha.delta) + hc->ha.delta++; + if (0 > hc->ha.delta) pos = pos->prev_in; - if (0 < ha.delta) + if (0 < hc->ha.delta) pos = pos->next_in; } - if ( (0 == json_array_size (history)) && - (! GNUNET_TIME_relative_is_zero (ha.lp_timeout)) && - (0 < ha.delta)) + if ( (0 == json_array_size (hc->history)) && + (! h->in_shutdown) && + (GNUNET_TIME_absolute_is_future (hc->timeout)) && + (0 < hc->ha.delta)) { - *con_cls = &special_ptr; start_lp (h, connection, - acc, - ha.lp_timeout, + hc->acc, + GNUNET_TIME_absolute_get_remaining (hc->timeout), LP_CREDIT, NULL); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); - json_decref (history); return MHD_YES; } GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); finish: - if (0 == json_array_size (history)) + if (0 == json_array_size (hc->history)) { - json_decref (history); + GNUNET_break (h->in_shutdown || + (! GNUNET_TIME_absolute_is_future (hc->timeout))); return TALER_MHD_reply_static (connection, MHD_HTTP_NO_CONTENT, NULL, NULL, 0); } - return TALER_MHD_REPLY_JSON_PACK (connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_array_steal ( - "incoming_transactions", - history)); + { + json_t *h = hc->history; + + hc->history = NULL; + return TALER_MHD_REPLY_JSON_PACK (connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_array_steal ( + "incoming_transactions", + h)); + } } @@ -2711,25 +2880,39 @@ get_withdrawal_operation (struct TALER_FAKEBANK_Handle *h, struct GNUNET_TIME_Relative lp, void **con_cls) { - struct WithdrawalOperation *wo; + struct ConnectionContext *cc = *con_cls; + struct WithdrawContext *wc; GNUNET_assert (0 == pthread_mutex_lock (&h->big_lock)); - wo = lookup_withdrawal_operation (h, - wopid); - if (NULL == wo) + if (NULL == cc) { - GNUNET_assert (0 == - pthread_mutex_unlock (&h->big_lock)); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_BANK_TRANSACTION_NOT_FOUND, - wopid); + cc = GNUNET_new (struct ConnectionContext); + cc->ctx_cleaner = &withdraw_cleanup; + *con_cls = cc; + wc = GNUNET_new (struct WithdrawContext); + cc->ctx = wc; + wc->wo = lookup_withdrawal_operation (h, + wopid); + if (NULL == wc->wo) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_BANK_TRANSACTION_NOT_FOUND, + wopid); + } + wc->timeout = GNUNET_TIME_relative_to_absolute (lp); } - if ( (NULL != *con_cls) || - (GNUNET_TIME_relative_is_zero (lp)) || - wo->confirmation_done || - wo->aborted) + else + { + wc = cc->ctx; + } + if (GNUNET_TIME_absolute_is_past (wc->timeout) || + h->in_shutdown || + wc->wo->confirmation_done || + wc->wo->aborted) { json_t *wt; @@ -2744,27 +2927,26 @@ get_withdrawal_operation (struct TALER_FAKEBANK_Handle *h, connection, MHD_HTTP_OK, GNUNET_JSON_pack_bool ("aborted", - wo->aborted), + wc->wo->aborted), GNUNET_JSON_pack_bool ("selection_done", - wo->selection_done), + wc->wo->selection_done), GNUNET_JSON_pack_bool ("transfer_done", - wo->confirmation_done), + wc->wo->confirmation_done), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_string ("suggested_exchange", h->exchange_url)), TALER_JSON_pack_amount ("amount", - &wo->amount), + &wc->wo->amount), GNUNET_JSON_pack_array_steal ("wire_types", wt)); } - *con_cls = &special_ptr; start_lp (h, connection, - wo->debit_account, - lp, + wc->wo->debit_account, + GNUNET_TIME_absolute_get_remaining (wc->timeout), LP_WITHDRAW, - wo); + wc->wo); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); return MHD_YES; @@ -2903,13 +3085,20 @@ post_withdrawal_operation (struct TALER_FAKEBANK_Handle *h, size_t *upload_data_size, void **con_cls) { + struct ConnectionContext *cc = *con_cls; enum GNUNET_JSON_PostResult pr; json_t *json; MHD_RESULT res; + if (NULL == cc) + { + cc = GNUNET_new (struct ConnectionContext); + cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup; + *con_cls = cc; + } pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, connection, - con_cls, + &cc->ctx, upload_data, upload_data_size, &json); @@ -3294,13 +3483,20 @@ post_account_withdrawals_access (struct TALER_FAKEBANK_Handle *h, size_t *upload_data_size, void **con_cls) { + struct ConnectionContext *cc = *con_cls; enum GNUNET_JSON_PostResult pr; json_t *json; MHD_RESULT res; + if (NULL == cc) + { + cc = GNUNET_new (struct ConnectionContext); + cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup; + *con_cls = cc; + } pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, connection, - con_cls, + &cc->ctx, upload_data, upload_data_size, &json); @@ -3367,13 +3563,20 @@ post_testing_register (struct TALER_FAKEBANK_Handle *h, size_t *upload_data_size, void **con_cls) { + struct ConnectionContext *cc = *con_cls; enum GNUNET_JSON_PostResult pr; json_t *json; MHD_RESULT res; + if (NULL == cc) + { + cc = GNUNET_new (struct ConnectionContext); + cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup; + *con_cls = cc; + } pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, connection, - con_cls, + &cc->ctx, upload_data, upload_data_size, &json); diff --git a/src/exchange/taler-exchange-wirewatch.c b/src/exchange/taler-exchange-wirewatch.c index 2bffc3b85..235c0153f 100644 --- a/src/exchange/taler-exchange-wirewatch.c +++ b/src/exchange/taler-exchange-wirewatch.c @@ -57,6 +57,12 @@ static struct TALER_BANK_CreditHistoryHandle *hh; */ static bool hh_returned_data; +/** + * Set to true if the request for history did not + * succeed because the account was unknown. + */ +static bool hh_account_404; + /** * When did we start the last @e hh request? */ @@ -472,9 +478,9 @@ transaction_completed (void) GNUNET_SCHEDULER_shutdown (); return; } - if (! hh_returned_data) + if (! (hh_returned_data || hh_account_404) ) { - /* Enforce long polling delay even if the server ignored it + /* Enforce long-polling delay even if the server ignored it and returned earlier */ struct GNUNET_TIME_Relative latency; struct GNUNET_TIME_Relative left; @@ -482,12 +488,17 @@ transaction_completed (void) latency = GNUNET_TIME_absolute_get_duration (hh_start_time); left = GNUNET_TIME_relative_subtract (longpoll_timeout, latency); -#if 1 - left = GNUNET_TIME_relative_min (left, - GNUNET_TIME_UNIT_SECONDS); -#endif + if (! (test_mode || + GNUNET_TIME_relative_is_zero (left)) ) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, // WARNING, + "Server did not respect long-polling, enforcing client-side by sleeping for %s\n", + GNUNET_TIME_relative2s (left, + true)); delayed_until = GNUNET_TIME_relative_to_absolute (left); } + if (hh_account_404) + delayed_until = GNUNET_TIME_relative_to_absolute ( + GNUNET_TIME_UNIT_MILLISECONDS); if (test_mode) delayed_until = GNUNET_TIME_UNIT_ZERO_ABS; GNUNET_assert (NULL == task); @@ -713,7 +724,7 @@ history_cb (void *cls, } GNUNET_assert (NULL == task); hh = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "History request returned with HTTP status %u\n", reply->http_status); switch (reply->http_status) @@ -727,6 +738,7 @@ history_cb (void *cls, transaction_completed (); return; case MHD_HTTP_NOT_FOUND: + hh_account_404 = true; if (ignore_account_404) { transaction_completed (); @@ -765,6 +777,7 @@ continue_with_shard (void *cls) (unsigned long long) latest_row_off); hh_start_time = GNUNET_TIME_absolute_get (); hh_returned_data = false; + hh_account_404 = false; hh = TALER_BANK_credit_history (ctx, ai->auth, latest_row_off, @@ -862,6 +875,13 @@ lock_shard (void *cls) GNUNET_STRINGS_relative_time_to_string (rdelay, true)); #if 1 + if (GNUNET_TIME_relative_cmp (rdelay, + >, + GNUNET_TIME_UNIT_SECONDS)) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Delay would have been for %s\n", + GNUNET_TIME_relative2s (rdelay, + true)); rdelay = GNUNET_TIME_relative_min (rdelay, GNUNET_TIME_UNIT_SECONDS); #endif From acbee86745552a9b6361a8969d3c0a9d0399fc88 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 22 Apr 2023 15:02:47 +0200 Subject: [PATCH 12/12] simplify batch insert: no cursor where not required, replace out_reserve_found with ruuid being allowed to remain NULL --- .../exchange_do_reserves_in_insert.sql | 119 +++--------------- src/exchangedb/pg_reserves_in_insert.c | 31 ++--- 2 files changed, 25 insertions(+), 125 deletions(-) diff --git a/src/exchangedb/exchange_do_reserves_in_insert.sql b/src/exchangedb/exchange_do_reserves_in_insert.sql index 6cd5847df..dffcd8b55 100644 --- a/src/exchangedb/exchange_do_reserves_in_insert.sql +++ b/src/exchangedb/exchange_do_reserves_in_insert.sql @@ -26,21 +26,11 @@ CREATE OR REPLACE FUNCTION exchange_do_batch_reserves_in_insert( IN in_wire_source_h_payto BYTEA, IN in_payto_uri VARCHAR, IN in_notify TEXT, - OUT out_reserve_found0 BOOLEAN, OUT transaction_duplicate0 BOOLEAN, OUT ruuid0 INT8) LANGUAGE plpgsql AS $$ -DECLARE - curs REFCURSOR; -DECLARE - i RECORD; -DECLARE - curs_trans REFCURSOR; BEGIN - ruuid0 = 0; - out_reserve_found0 = TRUE; - transaction_duplicate0 = TRUE; INSERT INTO wire_targets (wire_target_h_payto @@ -50,35 +40,22 @@ BEGIN ,in_payto_uri) ON CONFLICT DO NOTHING; - OPEN curs FOR - WITH reserve_changes AS ( - INSERT INTO reserves - (reserve_pub - ,current_balance_val - ,current_balance_frac - ,expiration_date - ,gc_date) - VALUES - (in_reserve_pub - ,in_credit_val - ,in_credit_frac - ,in_reserve_expiration - ,in_gc_date) - ON CONFLICT DO NOTHING - RETURNING reserve_uuid, reserve_pub) - SELECT reserve_uuid, reserve_pub FROM reserve_changes; + INSERT INTO reserves + (reserve_pub + ,current_balance_val + ,current_balance_frac + ,expiration_date + ,gc_date) + VALUES + (in_reserve_pub + ,in_credit_val + ,in_credit_frac + ,in_reserve_expiration + ,in_gc_date) + ON CONFLICT DO NOTHING + RETURNING reserve_uuid + INTO ruuid0; - FETCH FROM curs INTO i; - IF FOUND - THEN - -- We made a change, so the reserve did not previously exist. - out_reserve_found0 = FALSE; - ruuid0 = i.reserve_uuid; - END IF; - CLOSE curs; - - OPEN curs_trans FOR - WITH reserve_transaction AS( INSERT INTO reserves_in (reserve_pub ,wire_reference @@ -95,21 +72,15 @@ BEGIN ,in_exchange_account_name ,in_wire_source_h_payto ,in_execution_date) - ON CONFLICT DO NOTHING - RETURNING reserve_pub) - SELECT reserve_pub FROM reserve_transaction; + ON CONFLICT DO NOTHING; - FETCH FROM curs_trans INTO i; + transaction_duplicate0 = NOT FOUND; IF FOUND THEN - transaction_duplicate0 = FALSE; EXECUTE FORMAT ( 'NOTIFY %s' ,in_notify); END IF; - - CLOSE curs_trans; - RETURN; END $$; @@ -135,8 +106,6 @@ CREATE OR REPLACE FUNCTION exchange_do_batch2_reserves_insert( IN in1_wire_source_h_payto BYTEA, IN in1_payto_uri VARCHAR, IN in1_notify TEXT, - OUT out_reserve_found0 BOOLEAN, - OUT out_reserve_found1 BOOLEAN, OUT transaction_duplicate0 BOOLEAN, OUT transaction_duplicate1 BOOLEAN, OUT ruuid0 INT8, @@ -154,10 +123,6 @@ DECLARE BEGIN transaction_duplicate0 = TRUE; transaction_duplicate1 = TRUE; - out_reserve_found0 = TRUE; - out_reserve_found1 = TRUE; - ruuid0=0; - ruuid1=0; INSERT INTO wire_targets (wire_target_h_payto @@ -207,7 +172,6 @@ BEGIN IF in0_reserve_pub = i.reserve_pub THEN ruuid0 = i.reserve_uuid; - out_reserve_found0 = FALSE; CONTINUE loop_reserve; END IF; CONTINUE loop_k; @@ -215,7 +179,6 @@ BEGIN IF in1_reserve_pub = i.reserve_pub THEN ruuid1 = i.reserve_uuid; - out_reserve_found1 = FALSE; END IF; EXIT loop_reserve; END CASE; @@ -332,10 +295,6 @@ CREATE OR REPLACE FUNCTION exchange_do_batch4_reserves_insert( IN in3_wire_source_h_payto BYTEA, IN in3_payto_uri VARCHAR, IN in3_notify TEXT, - OUT out_reserve_found0 BOOLEAN, - OUT out_reserve_found1 BOOLEAN, - OUT out_reserve_found2 BOOLEAN, - OUT out_reserve_found3 BOOLEAN, OUT transaction_duplicate0 BOOLEAN, OUT transaction_duplicate1 BOOLEAN, OUT transaction_duplicate2 BOOLEAN, @@ -359,14 +318,6 @@ BEGIN transaction_duplicate1=TRUE; transaction_duplicate2=TRUE; transaction_duplicate3=TRUE; - out_reserve_found0 = TRUE; - out_reserve_found1 = TRUE; - out_reserve_found2 = TRUE; - out_reserve_found3 = TRUE; - ruuid0=0; - ruuid1=0; - ruuid2=0; - ruuid3=0; INSERT INTO wire_targets (wire_target_h_payto @@ -430,7 +381,6 @@ BEGIN IF in0_reserve_pub = i.reserve_pub THEN ruuid0 = i.reserve_uuid; - out_reserve_found0 = FALSE; CONTINUE loop_reserve; END IF; CONTINUE loop_k; @@ -439,7 +389,6 @@ BEGIN IF in1_reserve_pub = i.reserve_pub THEN ruuid1 = i.reserve_uuid; - out_reserve_found1 = FALSE; CONTINUE loop_reserve; END IF; CONTINUE loop_k; @@ -448,7 +397,6 @@ BEGIN IF in2_reserve_pub = i.reserve_pub THEN ruuid2 = i.reserve_uuid; - out_reserve_found2 = FALSE; CONTINUE loop_reserve; END IF; CONTINUE loop_k; @@ -456,7 +404,6 @@ BEGIN IF in3_reserve_pub = i.reserve_pub THEN ruuid3 = i.reserve_uuid; - out_reserve_found3 = FALSE; END IF; EXIT loop_reserve; END CASE; @@ -645,14 +592,6 @@ CREATE OR REPLACE FUNCTION exchange_do_batch8_reserves_insert( IN in7_wire_source_h_payto BYTEA, IN in7_payto_uri VARCHAR, IN in7_notify TEXT, - OUT out_reserve_found0 BOOLEAN, - OUT out_reserve_found1 BOOLEAN, - OUT out_reserve_found2 BOOLEAN, - OUT out_reserve_found3 BOOLEAN, - OUT out_reserve_found4 BOOLEAN, - OUT out_reserve_found5 BOOLEAN, - OUT out_reserve_found6 BOOLEAN, - OUT out_reserve_found7 BOOLEAN, OUT transaction_duplicate0 BOOLEAN, OUT transaction_duplicate1 BOOLEAN, OUT transaction_duplicate2 BOOLEAN, @@ -691,22 +630,6 @@ BEGIN transaction_duplicate5=TRUE; transaction_duplicate6=TRUE; transaction_duplicate7=TRUE; - out_reserve_found0 = TRUE; - out_reserve_found1 = TRUE; - out_reserve_found2 = TRUE; - out_reserve_found3 = TRUE; - out_reserve_found4 = TRUE; - out_reserve_found5 = TRUE; - out_reserve_found6 = TRUE; - out_reserve_found7 = TRUE; - ruuid0=0; - ruuid1=0; - ruuid2=0; - ruuid3=0; - ruuid4=0; - ruuid5=0; - ruuid6=0; - ruuid7=0; INSERT INTO wire_targets (wire_target_h_payto @@ -803,7 +726,6 @@ BEGIN IF in0_reserve_pub = i.reserve_pub THEN ruuid0 = i.reserve_uuid; - out_reserve_found0 = FALSE; CONTINUE loop_reserve; END IF; CONTINUE loop_k; @@ -812,7 +734,6 @@ BEGIN IF in1_reserve_pub = i.reserve_pub THEN ruuid1 = i.reserve_uuid; - out_reserve_found1 = FALSE; CONTINUE loop_reserve; END IF; CONTINUE loop_k; @@ -821,7 +742,6 @@ BEGIN IF in2_reserve_pub = i.reserve_pub THEN ruuid2 = i.reserve_uuid; - out_reserve_found2 = FALSE; CONTINUE loop_reserve; END IF; CONTINUE loop_k; @@ -830,7 +750,6 @@ BEGIN IF in3_reserve_pub = i.reserve_pub THEN ruuid3 = i.reserve_uuid; - out_reserve_found3 = FALSE; CONTINUE loop_reserve; END IF; CONTINUE loop_k; @@ -839,7 +758,6 @@ BEGIN IF in4_reserve_pub = i.reserve_pub THEN ruuid4 = i.reserve_uuid; - out_reserve_found4 = FALSE; CONTINUE loop_reserve; END IF; CONTINUE loop_k; @@ -848,7 +766,6 @@ BEGIN IF in5_reserve_pub = i.reserve_pub THEN ruuid5 = i.reserve_uuid; - out_reserve_found5 = FALSE; CONTINUE loop_reserve; END IF; CONTINUE loop_k; @@ -857,7 +774,6 @@ BEGIN IF in6_reserve_pub = i.reserve_pub THEN ruuid6 = i.reserve_uuid; - out_reserve_found6 = FALSE; CONTINUE loop_reserve; END IF; CONTINUE loop_k; @@ -865,7 +781,6 @@ BEGIN IF in7_reserve_pub = i.reserve_pub THEN ruuid7 = i.reserve_uuid; - out_reserve_found7 = FALSE; END IF; EXIT loop_reserve; END CASE; diff --git a/src/exchangedb/pg_reserves_in_insert.c b/src/exchangedb/pg_reserves_in_insert.c index 2e29a1857..691c57d38 100644 --- a/src/exchangedb/pg_reserves_in_insert.c +++ b/src/exchangedb/pg_reserves_in_insert.c @@ -113,12 +113,12 @@ struct ReserveRecord * index @a index */ #define RR_RESULT_PARAM(rr,index) \ - GNUNET_PQ_result_spec_bool ("conflicted" TALER_S (index), \ - &rr[index].conflicts), \ GNUNET_PQ_result_spec_bool ("transaction_duplicate" TALER_S (index), \ &rr[index].transaction_duplicate), \ - GNUNET_PQ_result_spec_uint64 ("reserve_uuid" TALER_S (index), \ - &rr[index].reserve_uuid) + GNUNET_PQ_result_spec_allow_null ( \ + GNUNET_PQ_result_spec_uint64 ("reserve_uuid" TALER_S (index), \ + &rr[index].reserve_uuid), \ + &rr[index].conflicts) /** @@ -151,8 +151,7 @@ insert1 (struct PostgresClosure *pg, PREPARE (pg, "batch1_reserve_create", "SELECT " - " out_reserve_found0 AS conflicted0" - ",transaction_duplicate0 AS transaction_duplicate0" + " transaction_duplicate0 AS transaction_duplicate0" ",ruuid0 AS reserve_uuid0" " FROM exchange_do_batch_reserves_in_insert" " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);"); @@ -210,9 +209,7 @@ insert2 (struct PostgresClosure *pg, PREPARE (pg, "batch2_reserve_create", "SELECT" - " out_reserve_found0 AS conflicted0" - ",out_reserve_found1 AS conflicted1" - ",transaction_duplicate0" + " transaction_duplicate0" ",transaction_duplicate1" ",ruuid0 AS reserve_uuid0" ",ruuid1 AS reserve_uuid1" @@ -279,11 +276,7 @@ insert4 (struct PostgresClosure *pg, PREPARE (pg, "batch4_reserve_create", "SELECT" - " out_reserve_found0 AS conflicted0" - ",out_reserve_found1 AS conflicted1" - ",out_reserve_found2 AS conflicted2" - ",out_reserve_found3 AS conflicted3" - ",transaction_duplicate0" + " transaction_duplicate0" ",transaction_duplicate1" ",transaction_duplicate2" ",transaction_duplicate3" @@ -363,15 +356,7 @@ insert8 (struct PostgresClosure *pg, PREPARE (pg, "batch8_reserve_create", "SELECT" - " out_reserve_found0 AS conflicted0" - ",out_reserve_found1 AS conflicted1" - ",out_reserve_found2 AS conflicted2" - ",out_reserve_found3 AS conflicted3" - ",out_reserve_found4 AS conflicted4" - ",out_reserve_found5 AS conflicted5" - ",out_reserve_found6 AS conflicted6" - ",out_reserve_found7 AS conflicted7" - ",transaction_duplicate0" + " transaction_duplicate0" ",transaction_duplicate1" ",transaction_duplicate2" ",transaction_duplicate3"