diff options
| -rw-r--r-- | contrib/Makefile.am | 2 | ||||
| m--------- | contrib/gana | 0 | ||||
| -rw-r--r-- | src/exchangedb/Makefile.am | 18 | ||||
| -rw-r--r-- | src/exchangedb/perf_exchangedb_reserves_in_insert.c | 199 | ||||
| -rw-r--r-- | src/exchangedb/pg_batch_reserves_in_insert.c | 150 | ||||
| -rw-r--r-- | src/exchangedb/pg_batch_reserves_in_insert.h | 35 | ||||
| -rw-r--r-- | src/exchangedb/pg_reserves_in_insert.c | 14 | ||||
| -rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 5 | ||||
| -rw-r--r-- | src/exchangedb/procedures.sql | 116 | ||||
| -rw-r--r-- | src/exchangedb/test-exchange-db-postgres.conf | 2 | ||||
| -rw-r--r-- | src/exchangedb/test_exchangedb_by_j.c | 49 | ||||
| -rw-r--r-- | src/include/taler_exchangedb_plugin.h | 28 | 
12 files changed, 586 insertions, 32 deletions
diff --git a/contrib/Makefile.am b/contrib/Makefile.am index 6ad5c8ae..cc1cf4d7 100644 --- a/contrib/Makefile.am +++ b/contrib/Makefile.am @@ -63,7 +63,7 @@ EXTRA_DIST = \    pp/Makefile \    pp/README \    pp/pp-v0.rst \ -  pp/conf.py \ +  pp/conf.py.in \    pp/locale/de/LC_MESSAGES/pp.po \    $(rdata_DATA) \    coverage.sh \ diff --git a/contrib/gana b/contrib/gana -Subproject 212ee0a78adc43cb5c04d6ea96ccc2fe74fed62 +Subproject a4a6b9ba4b2634c56194d53e36344686d7052ce diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index 4d892efe..59aeb321 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -239,6 +239,7 @@ 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_select_reserve_open_above_serial_id.c pg_select_reserve_open_above_serial_id.h  libtaler_plugin_exchangedb_postgres_la_LIBADD = \    $(LTLIBINTL) @@ -275,11 +276,13 @@ libtalerexchangedb_la_LDFLAGS = \  check_PROGRAMS = \    test-exchangedb-postgres \    bench-db-postgres\ +  perf-exchangedb-reserves-in-insert-postgres\    test-exchangedb-by-j-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 +  test-exchangedb-by-j-postgres\ +  perf-exchangedb-reserves-in-insert-postgres  test_exchangedb_postgres_SOURCES = \    test_exchangedb.c  test_exchangedb_postgres_LDADD = \ @@ -304,6 +307,19 @@ test_exchangedb_by_j_postgres_LDADD = \    -lgnunetutil \    $(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 = \ diff --git a/src/exchangedb/perf_exchangedb_reserves_in_insert.c b/src/exchangedb/perf_exchangedb_reserves_in_insert.c new file mode 100644 index 00000000..9a0ec094 --- /dev/null +++ b/src/exchangedb/perf_exchangedb_reserves_in_insert.c @@ -0,0 +1,199 @@ +/* +  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" + +/** + * 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)) +  { +    GNUNET_break (0); +    result = 77; +    goto cleanup; +  } +  if (GNUNET_OK != +      plugin->setup_partitions (plugin->cls, +                                num_partitions)) +  { +    GNUNET_break (0); +    result = 77; +    goto cleanup; +  } + +  for (unsigned int i = 0; i< 8; 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 GNUNET_TIME_Absolute now; +    struct GNUNET_TIME_Timestamp ts; +    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++) +    { +      RND_BLK (&reserve_pub); +      FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != +              plugin->reserves_in_insert (plugin->cls, +                                          &reserve_pub, +                                          &value, +                                          ts, +                                          sndr, +                                          "section", +                                          4)); +    } +    plugin->commit (plugin->cls); +    } +    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 */ diff --git a/src/exchangedb/pg_batch_reserves_in_insert.c b/src/exchangedb/pg_batch_reserves_in_insert.c new file mode 100644 index 00000000..4a1a2792 --- /dev/null +++ b/src/exchangedb/pg_batch_reserves_in_insert.c @@ -0,0 +1,150 @@ +/* +   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 JOSEPHxu + */ +#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" + + +/** + * Generate event notification for the reserve + * change. + * + * @param pg plugin state + * @param reserve_pub reserve to notfiy on + */ +static void +notify_on_reserve (struct PostgresClosure *pg, +                   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 +  }; + +  GNUNET_log (GNUNET_ERROR_TYPE_INFO, +              "Notifying on reserve!\n"); +  TEH_PG_event_notify (pg, +                       &rep.header, +                       NULL, +                       0); +} + + +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; +  bool conflicted; +  bool transaction_duplicate; +  struct GNUNET_TIME_Timestamp reserve_expiration +    = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); + +  PREPARE (pg, +           "reserve_create", +           "SELECT " +           "out_reserve_found AS conflicted" +           ",transaction_duplicate" +           ",ruuid AS reserve_uuid" +           " FROM batch_reserves_in" +           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);"); +  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)); +  /* 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]; +    struct GNUNET_PQ_QueryParam params[] = { +      GNUNET_PQ_query_param_auto_from_type (&reserve->reserve_pub), /*$1*/ +      GNUNET_PQ_query_param_timestamp (&expiry),  /*$4*/ +      GNUNET_PQ_query_param_timestamp (&gc),  /*$5*/ +      GNUNET_PQ_query_param_uint64 (&reserve->wire_reference), /*6*/ +      TALER_PQ_query_param_amount (&reserve->balance), /*7+8*/ +      GNUNET_PQ_query_param_string (reserve->exchange_account_name), /*9*/ +      GNUNET_PQ_query_param_timestamp (&reserve->execution_time), /*10*/ +      GNUNET_PQ_query_param_auto_from_type (&h_payto), /*11*/ +      GNUNET_PQ_query_param_string (reserve->sender_account_details),/*12*/ +      GNUNET_PQ_query_param_timestamp (&reserve_expiration),/*13*/ +      GNUNET_PQ_query_param_end +    }; +    /* We should get all our results into results[]*/ +    struct GNUNET_PQ_ResultSpec rs[] = { +      GNUNET_PQ_result_spec_uint64 ("reserve_uuid", +                                    &reserve_uuid), +      GNUNET_PQ_result_spec_bool ("conflicted", +                                  &conflicted), +      GNUNET_PQ_result_spec_bool ("transaction_duplicate", +                                  &transaction_duplicate), +      GNUNET_PQ_result_spec_end +    }; + +    TALER_payto_hash (reserve->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) +      return qs1;  +    notify_on_reserve (pg, +                       &reserve->reserve_pub); +    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 ( (! conflicted) && transaction_duplicate) +      TEH_PG_rollback(pg); +  } +  return reserves_length; +} diff --git a/src/exchangedb/pg_batch_reserves_in_insert.h b/src/exchangedb/pg_batch_reserves_in_insert.h new file mode 100644 index 00000000..76679567 --- /dev/null +++ b/src/exchangedb/pg_batch_reserves_in_insert.h @@ -0,0 +1,35 @@ +/* +   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 diff --git a/src/exchangedb/pg_reserves_in_insert.c b/src/exchangedb/pg_reserves_in_insert.c index 2fcca241..428e1923 100644 --- a/src/exchangedb/pg_reserves_in_insert.c +++ b/src/exchangedb/pg_reserves_in_insert.c @@ -31,6 +31,8 @@  #include "pg_reserves_update.h"  #include "pg_setup_wire_target.h"  #include "pg_event_notify.h" + +  /**   * Generate event notification for the reserve   * change. @@ -38,7 +40,6 @@   * @param pg plugin state   * @param reserve_pub reserve to notfiy on   */ -  static void  notify_on_reserve (struct PostgresClosure *pg,                     const struct TALER_ReservePublicKeyP *reserve_pub) @@ -52,11 +53,12 @@ notify_on_reserve (struct PostgresClosure *pg,    GNUNET_log (GNUNET_ERROR_TYPE_INFO,                "Notifying on reserve!\n");    TEH_PG_event_notify (pg, -                         &rep.header, -                         NULL, -                         0); +                       &rep.header, +                       NULL, +                       0);  } +  enum GNUNET_DB_QueryStatus  TEH_PG_reserves_in_insert (void *cls,                             const struct TALER_ReservePublicKeyP *reserve_pub, @@ -135,8 +137,8 @@ TEH_PG_reserves_in_insert (void *cls,      struct TALER_PaytoHashP h_payto;      qs3 = TEH_PG_setup_wire_target (pg, -                             sender_account_details, -                             &h_payto); +                                    sender_account_details, +                                    &h_payto);      if (qs3 < 0)        return qs3;      /* We do not have the UUID, so insert by public key */ diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 6a2a473c..5b59d4b0 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -207,7 +207,7 @@  #include "pg_reserves_update.h"  #include "pg_setup_wire_target.h"  #include "pg_compute_shard.h" - +#include "pg_batch_reserves_in_insert.h"  /**   * Set to 1 to enable Postgres auto_explain module. This will   * slow down things a _lot_, but also provide extensive logging @@ -5447,6 +5447,9 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)    plugin->set_purse_balance      = &TEH_PG_set_purse_balance; +  plugin->batch_reserves_in_insert +    = &TEH_PG_batch_reserves_in_insert; +    return plugin;  } diff --git a/src/exchangedb/procedures.sql b/src/exchangedb/procedures.sql index a732ef75..ff282735 100644 --- a/src/exchangedb/procedures.sql +++ b/src/exchangedb/procedures.sql @@ -2520,4 +2520,120 @@ BEGIN                 policy_details_serial_id = out_policy_details_serial_id;  END $$; +CREATE OR REPLACE FUNCTION batch_reserves_in( +  IN in_reserve_pub BYTEA, +  IN in_expiration_date INT8, +  IN in_gc_date INT8, +  IN in_wire_ref INT8, +  IN in_credit_val INT8, +  IN in_credit_frac INT4, +  IN in_exchange_account_name VARCHAR, +  IN in_exectution_date INT8, +  IN in_wire_source_h_payto BYTEA,    ---h_payto +  IN in_payto_uri VARCHAR, +  IN in_reserve_expiration INT8, +  OUT out_reserve_found BOOLEAN, +  OUT transaction_duplicate BOOLEAN, +  OUT ruuid INT8) +LANGUAGE plpgsql +AS $$ +DECLARE +  my_amount_val INT8; +DECLARE +  my_amount_frac INT4; +BEGIN + +  INSERT INTO reserves +    (reserve_pub +    ,current_balance_val +    ,current_balance_frac +    ,expiration_date +    ,gc_date) +    VALUES +    (in_reserve_pub +    ,in_credit_val +    ,in_credit_frac +    ,in_expiration_date +    ,in_gc_date) +   ON CONFLICT DO NOTHING +   RETURNING reserve_uuid INTO ruuid; + +  IF FOUND +  THEN +    -- We made a change, so the reserve did not previously exist. +    out_reserve_found = FALSE; +  ELSE +    -- We made no change, which means the reserve existed. +    out_reserve_found = TRUE; +  END IF; + +  --SIMPLE INSERT ON CONFLICT DO NOTHING +  INSERT INTO wire_targets +    (wire_target_h_payto +    ,payto_uri) +    VALUES +    (in_wire_source_h_payto +    ,in_payto_uri) +  ON CONFLICT DO NOTHING; + +  INSERT INTO reserves_in +    (reserve_pub +    ,wire_reference +    ,credit_val +    ,credit_frac +    ,exchange_account_section +    ,wire_source_h_payto +    ,execution_date) +    VALUES +    (in_reserve_pub +    ,in_wire_ref +    ,in_credit_val +    ,in_credit_frac +    ,in_exchange_account_name +    ,in_wire_source_h_payto +    ,in_expiration_date); + +  --IF THE INSERTION WAS A SUCCESS IT MEANS NO DUPLICATED TRANSACTION +  IF FOUND +  THEN +    transaction_duplicate = FALSE; +    IF out_reserve_found +    THEN +      UPDATE reserves +        SET +           current_balance_frac = current_balance_frac+in_credit_frac +             - CASE +               WHEN current_balance_frac + in_credit_frac >= 100000000 +                 THEN 100000000 +               ELSE 1 +               END +              ,current_balance_val = current_balance_val+in_credit_val +             + CASE +               WHEN current_balance_frac + in_credit_frac >= 100000000 +                 THEN 1 +               ELSE 0 +               END +               ,expiration_date=GREATEST(expiration_date,in_expiration_date) +               ,gc_date=GREATEST(gc_date,in_expiration_date) +      	      WHERE reserves.reserve_pub=in_reserve_pub; +      out_reserve_found = TRUE; +      RETURN; +    ELSE +      out_reserve_found=FALSE; +      RETURN; +    END IF; +    out_reserve_found = TRUE; +  ELSE +    transaction_duplicate = TRUE; +    IF out_reserve_found +    THEN +      out_reserve_found = TRUE; +      RETURN; +    ELSE +      out_reserve_found = FALSE; +      RETURN; +    END IF; +  END IF; +END $$; +  COMMIT; diff --git a/src/exchangedb/test-exchange-db-postgres.conf b/src/exchangedb/test-exchange-db-postgres.conf index 05104cb7..92bdde39 100644 --- a/src/exchangedb/test-exchange-db-postgres.conf +++ b/src/exchangedb/test-exchange-db-postgres.conf @@ -7,7 +7,7 @@ BASE_URL = http://localhost/  [exchangedb-postgres]  #The connection string the plugin has to use for connecting to the database -CONFIG = postgres:///talercheck +CONFIG = postgres://dab:test@localhost/talercheck  # Where are the SQL files to setup our tables?  SQL_DIR = $DATADIR/sql/exchange/ diff --git a/src/exchangedb/test_exchangedb_by_j.c b/src/exchangedb/test_exchangedb_by_j.c index b81d82d6..b2f6ddeb 100644 --- a/src/exchangedb/test_exchangedb_by_j.c +++ b/src/exchangedb/test_exchangedb_by_j.c @@ -33,7 +33,7 @@ static int result;   */  #define FAILIF(cond)                            \    do {                                          \ -    if (! (cond)) { break;}                     \ +      if (! (cond)) {break;}                    \      GNUNET_break (0);                           \      goto drop;                                  \    } while (0) @@ -100,45 +100,51 @@ run (void *cls)    for (unsigned int i = 0; i< 7; i++)    { -    static unsigned int batches[] = {1, 1, 0, 2, 4, 16, 64}; +    static unsigned int batches[] = {1, 1, 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 GNUNET_TIME_Absolute now;      struct GNUNET_TIME_Timestamp ts;      struct GNUNET_TIME_Relative duration; -    struct TALER_ReservePublicKeyP reserve_pub; - +    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 (); -    fprintf (stdout, -             "Now: %llu\n", -             now.abs_value_us); -    plugin->start (plugin->cls, -                   "test_by_exchange_j"); +    for (unsigned int r=0;r<10;r++) +    { +    plugin->start_read_committed (plugin->cls, +                                  "test_by_j"); +      for (unsigned int k = 0; k<batch_size; 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 (&reserves[k].reserve_pub); +      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)); +      plugin->commit (plugin->cls); +    }      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_YES) ); +                                                     GNUNET_NO) );    } +  result = 0;  drop:    GNUNET_break (GNUNET_OK ==                  plugin->drop_tables (plugin->cls)); @@ -174,7 +180,7 @@ main (int argc,    (void) GNUNET_asprintf (&config_filename,                            "%s.conf",                            testname); -  fprintf (stderr, +  fprintf (stdout,             "Using config: %s\n",             config_filename);    cfg = GNUNET_CONFIGURATION_create (); @@ -195,5 +201,4 @@ main (int argc,    return result;  } - -/* end of test_exchangedb.c */ +/* end of test_exchangedb_by_j.c */ diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index f21301e7..6f5dedd0 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -2571,6 +2571,17 @@ struct TALER_EXCHANGEDB_KycStatus  }; +struct TALER_EXCHANGEDB_ReserveInInfo +{ +  struct TALER_ReservePublicKeyP reserve_pub; +  struct TALER_Amount balance; +  struct GNUNET_TIME_Timestamp execution_time; +  const char *sender_account_details; +  const char *exchange_account_name; +  uint64_t wire_reference; +}; + +  /**   * Function called on each @a amount that was found to   * be relevant for a KYC check. @@ -3458,6 +3469,23 @@ struct TALER_EXCHANGEDB_Plugin    /** +   * 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 +  (*batch_reserves_in_insert)(void *cls, +                              const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, +                              unsigned int reserves_length, +                              enum GNUNET_DB_QueryStatus *results); + + +  /**     * Locate a nonce for use with a particular public key.     *     * @param cls the @e cls of this struct with the plugin-specific state  | 
