gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-exchange] branch master updated (e0935af -> e0585f2)


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] branch master updated (e0935af -> e0585f2)
Date: Fri, 10 Aug 2018 22:32:47 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a change to branch master
in repository exchange.

    from e0935af  add a few more FOR UPDATE where appropriate
     new abb84bd  add variant that allows us to control the timeout
     new b2f602b  add more logging to more clearly see real conficts, add 
AUTO_EXPLAIN option to analyze query performance
     new 1314b5f  use timeout option in benchmark
     new e606f90  break up refresh/reveal transaction to reduce failure rate, 
increase retries in general
     new e0585f2  resign account-2

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../.config/taler/account-2.json                   |   4 +-
 src/benchmark/taler-exchange-benchmark.c           |   8 +-
 src/exchange-lib/testing_api_loop.c                |  70 +++++---
 src/exchange/taler-exchange-httpd_db.c             |   2 +-
 src/exchange/taler-exchange-httpd_refresh_reveal.c | 197 ++++++++++++++++-----
 src/exchangedb/plugin_exchangedb_postgres.c        |  76 +++++++-
 src/include/taler_testing_lib.h                    |  14 ++
 7 files changed, 289 insertions(+), 82 deletions(-)

diff --git a/src/benchmark/exchange_benchmark_home/.config/taler/account-2.json 
b/src/benchmark/exchange_benchmark_home/.config/taler/account-2.json
index 35a5ec3..b01af76 100644
--- a/src/benchmark/exchange_benchmark_home/.config/taler/account-2.json
+++ b/src/benchmark/exchange_benchmark_home/.config/taler/account-2.json
@@ -1,5 +1,5 @@
 {
   "url": "payto://x-taler-bank/localhost:8082/2",
-  "salt": 
"1D8FXNTNHJZH0FQ60CT136GTHCMBM3WBDMGWNBFXMQ2R7XSCY69Y5MG1745WBJZAWWPNRCXD7KV8CCRWYZ10Y6D1694RVSGBFZFND2R",
-  "master_sig": 
"CRYKJBSH7QJ9Q32SPSR2PQNMFNSV76Q6JN4GHNQXYZ14CC4SFWYM9XWK678XZ05T6QYV0PD76Q4S1E5V7SJ7A49GQW6CZJS8YWH6W28"
+  "salt": 
"4362KHFWBXVY0191AQB6CHAG4GSFAJ3HHWQ3GN86SDZ1TMNZS9TC0201ZJDG7S4JP0K9GE5E4ZBSAE8SEMQRN3ZSGVBPGB7HE7XBHXR",
+  "master_sig": 
"GW122W2JPED3BEPB20T36WN8VMSGDGD7E4NPH8SJ4CBFFY43T1YF2AWE84DA4YNMNYH1NN2C1ZTZNDG08SFG9RQ9V825DDRZ63RWY1R"
 }
\ No newline at end of file
diff --git a/src/benchmark/taler-exchange-benchmark.c 
b/src/benchmark/taler-exchange-benchmark.c
index 3a59bc6..dc6fffa 100644
--- a/src/benchmark/taler-exchange-benchmark.c
+++ b/src/benchmark/taler-exchange-benchmark.c
@@ -428,8 +428,9 @@ run (void *cls,
                                                    unit);
   }
   all_commands[1 + howmany_coins] = TALER_TESTING_cmd_end ();
-  TALER_TESTING_run (is,
-                     all_commands);
+  TALER_TESTING_run2 (is,
+                      all_commands,
+                      GNUNET_TIME_UNIT_FOREVER_REL); /* no timeout */
   result = 1;
 }
 
@@ -586,6 +587,9 @@ parallel_benchmark (TALER_TESTING_Main main_cb,
          NULL,
          cfg_filename,
          exchanged);
+      if (GNUNET_OK != result)
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "Failure in child process test suite!\n");
       if (GNUNET_OK == result)
         exit (0);
       else
diff --git a/src/exchange-lib/testing_api_loop.c 
b/src/exchange-lib/testing_api_loop.c
index 29cafe9..5538a14 100644
--- a/src/exchange-lib/testing_api_loop.c
+++ b/src/exchange-lib/testing_api_loop.c
@@ -204,9 +204,7 @@ TALER_TESTING_interpreter_fail
   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
               "Failed at command `%s'\n",
               cmd->label);
-
   is->result = GNUNET_SYSERR;
-  // this cleans up too.
   GNUNET_SCHEDULER_shutdown ();
 }
 
@@ -332,6 +330,8 @@ do_timeout (void *cls)
   struct TALER_TESTING_Interpreter *is = cls;
 
   is->timeout_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "Terminating test due to timeout\n");
   GNUNET_SCHEDULER_shutdown ();
 }
 
@@ -437,13 +437,14 @@ TALER_TESTING_wait_for_sigchld
  * defined into the "run" method that returns after
  * having scheduled the test interpreter.
  *
- *
  * @param is the interpreter state
  * @param commands the list of command to execute
+ * @param timeout how long to wait
  */
 void
-TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
-                   struct TALER_TESTING_Command *commands)
+TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is,
+                    struct TALER_TESTING_Command *commands,
+                    struct GNUNET_TIME_Relative timeout)
 {
   unsigned int i;
   /* get the number of commands */
@@ -455,14 +456,36 @@ TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
           commands,
           sizeof (struct TALER_TESTING_Command) * i);
   is->timeout_task = GNUNET_SCHEDULER_add_delayed
-    (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300),
-     &do_timeout, is);
+    (timeout,
+     &do_timeout,
+     is);
   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is);
   is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, is);
 }
 
 
 /**
+ * Run the testsuite.  Note, CMDs are copied into
+ * the interpreter state because they are _usually_
+ * defined into the "run" method that returns after
+ * having scheduled the test interpreter.
+ *
+ *
+ * @param is the interpreter state
+ * @param commands the list of command to execute
+ */
+void
+TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
+                   struct TALER_TESTING_Command *commands)
+{
+  TALER_TESTING_run2 (is,
+                      commands,
+                      GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES,
+                                                     5));
+}
+
+
+/**
  * Information used by the wrapper around the main
  * "run" method.
  */
@@ -529,15 +552,15 @@ cert_cb (void *cls,
 
   if (NULL == keys)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Got NULL response for /keys\n");
-
   }
   else
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Got %d DK from /keys\n",
                 keys->num_denom_keys);
-
+  }
   main_ctx->is->key_generation++;
   main_ctx->is->keys = keys;
 
@@ -596,8 +619,9 @@ main_wrapper_exchange_connect (void *cls)
   char *exchange_url;
 
   cfg = GNUNET_CONFIGURATION_create ();
-  if (GNUNET_OK != GNUNET_CONFIGURATION_load
-    (cfg, main_ctx->config_filename))
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_load (cfg,
+                                 main_ctx->config_filename))
     return;
 
   if (GNUNET_OK !=
@@ -612,11 +636,11 @@ main_wrapper_exchange_connect (void *cls)
     GNUNET_CONFIGURATION_destroy (cfg);
     return;
   }
-  GNUNET_assert ( NULL !=
-    (is->exchange = TALER_EXCHANGE_connect (is->ctx,
-                                            exchange_url,
-                                            cert_cb,
-                                            main_ctx)) );
+  GNUNET_assert (NULL !=
+                 (is->exchange = TALER_EXCHANGE_connect (is->ctx,
+                                                         exchange_url,
+                                                         &cert_cb,
+                                                         main_ctx)));
   GNUNET_free (exchange_url);
   GNUNET_CONFIGURATION_destroy (cfg);
 }
@@ -635,9 +659,8 @@ main_wrapper_exchange_connect (void *cls)
  *        signal to it, for example to let it know to reload the
  *        key state.. if NULL, the interpreter will run without
  *        trying to connect to the exchange first.
- *
- * @return GNUNET_OK if all is okay, != GNUNET_OK otherwise.
- *         non-GNUNET_OK codes are GNUNET_SYSERR most of the
+ * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
+ *         non-GNUNET_OK codes are #GNUNET_SYSERR most of the
  *         times.
  */
 int
@@ -657,7 +680,7 @@ TALER_TESTING_setup (TALER_TESTING_Main main_cb,
     .config_filename = config_filename
   };
   struct GNUNET_SIGNAL_Context *shc_chld;
-  /* zero-ing the state */
+
   memset (&is,
           0,
           sizeof (is));
@@ -669,7 +692,8 @@ TALER_TESTING_setup (TALER_TESTING_Main main_cb,
     (GNUNET_SIGCHLD, &sighandler_child_death);
 
   is.ctx = GNUNET_CURL_init
-    (&GNUNET_CURL_gnunet_scheduler_reschedule, &is.rc);
+    (&GNUNET_CURL_gnunet_scheduler_reschedule,
+     &is.rc);
   GNUNET_assert (NULL != is.ctx);
   is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx);
 
diff --git a/src/exchange/taler-exchange-httpd_db.c 
b/src/exchange/taler-exchange-httpd_db.c
index 1f7e0f2..76a45e2 100644
--- a/src/exchange/taler-exchange-httpd_db.c
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -30,7 +30,7 @@
  * How often should we retry a transaction before giving up
  * (for transactions resulting in serialization/dead locks only).
  */
-#define MAX_TRANSACTION_COMMIT_RETRIES 2
+#define MAX_TRANSACTION_COMMIT_RETRIES 10
 
 
 /**
diff --git a/src/exchange/taler-exchange-httpd_refresh_reveal.c 
b/src/exchange/taler-exchange-httpd_refresh_reveal.c
index b045184..39e17df 100644
--- a/src/exchange/taler-exchange-httpd_refresh_reveal.c
+++ b/src/exchange/taler-exchange-httpd_refresh_reveal.c
@@ -36,6 +36,13 @@
  */
 #define MAX_FRESH_COINS 256
 
+/**
+ * How often do we at most retry the reveal transaction sequence?
+ * Twice should really suffice in all cases (as the possible conflict
+ * cannot happen more than once).
+ */
+#define MAX_REVEAL_RETRIES 2
+
 
 /**
  * Send a response for "/refresh/reveal".
@@ -142,6 +149,14 @@ struct RevealContext
    */
   unsigned int num_fresh_coins;
 
+  /**
+   * Result from preflight checks. #GNUNET_NO for no result,
+   * #GNUNET_YES if preflight found previous successful operation,
+   * #GNUNET_SYSERR if prefight check failed hard (and generated
+   * an MHD response already).
+   */
+  int preflight_ok;
+
 };
 
 
@@ -189,17 +204,8 @@ check_exists_cb (void *cls,
 
 
 /**
- * Execute a "/refresh/reveal".  The client is revealing to us the
- * transfer keys for @a #TALER_CNC_KAPPA-1 sets of coins.  Verify that the
- * revealed transfer keys would allow linkage to the blinded coins,
- * and if so, return the signed coins for corresponding to the set of
- * coins that was not chosen.
- *
- * IF it returns a non-error code, the transaction logic MUST
- * NOT queue a MHD response.  IF it returns an hard error, the
- * transaction logic MUST queue a MHD response and set @a mhd_ret.  IF
- * it returns the soft error code, the function MAY be called again to
- * retry and MUST not queue a MHD response.
+ * Check if the "/refresh/reveal" was already successful before.
+ * If so, just return the old result.
  *
  * @param cls closure of type `struct RevealContext`
  * @param connection MHD request which triggered the transaction
@@ -209,13 +215,12 @@ check_exists_cb (void *cls,
  * @return transaction status
  */
 static enum GNUNET_DB_QueryStatus
-refresh_reveal_transaction (void *cls,
-                           struct MHD_Connection *connection,
-                           struct TALER_EXCHANGEDB_Session *session,
-                           int *mhd_ret)
+refresh_reveal_preflight (void *cls,
+                          struct MHD_Connection *connection,
+                          struct TALER_EXCHANGEDB_Session *session,
+                          int *mhd_ret)
 {
   struct RevealContext *rctx = cls;
-  struct TALER_EXCHANGEDB_RefreshMelt refresh_melt;
   enum GNUNET_DB_QueryStatus qs;
 
   /* Try to see if we already have given an answer before. */
@@ -226,21 +231,52 @@ refresh_reveal_transaction (void *cls,
                                        rctx);
   switch (qs) {
   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
-    /* continue normal execution */
-    break;
+    return qs; /* continue normal execution */
   case GNUNET_DB_STATUS_SOFT_ERROR:
     return qs;
   case GNUNET_DB_STATUS_HARD_ERROR:
     GNUNET_break (qs);
     *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
                                                     
TALER_EC_REFRESH_REVEAL_DB_FETCH_REVEAL_ERROR);
+    rctx->preflight_ok = GNUNET_SYSERR;
     return GNUNET_DB_STATUS_HARD_ERROR;
   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   default:
     /* Hossa, already found our reply! */
     GNUNET_assert (NULL != rctx->ev_sigs);
+    rctx->preflight_ok = GNUNET_YES;
     return qs;
   }
+}
+
+
+/**
+ * Execute a "/refresh/reveal".  The client is revealing to us the
+ * transfer keys for @a #TALER_CNC_KAPPA-1 sets of coins.  Verify that the
+ * revealed transfer keys would allow linkage to the blinded coins.
+ *
+ * IF it returns a non-error code, the transaction logic MUST
+ * NOT queue a MHD response.  IF it returns an hard error, the
+ * transaction logic MUST queue a MHD response and set @a mhd_ret.  IF
+ * it returns the soft error code, the function MAY be called again to
+ * retry and MUST not queue a MHD response.
+ *
+ * @param cls closure of type `struct RevealContext`
+ * @param connection MHD request which triggered the transaction
+ * @param session database session to use
+ * @param[out] mhd_ret set to MHD response status for @a connection,
+ *             if transaction failed (!)
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+refresh_reveal_transaction (void *cls,
+                           struct MHD_Connection *connection,
+                           struct TALER_EXCHANGEDB_Session *session,
+                           int *mhd_ret)
+{
+  struct RevealContext *rctx = cls;
+  struct TALER_EXCHANGEDB_RefreshMelt refresh_melt;
+  enum GNUNET_DB_QueryStatus qs;
 
   /* Obtain basic information about the refresh operation and what
      gamma we committed to. */
@@ -394,23 +430,28 @@ refresh_reveal_transaction (void *cls,
       return GNUNET_DB_STATUS_HARD_ERROR;
     }
   }
+  return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+}
 
-  /* Client request OK, sign coins */
-  rctx->ev_sigs = GNUNET_new_array (rctx->num_fresh_coins,
-                                    struct TALER_DenominationSignature);
-  for (unsigned int i=0;i<rctx->num_fresh_coins;i++)
-  {
-    rctx->ev_sigs[i].rsa_signature
-      = GNUNET_CRYPTO_rsa_sign_blinded 
(rctx->dkis[i]->denom_priv.rsa_private_key,
-                                        rctx->rcds[i].coin_ev,
-                                        rctx->rcds[i].coin_ev_size);
-    if (NULL == rctx->ev_sigs[i].rsa_signature)
-    {
-      *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
-                                                       
TALER_EC_REFRESH_REVEAL_SIGNING_ERROR);
-      return GNUNET_DB_STATUS_HARD_ERROR;
-    }
-  }
+
+/**
+ * Persist result of a "/refresh/reveal".
+ *
+ * @param cls closure of type `struct RevealContext`
+ * @param connection MHD request which triggered the transaction
+ * @param session database session to use
+ * @param[out] mhd_ret set to MHD response status for @a connection,
+ *             if transaction failed (!)
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+refresh_reveal_persist (void *cls,
+                        struct MHD_Connection *connection,
+                        struct TALER_EXCHANGEDB_Session *session,
+                        int *mhd_ret)
+{
+  struct RevealContext *rctx = cls;
+  enum GNUNET_DB_QueryStatus qs;
 
   /* Persist operation result in DB */
   {
@@ -584,22 +625,84 @@ handle_refresh_reveal_json (struct MHD_Connection 
*connection,
     rctx->num_fresh_coins = num_fresh_coins;
     rctx->rcds = rcds;
     rctx->dkis = dkis;
-    /* do transactional work */
-    if (GNUNET_OK ==
-        TEH_DB_run_transaction (connection,
-                                "run reveal",
-                                &res,
-                                &refresh_reveal_transaction,
-                                rctx))
-    {
-      /* Generate final (positive) response */
-      GNUNET_assert (NULL != rctx->ev_sigs);
-      res = reply_refresh_reveal_success (connection,
-                                         num_fresh_coins,
-                                         rctx->ev_sigs);
 
+    /* sign _early_ (optimistic!) to keep out of transaction scope! */
+    rctx->ev_sigs = GNUNET_new_array (rctx->num_fresh_coins,
+                                      struct TALER_DenominationSignature);
+    for (unsigned int i=0;i<rctx->num_fresh_coins;i++)
+    {
+      rctx->ev_sigs[i].rsa_signature
+        = GNUNET_CRYPTO_rsa_sign_blinded 
(rctx->dkis[i]->denom_priv.rsa_private_key,
+                                          rctx->rcds[i].coin_ev,
+                                          rctx->rcds[i].coin_ev_size);
+      if (NULL == rctx->ev_sigs[i].rsa_signature)
+      {
+        GNUNET_break (0);
+        res = TEH_RESPONSE_reply_internal_db_error (connection,
+                                                    
TALER_EC_REFRESH_REVEAL_SIGNING_ERROR);
+        goto cleanup;
+      }
     }
 
+    /* We try the three transactions a few times, as theoretically
+       the pre-check might be satisfied by a concurrent transaction
+       voiding our final commit due to uniqueness violation; naturally,
+       on hard errors we exit immediately */
+    for (unsigned int retries=0;retries < MAX_REVEAL_RETRIES;retries++)
+    {
+      /* do transactional work */
+      rctx->preflight_ok = GNUNET_NO;
+      if ( (GNUNET_OK ==
+            TEH_DB_run_transaction (connection,
+                                    "reveal pre-check",
+                                    &res,
+                                    &refresh_reveal_preflight,
+                                    rctx)) &&
+           (GNUNET_YES == rctx->preflight_ok) )
+      {
+        /* Generate final (positive) response */
+        GNUNET_assert (NULL != rctx->ev_sigs);
+        res = reply_refresh_reveal_success (connection,
+                                            num_fresh_coins,
+                                            rctx->ev_sigs);
+        GNUNET_break (MHD_NO != res);
+        goto cleanup; /* aka 'break' */
+      }
+      if (GNUNET_SYSERR == rctx->preflight_ok)
+      {
+        GNUNET_break (0);
+        goto cleanup; /* aka 'break' */
+      }
+      if (GNUNET_OK !=
+          TEH_DB_run_transaction (connection,
+                                  "run reveal",
+                                  &res,
+                                  &refresh_reveal_transaction,
+                                  rctx))
+      {
+        /* reveal failed, too bad */
+        GNUNET_break_op (0);
+        goto cleanup; /* aka 'break' */
+      }
+      if (GNUNET_OK ==
+          TEH_DB_run_transaction (connection,
+                                  "persist reveal",
+                                  &res,
+                                  &refresh_reveal_persist,
+                                  rctx))
+      {
+        /* Generate final (positive) response */
+        GNUNET_assert (NULL != rctx->ev_sigs);
+        res = reply_refresh_reveal_success (connection,
+                                            num_fresh_coins,
+                                            rctx->ev_sigs);
+        break;
+      }
+    } /* end for (retries...) */
+    GNUNET_break (MHD_NO != res);
+
+  cleanup:
+    GNUNET_break (MHD_NO != res);
     /* free resources */
     if (NULL != rctx->ev_sigs)
     {
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index ac8d395..02ab5d7 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -31,6 +31,12 @@
 
 #include "plugin_exchangedb_common.c"
 
+/**
+ * Set to 1 to enable Postgres auto_explain module. This will
+ * slow down things a _lot_, but also provide extensive logging
+ * in the Postgres database logger for performance analysis.
+ */
+#define AUTO_EXPLAIN 1
 
 /**
  * Log a really unexpected PQ error with all the details we can get hold of.
@@ -204,7 +210,7 @@ postgres_create_tables (void *cls)
                             ",current_balance_curr 
VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
                             ",expiration_date INT8 NOT NULL"
                             ");"),
-    /* index on reserves table */
+    /* index on reserves table (TODO: useless due to primary key!?) */
     GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_reserve_pub_index ON "
                                 "reserves (reserve_pub);"),
     /* index for get_expired_reserves */
@@ -228,6 +234,13 @@ postgres_create_tables (void *cls)
     /* Create indices on reserves_in */
     GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_in_execution_index"
                                 " ON reserves_in 
(exchange_account_section,execution_date);"),
+    /* TODO: verify this actually helps, given the PRIMARY_KEY already includes
+       reserve_pub as the first dimension! */
+    GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_in_reserve_pub"
+                                " ON reserves_in (reserve_pub);"),
+    GNUNET_PQ_make_try_execute ("CREATE INDEX 
reserves_in_exchange_account_serial"
+                                " ON reserves_in 
(exchange_account_section,reserve_in_serial_id DESC);"),
+
     /* This table contains the data for wire transfers the exchange has
        executed to close a reserve. */
     GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS reserves_close "
@@ -267,6 +280,8 @@ postgres_create_tables (void *cls)
                                 " reserves_out (reserve_pub)"),
     GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_out_execution_date ON "
                                 "reserves_out (execution_date)"),
+    GNUNET_PQ_make_try_execute ("CREATE INDEX 
reserves_out_for_get_withdraw_info ON "
+                                "reserves_out (denom_pub_hash,h_blind_ev)"),
     /* Table with coins that have been (partially) spent, used to track
        coin information only once. */
     GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS known_coins "
@@ -303,6 +318,8 @@ postgres_create_tables (void *cls)
                            ",ev_sig BYTEA NOT NULL"
                            ",PRIMARY KEY (rc, newcoin_index)"
                            ");"),
+    GNUNET_PQ_make_try_execute ("CREATE INDEX 
refresh_revealed_coins_coin_pub_index ON "
+                                "refresh_revealed_coins (denom_pub_hash);"),
 
     /* Table with the transfer keys of a refresh operation; includes
        the rc for which this is the link information, the
@@ -313,6 +330,12 @@ postgres_create_tables (void *cls)
                            ",transfer_pub BYTEA NOT NULL 
CHECK(LENGTH(transfer_pub)=32)"
                            ",transfer_privs BYTEA NOT NULL"
                            ");"),
+    /* for "get_link" (not sure if this helps, as there should be very few
+       transfer_pubs per rc, but at least in theory this helps the ORDER BY
+       clause. */
+    GNUNET_PQ_make_try_execute ("CREATE INDEX refresh_transfer_keys_coin_tpub 
ON "
+                                "refresh_transfer_keys (rc,transfer_pub);"),
+
 
     /* This table contains the wire transfers the exchange is supposed to
        execute to transmit funds to the merchants (and manage refunds). */
@@ -332,12 +355,9 @@ postgres_create_tables (void *cls)
                            ",wire TEXT NOT NULL"
                            ",tiny BOOLEAN NOT NULL DEFAULT FALSE"
                            ",done BOOLEAN NOT NULL DEFAULT FALSE"
-                           ",UNIQUE (coin_pub, h_contract_terms, merchant_pub)"
+                           ",UNIQUE (coin_pub, merchant_pub, h_contract_terms)"
                            ");"),
-    /* Index for get_deposit statement on coin_pub, h_contract_terms and 
merchant_pub */
-    GNUNET_PQ_make_try_execute("CREATE INDEX deposits_coin_pub_index "
-                               "ON deposits(coin_pub, h_contract_terms, 
merchant_pub)"),
-    /* Index for get_deposit_for_wtid */
+    /* Index for get_deposit_for_wtid and get_deposit_statement */
     GNUNET_PQ_make_try_execute("CREATE INDEX 
deposits_coin_pub_merchant_contract_index "
                                "ON deposits(coin_pub, merchant_pub, 
h_contract_terms)"),
     /* Index for deposits_get_ready */
@@ -419,8 +439,12 @@ postgres_create_tables (void *cls)
                            ");"),
     GNUNET_PQ_make_try_execute("CREATE INDEX payback_by_coin_index "
                                "ON payback(coin_pub);"),
+    GNUNET_PQ_make_try_execute("CREATE INDEX payback_by_h_blind_ev "
+                               "ON payback(h_blind_ev);"),
     GNUNET_PQ_make_try_execute("CREATE INDEX payback_by_reserve_index "
                                "ON payback(reserve_pub);"),
+    GNUNET_PQ_make_try_execute("CREATE INDEX payback_for_by_reserve "
+                               "ON 
payback(coin_pub,denom_pub_hash,h_blind_ev);"),
 
     /* This table contains the pre-commit data for
        wire transfers the exchange is about to execute. */
@@ -1009,8 +1033,8 @@ postgres_prepare (PGconn *db_conn)
                             " FROM deposits"
                             " WHERE ("
                             "        (coin_pub=$1)"
-                            "    AND (h_contract_terms=$2)"
                             "    AND (merchant_pub=$3)"
+                            "    AND (h_contract_terms=$2)"
                             " )"
                             " FOR UPDATE;",
                             3),
@@ -1665,6 +1689,26 @@ postgres_get_session (void *cls)
     PQfinish (db_conn);
     return NULL;
   }
+
+#if AUTO_EXPLAIN
+  /* Enable verbose logging to see where queries do not
+     properly use indices */
+  {
+    struct GNUNET_PQ_ExecuteStatement es[] = {
+      GNUNET_PQ_make_execute ("LOAD 'auto_explain';"),
+      GNUNET_PQ_make_execute ("SET auto_explain.log_min_duration=50;"),
+      GNUNET_PQ_make_execute ("SET auto_explain.log_timing=TRUE;"),
+      GNUNET_PQ_make_execute ("SET auto_explain.log_analyze=TRUE;"),
+      GNUNET_PQ_make_execute ("SET enable_sort=OFF;"),
+      GNUNET_PQ_make_execute ("SET enable_seqscan=OFF;"),
+      GNUNET_PQ_EXECUTE_STATEMENT_END
+    };
+
+    (void) GNUNET_PQ_exec_statements (db_conn,
+                                      es);
+  }
+#endif
+
   session = GNUNET_new (struct TALER_EXCHANGEDB_Session);
   session->conn = db_conn;
   if (0 != pthread_setspecific (pc->db_conn_threadlocal,
@@ -1696,6 +1740,9 @@ postgres_start (void *cls,
   PGresult *result;
   ExecStatusType ex;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Starting transaction on %p\n",
+              session->conn);
   result = PQexec (session->conn,
                    "START TRANSACTION ISOLATION LEVEL SERIALIZABLE");
   if (PGRES_COMMAND_OK !=
@@ -1727,6 +1774,9 @@ postgres_rollback (void *cls,
 {
   PGresult *result;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Rolling back transaction on %p\n",
+              session->conn);
   result = PQexec (session->conn,
                    "ROLLBACK");
   GNUNET_break (PGRES_COMMAND_OK ==
@@ -2696,6 +2746,9 @@ postgres_have_deposit (void *cls,
   };
   enum GNUNET_DB_QueryStatus qs;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Getting deposits for coin %s\n",
+              TALER_B2S (&deposit->coin.coin_pub));
   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
                                                 "get_deposit",
                                                 params,
@@ -3090,6 +3143,9 @@ get_known_coin (void *cls,
     GNUNET_PQ_result_spec_end
   };
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Getting known coin data for coin %s\n",
+              TALER_B2S (coin_pub));
   coin_info->coin_pub = *coin_pub;
   return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
                                                   "get_known_coin",
@@ -3121,6 +3177,9 @@ insert_known_coin (void *cls,
     GNUNET_PQ_query_param_end
   };
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Creating known coin %s\n",
+              TALER_B2S (&coin_info->coin_pub));
   GNUNET_CRYPTO_rsa_public_key_hash (coin_info->denom_pub.rsa_public_key,
                                     &denom_pub_hash);
   return GNUNET_PQ_eval_prepared_non_select (session->conn,
@@ -4259,6 +4318,9 @@ postgres_get_coin_transactions (void *cls,
     { NULL, NULL }
   };
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Getting transactions for coin %s\n",
+              TALER_B2S (coin_pub));
   chc.head = NULL;
   chc.status = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
   chc.coin_pub = coin_pub;
diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h
index 71bc8cd..8e55c05 100644
--- a/src/include/taler_testing_lib.h
+++ b/src/include/taler_testing_lib.h
@@ -420,6 +420,20 @@ TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
                    struct TALER_TESTING_Command *commands);
 
 
+/**
+ * Run the testsuite.  Note, CMDs are copied into
+ * the interpreter state because they are _usually_
+ * defined into the "run" method that returns after
+ * having scheduled the test interpreter.
+ *
+ * @param is the interpreter state
+ * @param commands the list of command to execute
+ * @param timeout how long to wait
+ */
+void
+TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is,
+                    struct TALER_TESTING_Command *commands,
+                    struct GNUNET_TIME_Relative timeout);
 
 
 /**

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]