exchangedb: use partial index instead of materialized tables deposits_by_ready and deposits_by_matching; remove now broken code; rename benchmarks to use perf_-prefix and correspond to function they benchmark

This commit is contained in:
Christian Grothoff 2023-02-05 19:11:47 +01:00
parent e66087987f
commit ab03ba16e9
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
22 changed files with 1508 additions and 3501 deletions

View File

@ -491,389 +491,6 @@ transaction_completed (void)
}
/**
* We got incoming transaction details from the bank. Add them
* to the database.
*
* @param details array of transaction details
* @param details_length length of the @a details array
*/
static void
process_reply (const struct TALER_BANK_CreditDetails *details,
unsigned int details_length)
{
enum GNUNET_DB_QueryStatus qs;
bool shard_done;
uint64_t lroff = latest_row_off;
if (0 == details_length)
{
/* Server should have used 204, not 200! */
GNUNET_break_op (0);
transaction_completed ();
return;
}
hh_returned_data = true;
/* check serial IDs for range constraints */
for (unsigned int i = 0; i<details_length; i++)
{
const struct TALER_BANK_CreditDetails *cd = &details[i];
if (cd->serial_id < lroff)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Serial ID %llu not monotonic (got %llu before). Failing!\n",
(unsigned long long) cd->serial_id,
(unsigned long long) lroff);
db_plugin->rollback (db_plugin->cls);
GNUNET_SCHEDULER_shutdown ();
return;
}
if (cd->serial_id > shard_end)
{
/* we are *past* the current shard (likely because the serial_id of the
shard_end happens to not exist in the DB). So commit and stop this
iteration! */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Serial ID %llu past shard end at %llu, ending iteration early!\n",
(unsigned long long) cd->serial_id,
(unsigned long long) shard_end);
details_length = i;
progress = true;
lroff = cd->serial_id - 1;
break;
}
lroff = cd->serial_id;
}
if (GNUNET_OK !=
db_plugin->start_read_committed (db_plugin->cls,
"wirewatch check for incoming wire transfers"))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to start database transaction!\n");
global_ret = EXIT_FAILURE;
GNUNET_SCHEDULER_shutdown ();
return;
}
started_transaction = true;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Importing %u transactions\n",
details_length);
for (unsigned int i = 0; i<details_length; i++)
{
const struct TALER_BANK_CreditDetails *cd = &details[i];
/* FIXME #7276: Consider using Postgres multi-valued insert here,
for up to 15x speed-up according to
https://dba.stackexchange.com/questions/224989/multi-row-insert-vs-transactional-single-row-inserts#225006
(Note: this may require changing both the
plugin API as well as modifying how this function is called.) */
qs = db_plugin->reserves_in_insert (db_plugin->cls,
&cd->reserve_pub,
&cd->amount,
cd->execution_date,
cd->debit_account_uri,
ai->section_name,
cd->serial_id);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
GNUNET_break (0);
GNUNET_SCHEDULER_shutdown ();
return;
case GNUNET_DB_STATUS_SOFT_ERROR:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got DB soft error for reserves_in_insert. Rolling back.\n");
handle_soft_error ();
return;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
/* Either wirewatch was freshly started after the system was
shutdown and we're going over an incomplete shard again
after being restarted, or the shard lock period was too
short (number of workers set incorrectly?) and a 2nd
wirewatcher has been stealing our work while we are still
at it. */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Attempted to import transaction %llu (%s) twice. "
"This should happen rarely (if not, ask for support).\n",
(unsigned long long) cd->serial_id,
job_name);
break;
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Imported transaction %llu.",
(unsigned long long) cd->serial_id);
/* normal case */
progress = true;
break;
}
}
latest_row_off = lroff;
shard_done = (shard_end <= latest_row_off);
if (shard_done)
{
/* shard is complete, mark this as well */
qs = db_plugin->complete_shard (db_plugin->cls,
job_name,
shard_start,
shard_end);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
GNUNET_break (0);
GNUNET_SCHEDULER_shutdown ();
return;
case GNUNET_DB_STATUS_SOFT_ERROR:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got DB soft error for complete_shard. Rolling back.\n");
handle_soft_error ();
return;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
GNUNET_break (0);
/* Not expected, but let's just continue */
break;
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
/* normal case */
progress = true;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Completed shard %s (%llu,%llu] after %s\n",
job_name,
(unsigned long long) shard_start,
(unsigned long long) shard_end,
GNUNET_STRINGS_relative_time_to_string (
GNUNET_TIME_absolute_get_duration (shard_start_time),
true));
break;
}
}
if (! progress)
{
db_plugin->rollback (db_plugin->cls);
}
else
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Committing %s progress (%llu,%llu] at %llu\n (%s)",
job_name,
(unsigned long long) shard_start,
(unsigned long long) shard_end,
(unsigned long long) latest_row_off,
shard_done
? "shard done"
: "shard incomplete");
qs = db_plugin->commit (db_plugin->cls);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
GNUNET_break (0);
GNUNET_SCHEDULER_shutdown ();
return;
case GNUNET_DB_STATUS_SOFT_ERROR:
/* reduce transaction size to reduce rollback probability */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got DB soft error on commit. Reducing transaction size.\n");
handle_soft_error ();
return;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
started_transaction = false;
/* normal case */
break;
}
}
if (shard_done)
{
shard_delay = GNUNET_TIME_absolute_get_duration (shard_start_time);
shard_open = false;
transaction_completed ();
return;
}
GNUNET_assert (NULL == task);
task = GNUNET_SCHEDULER_add_now (&continue_with_shard,
NULL);
}
/**
* We got incoming transaction details from the bank. Add them
* to the database.
*
* @param details array of transaction details
* @param details_length length of the @a details array
*/
static void
process_reply_batched (const struct TALER_BANK_CreditDetails *details,
unsigned int details_length)
{
enum GNUNET_DB_QueryStatus qs;
bool shard_done;
uint64_t lroff = latest_row_off;
if (0 == details_length)
{
/* Server should have used 204, not 200! */
GNUNET_break_op (0);
transaction_completed ();
return;
}
/* check serial IDs for range constraints */
for (unsigned int i = 0; i<details_length; i++)
{
const struct TALER_BANK_CreditDetails *cd = &details[i];
if (cd->serial_id < lroff)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Serial ID %llu not monotonic (got %llu before). Failing!\n",
(unsigned long long) cd->serial_id,
(unsigned long long) lroff);
db_plugin->rollback (db_plugin->cls);
GNUNET_SCHEDULER_shutdown ();
return;
}
if (cd->serial_id > shard_end)
{
/* we are *past* the current shard (likely because the serial_id of the
shard_end happens to not exist in the DB). So commit and stop this
iteration! */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Serial ID %llu past shard end at %llu, ending iteration early!\n",
(unsigned long long) cd->serial_id,
(unsigned long long) shard_end);
details_length = i;
progress = true;
lroff = cd->serial_id - 1;
break;
}
lroff = cd->serial_id;
}
if (0 != details_length)
{
enum GNUNET_DB_QueryStatus qss[details_length];
struct TALER_EXCHANGEDB_ReserveInInfo reserves[details_length];
hh_returned_data = true;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Importing %u transactions\n",
details_length);
for (unsigned int i = 0; i<details_length; i++)
{
const struct TALER_BANK_CreditDetails *cd = &details[i];
struct TALER_EXCHANGEDB_ReserveInInfo *res = &reserves[i];
res->reserve_pub = &cd->reserve_pub;
res->balance = &cd->amount;
res->execution_time = cd->execution_date;
res->sender_account_details = cd->debit_account_uri;
res->exchange_account_name = ai->section_name;
res->wire_reference = cd->serial_id;
}
qs = db_plugin->batch_reserves_in_insert (db_plugin->cls,
reserves,
details_length,
qss);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
GNUNET_break (0);
GNUNET_SCHEDULER_shutdown ();
return;
case GNUNET_DB_STATUS_SOFT_ERROR:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got DB soft error for batch_reserves_in_insert. Rolling back.\n");
handle_soft_error ();
return;
default:
break;
}
for (unsigned int i = 0; i<details_length; i++)
{
const struct TALER_BANK_CreditDetails *cd = &details[i];
switch (qss[i])
{
case GNUNET_DB_STATUS_HARD_ERROR:
GNUNET_break (0);
GNUNET_SCHEDULER_shutdown ();
return;
case GNUNET_DB_STATUS_SOFT_ERROR:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got DB soft error for batch_reserves_in_insert(%u). Rolling back.\n",
i);
handle_soft_error ();
return;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
/* Either wirewatch was freshly started after the system was
shutdown and we're going over an incomplete shard again
after being restarted, or the shard lock period was too
short (number of workers set incorrectly?) and a 2nd
wirewatcher has been stealing our work while we are still
at it. */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Attempted to import transaction %llu (%s) twice. "
"This should happen rarely (if not, ask for support).\n",
(unsigned long long) cd->serial_id,
job_name);
break;
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Imported transaction %llu.",
(unsigned long long) cd->serial_id);
/* normal case */
progress = true;
break;
}
}
}
latest_row_off = lroff;
shard_done = (shard_end <= latest_row_off);
if (shard_done)
{
/* shard is complete, mark this as well */
qs = db_plugin->complete_shard (db_plugin->cls,
job_name,
shard_start,
shard_end);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
GNUNET_break (0);
GNUNET_SCHEDULER_shutdown ();
return;
case GNUNET_DB_STATUS_SOFT_ERROR:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got DB soft error for complete_shard. Rolling back.\n");
handle_soft_error ();
return;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
GNUNET_break (0);
/* Not expected, but let's just continue */
break;
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
/* normal case */
progress = true;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Completed shard %s (%llu,%llu] after %s\n",
job_name,
(unsigned long long) shard_start,
(unsigned long long) shard_end,
GNUNET_STRINGS_relative_time_to_string (
GNUNET_TIME_absolute_get_duration (shard_start_time),
true));
break;
}
shard_delay = GNUNET_TIME_absolute_get_duration (shard_start_time);
shard_open = false;
transaction_completed ();
return;
}
GNUNET_assert (NULL == task);
task = GNUNET_SCHEDULER_add_now (&continue_with_shard,
NULL);
}
/**
* We got incoming transaction details from the bank. Add them
* to the database.
@ -883,7 +500,7 @@ process_reply_batched (const struct TALER_BANK_CreditDetails *details,
* @param details_length length of the @a details array
*/
static void
process_reply_batched2 (unsigned int batch_size,
process_reply (unsigned int batch_size,
const struct TALER_BANK_CreditDetails *details,
unsigned int details_length)
{
@ -950,7 +567,7 @@ process_reply_batched2 (unsigned int batch_size,
res->exchange_account_name = ai->section_name;
res->wire_reference = cd->serial_id;
}
qs = db_plugin->batch2_reserves_in_insert (db_plugin->cls,
qs = db_plugin->reserves_in_insert (db_plugin->cls,
reserves,
details_length,
batch_size,
@ -1074,7 +691,7 @@ history_cb (void *cls,
(void) cls;
if (-2 == batch_mode)
{
const char *mode = getenv ("TALER_USE_BATCH");
const char *mode = getenv ("TALER_WIREWATCH_BATCH_SIZE");
char dummy;
if ( (NULL == mode) ||
@ -1087,7 +704,7 @@ history_cb (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Bad batch mode `%s' specified\n",
mode);
batch_mode = -1;
batch_mode = 8; /* maximum supported is currently 8 */
}
}
GNUNET_assert (NULL == task);
@ -1098,22 +715,9 @@ history_cb (void *cls,
switch (reply->http_status)
{
case MHD_HTTP_OK:
switch (batch_mode)
{
case -1:
process_reply (reply->details.success.details,
reply->details.success.details_length);
break;
case 0:
process_reply_batched (reply->details.success.details,
reply->details.success.details_length);
break;
default:
process_reply_batched2 ((unsigned int) batch_mode,
process_reply (batch_mode,
reply->details.success.details,
reply->details.success.details_length);
break;
}
return;
case MHD_HTTP_NO_CONTENT:
transaction_completed ();

View File

@ -1,17 +1,9 @@
test-exchangedb-auditors
test-exchangedb-denomkeys
test-exchangedb-fees
test-exchangedb-postgres
test-exchangedb-signkeys
test-perf-taler-exchangedb
bench-db-postgres
shard-drop0001.sqltest-exchangedb-by-j-postgres
test-exchangedb-by-j-postgres
perf-exchangedb-reserves-in-insert-postgres
perf_deposits_get_ready-postgres
perf_get_link_data-postgres
perf_reserves_in_insert-postgres
perf_select_refunds_by_coin-postgres
exchange-0002.sql
procedures.sql
exchange-0003.sql
test-exchangedb-batch-reserves-in-insert-postgres
test-exchangedb-populate-table-postgres
test-exchangedb-populate-link-data-postgres
test-exchangedb-populate-ready-deposit-postgres

View File

@ -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 General Public License as published by the Free Software
@ -116,6 +116,22 @@ BEGIN
',ADD CONSTRAINT ' || table_name || '_coin_pub_merchant_pub_h_contract_terms_key'
' UNIQUE (coin_pub, merchant_pub, h_contract_terms)'
);
EXECUTE FORMAT (
'CREATE INDEX ' || table_name || '_by_ready '
'ON ' || table_name || ' '
'(wire_deadline ASC'
',shard ASC'
',coin_pub'
') WHERE NOT (done OR policy_blocked);'
);
EXECUTE FORMAT (
'CREATE INDEX ' || table_name || '_for_matching '
'ON ' || table_name || ' '
'(refund_deadline ASC'
',merchant_pub'
',coin_pub'
') WHERE NOT (done OR policy_blocked);'
);
END
$$;
@ -399,29 +415,5 @@ INSERT INTO exchange_tables
,'exchange-0002'
,'foreign'
,TRUE
,FALSE),
('deposits_by_ready'
,'exchange-0002'
,'create'
,TRUE
,TRUE),
('deposits_by_ready'
,'exchange-0002'
,'constrain'
,TRUE
,TRUE),
('deposits_for_matching'
,'exchange-0002'
,'create'
,TRUE
,TRUE),
('deposits_for_matching'
,'exchange-0002'
,'constrain'
,TRUE
,TRUE),
('deposits'
,'exchange-0002'
,'master'
,TRUE
,FALSE);
,FALSE)
;

View File

@ -255,8 +255,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \
pg_select_purse_deposits_above_serial_id.h pg_select_purse_deposits_above_serial_id.c \
pg_select_account_merges_above_serial_id.h pg_select_account_merges_above_serial_id.c \
pg_select_all_purse_decisions_above_serial_id.h pg_select_all_purse_decisions_above_serial_id.c \
pg_batch_reserves_in_insert.h pg_batch_reserves_in_insert.c \
pg_batch2_reserves_in_insert.h pg_batch2_reserves_in_insert.c \
pg_select_reserve_open_above_serial_id.c pg_select_reserve_open_above_serial_id.h
libtaler_plugin_exchangedb_postgres_la_LIBADD = \
$(LTLIBINTL)
@ -295,22 +293,14 @@ check_PROGRAMS = \
noinst_PROGRAMS = \
bench-db-postgres\
perf-exchangedb-reserves-in-insert-postgres\
test-exchangedb-by-j-postgres\
test-exchangedb-batch-reserves-in-insert-postgres\
test-exchangedb-populate-select-refunds-by-coin-postgres\
test-exchangedb-populate-link-data-postgres\
test-exchangedb-populate-ready-deposit-postgres
perf_get_link_data-postgres\
perf_select_refunds_by_coin-postgres\
perf_reserves_in_insert-postgres \
perf_deposits_get_ready-postgres
AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
TESTS = \
test-exchangedb-postgres\
test-exchangedb-by-j-postgres\
perf-exchangedb-reserves-in-insert-postgres\
test-exchangedb-batch-reserves-in-insert-postgres\
test-exchangedb-populate-select-refunds-by-coin-postgres\
test-exchangedb-populate-link-data-postgres\
test-exchangedb-populate-ready-deposit-postgres
(check_PROGRAMS)
test_exchangedb_postgres_SOURCES = \
test_exchangedb.c
test_exchangedb_postgres_LDADD = \
@ -323,32 +313,6 @@ test_exchangedb_postgres_LDADD = \
-lgnunetutil \
$(XLIB)
test_exchangedb_by_j_postgres_SOURCES = \
test_exchangedb_by_j.c
test_exchangedb_by_j_postgres_LDADD = \
libtalerexchangedb.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/pq/libtalerpq.la \
-ljansson \
-lgnunetjson \
-lgnunetutil \
-lm \
$(XLIB)
perf_exchangedb_reserves_in_insert_postgres_SOURCES = \
perf_exchangedb_reserves_in_insert.c
perf_exchangedb_reserves_in_insert_postgres_LDADD = \
libtalerexchangedb.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/pq/libtalerpq.la \
-ljansson \
-lgnunetjson \
-lgnunetutil \
$(XLIB)
bench_db_postgres_SOURCES = \
bench_db.c
bench_db_postgres_LDADD = \
@ -359,21 +323,9 @@ bench_db_postgres_LDADD = \
-lgnunetutil \
$(XLIB)
test_exchangedb_batch_reserves_in_insert_postgres_SOURCES = \
test_exchangedb_batch_reserves_in_insert.c
test_exchangedb_batch_reserves_in_insert_postgres_LDADD = \
libtalerexchangedb.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/pq/libtalerpq.la \
-ljansson \
-lgnunetjson \
-lgnunetutil \
$(XLIB)
test_exchangedb_populate_select_refunds_by_coin_postgres_SOURCES = \
test_exchangedb_populate_select_refunds_by_coin.c
test_exchangedb_populate_select_refunds_by_coin_postgres_LDADD = \
perf_reserves_in_insert_postgres_SOURCES = \
perf_reserves_in_insert.c
perf_reserves_in_insert_postgres_LDADD = \
libtalerexchangedb.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
@ -384,9 +336,9 @@ test_exchangedb_populate_select_refunds_by_coin_postgres_LDADD = \
-lm \
$(XLIB)
test_exchangedb_populate_link_data_postgres_SOURCES = \
test_exchangedb_populate_link_data.c
test_exchangedb_populate_link_data_postgres_LDADD = \
perf_select_refunds_by_coin_postgres_SOURCES = \
perf_select_refunds_by_coin.c
perf_select_refunds_by_coin_postgres_LDADD = \
libtalerexchangedb.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
@ -397,9 +349,22 @@ test_exchangedb_populate_link_data_postgres_LDADD = \
-lm \
$(XLIB)
test_exchangedb_populate_ready_deposit_postgres_SOURCES = \
test_exchangedb_populate_ready_deposit.c
test_exchangedb_populate_ready_deposit_postgres_LDADD = \
perf_get_link_data_postgres_SOURCES = \
perf_get_link_data.c
perf_get_link_data_postgres_LDADD = \
libtalerexchangedb.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/pq/libtalerpq.la \
-ljansson \
-lgnunetjson \
-lgnunetutil \
-lm \
$(XLIB)
perf_deposits_get_ready_postgres_SOURCES = \
perf_deposits_get_ready.c
perf_deposits_get_ready_postgres_LDADD = \
libtalerexchangedb.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \

View File

@ -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 General Public License as published by the Free Software
@ -14,8 +14,8 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file exchangedb/test_exchangedb_populate_ready_deposit.c
* @brief test cases for DB interaction functions
* @file exchangedb/perf_deposits_get_ready.c
* @brief benchmark for deposits_get_ready
* @author Joseph Xu
*/
#include "platform.h"
@ -57,21 +57,27 @@ static int result;
*/
#define CURRENCY "EUR"
#define RSA_KEY_SIZE 1024
#define NUM_ROWS 1000000
#define ROUNDS 10000
#define NUM_ROWS 1000
#define ROUNDS 100
#define MELT_NEW_COINS 5
#define MELT_NOREVEAL_INDEX 1
/**
* Database plugin under test.
*/
static struct TALER_EXCHANGEDB_Plugin *plugin;
static struct TALER_DenomFeeSet fees;
static struct TALER_MerchantWireHashP h_wire_wt;
/**
* Denomination keys used for fresh coins in melt test.
*/
static struct DenomKeyPair **new_dkp;
static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins;
struct DenomKeyPair
{
struct TALER_DenominationPrivateKey priv;
@ -173,8 +179,6 @@ create_denom_key_pair (unsigned int size,
}
/**
* Main function that will be run by the scheduler.
*
@ -191,9 +195,9 @@ run (void *cls)
struct TALER_EXCHANGEDB_CollectableBlindcoin cbc;
struct TALER_DenominationPublicKey *new_denom_pubs = NULL;
struct GNUNET_TIME_Relative times = GNUNET_TIME_UNIT_ZERO;
unsigned long long sqrs=0;
struct TALER_EXCHANGEDB_Deposit *depos=NULL;
struct TALER_EXCHANGEDB_Refund *ref=NULL;
unsigned long long sqrs = 0;
struct TALER_EXCHANGEDB_Deposit *depos = NULL;
struct TALER_EXCHANGEDB_Refund *ref = NULL;
unsigned int *perm;
unsigned long long duration_sq;
struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin;
@ -201,9 +205,9 @@ run (void *cls)
.cipher = TALER_DENOMINATION_RSA
};
ref = GNUNET_new_array (ROUNDS +1,
ref = GNUNET_new_array (ROUNDS + 1,
struct TALER_EXCHANGEDB_Refund);
depos = GNUNET_new_array (ROUNDS +1,
depos = GNUNET_new_array (ROUNDS + 1,
struct TALER_EXCHANGEDB_Deposit);
if (NULL ==
@ -245,16 +249,12 @@ run (void *cls)
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":0.000010",
&fees.refund));
//DENOMINATION
{
ZR_BLK (&cbc);
//PAIR KEY LIST
new_dkp = GNUNET_new_array (MELT_NEW_COINS,
struct DenomKeyPair *);
//PUBLIC KEY LIST
new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,
struct TALER_DenominationPublicKey);
//REFRESH REVEAL COIN LIST
revealed_coins
= GNUNET_new_array (MELT_NEW_COINS,
struct TALER_EXCHANGEDB_RefreshRevealedCoin);
@ -265,7 +265,6 @@ run (void *cls)
struct TALER_BlindedPlanchet *bp;
now = GNUNET_TIME_timestamp_get ();
//5 KEY PAIR
new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE,
now,
&value,
@ -309,7 +308,6 @@ run (void *cls)
}
perm = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_NONCE,
NUM_ROWS);
//BEGIN
FAILIF (GNUNET_OK !=
plugin->start (plugin->cls,
"Transaction"));
@ -321,7 +319,7 @@ run (void *cls)
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_CoinPubHashP c_hash;
unsigned int k = (unsigned int)rand()%5;
unsigned int k = (unsigned int) rand () % 5;
unsigned int i = perm[j];
if (i >= ROUNDS)
i = ROUNDS; /* throw-away slot, do not keep around */
@ -362,12 +360,12 @@ run (void *cls)
TALER_amount_set_zero (CURRENCY,
&cbc.withdraw_fee));
{
/* INSERT WIRE TARGETS */
bool found;
bool nonce_ok;
bool balance_ok;
uint64_t ruuid;
struct GNUNET_TIME_Timestamp now;
now = GNUNET_TIME_timestamp_get ();
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->do_withdraw (plugin->cls,
@ -396,9 +394,9 @@ run (void *cls)
refresh.amount_with_fee = value;
refresh.noreveal_index = MELT_NOREVEAL_INDEX;
}
/*STORE INTO DEPOSIT*/
{
struct GNUNET_TIME_Timestamp now;
now = GNUNET_TIME_timestamp_get ();
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_deposit (plugin->cls,
@ -408,31 +406,33 @@ run (void *cls)
if (ROUNDS == i)
TALER_denom_sig_free (&depos[i].coin.denom_sig);
}
/* End of benchmark setup */
GNUNET_free(perm);
// commit
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->commit (plugin->cls));
GNUNET_free (perm);
/* End of benchmark setup */
/**** CALL GET READY DEPOSIT ****/
for (unsigned int r=0; r< ROUNDS; r++)
for (unsigned int r = 0; r< ROUNDS; r++)
{
struct GNUNET_TIME_Absolute time;
struct GNUNET_TIME_Relative duration;
struct TALER_MerchantPublicKeyP merchant_pub;
char *payto_uri;
time = GNUNET_TIME_absolute_get();
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_ready_deposit (plugin->cls,
enum GNUNET_DB_QueryStatus qs;
time = GNUNET_TIME_absolute_get ();
qs = plugin->get_ready_deposit (plugin->cls,
0,
INT32_MAX,
&merchant_pub,
&payto_uri));
&payto_uri);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
duration = GNUNET_TIME_absolute_get_duration (time);
times = GNUNET_TIME_relative_add (times,
duration);
duration_sq = duration.rel_value_us * duration.rel_value_us;
GNUNET_assert (duration_sq / duration.rel_value_us == duration.rel_value_us);
GNUNET_assert (duration_sq / duration.rel_value_us ==
duration.rel_value_us);
GNUNET_assert (sqrs + duration_sq >= sqrs);
sqrs += duration_sq;
}
@ -447,15 +447,14 @@ run (void *cls)
ROUNDS);
avg_dbl = avg.rel_value_us;
variance = sqrs - (avg_dbl * avg_dbl * ROUNDS);
fprintf(stdout,
fprintf (stdout,
"%8llu ± %6.0f\n",
(unsigned long long) avg.rel_value_us,
sqrt (variance / (ROUNDS-1)));
sqrt (variance / (ROUNDS - 1)));
}
result = 0;
drop:
GNUNET_break (GNUNET_OK ==
plugin->drop_tables (plugin->cls));
// GNUNET_break (GNUNET_OK == plugin->drop_tables (plugin->cls));
cleanup:
if (NULL != revealed_coins)
{
@ -473,12 +472,12 @@ cleanup:
cnt++)
destroy_denom_key_pair (new_dkp[cnt]);
GNUNET_free (new_dkp);
for (unsigned int i=0; i< ROUNDS ; i++)
for (unsigned int i = 0; i< ROUNDS; i++)
{
TALER_denom_sig_free (&depos[i].coin.denom_sig);
}
GNUNET_free(depos);
GNUNET_free(ref);
GNUNET_free (depos);
GNUNET_free (ref);
TALER_EXCHANGEDB_plugin_unload (plugin);
plugin = NULL;
}
@ -490,7 +489,6 @@ main (int argc,
{
const char *plugin_name;
char *config_filename;
char *testname;
struct GNUNET_CONFIGURATION_Handle *cfg;
(void) argc;
@ -504,15 +502,17 @@ main (int argc,
"WARNING",
NULL);
plugin_name++;
(void) GNUNET_asprintf (&testname,
{
char *testname;
GNUNET_asprintf (&testname,
"test-exchange-db-%s",
plugin_name);
(void) GNUNET_asprintf (&config_filename,
GNUNET_asprintf (&config_filename,
"%s.conf",
testname);
fprintf (stdout,
"Using config: %s\n",
config_filename);
GNUNET_free (testname);
}
cfg = GNUNET_CONFIGURATION_create ();
if (GNUNET_OK !=
GNUNET_CONFIGURATION_parse (cfg,
@ -520,16 +520,14 @@ main (int argc,
{
GNUNET_break (0);
GNUNET_free (config_filename);
GNUNET_free (testname);
return 2;
}
GNUNET_SCHEDULER_run (&run,
cfg);
GNUNET_CONFIGURATION_destroy (cfg);
GNUNET_free (config_filename);
GNUNET_free (testname);
return result;
}
/* end of test_exchangedb_by_j.c */
/* end of perf_deposits_get_ready.c */

View File

@ -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 General Public License as published by the Free Software
@ -14,8 +14,8 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file exchangedb/test_exchangedb_populate_link_data.c
* @brief test cases for DB interaction functions
* @file exchangedb/perf_get_link_data.c
* @brief benchmark for get_link_data
* @author Joseph Xu
*/
#include "platform.h"
@ -166,6 +166,8 @@ create_denom_key_pair (unsigned int size,
}
return dkp;
}
/**
* Function called with the session hashes and transfer secret
* information for a given coin.
@ -199,22 +201,22 @@ run (void *cls)
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
const uint32_t num_partitions = 10;
struct DenomKeyPair *dkp = NULL;
struct TALER_EXCHANGEDB_Deposit *depos=NULL;
struct TALER_EXCHANGEDB_Deposit *depos = NULL;
struct TALER_Amount value;
struct GNUNET_TIME_Relative times = GNUNET_TIME_UNIT_ZERO;
unsigned long long sqrs=0;
struct TALER_EXCHANGEDB_Refund *ref=NULL;
unsigned long long sqrs = 0;
struct TALER_EXCHANGEDB_Refund *ref = NULL;
unsigned int *perm;
unsigned long long duration_sq;
struct TALER_ExchangeWithdrawValues alg_values = {
.cipher = TALER_DENOMINATION_RSA
};
ref = GNUNET_new_array (ROUNDS +1,
ref = GNUNET_new_array (ROUNDS + 1,
struct TALER_EXCHANGEDB_Refund);
depos = GNUNET_new_array (ROUNDS +1,
depos = GNUNET_new_array (ROUNDS + 1,
struct TALER_EXCHANGEDB_Deposit);
refresh = GNUNET_new_array (ROUNDS +1,
refresh = GNUNET_new_array (ROUNDS + 1,
struct TALER_EXCHANGEDB_Refresh);
if (NULL ==
@ -256,9 +258,7 @@ run (void *cls)
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":0.000010",
&fees.refund));
//DENOMINATION
{
//PAIR KEY LIST
new_dkp = GNUNET_new_array (MELT_NEW_COINS,
struct DenomKeyPair *);
@ -275,7 +275,6 @@ run (void *cls)
}
perm = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_NONCE,
NUM_ROWS);
//BEGIN
FAILIF (GNUNET_OK !=
plugin->start (plugin->cls,
"Transaction"));
@ -290,17 +289,19 @@ run (void *cls)
i = ROUNDS; /* throw-away slot, do not keep around */
RND_BLK (&depos[i].coin.coin_pub);
ZR_BLK (&cbc);
TALER_denom_pub_hash (&new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->pub,
TALER_denom_pub_hash (&new_dkp[(unsigned int) rand ()
% MELT_NEW_COINS]->pub,
&depos[i].coin.denom_pub_hash);
{
struct TALER_EXCHANGEDB_RefreshRevealedCoin revealed_coins[MELT_NEW_COINS];
struct TALER_EXCHANGEDB_RefreshRevealedCoin
revealed_coins[MELT_NEW_COINS];
for (unsigned int p=0;p<MELT_NEW_COINS;p++)
for (unsigned int p = 0; p<MELT_NEW_COINS; p++)
{
struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coin = &revealed_coins[p];
struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coin =
&revealed_coins[p];
struct TALER_BlindedPlanchet *bp = &revealed_coin->blinded_planchet;
struct TALER_BlindedRsaPlanchet *rp = &bp->details.rsa_blinded_planchet;
@ -316,7 +317,8 @@ run (void *cls)
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
rp->blinded_msg,
rp->blinded_msg_size);
TALER_denom_pub_hash (&new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->pub,
TALER_denom_pub_hash (&new_dkp[(unsigned int) rand ()
% MELT_NEW_COINS]->pub,
&revealed_coin->h_denom_pub);
revealed_coin->exchange_vals = alg_values;
TALER_coin_ev_hash (bp,
@ -324,14 +326,17 @@ run (void *cls)
&revealed_coin->coin_envelope_hash);
GNUNET_assert (GNUNET_OK ==
TALER_denom_sign_blinded (&revealed_coin->coin_sig,
&new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->priv,
&new_dkp[(unsigned
int) rand ()
% MELT_NEW_COINS]->
priv,
true,
bp));
GNUNET_assert (
GNUNET_OK ==
TALER_denom_sign_blinded (
&cbc.sig,
&new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->priv,
&new_dkp[(unsigned int) rand () % MELT_NEW_COINS]->priv,
false,
bp));
}
@ -341,7 +346,8 @@ run (void *cls)
&bks,
&c_hash,
&alg_values,
&new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->pub));
&new_dkp[(unsigned int) rand ()
% MELT_NEW_COINS]->pub));
{
/* ENSURE_COIN_KNOWN */
struct TALER_DenominationHashP dph;
@ -417,17 +423,15 @@ run (void *cls)
TALER_denom_sig_free (&depos[i].coin.denom_sig);
}
/* End of benchmark setup */
GNUNET_free(perm);
// commit
GNUNET_free (perm);
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->commit (plugin->cls));
/**** CALL GET LINK DATA ****/
for (unsigned int r=0; r< ROUNDS; r++)
for (unsigned int r = 0; r< ROUNDS; r++)
{
struct GNUNET_TIME_Absolute time;
struct GNUNET_TIME_Relative duration;
enum GNUNET_DB_QueryStatus qs;
time = GNUNET_TIME_absolute_get();
time = GNUNET_TIME_absolute_get ();
qs = plugin->get_link_data (plugin->cls,
&refresh[r].coin.coin_pub,
@ -439,7 +443,8 @@ run (void *cls)
times = GNUNET_TIME_relative_add (times,
duration);
duration_sq = duration.rel_value_us * duration.rel_value_us;
GNUNET_assert (duration_sq / duration.rel_value_us == duration.rel_value_us);
GNUNET_assert (duration_sq / duration.rel_value_us ==
duration.rel_value_us);
GNUNET_assert (sqrs + duration_sq >= sqrs);
sqrs += duration_sq;
}
@ -454,10 +459,10 @@ run (void *cls)
ROUNDS);
avg_dbl = avg.rel_value_us;
variance = sqrs - (avg_dbl * avg_dbl * ROUNDS);
fprintf(stdout,
fprintf (stdout,
"%8llu ± %6.0f\n",
(unsigned long long) avg.rel_value_us,
sqrt (variance / (ROUNDS-1)));
sqrt (variance / (ROUNDS - 1)));
}
result = 0;
drop:
@ -470,13 +475,13 @@ cleanup:
cnt++)
destroy_denom_key_pair (new_dkp[cnt]);
GNUNET_free (new_dkp);
for (unsigned int i=0; i< ROUNDS; i++)
for (unsigned int i = 0; i< ROUNDS; i++)
{
TALER_denom_sig_free (&depos[i].coin.denom_sig);
}
GNUNET_free(depos);
GNUNET_free(ref);
GNUNET_free(refresh);
GNUNET_free (depos);
GNUNET_free (ref);
GNUNET_free (refresh);
dkp = NULL;
TALER_EXCHANGEDB_plugin_unload (plugin);
plugin = NULL;
@ -509,9 +514,6 @@ main (int argc,
(void) GNUNET_asprintf (&config_filename,
"%s.conf",
testname);
fprintf (stdout,
"Using config: %s\n",
config_filename);
cfg = GNUNET_CONFIGURATION_create ();
if (GNUNET_OK !=
GNUNET_CONFIGURATION_parse (cfg,

View File

@ -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 General Public License as published by the Free Software
@ -14,8 +14,8 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file exchangedb/test_exchangedb_by_j.c
* @brief test cases for DB interaction functions
* @file exchangedb/perf_reserves_in_insert.c
* @brief benchmark for 'reserves_in_insert'
* @author Joseph Xu
*/
#include "platform.h"
@ -23,6 +23,7 @@
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
/**
* Global result from the testcase.
*/
@ -33,7 +34,7 @@ static int result;
*/
#define FAILIF(cond) \
do { \
if (! (cond)) { break;} \
if (! (cond)) {break;} \
GNUNET_break (0); \
goto drop; \
} while (0)
@ -51,6 +52,10 @@ static int result;
#define ZR_BLK(ptr) \
memset (ptr, 0, sizeof (*ptr))
/**
* How many rounds do we average over?
*/
#define ROUNDS 5
/**
* Currency we use. Must match test-exchange-db-*.conf.
@ -73,6 +78,10 @@ run (void *cls)
{
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
const uint32_t num_partitions = 10;
static unsigned int batches[] = {1, 1, 2, 3, 4, 16, 32 };
const unsigned int lcm = 3 * 32;
struct GNUNET_TIME_Relative times[sizeof (batches) / sizeof(*batches)];
unsigned long long sqrs[sizeof (batches) / sizeof(*batches)];
if (NULL ==
(plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
@ -91,46 +100,78 @@ run (void *cls)
result = 77;
goto cleanup;
}
for (unsigned int i = 0; i< 8; i++)
memset (times, 0, sizeof (times));
memset (sqrs, 0, sizeof (sqrs));
for (unsigned int r = 0; r < ROUNDS; r++)
{
for (unsigned int i = 0;
i< sizeof(batches) / sizeof(*batches);
i++)
{
static unsigned int batches[] = {1, 1, 0, 2, 4, 16, 64, 256};
const char *sndr = "payto://x-taler-bank/localhost:8080/1";
struct TALER_Amount value;
unsigned int batch_size = batches[i];
struct TALER_Amount value;
struct GNUNET_TIME_Absolute now;
struct GNUNET_TIME_Timestamp ts;
unsigned long long duration_sq;
struct GNUNET_TIME_Relative duration;
struct TALER_ReservePublicKeyP reserve_pub;
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":1.000010",
&value));
now = GNUNET_TIME_absolute_get ();
ts = GNUNET_TIME_timestamp_get ();
for (unsigned int r = 0; r<10; r++)
{
plugin->start (plugin->cls,
"test_by_exchange_j");
for (unsigned int k = 0; k<batch_size; k++)
const char *sndr = "payto://x-taler-bank/localhost:8080/1";
struct TALER_ReservePublicKeyP reserve_pubs[lcm];
struct TALER_EXCHANGEDB_ReserveInInfo reserves[lcm];
enum GNUNET_DB_QueryStatus results[lcm];
for (unsigned int k = 0; k<lcm; k++)
{
RND_BLK (&reserve_pub);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->reserves_in_insert (plugin->cls,
&reserve_pub,
&value,
ts,
sndr,
"section",
4));
RND_BLK (&reserve_pubs[k]);
reserves[k].reserve_pub = &reserve_pubs[k];
reserves[k].balance = &value;
reserves[k].execution_time = ts;
reserves[k].sender_account_details = sndr;
reserves[k].exchange_account_name = "name";
reserves[k].wire_reference = k;
}
plugin->commit (plugin->cls);
FAILIF (lcm !=
plugin->reserves_in_insert (plugin->cls,
reserves,
lcm,
batch_size,
results));
}
duration = GNUNET_TIME_absolute_get_duration (now);
times[i] = GNUNET_TIME_relative_add (times[i],
duration);
duration_sq = duration.rel_value_us * duration.rel_value_us;
GNUNET_assert (duration_sq / duration.rel_value_us ==
duration.rel_value_us);
GNUNET_assert (sqrs[i] + duration_sq >= sqrs[i]);
sqrs[i] += duration_sq;
} /* for 'i' batch size */
} /* for 'r' ROUNDS */
for (unsigned int i = 0;
i< sizeof(batches) / sizeof(*batches);
i++)
{
struct GNUNET_TIME_Relative avg;
double avg_dbl;
double variance;
avg = GNUNET_TIME_relative_divide (times[i],
ROUNDS);
avg_dbl = avg.rel_value_us;
variance = sqrs[i] - (avg_dbl * avg_dbl * ROUNDS);
fprintf (stdout,
"for a batchsize equal to %d it took %s\n",
batch_size,
GNUNET_STRINGS_relative_time_to_string (duration,
GNUNET_NO) );
"Batch[%2u]: %8llu ± %6.0f\n",
batches[i],
(unsigned long long) avg.rel_value_us,
sqrt (variance / (ROUNDS - 1)));
}
result = 0;
drop:
@ -150,7 +191,6 @@ main (int argc,
char *config_filename;
char *testname;
struct GNUNET_CONFIGURATION_Handle *cfg;
(void) argc;
result = -1;
if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
@ -158,6 +198,7 @@ main (int argc,
GNUNET_break (0);
return -1;
}
GNUNET_log_setup (argv[0],
"WARNING",
NULL);
@ -168,9 +209,6 @@ main (int argc,
(void) GNUNET_asprintf (&config_filename,
"%s.conf",
testname);
fprintf (stdout,
"Using config: %s\n",
config_filename);
cfg = GNUNET_CONFIGURATION_create ();
if (GNUNET_OK !=
GNUNET_CONFIGURATION_parse (cfg,
@ -190,4 +228,4 @@ main (int argc,
}
/* end of test_exchangedb_by_j.c */
/* end of perf_reserves_in_insert.c */

View File

@ -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 General Public License as published by the Free Software
@ -14,8 +14,8 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file exchangedb/test_exchangedb_populate_table.c
* @brief test cases for DB interaction functions
* @file exchangedb/perf_select_refunds_by_coin.c
* @brief benchmark for select_refunds_by_coin
* @author Joseph Xu
*/
#include "platform.h"
@ -56,24 +56,31 @@ static int result;
*/
#define CURRENCY "EUR"
#define RSA_KEY_SIZE 1024
#define ROUNDS 10000
#define NUM_ROWS 1000000
#define ROUNDS 100
#define NUM_ROWS 1000
#define MELT_NEW_COINS 5
#define MELT_NOREVEAL_INDEX 1
/**
* Database plugin under test.
*/
static struct TALER_EXCHANGEDB_Plugin *plugin;
static struct TALER_DenomFeeSet fees;
static struct TALER_MerchantWireHashP h_wire_wt;
static struct DenomKeyPair **new_dkp;
static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins;
struct DenomKeyPair
{
struct TALER_DenominationPrivateKey priv;
struct TALER_DenominationPublicKey pub;
};
/**
* Destroy a denomination key pair. The key is not necessarily removed from the DB.
*
@ -166,6 +173,8 @@ create_denom_key_pair (unsigned int size,
}
return dkp;
}
/**
* Callback invoked with information about refunds applicable
* to a particular coin.
@ -179,6 +188,7 @@ check_refund_cb (void *cls,
const struct TALER_Amount *amount_with_fee)
{
const struct TALER_EXCHANGEDB_Refund *refund = cls;
if (0 != TALER_amount_cmp (amount_with_fee,
&refund->details.refund_amount))
{
@ -201,7 +211,7 @@ run (void *cls)
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
const uint32_t num_partitions = 10;
struct GNUNET_TIME_Timestamp ts;
struct TALER_EXCHANGEDB_Deposit *depos=NULL;
struct TALER_EXCHANGEDB_Deposit *depos = NULL;
struct GNUNET_TIME_Timestamp deadline;
struct TALER_Amount value;
union TALER_DenominationBlindingKeyP bks;
@ -212,17 +222,17 @@ run (void *cls)
};
struct GNUNET_TIME_Relative times = GNUNET_TIME_UNIT_ZERO;
unsigned long long sqrs = 0;
struct TALER_EXCHANGEDB_Refund *ref=NULL;
struct TALER_EXCHANGEDB_Refund *ref = NULL;
unsigned int *perm;
unsigned long long duration_sq;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin;
struct TALER_DenominationPublicKey *new_denom_pubs = NULL;
unsigned int count=0;
unsigned int count = 0;
ref = GNUNET_new_array (ROUNDS +1,
ref = GNUNET_new_array (ROUNDS + 1,
struct TALER_EXCHANGEDB_Refund);
depos = GNUNET_new_array (ROUNDS +1,
depos = GNUNET_new_array (ROUNDS + 1,
struct TALER_EXCHANGEDB_Deposit);
ZR_BLK (&cbc);
@ -249,8 +259,6 @@ run (void *cls)
GNUNET_break (0);
goto cleanup;
}
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":1.000010",
&value));
@ -270,15 +278,11 @@ run (void *cls)
ts = GNUNET_TIME_timestamp_get ();
deadline = GNUNET_TIME_timestamp_get ();
//DENOMINATION
{
//PAIR KEY LIST
new_dkp = GNUNET_new_array (MELT_NEW_COINS,
struct DenomKeyPair *);
//PUBLIC KEY LIST
new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,
struct TALER_DenominationPublicKey);
//REFRESH REVEAL COIN LIST
revealed_coins
= GNUNET_new_array (MELT_NEW_COINS,
struct TALER_EXCHANGEDB_RefreshRevealedCoin);
@ -289,7 +293,6 @@ run (void *cls)
struct TALER_BlindedPlanchet *bp;
now = GNUNET_TIME_timestamp_get ();
//5 KEY PAIR
new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE,
now,
&value,
@ -334,14 +337,13 @@ run (void *cls)
perm = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_NONCE,
NUM_ROWS);
// begin
FAILIF (GNUNET_OK !=
plugin->start (plugin->cls,
"Transaction"));
for (unsigned int j=0; j< NUM_ROWS; j++)
for (unsigned int j = 0; j< NUM_ROWS; j++)
{
unsigned int i = perm[j];
unsigned int k = (unsigned int)rand()%5;
unsigned int k = (unsigned int) rand () % 5;
if (i >= ROUNDS)
i = ROUNDS; /* throw-away slot, do not keep around */
RND_BLK (&coin_pub);
@ -350,8 +352,6 @@ run (void *cls)
RND_BLK (&depos[i].coin.coin_pub);
TALER_denom_pub_hash (&new_dkp[k]->pub,
&depos[i].coin.denom_pub_hash);
// TALER_denom_pub_hash (&dkp->pub,
// &ref.coin.denom_pub_hash);
GNUNET_assert (GNUNET_OK ==
TALER_denom_sig_unblind (&depos[i].coin.denom_sig,
&cbc.sig,
@ -374,10 +374,10 @@ run (void *cls)
&h_wire_wt);
depos[i].timestamp = ts;
uint64_t known_coin_id;
{//ENSURE_COIN_KNOWN
{
struct TALER_DenominationHashP dph;
struct TALER_AgeCommitmentHash agh;
FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
plugin->ensure_coin_known (plugin->cls,
&depos[i].coin,
@ -385,9 +385,9 @@ run (void *cls)
&dph,
&agh));
}
/*STORE INTO DEPOSIT*/
{
struct GNUNET_TIME_Timestamp now;
now = GNUNET_TIME_timestamp_get ();
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_deposit (plugin->cls,
@ -399,12 +399,13 @@ run (void *cls)
bool refund_ok;
bool gone;
bool conflict;
unsigned int refund_percent=0;
switch (refund_percent){
case 2 ://100% refund
unsigned int refund_percent = 0;
switch (refund_percent)
{
case 2: // 100% refund
ref[i].coin = depos[i].coin;
ref[i].details.merchant_pub = depos[i].merchant_pub;
RND_BLK(&ref[i].details.merchant_sig);
RND_BLK (&ref[i].details.merchant_sig);
ref[i].details.h_contract_terms = depos[i].h_contract_terms;
ref[i].coin.coin_pub = depos[i].coin.coin_pub;
ref[i].details.rtransaction_id = i;
@ -420,12 +421,12 @@ run (void *cls)
&gone,
&conflict));
break;
case 1 ://10% refund
if (count < (NUM_ROWS/10))
case 1:// 10% refund
if (count < (NUM_ROWS / 10))
{
ref[i].coin = depos[i].coin;
ref[i].details.merchant_pub = depos[i].merchant_pub;
RND_BLK(&ref[i].details.merchant_sig);
RND_BLK (&ref[i].details.merchant_sig);
ref[i].details.h_contract_terms = depos[i].h_contract_terms;
ref[i].coin.coin_pub = depos[i].coin.coin_pub;
ref[i].details.rtransaction_id = i;
@ -435,10 +436,10 @@ run (void *cls)
else
{
ref[i].coin = depos[i].coin;
RND_BLK(&ref[i].details.merchant_pub);
RND_BLK(&ref[i].details.merchant_sig);
RND_BLK(&ref[i].details.h_contract_terms);
RND_BLK(&ref[i].coin.coin_pub);
RND_BLK (&ref[i].details.merchant_pub);
RND_BLK (&ref[i].details.merchant_sig);
RND_BLK (&ref[i].details.h_contract_terms);
RND_BLK (&ref[i].coin.coin_pub);
ref[i].details.rtransaction_id = i;
ref[i].details.refund_amount = value;
ref[i].details.refund_fee = fees.refund;
@ -454,12 +455,12 @@ run (void *cls)
&conflict));
count++;
break;
case 0://no refund
ref[i].coin=depos[i].coin;
RND_BLK(&ref[i].details.merchant_pub);
RND_BLK(&ref[i].details.merchant_sig);
RND_BLK(&ref[i].details.h_contract_terms);
RND_BLK(&ref[i].coin.coin_pub);
case 0:// no refund
ref[i].coin = depos[i].coin;
RND_BLK (&ref[i].details.merchant_pub);
RND_BLK (&ref[i].details.merchant_sig);
RND_BLK (&ref[i].details.h_contract_terms);
RND_BLK (&ref[i].coin.coin_pub);
ref[i].details.rtransaction_id = i;
ref[i].details.refund_amount = value;
ref[i].details.refund_fee = fees.refund;
@ -480,7 +481,6 @@ run (void *cls)
}
/* End of benchmark setup */
GNUNET_free (perm);
// commit
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->commit (plugin->cls));
for (unsigned int r = 0; r < ROUNDS; r++)
@ -500,7 +500,8 @@ run (void *cls)
times = GNUNET_TIME_relative_add (times,
duration);
duration_sq = duration.rel_value_us * duration.rel_value_us;
GNUNET_assert (duration_sq / duration.rel_value_us == duration.rel_value_us);
GNUNET_assert (duration_sq / duration.rel_value_us ==
duration.rel_value_us);
GNUNET_assert (sqrs + duration_sq >= sqrs);
sqrs += duration_sq;
}
@ -514,10 +515,10 @@ run (void *cls)
ROUNDS);
avg_dbl = avg.rel_value_us;
variance = sqrs - (avg_dbl * avg_dbl * ROUNDS);
fprintf(stdout,
fprintf (stdout,
"%8llu ± %6.0f\n",
(unsigned long long) avg.rel_value_us,
sqrt (variance / (ROUNDS-1)));
sqrt (variance / (ROUNDS - 1)));
}
result = 0;
drop:
@ -540,12 +541,12 @@ cleanup:
cnt++)
destroy_denom_key_pair (new_dkp[cnt]);
GNUNET_free (new_dkp);
for (unsigned int i=0; i< ROUNDS +1 ; i++)
for (unsigned int i = 0; i< ROUNDS + 1; i++)
{
TALER_denom_sig_free (&depos[i].coin.denom_sig);
}
GNUNET_free(depos);
GNUNET_free(ref);
GNUNET_free (depos);
GNUNET_free (ref);
TALER_EXCHANGEDB_plugin_unload (plugin);
plugin = NULL;
}
@ -557,7 +558,6 @@ main (int argc,
{
const char *plugin_name;
char *config_filename;
char *testname;
struct GNUNET_CONFIGURATION_Handle *cfg;
(void) argc;
@ -571,15 +571,17 @@ main (int argc,
"WARNING",
NULL);
plugin_name++;
(void) GNUNET_asprintf (&testname,
{
char *testname;
GNUNET_asprintf (&testname,
"test-exchange-db-%s",
plugin_name);
(void) GNUNET_asprintf (&config_filename,
GNUNET_asprintf (&config_filename,
"%s.conf",
testname);
fprintf (stdout,
"Using config: %s\n",
config_filename);
GNUNET_free (testname);
}
cfg = GNUNET_CONFIGURATION_create ();
if (GNUNET_OK !=
GNUNET_CONFIGURATION_parse (cfg,
@ -587,16 +589,14 @@ main (int argc,
{
GNUNET_break (0);
GNUNET_free (config_filename);
GNUNET_free (testname);
return 2;
}
GNUNET_SCHEDULER_run (&run,
cfg);
GNUNET_CONFIGURATION_destroy (cfg);
GNUNET_free (config_filename);
GNUNET_free (testname);
return result;
}
/* end of test_exchangedb_by_j.c */
/* end of perf_select_refunds_by_coin.c */

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2022 Taler Systems SA
Copyright (C) 2022, 2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@ -75,23 +75,13 @@ TEH_PG_aggregate (
/* Used in #postgres_aggregate() */
PREPARE (pg,
"aggregate",
"WITH rdy AS (" /* find deposits ready by merchant */
" SELECT"
" coin_pub"
" FROM deposits_for_matching"
" WHERE refund_deadline<$1" /* filter by shard, only actually executable deposits */
" AND merchant_pub=$2" /* filter by target merchant */
" ORDER BY refund_deadline ASC" /* ordering is not critical */
" LIMIT "
TALER_QUOTE (TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT) /* limits transaction size */
" )"
" ,dep AS (" /* restrict to our merchant and account and mark as done */
"WITH dep AS (" /* restrict to our merchant and account and mark as done */
" UPDATE deposits"
" SET done=TRUE"
" WHERE coin_pub IN (SELECT coin_pub FROM rdy)"
" AND merchant_pub=$2" /* theoretically, same coin could be spent at another merchant */
" WHERE NOT (done OR policy_blocked)" /* only actually executable deposits */
" AND refund_deadline<$1" /* filter by shard */
" AND merchant_pub=$2" /* filter by target merchant */
" AND wire_target_h_payto=$3" /* merchant could have a 2nd bank account */
" AND done=FALSE" /* theoretically, same coin could be spend at the same merchant a 2nd time */
" RETURNING"
" deposit_serial_id"
" ,coin_pub"

View File

@ -1,914 +0,0 @@
/*
This file is part of TALER
Copyright (C) 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file exchangedb/pg_batch2_reserves_in_insert.c
* @brief Implementation of the reserves_in_insert function for Postgres
* @author Joseph Xu
*/
#include "platform.h"
#include "taler_error_codes.h"
#include "taler_dbevents.h"
#include "taler_pq_lib.h"
#include "pg_batch2_reserves_in_insert.h"
#include "pg_helper.h"
#include "pg_start.h"
#include "pg_rollback.h"
#include "pg_start_read_committed.h"
#include "pg_commit.h"
#include "pg_reserves_get.h"
#include "pg_reserves_update.h"
#include "pg_setup_wire_target.h"
#include "pg_event_notify.h"
#include "pg_preflight.h"
/**
* Generate event notification for the reserve change.
*
* @param reserve_pub reserve to notfiy on
*/
static char *
compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub)
{
struct TALER_ReserveEventP rep = {
.header.size = htons (sizeof (rep)),
.header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING),
.reserve_pub = *reserve_pub
};
return GNUNET_PG_get_event_notify_channel (&rep.header);
}
static enum GNUNET_DB_QueryStatus
insert1(struct PostgresClosure *pg,
const struct TALER_EXCHANGEDB_ReserveInInfo reserves[1],
struct GNUNET_TIME_Timestamp expiry,
struct GNUNET_TIME_Timestamp gc,
struct TALER_PaytoHashP h_payto,
char *const * notify_s,
struct GNUNET_TIME_Timestamp reserve_expiration,
bool *transaction_duplicate,
bool *conflict,
uint64_t *reserve_uuid,
enum GNUNET_DB_QueryStatus results[1])
{
enum GNUNET_DB_QueryStatus qs2;
PREPARE (pg,
"batch1_reserve_create",
"SELECT "
" out_reserve_found AS conflicted"
",transaction_duplicate"
",ruuid AS reserve_uuid"
" FROM exchange_do_batch_reserves_in_insert"
" ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);");
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_timestamp (&gc),
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),
GNUNET_PQ_query_param_string (reserves[0].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
GNUNET_PQ_query_param_string (notify_s[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]),
GNUNET_PQ_result_spec_end
};
TALER_payto_hash (reserves[0].sender_account_details,
&h_payto);
qs2 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"batch1_reserve_create",
params,
rs);
if (qs2 < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to create reserves 1(%d)\n",
qs2);
results[0] = qs2;
return qs2;
}
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs2);
if ((! conflict[0]) && transaction_duplicate[0])
{
GNUNET_break (0);
TEH_PG_rollback (pg);
results[0] = GNUNET_DB_STATUS_HARD_ERROR;
return GNUNET_DB_STATUS_HARD_ERROR;
}
results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
return qs2;
}
static enum GNUNET_DB_QueryStatus
insert2 (struct PostgresClosure *pg,
const struct TALER_EXCHANGEDB_ReserveInInfo reserves[2],
struct GNUNET_TIME_Timestamp expiry,
struct GNUNET_TIME_Timestamp gc,
struct TALER_PaytoHashP h_payto,
char *const*notify_s,
struct GNUNET_TIME_Timestamp reserve_expiration,
bool *transaction_duplicate,
bool *conflict,
uint64_t *reserve_uuid,
enum GNUNET_DB_QueryStatus results[1])
{
enum GNUNET_DB_QueryStatus qs1;
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"
" 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,$21,$22);");
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_timestamp (&gc),
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),
GNUNET_PQ_query_param_string (reserves[0].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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),
GNUNET_PQ_query_param_string (reserves[1].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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]),
GNUNET_PQ_result_spec_end
};
TALER_payto_hash (reserves[0].sender_account_details,
&h_payto);
TALER_payto_hash (reserves[1].sender_account_details,
&h_payto);
qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"batch2_reserve_create",
params,
rs);
if (qs1 < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to create reserves 2(%d)\n",
qs1);
results[0]=qs1;
return qs1;
}
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1);
/* results[i] = (transaction_duplicate)
? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
: GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/
if (
((! conflict[0]) && (transaction_duplicate[0]))
||((! conflict[1]) && (transaction_duplicate[1]))
)
{
GNUNET_break (0);
TEH_PG_rollback (pg); //ROLLBACK
results[0] = GNUNET_DB_STATUS_HARD_ERROR;
return GNUNET_DB_STATUS_HARD_ERROR;
}
results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
return qs1;
}
static enum GNUNET_DB_QueryStatus
insert4 (struct PostgresClosure *pg,
const struct TALER_EXCHANGEDB_ReserveInInfo reserves[4],
struct GNUNET_TIME_Timestamp expiry,
struct GNUNET_TIME_Timestamp gc,
struct TALER_PaytoHashP h_payto,
char *const*notify_s,
struct GNUNET_TIME_Timestamp reserve_expiration,
bool *transaction_duplicate,
bool *conflict,
uint64_t *reserve_uuid,
enum GNUNET_DB_QueryStatus results[1])
{
enum GNUNET_DB_QueryStatus qs3;
PREPARE (pg,
"batch4_reserve_create",
"SELECT "
"out_reserve_found AS conflicted"
",out_reserve_found2 AS conflicted2"
",out_reserve_found3 AS conflicted3"
",out_reserve_found4 AS conflicted4"
",transaction_duplicate"
",transaction_duplicate2"
",transaction_duplicate3"
",transaction_duplicate4"
",ruuid AS reserve_uuid"
",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,$39, $40, $41,$42);");
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_timestamp (&gc),
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),
GNUNET_PQ_query_param_string (reserves[0].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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),
GNUNET_PQ_query_param_string (reserves[1].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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),
GNUNET_PQ_query_param_string (reserves[2].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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),
GNUNET_PQ_query_param_string (reserves[3].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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]),
GNUNET_PQ_result_spec_end
};
TALER_payto_hash (reserves[0].sender_account_details,
&h_payto);
TALER_payto_hash (reserves[1].sender_account_details,
&h_payto);
TALER_payto_hash (reserves[2].sender_account_details,
&h_payto);
TALER_payto_hash (reserves[3].sender_account_details,
&h_payto);
qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"batch4_reserve_create",
params,
rs);
if (qs3 < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to create reserves4 (%d)\n",
qs3);
results[0] = qs3;
return qs3;
}
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_break (0);
TEH_PG_rollback (pg);
results[0] = GNUNET_DB_STATUS_HARD_ERROR;
return GNUNET_DB_STATUS_HARD_ERROR;
}
results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
return qs3;
}
static enum GNUNET_DB_QueryStatus
insert8 (struct PostgresClosure *pg,
const struct TALER_EXCHANGEDB_ReserveInInfo reserves[8],
struct GNUNET_TIME_Timestamp expiry,
struct GNUNET_TIME_Timestamp gc,
struct TALER_PaytoHashP h_payto,
char *const*notify_s,
struct GNUNET_TIME_Timestamp reserve_expiration,
bool *transaction_duplicate,
bool *conflict,
uint64_t *reserve_uuid,
enum GNUNET_DB_QueryStatus results[1])
{
enum GNUNET_DB_QueryStatus qs3;
PREPARE (pg,
"batch8_reserve_create",
"SELECT "
"out_reserve_found AS conflicted"
",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_duplicate2"
",transaction_duplicate3"
",transaction_duplicate4"
",transaction_duplicate5"
",transaction_duplicate6"
",transaction_duplicate7"
",transaction_duplicate8"
",ruuid AS reserve_uuid"
",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,$75,$76,$77,$78,$79,$80,$81,$82);");
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_timestamp (&gc),
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),
GNUNET_PQ_query_param_string (reserves[0].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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),
GNUNET_PQ_query_param_string (reserves[1].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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),
GNUNET_PQ_query_param_string (reserves[2].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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),
GNUNET_PQ_query_param_string (reserves[3].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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),
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),
GNUNET_PQ_query_param_string (reserves[5].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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),
GNUNET_PQ_query_param_string (reserves[6].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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),
GNUNET_PQ_query_param_string (reserves[7].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
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]),
GNUNET_PQ_result_spec_end
};
TALER_payto_hash (reserves[0].sender_account_details,
&h_payto);
TALER_payto_hash (reserves[1].sender_account_details,
&h_payto);
TALER_payto_hash (reserves[2].sender_account_details,
&h_payto);
TALER_payto_hash (reserves[3].sender_account_details,
&h_payto);
TALER_payto_hash (reserves[4].sender_account_details,
&h_payto);
TALER_payto_hash (reserves[5].sender_account_details,
&h_payto);
TALER_payto_hash (reserves[6].sender_account_details,
&h_payto);
TALER_payto_hash (reserves[7].sender_account_details,
&h_payto);
qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"batch8_reserve_create",
params,
rs);
if (qs3 < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to create reserves8 (%d)\n",
qs3);
results[0]=qs3;
return qs3;
}
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3);
/* results[i] = (transaction_duplicate)
? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
: GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/
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_break (0);
TEH_PG_rollback (pg);
results[0]=GNUNET_DB_STATUS_HARD_ERROR;
return GNUNET_DB_STATUS_HARD_ERROR;
}
results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
return qs3;
}
enum GNUNET_DB_QueryStatus
TEH_PG_batch2_reserves_in_insert (void *cls,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserves,
unsigned int reserves_length,
unsigned int batch_size,
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;
struct GNUNET_TIME_Timestamp expiry;
struct GNUNET_TIME_Timestamp gc;
struct TALER_PaytoHashP h_payto;
uint64_t reserve_uuid[reserves_length];
bool transaction_duplicate[reserves_length];
bool need_update = false;
bool t_duplicate=false;
struct GNUNET_TIME_Timestamp reserve_expiration
= GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time);
bool conflicts[reserves_length];
char *notify_s[reserves_length];
if (GNUNET_OK !=
TEH_PG_preflight (pg))
{
GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR;
}
expiry = GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_absolute_add (reserves->execution_time.abs_time,
pg->idle_reserve_expiration_time));
gc = GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
pg->legal_reserve_expiration_time));
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;i<reserves_length;i++)
{
const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i];
notify_s[i] = compute_notify_on_reserve (reserve->reserve_pub);
}
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],
expiry,
gc,
h_payto,
&notify_s[i],
reserve_expiration,
&transaction_duplicate[i],
&conflicts[i],
&reserve_uuid[i],
&results[i]);
if (qs1<0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to create reserve batch_8 (%d)\n",
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];
t_duplicate |= transaction_duplicate[i];
t_duplicate |= transaction_duplicate[i+1];
t_duplicate |= transaction_duplicate[i+2];
t_duplicate |= transaction_duplicate[i+3];
t_duplicate |= transaction_duplicate[i+4];
t_duplicate |= transaction_duplicate[i+5];
t_duplicate |= transaction_duplicate[i+6];
t_duplicate |= transaction_duplicate[i+7];
i+=8;
continue;
}
switch (bs)
{
case 7:
case 6 :
case 5:
case 4 :
qs4=insert4(pg,
&reserves[i],
expiry,
gc,
h_payto,
&notify_s[i],
reserve_expiration,
&transaction_duplicate[i],
&conflicts[i],
&reserve_uuid[i],
&results[i]);
if (qs4<0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to create reserve batch_4 (%d)\n",
qs4);
return qs4;
}
need_update |= conflicts[i];
need_update |= conflicts[i+1];
need_update |= conflicts[i+2];
need_update |= conflicts[i+3];
t_duplicate |= transaction_duplicate[i];
t_duplicate |= transaction_duplicate[i+1];
t_duplicate |= transaction_duplicate[i+2];
t_duplicate |= transaction_duplicate[i+3];
// fprintf(stdout, "reserve_uuid : %ld %ld %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1], reserve_uuid[i+2], reserve_uuid[i+3]);
i += 4;
break;
case 3:
case 2:
qs5=insert2(pg,
&reserves[i],
expiry,
gc,
h_payto,
&notify_s[i],
reserve_expiration,
&transaction_duplicate[i],
&conflicts[i],
&reserve_uuid[i],
&results[i]);
if (qs5<0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to create reserve batch_2 (%d)\n",
qs5);
return qs5;
}
need_update |= conflicts[i];
need_update |= conflicts[i+1];
t_duplicate |= transaction_duplicate[i];
t_duplicate |= transaction_duplicate[i+1];
results[i] = (t_duplicate)
? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
: GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
// fprintf(stdout, "reserve_uuid : %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1]);
i += 2;
break;
case 1:
qs2 = insert1(pg,
&reserves[i],
expiry,
gc,
h_payto,
&notify_s[i],
reserve_expiration,
&transaction_duplicate[i],
&conflicts[i],
&reserve_uuid[i],
&results[i]);
if (qs2<0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to create reserve batch_1 (%d)\n)"
,qs2);
return qs2;
}
need_update |= conflicts[i];
t_duplicate |= transaction_duplicate[i];
// fprintf(stdout, "reserve uuid : %ld c :%d t:%d\n", reserve_uuid[i], conflicts[i], transaction_duplicate[i]);
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;
}
}
enum GNUNET_DB_QueryStatus qs3;
PREPARE (pg,
"reserves_update",
"SELECT"
" out_duplicate AS duplicate "
"FROM exchange_do_batch_reserves_update"
" ($1,$2,$3,$4,$5,$6,$7,$8);");
for (unsigned int i = 0; i<reserves_length; i++)
{
if (! conflicts[i])
continue;
{
bool duplicate;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (reserves[i].reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_uint64 (&reserves[i].wire_reference),
TALER_PQ_query_param_amount (reserves[i].balance),
GNUNET_PQ_query_param_string (reserves[i].exchange_account_name),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_string (notify_s[i]),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("duplicate",
&duplicate),
GNUNET_PQ_result_spec_end
};
qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"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)
return cs;
}
exit:
for (unsigned int i = 0; i<reserves_length; i++)
GNUNET_free (notify_s[i]);
return reserves_length;
}

View File

@ -1,34 +0,0 @@
/*
This file is part of TALER
Copyright (C) 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file exchangedb/pg_batch2_reserves_in_insert.h
* @brief implementation of the batch2_reserves_in_insert function for Postgres
* @author Joseph XU
*/
#ifndef PG_BATCH2_RESERVES_IN_INSERT_H
#define PG_BATCH2_RESERVES_IN_INSERT_H
#include "taler_util.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
enum GNUNET_DB_QueryStatus
TEH_PG_batch2_reserves_in_insert (void *cls,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserves,
unsigned int reserves_length,
unsigned int batch_size,
enum GNUNET_DB_QueryStatus *results);
#endif

View File

@ -1,595 +0,0 @@
/*
This file is part of TALER
Copyright (C) 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file exchangedb/pg_batch_reserves_in_insert.c
* @brief Implementation of the reserves_in_insert function for Postgres
* @author Joseph Xu
*/
#include "platform.h"
#include "taler_error_codes.h"
#include "taler_dbevents.h"
#include "taler_pq_lib.h"
#include "pg_batch_reserves_in_insert.h"
#include "pg_helper.h"
#include "pg_start.h"
#include "pg_rollback.h"
#include "pg_start_read_committed.h"
#include "pg_commit.h"
#include "pg_reserves_get.h"
#include "pg_reserves_update.h"
#include "pg_setup_wire_target.h"
#include "pg_event_notify.h"
#include "pg_preflight.h"
/**
* Generate event notification for the reserve change.
*
* @param reserve_pub reserve to notfiy on
*/
static char *
compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub)
{
struct TALER_ReserveEventP rep = {
.header.size = htons (sizeof (rep)),
.header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING),
.reserve_pub = *reserve_pub
};
return GNUNET_PG_get_event_notify_channel (&rep.header);
}
static enum GNUNET_DB_QueryStatus
insert1(struct PostgresClosure *pg,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserve,
struct GNUNET_TIME_Timestamp expiry,
struct GNUNET_TIME_Timestamp gc,
struct TALER_PaytoHashP h_payto,
const char *notify_s,
struct GNUNET_TIME_Timestamp reserve_expiration,
bool *transaction_duplicate,
bool *conflict,
uint64_t *reserve_uuid)
{
enum GNUNET_DB_QueryStatus qs2;
PREPARE (pg,
"reserve_creates",
"SELECT "
"out_reserve_found AS conflicted"
",transaction_duplicate"
",ruuid AS reserve_uuid"
" FROM exchange_do_batch_reserves_in_insert"
" ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);");
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&reserve->reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_timestamp (&gc),
GNUNET_PQ_query_param_uint64 (&reserve->wire_reference),
TALER_PQ_query_param_amount (&reserve->balance),
GNUNET_PQ_query_param_string (reserve->exchange_account_name),
GNUNET_PQ_query_param_timestamp (&reserve->execution_time),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_string (reserve->sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
GNUNET_PQ_query_param_string (notify_s),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("conflicted",
conflict),
GNUNET_PQ_result_spec_bool ("transaction_duplicate",
transaction_duplicate),
GNUNET_PQ_result_spec_uint64 ("reserve_uuid",
reserve_uuid),
GNUNET_PQ_result_spec_end
};
TALER_payto_hash (reserve->sender_account_details,
&h_payto);
/* Note: query uses 'on conflict do nothing' */
qs2 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"reserve_creates",
params,
rs);
if (qs2 < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to create reserves (%d)\n",
qs2);
return qs2;
}
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs2);
if ((*conflict) && (*transaction_duplicate))
{
GNUNET_break (0);
TEH_PG_rollback (pg);
return GNUNET_DB_STATUS_HARD_ERROR;
}
return qs2;
}
static enum GNUNET_DB_QueryStatus
insert2 (struct PostgresClosure *pg,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserve0,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserve1,
struct GNUNET_TIME_Timestamp expiry,
struct GNUNET_TIME_Timestamp gc,
struct TALER_PaytoHashP h_payto,
const char *notify_s,
struct GNUNET_TIME_Timestamp reserve_expiration,
bool *transaction_duplicate,
bool *transaction_duplicate2,
bool *conflict,
bool *conflict2,
uint64_t *reserve_uuid,
uint64_t *reserve_uuid2)
{
PREPARE (pg,
"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"
" 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,$21);");
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&reserve0->reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_timestamp (&gc),
GNUNET_PQ_query_param_uint64 (&reserve0->wire_reference),
TALER_PQ_query_param_amount (&reserve0->balance),
GNUNET_PQ_query_param_string (reserve0->exchange_account_name),
GNUNET_PQ_query_param_timestamp (&reserve0->execution_time),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_string (reserve0->sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
GNUNET_PQ_query_param_string (notify_s),
GNUNET_PQ_query_param_auto_from_type (&reserve1->reserve_pub),
GNUNET_PQ_query_param_uint64 (&reserve1->wire_reference),
TALER_PQ_query_param_amount (&reserve1->balance),
GNUNET_PQ_query_param_string (reserve1->exchange_account_name),
GNUNET_PQ_query_param_timestamp (&reserve1->execution_time),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_string (reserve1->sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("conflicted",
conflict),
GNUNET_PQ_result_spec_bool ("conflicted2",
conflict2),
GNUNET_PQ_result_spec_bool ("transaction_duplicate",
transaction_duplicate),
GNUNET_PQ_result_spec_bool ("transaction_duplicate2",
transaction_duplicate2),
GNUNET_PQ_result_spec_uint64 ("reserve_uuid",
reserve_uuid),
GNUNET_PQ_result_spec_uint64 ("reserve_uuid2",
reserve_uuid2),
GNUNET_PQ_result_spec_end
};
TALER_payto_hash (reserve0->sender_account_details,
&h_payto);
TALER_payto_hash (reserve1->sender_account_details,
&h_payto);
qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"reserve_create",
params,
rs);
if (qs1 < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to create reserves (%d)\n",
qs1);
return qs1;
}
/*
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1);
results[i] = (transaction_duplicate)
? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
: GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/
if ((*conflict) && (*transaction_duplicate) ||((*conflict2) && (*transaction_duplicate2)))
{
GNUNET_break (0);
TEH_PG_rollback (pg);
return GNUNET_DB_STATUS_HARD_ERROR;
}
}
static enum GNUNET_DB_QueryStatus
insert4 (struct PostgresClosure *pg,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserve0,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserve1,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserve2,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserve3,
struct GNUNET_TIME_Timestamp expiry,
struct GNUNET_TIME_Timestamp gc,
struct TALER_PaytoHashP h_payto,
const char *notify_s,
struct GNUNET_TIME_Timestamp reserve_expiration,
bool *transaction_duplicate,
bool *transaction_duplicate2,
bool *transaction_duplicate3,
bool *transaction_duplicate4,
bool *conflict,
bool *conflict2,
bool *conflict3,
bool *conflict4,
uint64_t *reserve_uuid,
uint64_t *reserve_uuid2,
uint64_t *reserve_uuid3,
uint64_t *reserve_uuid4)
{
PREPARE (pg,
"reserve_create",
"SELECT "
"out_reserve_found AS conflicted"
",out_reserve_found2 AS conflicted2"
",out_reserve_found3 AS conflicted3"
",out_reserve_found4 AS conflicted4"
",transaction_duplicate"
",transaction_duplicate2"
",transaction_duplicate3"
",transaction_duplicate4"
",ruuid AS reserve_uuid"
",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,$39);");
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&reserve0->reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_timestamp (&gc),
GNUNET_PQ_query_param_uint64 (&reserve0->wire_reference),
TALER_PQ_query_param_amount (&reserve0->balance),
GNUNET_PQ_query_param_string (reserve0->exchange_account_name),
GNUNET_PQ_query_param_timestamp (&reserve0->execution_time),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_string (reserve0->sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
GNUNET_PQ_query_param_string (notify_s),
GNUNET_PQ_query_param_auto_from_type (&reserve1->reserve_pub),
GNUNET_PQ_query_param_uint64 (&reserve1->wire_reference),
TALER_PQ_query_param_amount (&reserve1->balance),
GNUNET_PQ_query_param_string (reserve1->exchange_account_name),
GNUNET_PQ_query_param_timestamp (&reserve1->execution_time),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_string (reserve1->sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
GNUNET_PQ_query_param_auto_from_type (&reserve2->reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_timestamp (&gc),
GNUNET_PQ_query_param_uint64 (&reserve2->wire_reference),
TALER_PQ_query_param_amount (&reserve2->balance),
GNUNET_PQ_query_param_string (reserve2->exchange_account_name),
GNUNET_PQ_query_param_timestamp (&reserve2->execution_time),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_string (reserve2->sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
GNUNET_PQ_query_param_auto_from_type (&reserve3->reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_timestamp (&gc),
GNUNET_PQ_query_param_uint64 (&reserve3->wire_reference),
TALER_PQ_query_param_amount (&reserve3->balance),
GNUNET_PQ_query_param_string (reserve3->exchange_account_name),
GNUNET_PQ_query_param_timestamp (&reserve3->execution_time),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_string (reserve3->sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration)
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("conflicted",
conflict),
GNUNET_PQ_result_spec_bool ("conflicted2",
conflict2),
GNUNET_PQ_result_spec_bool ("conflicted3",
conflict3),
GNUNET_PQ_result_spec_bool ("conflicted4",
conflict4),
GNUNET_PQ_result_spec_bool ("transaction_duplicate",
transaction_duplicate),
GNUNET_PQ_result_spec_bool ("transaction_duplicate2",
transaction_duplicate2),
GNUNET_PQ_result_spec_bool ("transaction_duplicate3",
transaction_duplicate3),
GNUNET_PQ_result_spec_bool ("transaction_duplicate4",
transaction_duplicate4),
GNUNET_PQ_result_spec_uint64 ("reserve_uuid",
reserve_uuid),
GNUNET_PQ_result_spec_uint64 ("reserve_uuid2",
reserve_uuid2),
GNUNET_PQ_result_spec_uint64 ("reserve_uuid3",
reserve_uuid3),
GNUNET_PQ_result_spec_uint64 ("reserve_uuid4",
reserve_uuid4),
GNUNET_PQ_result_spec_end
};
TALER_payto_hash (reserve0->sender_account_details,
&h_payto);
TALER_payto_hash (reserve1->sender_account_details,
&h_payto);
qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"reserve_create",
params,
rs);
if (qs1 < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to create reserves (%d)\n",
qs1);
return qs1;
}
/*
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1);
results[i] = (transaction_duplicate)
? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
: GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/
if ((*conflict) && (*transaction_duplicate) ||((*conflict2) && (*transaction_duplicate2)))
{
GNUNET_break (0);
TEH_PG_rollback (pg);
return GNUNET_DB_STATUS_HARD_ERROR;
}
}
enum GNUNET_DB_QueryStatus
TEH_PG_batch2_reserves_in_insert (void *cls,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserves,
unsigned int reserves_length,
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;
struct GNUNET_TIME_Timestamp expiry;
struct GNUNET_TIME_Timestamp gc;
struct TALER_PaytoHashP h_payto;
uint64_t reserve_uuid[reserves_length];
bool conflicted;
bool conflicted2;
bool transaction_duplicate[reserves_length];
bool need_update = false;
bool need_update2 = false;
struct GNUNET_TIME_Timestamp reserve_expiration
= GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time);
bool conflicts[reserves_length];
char *notify_s[reserves_length];
if (GNUNET_OK !=
TEH_PG_preflight (pg))
{
GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR;
}
expiry = GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_absolute_add (reserves->execution_time.abs_time,
pg->idle_reserve_expiration_time));
gc = GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
pg->legal_reserve_expiration_time));
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;i<reserves_length;i++)
{
const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i];
notify_s[i] = compute_notify_on_reserve (&reserve->reserve_pub);
}
unsigned int i=0;
while (i < reserves_length)
{
if (reserves_length - i >= 4)
{
qs4=insert4(pg,
&reserves[i],
&reserves[i+2],
&reserves[i+3],
&reserves[i+4],
expiry,
gc,
h_payto,
&notify_s[i],
reserve_expiration,
&transaction_duplicate[i],
&transaction_duplicate[i+1],
&transaction_duplicate[i+2],
&transaction_duplicate[i+3],
&conflicts[i],
&conflicts[i+1],
&conflicts[i+2],
&conflicts[i+3],
&reserve_uuid[i],
&reserve_uuid[i+1],
&reserve_uuid[i+2],
&reserve_uuid[i+3]);
need_update |= conflicts[i];
need_update |= conflicts[i+1];
need_update |= conflicts[i+2];
need_update |= conflicts[i+3];
i += 4;
continue;
}
switch (reserves_length - i)
{
case 3:
case 2:
qs5=insert2(pg,
&reserves[i],
&reserves[i+1],
expiry,
gc,
h_payto,
notify_s[i],
reserve_expiration,
&transaction_duplicate[i],
&transaction_duplicate[i+1],
&conflicts[i],
&conflicts[i+1],
&reserve_uuid[i],
&reserve_uuid[i+1]);
need_update |= conflicts[i];
need_update |= conflicts[i+1];
i += 2;
break;
case 1:
qs2 = insert1(pg,
&reserves[i],
expiry,
gc,
h_payto,
notify_s[i],
reserve_expiration,
&transaction_duplicate[i],
&conflicts[i],
&reserve_uuid[i]);
need_update |= conflicts[i];
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)
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;
}
}
enum GNUNET_DB_QueryStatus qs3;
PREPARE (pg,
"reserves_in_add_transaction",
"CALL exchange_do_batch_reserves_update"
" ($1,$2,$3,$4,$5,$6,$7,$8,$9);");
for (unsigned int i=0;i<reserves_length;i++)
{
if (! conflicts[i])
continue;
{
const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i];
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (&reserve->reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_uint64 (&reserve->wire_reference),
TALER_PQ_query_param_amount (&reserve->balance),
GNUNET_PQ_query_param_string (reserve->exchange_account_name),
GNUNET_PQ_query_param_bool (conflicted),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_string (notify_s[i]),
GNUNET_PQ_query_param_end
};
qs3 = GNUNET_PQ_eval_prepared_non_select (pg->conn,
"reserves_in_add_transaction",
params);
if (qs3<0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to update reserves (%d)\n",
qs3);
return qs3;
}
}
}
{
enum GNUNET_DB_QueryStatus cs;
cs = TEH_PG_commit (pg);
if (cs < 0)
return cs;
}
exit:
for (unsigned int i=0;i<reserves_length;i++)
GNUNET_free (notify_s[i]);
return reserves_length;
}

View File

@ -1,252 +0,0 @@
/*
This file is part of TALER
Copyright (C) 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file exchangedb/pg_batch_reserves_in_insert.c
* @brief Implementation of the reserves_in_insert function for Postgres
* @author Joseph Xu
*/
#include "platform.h"
#include "taler_error_codes.h"
#include "taler_dbevents.h"
#include "taler_pq_lib.h"
#include "pg_batch_reserves_in_insert.h"
#include "pg_helper.h"
#include "pg_start.h"
#include "pg_rollback.h"
#include "pg_start_read_committed.h"
#include "pg_commit.h"
#include "pg_reserves_get.h"
#include "pg_reserves_update.h"
#include "pg_setup_wire_target.h"
#include "pg_event_notify.h"
#include "pg_preflight.h"
/**
* Generate event notification for the reserve change.
*
* @param reserve_pub reserve to notfiy on
*/
static char *
compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub)
{
struct TALER_ReserveEventP rep = {
.header.size = htons (sizeof (rep)),
.header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING),
.reserve_pub = *reserve_pub
};
return GNUNET_PG_get_event_notify_channel (&rep.header);
}
enum GNUNET_DB_QueryStatus
TEH_PG_batch_reserves_in_insert (
void *cls,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserves,
unsigned int reserves_length,
enum GNUNET_DB_QueryStatus *results)
{
struct PostgresClosure *pg = cls;
enum GNUNET_DB_QueryStatus qs1;
struct GNUNET_TIME_Timestamp expiry;
struct GNUNET_TIME_Timestamp gc;
struct TALER_PaytoHashP h_payto;
uint64_t reserve_uuid;
struct GNUNET_TIME_Timestamp reserve_expiration
= GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time);
bool conflicts[reserves_length];
char *notify_s[reserves_length];
if (GNUNET_OK !=
TEH_PG_preflight (pg))
{
GNUNET_break (0);
return GNUNET_DB_STATUS_HARD_ERROR;
}
PREPARE (pg,
"reserve_create",
"SELECT "
"out_reserve_found AS conflicted"
",transaction_duplicate"
",ruuid AS reserve_uuid"
" FROM exchange_do_batch_reserves_in_insert"
" ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);");
expiry = GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_absolute_add (reserves->execution_time.abs_time,
pg->idle_reserve_expiration_time));
gc = GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
pg->legal_reserve_expiration_time));
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; i<reserves_length; i++)
{
const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i];
notify_s[i] = compute_notify_on_reserve (reserve->reserve_pub);
}
bool need_update = false;
for (unsigned int i = 0; i<reserves_length; i++)
{
bool conflicted;
bool transaction_duplicate;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (reserves[i].reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_timestamp (&gc),
GNUNET_PQ_query_param_uint64 (&reserves[i].wire_reference),
TALER_PQ_query_param_amount (reserves[i].balance),
GNUNET_PQ_query_param_string (reserves[i].exchange_account_name),
GNUNET_PQ_query_param_timestamp (&reserves[i].execution_time),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_string (reserves[i].sender_account_details),
GNUNET_PQ_query_param_timestamp (&reserve_expiration),
GNUNET_PQ_query_param_string (notify_s[i]),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("conflicted",
&conflicted),
GNUNET_PQ_result_spec_bool ("transaction_duplicate",
&transaction_duplicate),
GNUNET_PQ_result_spec_uint64 ("reserve_uuid",
&reserve_uuid),
GNUNET_PQ_result_spec_end
};
TALER_payto_hash (reserves[i].sender_account_details,
&h_payto);
/* Note: query uses 'on conflict do nothing' */
qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"reserve_create",
params,
rs);
if (qs1 < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to create reserves (%d)\n",
qs1);
results[i] = qs1;
return qs1;
}
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1);
conflicts[i] = conflicted;
// fprintf(stdout, "%d", conflicts[i]);
if (conflicts[i] && transaction_duplicate)
{
GNUNET_break (0);
results[i] = GNUNET_DB_STATUS_HARD_ERROR;
TEH_PG_rollback (pg);
return GNUNET_DB_STATUS_HARD_ERROR;
}
results[i] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
need_update |= conflicted;
}
// commit
{
enum GNUNET_DB_QueryStatus cs;
cs = TEH_PG_commit (pg);
if (cs < 0)
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;
}
}
enum GNUNET_DB_QueryStatus qs2;
PREPARE (pg,
"reserves_in_add_transaction",
"SELECT"
" out_duplicate AS duplicate"
" FROM exchange_do_batch_reserves_update"
" ($1,$2,$3,$4,$5,$6,$7,$8);");
for (unsigned int i = 0; i<reserves_length; i++)
{
if (! conflicts[i])
continue;
{
bool duplicate;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (reserves[i].reserve_pub),
GNUNET_PQ_query_param_timestamp (&expiry),
GNUNET_PQ_query_param_uint64 (&reserves[i].wire_reference),
TALER_PQ_query_param_amount (reserves[i].balance),
GNUNET_PQ_query_param_string (reserves[i].exchange_account_name),
GNUNET_PQ_query_param_auto_from_type (&h_payto),
GNUNET_PQ_query_param_string (notify_s[i]),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_bool ("duplicate",
&duplicate),
GNUNET_PQ_result_spec_end
};
qs2 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"reserves_in_add_transaction",
params,
rs);
if (qs2 < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to update reserves (%d)\n",
qs2);
results[i] = qs2;
return qs2;
}
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)
return cs;
}
exit:
for (unsigned int i = 0; i<reserves_length; i++)
GNUNET_free (notify_s[i]);
return reserves_length;
}

View File

@ -1,35 +0,0 @@
/*
This file is part of TALER
Copyright (C) 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file exchangedb/pg_batch_reserves_in_insert.h
* @brief implementation of the batch_reserves_in_insert function for Postgres
* @author Christian Grothoff
*/
#ifndef PG_BATCH_RESERVES_IN_INSERT_H
#define PG_BATCH_RESERVES_IN_INSERT_H
#include "taler_util.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
enum GNUNET_DB_QueryStatus
TEH_PG_batch_reserves_in_insert (void *cls,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserves,
unsigned int reserves_length,
enum GNUNET_DB_QueryStatus *results);
#endif

View File

@ -55,7 +55,7 @@ struct LinkDataContext
/**
* Status, set to #GNUNET_SYSERR on errors,
*/
int status;
enum GNUNET_GenericReturnValue status;
};
@ -195,15 +195,13 @@ TEH_PG_get_link_data (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Bad mode `%s' specified\n",
mode);
percent_refund = 0;
}
if (NULL==mode)
percent_refund=0;
}
switch (percent_refund)
{
case 0:
query="get_link";
query = "get_link";
PREPARE (pg,
query,
"SELECT "
@ -225,7 +223,7 @@ TEH_PG_get_link_data (void *cls,
" ORDER BY tp.transfer_pub, rrc.freshcoin_index ASC");
break;
case 1:
query="get_link_v1";
query = "get_link_v1";
PREPARE (pg,
query,
"WITH rc AS MATERIALIZED ("
@ -252,7 +250,7 @@ TEH_PG_get_link_data (void *cls,
" ORDER BY tp.transfer_pub, rrc.freshcoin_index ASC");
break;
case 2:
query="get_link_v2";
query = "get_link_v2";
PREPARE (pg,
query,
"SELECT"
@ -300,5 +298,3 @@ TEH_PG_get_link_data (void *cls,
return GNUNET_DB_STATUS_HARD_ERROR;
return qs;
}

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2022 Taler Systems SA
Copyright (C) 2022, 2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@ -33,15 +33,16 @@ TEH_PG_get_ready_deposit (void *cls,
struct TALER_MerchantPublicKeyP *merchant_pub,
char **payto_uri)
{
static int choose_mode = -2;
struct PostgresClosure *pg = cls;
struct GNUNET_TIME_Absolute now = {0};
struct GNUNET_TIME_Absolute now
= GNUNET_TIME_absolute_get ();
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_absolute_time (&now),
GNUNET_PQ_query_param_uint64 (&start_shard_row),
GNUNET_PQ_query_param_uint64 (&end_shard_row),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
merchant_pub),
@ -49,22 +50,13 @@ TEH_PG_get_ready_deposit (void *cls,
payto_uri),
GNUNET_PQ_result_spec_end
};
now = GNUNET_TIME_absolute_round_down (GNUNET_TIME_absolute_get (),
pg->aggregator_shift);
GNUNET_assert (start_shard_row < end_shard_row);
GNUNET_assert (end_shard_row <= INT32_MAX);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Finding ready deposits by deadline %s (%llu)\n",
GNUNET_TIME_absolute2s (now),
(unsigned long long) now.abs_value_us);
int choose_mode =-2;
const char *query;
if (-2 == choose_mode)
{
const char *mode = getenv ("NEW_LOGIC");
const char *mode = getenv ("TALER_POSTGRES_GET_READY_LOGIC");
char dummy;
if ( (NULL==mode) ||
(1 != sscanf (mode,
"%d%c",
@ -75,155 +67,53 @@ TEH_PG_get_ready_deposit (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Bad mode `%s' specified\n",
mode);
choose_mode = 0;
}
if (NULL==mode)
choose_mode=0;
}
switch (choose_mode)
{
case 0:
query="deposits_get_ready";
query = "deposits_get_ready-v5";
PREPARE (pg,
query,
"SELECT"
" payto_uri"
",merchant_pub"
" FROM deposits_by_ready dbr"
" JOIN deposits dep"
" ON (dbr.coin_pub = dep.coin_pub AND"
" dbr.deposit_serial_id = dep.deposit_serial_id)"
" FROM deposits dep"
" JOIN wire_targets wt"
" USING (wire_target_h_payto)"
" WHERE dbr.wire_deadline<=$1"
" AND dbr.shard >= $2"
" AND dbr.shard <= $3"
" WHERE NOT (done OR policy_blocked)"
" AND dep.wire_deadline<=$1"
" AND dep.shard >= $2"
" AND dep.shard <= $3"
" ORDER BY "
" dbr.wire_deadline ASC"
" ,dbr.shard ASC"
" dep.wire_deadline ASC"
" ,dep.shard ASC"
" LIMIT 1;");
break;
case 1:
query="deposits_get_ready_v1";
query = "deposits_get_ready-v6";
PREPARE (pg,
query,
"WITH rc AS MATERIALIZED ("
" SELECT"
" coin_pub"
",deposit_serial_id"
" FROM deposits_by_ready"
" WHERE"
" wire_deadline<=$1"
" AND shard >= $2"
" AND shard <= $3"
" ORDER BY "
" wire_deadline ASC"
" ,shard ASC"
" LIMIT 1"
")"
"SELECT"
" wt.payto_uri"
",dep.merchant_pub"
" FROM ("
" SELECT"
" wire_target_h_payto"
",merchant_pub"
" FROM deposits"
" WHERE coin_pub=(SELECT coin_pub FROM rc)"
" AND deposit_serial_id=(SELECT deposit_serial_id FROM rc)"
") dep"
" JOIN wire_targets wt"
" ON (dep.wire_target_h_payto = wt.wire_target_h_payto)"
);
break;
case 2:
query = "stored_procedure_get_ready_deposit";
PREPARE (pg,
query,
"SELECT"
" out_payto_uri AS payto_uri"
",out_merchant_pub AS merchant_pub"
" FROM"
" exchange_do_get_ready_deposit"
" ($1, $2, $3) ");
break;
case 3:
query="deposits_get_ready_v3";
PREPARE (pg,
query,
"WITH rc AS MATERIALIZED ("
" SELECT"
" coin_pub"
",deposit_serial_id"
" FROM deposits_by_ready"
" WHERE"
" wire_deadline<=$1"
" AND shard >= $2"
" AND shard <= $3"
" ORDER BY "
" wire_deadline ASC"
" ,shard ASC"
" LIMIT 1"
")"
"SELECT"
" wt.payto_uri"
",dep.merchant_pub"
" FROM ("
" SELECT"
" wire_target_h_payto"
",merchant_pub"
",coin_pub"
" FROM deposits"
" WHERE coin_pub=(SELECT coin_pub FROM rc)"
" AND deposit_serial_id=(SELECT deposit_serial_id FROM rc)"
") dep"
" JOIN wire_targets wt"
" ON (dep.wire_target_h_payto = wt.wire_target_h_payto)"
" JOIN rc"
" ON (dep.coin_pub=rc.coin_pub)"
);
break;
case 4:
query="deposits_get_ready_v4";
PREPARE (pg,
query,
"WITH rc AS MATERIALIZED ("
" SELECT"
" coin_pub"
",deposit_serial_id"
" FROM deposits_by_ready"
" WHERE"
" wire_deadline<=$1"
" AND shard >= $2"
" AND shard <= $3"
" ORDER BY "
" wire_deadline ASC"
" ,shard ASC"
" LIMIT 1"
"),"
"WITH rv AS MATERIALIZED ("
" SELECT"
" payto_uri"
" merchant_pub"
",wire_target_h_payto"
" FROM wire_targets"
" FROM deposits"
" WHERE NOT (done OR policy_blocked)"
" AND wire_deadline<=$1"
" AND shard >= $2"
" AND shard <= $3"
" ORDER BY wire_deadline ASC"
" ,shard ASC"
" LIMIT 1"
")"
"SELECT"
" rv.payto_uri"
",dep.merchant_pub"
" FROM ("
" SELECT"
" wire_target_h_payto"
",merchant_pub"
" FROM deposits"
" WHERE coin_pub=(SELECT coin_pub FROM rc)"
" AND deposit_serial_id=(SELECT deposit_serial_id FROM rc)"
") dep"
" JOIN rv"
" ON (rv.wire_target_h_payto=dep.wire_target_h_payto)"
);
" wt.payto_uri"
",rc.merchant_pub"
" FROM wire_targets wt"
" JOIN rc"
" USING (wire_target_h_payto);");
break;
default:
GNUNET_break (0);

File diff suppressed because it is too large Load Diff

View File

@ -24,28 +24,26 @@
#include "taler_util.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
/**
* Insert an incoming transaction into reserves. New reserves are also
* created through this function. Started within the scope of an ongoing
* transaction.
* created through this function. Runs its own transaction(s).
*
* @param cls the `struct PostgresClosure` with the plugin-specific state
* @param reserve_pub public key of the reserve
* @param balance the amount that has to be added to the reserve
* @param execution_time when was the amount added
* @param sender_account_details account information for the sender (payto://-URL)
* @param exchange_account_section name of the section in the configuration for the exchange's
* account into which the deposit was made
* @param wire_ref unique reference identifying the wire transfer
* @param reserves array of reserves to insert
* @param reserves_length length of the @a reserves array
* @param batch_size how many inserts to do in one go
* @param[out] results set to query status per reserve, must be of length @a reserves_length
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
TEH_PG_reserves_in_insert (void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *balance,
struct GNUNET_TIME_Timestamp execution_time,
const char *sender_account_details,
const char *exchange_account_section,
uint64_t wire_ref);
TEH_PG_reserves_in_insert (
void *cls,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserves,
unsigned int reserves_length,
unsigned int batch_size,
enum GNUNET_DB_QueryStatus *results);
#endif

View File

@ -129,7 +129,7 @@ TEH_PG_select_refunds_by_coin (
if (-2 == percent_refund)
{
const char *mode = getenv ("NEW_LOGIC");
const char *mode = getenv ("TALER_POSTGRES_SELECT_REFUNDS_BY_COIN_LOGIC");
char dummy;
if ( (NULL==mode) ||
@ -142,9 +142,8 @@ TEH_PG_select_refunds_by_coin (
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Bad mode `%s' specified\n",
mode);
percent_refund = 0;
}
if (NULL==mode)
percent_refund=0;
}
switch (percent_refund)

View File

@ -203,8 +203,6 @@
#include "pg_reserves_update.h"
#include "pg_setup_wire_target.h"
#include "pg_compute_shard.h"
#include "pg_batch_reserves_in_insert.h"
#include "pg_batch2_reserves_in_insert.h"
#include "pg_insert_kyc_attributes.h"
#include "pg_update_kyc_attributes.h"
#include "pg_select_similar_kyc_attributes.h"
@ -747,10 +745,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
= &TEH_PG_select_purse_by_merge_pub;
plugin->set_purse_balance
= &TEH_PG_set_purse_balance;
plugin->batch_reserves_in_insert
= &TEH_PG_batch_reserves_in_insert;
plugin->batch2_reserves_in_insert
= &TEH_PG_batch2_reserves_in_insert;
plugin->insert_kyc_attributes
= &TEH_PG_insert_kyc_attributes;
plugin->update_kyc_attributes

View File

@ -1,196 +0,0 @@
/*
This file is part of TALER
Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file exchangedb/test_exchangedb_by_j.c
* @brief test cases for DB interaction functions
* @author Joseph Xu
*/
#include "platform.h"
#include "taler_exchangedb_lib.h"
#include "taler_json_lib.h"
#include "taler_exchangedb_plugin.h"
/**o
* Global result from the testcase.
*/
static int result;
/**
* Report line of error if @a cond is true, and jump to label "drop".
*/
#define FAILIF(cond) \
do { \
if (! (cond)) {break;} \
GNUNET_break (0); \
goto drop; \
} while (0)
/**
* Initializes @a ptr with random data.
*/
#define RND_BLK(ptr) \
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr))
/**
* Initializes @a ptr with zeros.
*/
#define ZR_BLK(ptr) \
memset (ptr, 0, sizeof (*ptr))
/**
* Currency we use. Must match test-exchange-db-*.conf.
*/
#define CURRENCY "EUR"
/**
* Database plugin under test.
*/
static struct TALER_EXCHANGEDB_Plugin *plugin;
/**
* Main function that will be run by the scheduler.
*
* @param cls closure with config
*/
static void
run (void *cls)
{
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
const uint32_t num_partitions = 10;
if (NULL ==
(plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
{
GNUNET_break (0);
result = 77;
return;
}
(void) plugin->drop_tables (plugin->cls);
if (GNUNET_OK !=
plugin->create_tables (plugin->cls,
true,
num_partitions))
{
GNUNET_break (0);
result = 77;
goto cleanup;
}
for (unsigned int i = 0; i< 8; i++)
{
static unsigned int batches[] = {1, 1, 2, 3, 4, 16, 64, 256};
const char *sndr = "payto://x-taler-bank/localhost:8080/1";
struct TALER_Amount value;
unsigned int batch_size = batches[i];
struct GNUNET_TIME_Absolute now;
struct GNUNET_TIME_Timestamp ts;
struct GNUNET_TIME_Relative duration;
struct TALER_ReservePublicKeyP reserve_pubs[batch_size];
struct TALER_EXCHANGEDB_ReserveInInfo reserves[batch_size];
enum GNUNET_DB_QueryStatus results[batch_size];
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":1.000010",
&value));
now = GNUNET_TIME_absolute_get ();
ts = GNUNET_TIME_timestamp_get ();
for (unsigned int k = 0; k<batch_size; k++)
{
RND_BLK (&reserve_pubs[k]);
reserves[k].reserve_pub = &reserve_pubs[k];
reserves[k].balance = &value;
reserves[k].execution_time = ts;
reserves[k].sender_account_details = sndr;
reserves[k].exchange_account_name = "name";
reserves[k].wire_reference = k;
}
FAILIF (batch_size !=
plugin->batch_reserves_in_insert (plugin->cls,
reserves,
batch_size,
results));
duration = GNUNET_TIME_absolute_get_duration (now);
fprintf (stdout,
"for a batchsize equal to %d it took %s\n",
batch_size,
GNUNET_STRINGS_relative_time_to_string (duration,
GNUNET_NO) );
}
result = 0;
drop:
GNUNET_break (GNUNET_OK ==
plugin->drop_tables (plugin->cls));
cleanup:
TALER_EXCHANGEDB_plugin_unload (plugin);
plugin = NULL;
}
int
main (int argc,
char *const argv[])
{
const char *plugin_name;
char *config_filename;
char *testname;
struct GNUNET_CONFIGURATION_Handle *cfg;
(void) argc;
result = -1;
if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
{
GNUNET_break (0);
return -1;
}
GNUNET_log_setup (argv[0],
"WARNING",
NULL);
plugin_name++;
(void) GNUNET_asprintf (&testname,
"test-exchange-db-%s",
plugin_name);
(void) GNUNET_asprintf (&config_filename,
"%s.conf",
testname);
fprintf (stdout,
"Using config: %s\n",
config_filename);
cfg = GNUNET_CONFIGURATION_create ();
if (GNUNET_OK !=
GNUNET_CONFIGURATION_parse (cfg,
config_filename))
{
GNUNET_break (0);
GNUNET_free (config_filename);
GNUNET_free (testname);
return 2;
}
GNUNET_SCHEDULER_run (&run,
cfg);
GNUNET_CONFIGURATION_destroy (cfg);
GNUNET_free (config_filename);
GNUNET_free (testname);
return result;
}
/* end of test_exchangedb_by_j.c */

View File

@ -3479,28 +3479,6 @@ struct TALER_EXCHANGEDB_Plugin
struct TALER_PaytoHashP *h_payto);
/**
* Insert a incoming transaction into reserves. New reserves are
* also created through this function.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param reserve_pub public key of the reserve
* @param balance the amount that has to be added to the reserve
* @param execution_time when was the amount added
* @param sender_account_details information about the sender's bank account, in payto://-format
* @param wire_reference unique reference identifying the wire transfer
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
(*reserves_in_insert)(void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *balance,
struct GNUNET_TIME_Timestamp execution_time,
const char *sender_account_details,
const char *exchange_account_name,
uint64_t wire_reference);
/**
* Insert a batch of incoming transaction into reserves. New reserves are
* also created through this function.
@ -3512,25 +3490,7 @@ struct TALER_EXCHANGEDB_Plugin
* set to the status of the
*/
enum GNUNET_DB_QueryStatus
(*batch_reserves_in_insert)(
void *cls,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserves,
unsigned int reserves_length,
enum GNUNET_DB_QueryStatus *results);
/**
* Insert a batch of incoming transaction into reserves. New reserves are
* also created through this function.
*
* @param cls the @e cls of this struct with the plugin-specific state
* @param reserves
* @param reserves_length length of the @a reserves array
* @param[out] results array of transaction status codes of length @a reserves_length,
* set to the status of the
*/
enum GNUNET_DB_QueryStatus
(*batch2_reserves_in_insert)(
(*reserves_in_insert)(
void *cls,
const struct TALER_EXCHANGEDB_ReserveInInfo *reserves,
unsigned int reserves_length,
@ -4102,13 +4062,6 @@ struct TALER_EXCHANGEDB_Plugin
char **payto_uri);
/**
* Maximum number of results we return from iterate_matching_deposits().
*
* Limit on the number of transactions we aggregate at once.
*/
#define TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT 10000
/**
* Aggregate all matching deposits for @a h_payto and
* @a merchant_pub, returning the total amounts.