diff options
| author | Joseph <Joseph.xu@efrei.net> | 2022-12-19 10:02:43 -0500 | 
|---|---|---|
| committer | Joseph <Joseph.xu@efrei.net> | 2022-12-20 05:00:38 -0500 | 
| commit | b0c106124c99a45282d94499f87fb1768914dba3 (patch) | |
| tree | 49742d64f4e5f692d3a60253740dcec08c82e5aa /src/exchangedb | |
| parent | 48b7d45959d40cc129991a191a6aa3167412bd9e (diff) | |
new batch test and standard deviation
Diffstat (limited to 'src/exchangedb')
| -rw-r--r-- | src/exchangedb/Makefile.am | 1 | ||||
| -rw-r--r-- | src/exchangedb/exchange_do_batch2_reserves_in_insert.sql | 155 | ||||
| -rw-r--r-- | src/exchangedb/exchange_do_batch4_reserves_in_insert.sql | 333 | ||||
| -rw-r--r-- | src/exchangedb/pg_batch2_reserves_in_insert.c | 487 | ||||
| -rw-r--r-- | src/exchangedb/pg_batch2_reserves_in_insert.h | 1 | ||||
| -rw-r--r-- | src/exchangedb/pg_batch4_reserves_in_insert.c | 505 | ||||
| -rw-r--r-- | src/exchangedb/pg_batch4_reserves_in_insert.h | 34 | ||||
| -rw-r--r-- | src/exchangedb/pg_batch_reserves_in_insert.c | 18 | ||||
| -rw-r--r-- | src/exchangedb/procedures.sql.in | 2 | ||||
| -rw-r--r-- | src/exchangedb/test_exchangedb_batch_reserves_in_insert.c | 7 | ||||
| -rw-r--r-- | src/exchangedb/test_exchangedb_by_j.c | 113 | 
11 files changed, 1341 insertions, 315 deletions
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index 56fe2ff5..755de66a 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -315,6 +315,7 @@ test_exchangedb_by_j_postgres_LDADD = \    -ljansson \    -lgnunetjson \    -lgnunetutil \ +  -lm \    $(XLIB) diff --git a/src/exchangedb/exchange_do_batch2_reserves_in_insert.sql b/src/exchangedb/exchange_do_batch2_reserves_in_insert.sql index 8d3942a6..6a0cc6d7 100644 --- a/src/exchangedb/exchange_do_batch2_reserves_in_insert.sql +++ b/src/exchangedb/exchange_do_batch2_reserves_in_insert.sql @@ -26,6 +26,7 @@ CREATE OR REPLACE FUNCTION exchange_do_batch2_reserves_insert(    IN in_payto_uri VARCHAR,    IN in_reserve_expiration INT8,    IN in_notify text, +  IN in2_notify text,    IN in2_reserve_pub BYTEA,    IN in2_wire_ref INT8,    IN in2_credit_val INT8, @@ -44,22 +45,29 @@ CREATE OR REPLACE FUNCTION exchange_do_batch2_reserves_insert(  LANGUAGE plpgsql  AS $$  DECLARE -  curs_reserve_exist CURSOR -  FOR SELECT reserve_pub -  FROM reserves -  WHERE ruuid = reserves.reserve_uuid OR ruuid2 = reserves.reserve_uuid; +  curs_reserve_exist REFCURSOR; +--  FOR SELECT reserve_pub +--  FROM reserves +--  WHERE in_reserve_pub = reserves.reserve_pub +--  OR in2_reserve_pub = reserves.reserve_pub; +DECLARE    curs_transaction_exist CURSOR    FOR SELECT reserve_pub    FROM reserves_in    WHERE in_reserve_pub = reserves_in.reserve_pub -  OR reserves_in.reserve_pub = in2_reserve_pub; - +  OR in2_reserve_pub = reserves_in.reserve_pub; +DECLARE    i RECORD;  BEGIN -    --SIMPLE INSERT ON CONFLICT DO NOTHING +  transaction_duplicate=FALSE; +  transaction_duplicate2=FALSE; +  out_reserve_found = TRUE; +  out_reserve_found2 = TRUE; +  ruuid=0; +  ruuid2=0;    INSERT INTO wire_targets      (wire_target_h_payto      ,payto_uri) @@ -70,93 +78,65 @@ BEGIN      ,in2_payto_uri)    ON CONFLICT DO NOTHING; -  FOR k IN curs_reserve_exist -  LOOP -    IF in_reserve_pub = k.reserve_pub +  OPEN curs_reserve_exist FOR +  WITH reserve_changes AS ( +    INSERT INTO reserves +      (reserve_pub +      ,current_balance_val +      ,current_balance_frac +      ,expiration_date +      ,gc_date) +      VALUES +      (in_reserve_pub +      ,in_credit_val +      ,in_credit_frac +      ,in_expiration_date +      ,in_gc_date), +      (in2_reserve_pub +      ,in2_credit_val +      ,in2_credit_frac +      ,in_expiration_date +      ,in_gc_date) +     ON CONFLICT DO NOTHING +     RETURNING reserve_uuid,reserve_pub) +    SELECT * FROM reserve_changes; + +  FETCH FROM curs_reserve_exist INTO i; +  IF FOUND +  THEN +    IF in_reserve_pub = i.reserve_pub      THEN -         out_reserve_found = TRUE; +       out_reserve_found = FALSE; +       ruuid = i.reserve_uuid;      END IF; - -    IF in2_reserve_pub = k.reserve_pub +    IF in2_reserve_pub = i.reserve_pub      THEN -         out_reserve_found2 = TRUE; +        out_reserve_found2 = FALSE; +        ruuid2 = i.reserve_uuid;      END IF; - -    IF out_reserve_found AND out_reserve_found2 +    FETCH FROM curs_reserve_exist INTO i; +    IF FOUND      THEN -        EXIT; -    END IF; -  END LOOP; - - -  IF out_reserve_found IS NULL -  THEN -        out_reserve_found=FALSE; -  END IF; -  IF out_reserve_found2 IS NULL -  THEN +      IF in_reserve_pub = i.reserve_pub +      THEN +        out_reserve_found = FALSE; +        ruuid = i.reserve_uuid; +      END IF; +      IF in2_reserve_pub = i.reserve_pub +      THEN          out_reserve_found2 = FALSE; +        ruuid2 = i.reserve_uuid; +     END IF; +    END IF;    END IF; +  CLOSE curs_reserve_exist;    IF out_reserve_found AND out_reserve_found2    THEN -     transaction_duplicate = FALSE; -     transaction_duplicate2 = FALSE; -     RETURN; +      RETURN;    END IF; -  /*LOOP TO STORE UUID*/ -  FOR i IN -  WITH input_rows -  (reserve_pub -    ,current_balance_val -    ,current_balance_frac -    ,expiration_date -    ,gc_date) -  AS -  ( -   VALUES -    (in_reserve_pub -    ,in_credit_val -    ,in_credit_frac -    ,in_expiration_date -    ,in_gc_date), -    (in2_reserve_pub -    ,in2_credit_val -    ,in2_credit_frac -    ,in_expiration_date -    ,in_gc_date) -   ), ins AS ( -   INSERT INTO reserves -   (reserve_pub -    ,current_balance_val -    ,current_balance_frac -    ,expiration_date -    ,gc_date) -    SELECT * FROM input_rows -    ON CONFLICT DO NOTHING -    RETURNING reserve_uuid) -   SELECT -	* -   FROM -	( -		SELECT -			reserve_uuid, -			ROW_NUMBER () OVER (ORDER BY reserve_uuid) -		FROM -			ins -	) x -  LOOP -    IF i.ROW_NUMBER = 1 -    THEN -      ruuid = i.reserve_uuid; -    ELSE -      ruuid2 = i.reserve_uuid; -    END IF; -  END LOOP; - - -    PERFORM pg_notify(in_notify, NULL); +  PERFORM pg_notify(in2_notify, NULL);    INSERT INTO reserves_in      (reserve_pub @@ -207,15 +187,8 @@ BEGIN      END LOOP;    END IF; -  IF transaction_duplicate IS NULL -  THEN -        transaction_duplicate=FALSE; -  END IF; -  IF transaction_duplicate2 IS NULL -  THEN -        transaction_duplicate2 = FALSE; -  END IF; - +  CLOSE curs_reserve_exist; +  CLOSE curs_transaction_exist;    RETURN;  END $$; diff --git a/src/exchangedb/exchange_do_batch4_reserves_in_insert.sql b/src/exchangedb/exchange_do_batch4_reserves_in_insert.sql new file mode 100644 index 00000000..ece92698 --- /dev/null +++ b/src/exchangedb/exchange_do_batch4_reserves_in_insert.sql @@ -0,0 +1,333 @@ +-- +-- 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/> +-- +CREATE OR REPLACE FUNCTION exchange_do_batch4_reserves_insert( +  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, +  IN in_notify text, +  IN in2_notify text, +  IN in3_notify text, +  IN in4_notify text, +  IN in2_reserve_pub BYTEA, +  IN in2_wire_ref INT8, +  IN in2_credit_val INT8, +  IN in2_credit_frac INT4, +  IN in2_exchange_account_name VARCHAR, +  IN in2_exectution_date INT8, +  IN in2_wire_source_h_payto BYTEA,    ---h_payto +  IN in2_payto_uri VARCHAR, +  IN in2_reserve_expiration INT8, +  IN in3_reserve_pub BYTEA, +  IN in3_wire_ref INT8, +  IN in3_credit_val INT8, +  IN in3_credit_frac INT4, +  IN in3_exchange_account_name VARCHAR, +  IN in3_exectution_date INT8, +  IN in3_wire_source_h_payto BYTEA,    ---h_payto +  IN in3_payto_uri VARCHAR, +  IN in3_reserve_expiration INT8, +  IN in4_reserve_pub BYTEA, +  IN in4_wire_ref INT8, +  IN in4_credit_val INT8, +  IN in4_credit_frac INT4, +  IN in4_exchange_account_name VARCHAR, +  IN in4_exectution_date INT8, +  IN in4_wire_source_h_payto BYTEA,    ---h_payto +  IN in4_payto_uri VARCHAR, +  IN in4_reserve_expiration INT8, +  OUT out_reserve_found BOOLEAN, +  OUT out_reserve_found2 BOOLEAN, +  OUT out_reserve_found3 BOOLEAN, +  OUT out_reserve_found4 BOOLEAN, +  OUT transaction_duplicate BOOLEAN, +  OUT transaction_duplicate2 BOOLEAN, +  OUT transaction_duplicate3 BOOLEAN, +  OUT transaction_duplicate4 BOOLEAN, +  OUT ruuid INT8, +  OUT ruuid2 INT8, +  OUT ruuid3 INT8, +  OUT ruuid4 INT8) +LANGUAGE plpgsql +AS $$ +DECLARE +  curs_reserve_exist refcursor; + +DECLARE +  curs_transaction_exist CURSOR +  FOR SELECT reserve_pub +  FROM reserves_in +  WHERE in_reserve_pub = reserves_in.reserve_pub +  OR in2_reserve_pub = reserves_in.reserve_pub +  OR in3_reserve_pub = reserves_in.reserve_pub +  OR in4_reserve_pub = reserves_in.reserve_pub; +DECLARE +  i RECORD; + +BEGIN +--INITIALIZATION +  transaction_duplicate=FALSE; +  transaction_duplicate2=FALSE; +  transaction_duplicate3=FALSE; +  transaction_duplicate4=FALSE; +  out_reserve_found = TRUE; +  out_reserve_found2 = TRUE; +  out_reserve_found3 = TRUE; +  out_reserve_found4 = TRUE; +  ruuid=0; +  ruuid2=0; +  ruuid3=0; +  ruuid4=0; + +  --SIMPLE INSERT ON CONFLICT DO NOTHING +  INSERT INTO wire_targets +    (wire_target_h_payto +    ,payto_uri) +    VALUES +    (in_wire_source_h_payto +    ,in_payto_uri), +    (in2_wire_source_h_payto +    ,in2_payto_uri), +    (in3_wire_source_h_payto +    ,in3_payto_uri), +    (in4_wire_source_h_payto +    ,in4_payto_uri) +  ON CONFLICT DO NOTHING; + +  OPEN curs_reserve_exist FOR +  WITH reserve_changes AS ( +    INSERT INTO reserves +      (reserve_pub +      ,current_balance_val +      ,current_balance_frac +      ,expiration_date +      ,gc_date) +      VALUES +      (in_reserve_pub +      ,in_credit_val +      ,in_credit_frac +      ,in_expiration_date +      ,in_gc_date), +      (in2_reserve_pub +      ,in2_credit_val +      ,in2_credit_frac +      ,in_expiration_date +      ,in_gc_date), +      (in3_reserve_pub +      ,in3_credit_val +      ,in3_credit_frac +      ,in_expiration_date +      ,in_gc_date), +      (in4_reserve_pub +      ,in4_credit_val +      ,in4_credit_frac +      ,in_expiration_date +      ,in_gc_date) +     ON CONFLICT DO NOTHING +     RETURNING reserve_uuid,reserve_pub) +    SELECT * FROM reserve_changes; + +  FETCH FROM curs_reserve_exist INTO i; +  IF FOUND +  THEN +    IF in_reserve_pub = i.reserve_pub +    THEN +       out_reserve_found = FALSE; +       ruuid = i.reserve_uuid; +    END IF; +    IF in2_reserve_pub = i.reserve_pub +    THEN +        out_reserve_found2 = FALSE; +        ruuid2 = i.reserve_uuid; +    END IF; +    IF in3_reserve_pub = i.reserve_pub +    THEN +        out_reserve_found3 = FALSE; +        ruuid3 = i.reserve_uuid; +    END IF; +    IF in4_reserve_pub = i.reserve_pub +    THEN +        out_reserve_found4 = FALSE; +        ruuid4 = i.reserve_uuid; +    END IF; +    FETCH FROM curs_reserve_exist INTO i; +    IF FOUND +    THEN +      IF in_reserve_pub = i.reserve_pub +      THEN +        out_reserve_found = FALSE; +        ruuid = i.reserve_uuid; +      END IF; +      IF in2_reserve_pub = i.reserve_pub +      THEN +        out_reserve_found2 = FALSE; +        ruuid2 = i.reserve_uuid; +      END IF; +      IF in3_reserve_pub = i.reserve_pub +      THEN +        out_reserve_found3 = FALSE; +        ruuid3 = i.reserve_uuid; +      END IF; +      IF in4_reserve_pub = i.reserve_pub +      THEN +        out_reserve_found4 = FALSE; +        ruuid4 = i.reserve_uuid; +      END IF; +    END IF; +    FETCH FROM curs_reserve_exist INTO i; +    IF FOUND +    THEN +      IF in_reserve_pub = i.reserve_pub +      THEN +          out_reserve_found = FALSE; +          ruuid = i.reserve_uuid; +      END IF; +      IF in2_reserve_pub = i.reserve_pub +      THEN +          out_reserve_found2 = FALSE; +          ruuid2 = i.reserve_uuid; +      END IF; +      IF in3_reserve_pub = i.reserve_pub +      THEN +          out_reserve_found3 = FALSE; +          ruuid3 = i.reserve_uuid; +      END IF; +      IF in4_reserve_pub = i.reserve_pub +      THEN +          out_reserve_found4 = FALSE; +          ruuid4 = i.reserve_uuid; +      END IF; +    END IF; +    FETCH FROM curs_reserve_exist INTO i; +    IF FOUND +    THEN +      IF in_reserve_pub = i.reserve_pub +      THEN +          out_reserve_found = FALSE; +          ruuid = i.reserve_uuid; +      END IF; +      IF in2_reserve_pub = i.reserve_pub +      THEN +          out_reserve_found2 = FALSE; +          ruuid2 = i.reserve_uuid; +      END IF; +      IF in3_reserve_pub = i.reserve_pub +      THEN +          out_reserve_found3 = FALSE; +          ruuid3 = i.reserve_uuid; +      END IF; +      IF in4_reserve_pub = i.reserve_pub +      THEN +          out_reserve_found4 = FALSE; +          ruuid4 = i.reserve_uuid; +      END IF; +    END IF; +  END IF; +  CLOSE curs_reserve_exist; +  IF out_reserve_found AND out_reserve_found2 AND out_reserve_found3 AND out_reserve_found4 +  THEN +      RETURN; +  END IF; + +  PERFORM pg_notify(in_notify, NULL); +  PERFORM pg_notify(in2_notify, NULL); +  PERFORM pg_notify(in3_notify, NULL); +  PERFORM pg_notify(in4_notify, NULL); + +  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), +    (in2_reserve_pub +    ,in2_wire_ref +    ,in2_credit_val +    ,in2_credit_frac +    ,in2_exchange_account_name +    ,in2_wire_source_h_payto +    ,in_expiration_date), +    (in3_reserve_pub +    ,in3_wire_ref +    ,in3_credit_val +    ,in3_credit_frac +    ,in3_exchange_account_name +    ,in3_wire_source_h_payto +    ,in_expiration_date), +    (in4_reserve_pub +    ,in4_wire_ref +    ,in4_credit_val +    ,in4_credit_frac +    ,in4_exchange_account_name +    ,in4_wire_source_h_payto +    ,in_expiration_date) +    ON CONFLICT DO NOTHING; +  IF FOUND +  THEN +    transaction_duplicate = FALSE;  /*HAPPY PATH THERE IS NO DUPLICATE TRANS AND NEW RESERVE*/ +    transaction_duplicate2 = FALSE; +    transaction_duplicate3 = FALSE; +    transaction_duplicate4 = FALSE; +    RETURN; +  ELSE +    FOR l IN curs_transaction_exist +    LOOP +      IF in_reserve_pub = l.reserve_pub +      THEN +         transaction_duplicate = TRUE; +      END IF; + +      IF in2_reserve_pub = l.reserve_pub +      THEN +         transaction_duplicate2 = TRUE; +      END IF; +      IF in3_reserve_pub = l.reserve_pub +      THEN +         transaction_duplicate3 = TRUE; +      END IF; +      IF in4_reserve_pub = l.reserve_pub +      THEN +         transaction_duplicate4 = TRUE; +      END IF; + +      IF transaction_duplicate AND transaction_duplicate2 AND transaction_duplicate3 AND transaction_duplicate4 +      THEN +        RETURN; +      END IF; +    END LOOP; +  END IF; + +  CLOSE curs_reserve_exist; +  CLOSE curs_transaction_exist; +  RETURN; +END $$; diff --git a/src/exchangedb/pg_batch2_reserves_in_insert.c b/src/exchangedb/pg_batch2_reserves_in_insert.c index 553dd316..64b7b1b0 100644 --- a/src/exchangedb/pg_batch2_reserves_in_insert.c +++ b/src/exchangedb/pg_batch2_reserves_in_insert.c @@ -1,4 +1,3 @@ -  /*     This file is part of TALER     Copyright (C) 2022 Taler Systems SA @@ -53,40 +52,106 @@ compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub)  } +<<<<<<< HEAD  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) +======= +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) +>>>>>>> b9baf781 (new batch test and standard deviation)  { -  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; -  uint64_t reserve_uuid2; -  bool conflicted; -  bool conflicted2; -  bool transaction_duplicate; -  bool transaction_duplicate2; -  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]; -  bool conflicts2[reserves_length]; -  char *notify_s[reserves_length]; +  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);"); -  if (GNUNET_OK != -      TEH_PG_preflight (pg)) -  { -    GNUNET_break (0); -    return GNUNET_DB_STATUS_HARD_ERROR; -  } +    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, +                                                    "batch1_reserve_create", +                                                    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 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 qs1;    PREPARE (pg, -           "reserve_create", +           "batch2_reserve_create",             "SELECT "             "out_reserve_found AS conflicted"             ",out_reserve_found2 AS conflicted2" @@ -95,6 +160,7 @@ TEH_PG_batch2_reserves_in_insert (void *cls,             ",ruuid AS reserve_uuid"             ",ruuid2 AS reserve_uuid2"             " FROM exchange_do_batch2_reserves_insert" +<<<<<<< HEAD             " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21);");    expiry = GNUNET_TIME_absolute_to_timestamp (      GNUNET_TIME_absolute_add (reserves->execution_time.abs_time, @@ -140,17 +206,39 @@ TEH_PG_batch2_reserves_in_insert (void *cls,        TALER_PQ_query_param_amount (reserve0->balance),        GNUNET_PQ_query_param_string (reserve0->exchange_account_name),        GNUNET_PQ_query_param_timestamp (&reserve0->execution_time), +======= +           " ($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), +>>>>>>> b9baf781 (new batch test and standard deviation)        GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserve0->sender_account_details), +      GNUNET_PQ_query_param_string (reserves[0].sender_account_details),        GNUNET_PQ_query_param_timestamp (&reserve_expiration), +<<<<<<< HEAD        GNUNET_PQ_query_param_string (notify_s[i]),        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_string (notify_s[0]), // FIXME: 2 different notifies! +      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), +>>>>>>> b9baf781 (new batch test and standard deviation)        GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserve1->sender_account_details), +      GNUNET_PQ_query_param_string (reserves[1].sender_account_details),        GNUNET_PQ_query_param_timestamp (&reserve_expiration),        GNUNET_PQ_query_param_end @@ -158,31 +246,30 @@ TEH_PG_batch2_reserves_in_insert (void *cls,      struct GNUNET_PQ_ResultSpec rs[] = {        GNUNET_PQ_result_spec_bool ("conflicted", -                                  &conflicted), +                                  &conflict[0]),        GNUNET_PQ_result_spec_bool ("conflicted2", -                                  &conflicted2), +                                  &conflict[1]),        GNUNET_PQ_result_spec_bool ("transaction_duplicate", -                                  &transaction_duplicate), +                                  &transaction_duplicate[0]),        GNUNET_PQ_result_spec_bool ("transaction_duplicate2", -                                  &transaction_duplicate2), +                                  &transaction_duplicate[1]),        GNUNET_PQ_result_spec_uint64 ("reserve_uuid", -                                    &reserve_uuid), +                                    &reserve_uuid[0]),        GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", -                                    &reserve_uuid2), +                                    &reserve_uuid[1]),        GNUNET_PQ_result_spec_end      }; -    TALER_payto_hash (reserve0->sender_account_details, +    TALER_payto_hash (reserves[0].sender_account_details,                        &h_payto); -    TALER_payto_hash (reserve1->sender_account_details, +    TALER_payto_hash (reserves[1].sender_account_details,                        &h_payto); -    /* Note: query uses 'on conflict do nothing' */ +      qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                    "reserve_create", +                                                    "batch2_reserve_create",                                                      params,                                                      rs); -      if (qs1 < 0)      {        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -190,8 +277,143 @@ TEH_PG_batch2_reserves_in_insert (void *cls,                    qs1);        return qs1;      } -    if (reserves_length & 1) + +    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); +     return GNUNET_DB_STATUS_HARD_ERROR; +   } +    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 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)      { +<<<<<<< HEAD        const struct TALER_EXCHANGEDB_ReserveInInfo *reserve =          &reserves[reserves_length - 1];        // single insert logic here @@ -205,25 +427,194 @@ TEH_PG_batch2_reserves_in_insert (void *cls,     // fprintf(stdout, "%d",conflicts[i]);     // fprintf(stdout, "%d", conflicts2[i]);     if ((!conflicts[i] && transaction_duplicate) ||(!conflicts2[i] && transaction_duplicate2)) +======= +      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                  "Failed to create reserves4 (%d)\n", +                  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]))) +>>>>>>> b9baf781 (new batch test and standard deviation)     {       GNUNET_break (0);       TEH_PG_rollback (pg);       return GNUNET_DB_STATUS_HARD_ERROR;     } -   need_update |= conflicted; -   need_update2 |= conflicted2; +    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; +  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 >= 4) +    { +      //   fprintf(stdout, "batch4"); +      qs4=insert4(pg, +                  &reserves[i], +                  expiry, +                  gc, +                  h_payto, +                  ¬ify_s[i], +                  reserve_expiration, +                  &transaction_duplicate[i], +                  &conflicts[i], +                  &reserve_uuid[i]); + +     if (qs4<0) +      { +        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                    "Failed to update reserves4 (%d)\n", +                    qs4); +        return qs4; +      } +      need_update |= conflicts[i]; +      need_update |= conflicts[i+1]; +      need_update |= conflicts[i+2]; +      need_update |= conflicts[i+3]; +      //     fprintf(stdout, "%ld %ld %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1], reserve_uuid[i+2], reserve_uuid[i+3]); +      //fprintf(stdout, "%d %d %d %d\n", transaction_duplicate[i], transaction_duplicate[i+1], transaction_duplicate[i+2], transaction_duplicate[i+3]); +      i += 4; +      continue; +    } +    switch (bs) +    { +    case 3: +    case 2: +      qs5=insert2(pg, +                  &reserves[i], +                  expiry, +                  gc, +                  h_payto, +                  ¬ify_s[i], +                  reserve_expiration, +                  &transaction_duplicate[i], +                  &conflicts[i], +                  &reserve_uuid[i]); +      if (qs5<0) +      { +        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                    "Failed to update reserves (%d)\n", +                    qs5); +        return qs5; +      } +      need_update |= conflicts[i]; +      need_update |= conflicts[i+1]; +      //      fprintf(stdout, "%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]); +      if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs2) +      { +        GNUNET_break (0); +        return GNUNET_DB_STATUS_HARD_ERROR; +      } +      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) +    { +      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                  "Failed to commit\n");        return cs; +    }    }    if (! need_update) +  {      goto exit; +  }    // begin serializable    {      if (GNUNET_OK != @@ -235,7 +626,7 @@ TEH_PG_batch2_reserves_in_insert (void *cls,      }    } -  enum GNUNET_DB_QueryStatus qs2; +  enum GNUNET_DB_QueryStatus qs3;    PREPARE (pg,             "reserves_in_add_transaction",             "CALL exchange_do_batch_reserves_update" @@ -252,21 +643,21 @@ TEH_PG_batch2_reserves_in_insert (void *cls,          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_bool (conflicts[i]),          GNUNET_PQ_query_param_auto_from_type (&h_payto),          GNUNET_PQ_query_param_string (notify_s[i]),          GNUNET_PQ_query_param_end        }; -      qs2 = GNUNET_PQ_eval_prepared_non_select (pg->conn, +      qs3 = GNUNET_PQ_eval_prepared_non_select (pg->conn,                                                  "reserves_in_add_transaction",                                                  params); -      if (qs2<0) +      if (qs3<0)        {          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,                      "Failed to update reserves (%d)\n", -                    qs2); -        return qs2; +                    qs3); +        return qs3;        }      }    } diff --git a/src/exchangedb/pg_batch2_reserves_in_insert.h b/src/exchangedb/pg_batch2_reserves_in_insert.h index bb6be3f6..491e789c 100644 --- a/src/exchangedb/pg_batch2_reserves_in_insert.h +++ b/src/exchangedb/pg_batch2_reserves_in_insert.h @@ -28,6 +28,7 @@ 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 diff --git a/src/exchangedb/pg_batch4_reserves_in_insert.c b/src/exchangedb/pg_batch4_reserves_in_insert.c index 604a31e7..6536eb56 100644 --- a/src/exchangedb/pg_batch4_reserves_in_insert.c +++ b/src/exchangedb/pg_batch4_reserves_in_insert.c @@ -1,3 +1,4 @@ +  /*     This file is part of TALER     Copyright (C) 2022 Taler Systems SA @@ -14,7 +15,7 @@     TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>   */  /** - * @file exchangedb/pg_batch4_reserves_in_insert.c + * @file exchangedb/pg_batch_reserves_in_insert.c   * @brief Implementation of the reserves_in_insert function for Postgres   * @author Joseph Xu   */ @@ -52,28 +53,357 @@ compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub)  } +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_batch4_reserves_in_insert (void *cls, +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; +  uint64_t reserve_uuid[reserves_length];    bool conflicted;    bool conflicted2; -  bool transaction_duplicate; -  bool transaction_duplicate2; +  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]; -  bool conflicts2[reserves_length];    char *notify_s[reserves_length];    if (GNUNET_OK != @@ -82,16 +412,7 @@ TEH_PG_batch4_reserves_in_insert (void *cls,      GNUNET_break (0);      return GNUNET_DB_STATUS_HARD_ERROR;    } -  PREPARE (pg, -           "reserve_create", -           "SELECT " -           "out_reserve_found AS conflicted" -           ",out_reserve_found2 AS conflicted2" -           ",transaction_duplicate" -           ",transaction_duplicate2" -           ",ruuid AS reserve_uuid" -           " FROM batch2_reserves_insert" -           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21);"); +    expiry = GNUNET_TIME_absolute_to_timestamp (      GNUNET_TIME_absolute_add (reserves->execution_time.abs_time,                                pg->idle_reserve_expiration_time)); @@ -124,75 +445,83 @@ TEH_PG_batch4_reserves_in_insert (void *cls,      notify_s[i] = compute_notify_on_reserve (&reserve->reserve_pub);    } -  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), -      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[i]), -      GNUNET_PQ_query_param_auto_from_type (&reserve->reserve_pub), -      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_end -    }; +  unsigned int i=0; -    struct GNUNET_PQ_ResultSpec rs[] = { -      GNUNET_PQ_result_spec_bool ("conflicted", -                                  &conflicted), -            GNUNET_PQ_result_spec_bool ("conflicted2", -                                  &conflicted2), -      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' */ -    qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                    "reserve_create", -                                                    params, -                                                    rs); +  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, +              ¬ify_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]); -    if (qs1 < 0) +      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)      { -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Failed to create reserves (%d)\n", -                  qs1); -      return qs1; +    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;      } -   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; -   conflicts[i] = conflicted; -   conflicts2[i] = conflicted2; -   //  fprintf(stdout, "%d", conflicts[i]); -   if (!conflicts[i] && !conflicts2[i]&& transaction_duplicate) -   { -     GNUNET_break (0); -     TEH_PG_rollback (pg); -     return GNUNET_DB_STATUS_HARD_ERROR; -   } -   need_update |= conflicted |= conflicted2; -  } +  } /* end while */    // commit    {      enum GNUNET_DB_QueryStatus cs; @@ -202,7 +531,7 @@ TEH_PG_batch4_reserves_in_insert (void *cls,        return cs;    } -  if (!need_update) +  if (!need_update )      goto exit;    // begin serializable    { @@ -215,10 +544,10 @@ TEH_PG_batch4_reserves_in_insert (void *cls,      }    } -  enum GNUNET_DB_QueryStatus qs2; +  enum GNUNET_DB_QueryStatus qs3;    PREPARE (pg,             "reserves_in_add_transaction", -           "SELECT batch_reserves_update" +           "CALL exchange_do_batch_reserves_update"             " ($1,$2,$3,$4,$5,$6,$7,$8,$9);");    for (unsigned int i=0;i<reserves_length;i++)    { @@ -238,15 +567,15 @@ TEH_PG_batch4_reserves_in_insert (void *cls,          GNUNET_PQ_query_param_end        }; -      qs2 = GNUNET_PQ_eval_prepared_non_select (pg->conn, +      qs3 = GNUNET_PQ_eval_prepared_non_select (pg->conn,                                                  "reserves_in_add_transaction",                                                  params); -      if (qs2<0) +      if (qs3<0)        {          GNUNET_log (GNUNET_ERROR_TYPE_WARNING,                      "Failed to update reserves (%d)\n", -                    qs2); -        return qs2; +                    qs3); +        return qs3;        }      }    } diff --git a/src/exchangedb/pg_batch4_reserves_in_insert.h b/src/exchangedb/pg_batch4_reserves_in_insert.h deleted file mode 100644 index 3b3a629f..00000000 --- a/src/exchangedb/pg_batch4_reserves_in_insert.h +++ /dev/null @@ -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_batch4_reserves_in_insert.h - * @brief implementation of the batch4_reserves_in_insert function for Postgres - * @author XU Joseph - */ -#ifndef PG_BATCH4_RESERVES_IN_INSERT_H -#define PG_BATCH4_RESERVES_IN_INSERT_H - -#include "taler_util.h" -#include "taler_json_lib.h" -#include "taler_exchangedb_plugin.h" - -enum GNUNET_DB_QueryStatus -TEH_PG_batch4_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_batch_reserves_in_insert.c b/src/exchangedb/pg_batch_reserves_in_insert.c index 00c6b922..5b6ab83a 100644 --- a/src/exchangedb/pg_batch_reserves_in_insert.c +++ b/src/exchangedb/pg_batch_reserves_in_insert.c @@ -168,15 +168,15 @@ TEH_PG_batch_reserves_in_insert (      results[i] = (transaction_duplicate)        ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS        : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; -    conflicts[i] = conflicted; -    //  fprintf(stdout, "%d", conflicts[i]); -    if (! conflicts[i] && transaction_duplicate) -    { -      GNUNET_break (0); -      TEH_PG_rollback (pg); -      return GNUNET_DB_STATUS_HARD_ERROR; -    } -    need_update |= conflicted; +   conflicts[i] = conflicted; +   //   fprintf(stdout, "%d", conflicts[i]); +   if (!conflicts[i] && transaction_duplicate) +   { +     GNUNET_break (0); +     TEH_PG_rollback (pg); +     return GNUNET_DB_STATUS_HARD_ERROR; +   } +   need_update |= conflicted;    }    // commit    { diff --git a/src/exchangedb/procedures.sql.in b/src/exchangedb/procedures.sql.in index dc918101..8ddc0ee2 100644 --- a/src/exchangedb/procedures.sql.in +++ b/src/exchangedb/procedures.sql.in @@ -38,5 +38,5 @@ SET search_path TO exchange;  #include "exchange_do_batch_reserves_in_insert.sql"  #include "exchange_do_batch_reserves_update.sql"  #include "exchange_do_batch2_reserves_in_insert.sql" - +#include "exchange_do_batch4_reserves_in_insert.sql"  COMMIT; diff --git a/src/exchangedb/test_exchangedb_batch_reserves_in_insert.c b/src/exchangedb/test_exchangedb_batch_reserves_in_insert.c index b9b5a874..921bffa8 100644 --- a/src/exchangedb/test_exchangedb_batch_reserves_in_insert.c +++ b/src/exchangedb/test_exchangedb_batch_reserves_in_insert.c @@ -94,12 +94,13 @@ run (void *cls)    for (unsigned int i = 0; i< 8; i++)    { -    static unsigned int batches[] = {1, 1,0, 2, 4, 16, 64, 256}; +    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; +    unsigned int iterations = 1024 / batch_size;      struct GNUNET_TIME_Relative duration;      struct TALER_EXCHANGEDB_ReserveInInfo reserves[batch_size];      enum GNUNET_DB_QueryStatus results[batch_size]; @@ -108,9 +109,9 @@ run (void *cls)                                             &value));      now = GNUNET_TIME_absolute_get ();      ts = GNUNET_TIME_timestamp_get (); -    for (unsigned int r=0;r<10;r++) -    { +    for (unsigned int r = 0; r<iterations; r++) +    {        for (unsigned int k = 0; k<batch_size; k++)        {          RND_BLK (&reserves[k].reserve_pub); diff --git a/src/exchangedb/test_exchangedb_by_j.c b/src/exchangedb/test_exchangedb_by_j.c index 3b9b0eea..f0257e2c 100644 --- a/src/exchangedb/test_exchangedb_by_j.c +++ b/src/exchangedb/test_exchangedb_by_j.c @@ -22,6 +22,8 @@  #include "taler_exchangedb_lib.h"  #include "taler_json_lib.h"  #include "taler_exchangedb_plugin.h" +#include "math.h" +#define ROUNDS 100  /**   * Global result from the testcase. @@ -71,6 +73,9 @@ static struct TALER_EXCHANGEDB_Plugin *plugin;  static void  run (void *cls)  { +  static const unsigned int batches[] = {1, 2, 3, 4, 16 }; +  struct GNUNET_TIME_Relative times[sizeof (batches)/sizeof(*batches)]; +  unsigned long long sqrs[sizeof (batches)/sizeof(*batches)];    struct GNUNET_CONFIGURATION_Handle *cfg = cls;    const uint32_t num_partitions = 10; @@ -81,7 +86,8 @@ run (void *cls)      result = 77;      return;    } -  (void) plugin->drop_tables (plugin->cls); + +    if (GNUNET_OK !=        plugin->create_tables (plugin->cls,                               true, @@ -92,51 +98,76 @@ run (void *cls)      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_EXCHANGEDB_ReserveInInfo reserves[batch_size]; -    /*   struct TALER_EXCHANGEDB_ReserveInInfo reserves2[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 r = 0; r<10; r++) +  memset (times, 0, sizeof (times)); +  memset (sqrs, 0, sizeof (sqrs)); +  for (unsigned int r = 0; r < ROUNDS; r++)      { - -       for (unsigned int k = 0; k<batch_size; k++) +    for (unsigned int i = 0; i< 5; i++)        { -        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; +        const char *sndr = "payto://x-taler-bank/localhost:8080/1"; +        struct TALER_Amount value; +        unsigned int batch_size = batches[i]; +        unsigned int iterations = 1024*10; +        struct GNUNET_TIME_Absolute now; +        struct GNUNET_TIME_Timestamp ts; +        struct GNUNET_TIME_Relative duration; +        struct TALER_EXCHANGEDB_ReserveInInfo reserves[iterations]; +        enum GNUNET_DB_QueryStatus results[iterations]; +        unsigned long long duration_sq; + +        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<iterations; r++) +          { +            RND_BLK (&reserves[r].reserve_pub); +            reserves[r].balance = value; +            reserves[r].execution_time = ts; +            reserves[r].sender_account_details = sndr; +            reserves[r].exchange_account_name = "name"; +            reserves[r].wire_reference = r; +          } +        FAILIF (iterations != +                plugin->batch2_reserves_in_insert (plugin->cls, +                                                   reserves, +                                                   iterations, +                                                   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; +        fprintf (stdout, +                 "for a batchsize equal to %d it took %s\n", +                 batch_size, +                 GNUNET_STRINGS_relative_time_to_string (duration, +                                                         GNUNET_NO) ); + +        system ("./test.sh"); //DELETE AFTER TIMER        } -      FAILIF (batch_size != -            plugin->batch2_reserves_in_insert (plugin->cls, -                                              reserves, -                                              batch_size, -                                              results)); +    } +    for (unsigned int i = 0; i< 5; 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, +              "Batch[%2u]: %8llu ± %6.0f\n", +              batches[i], +              (unsigned long long) avg.rel_value_us, +              sqrt (variance / (ROUNDS-1)));      } -    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 ==  | 
