save 2ms on deposit by not doing idempotency check twice

This commit is contained in:
Christian Grothoff 2021-12-04 23:24:44 +01:00
parent ec45eaae18
commit e61a53806e
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC

View File

@ -139,11 +139,12 @@ struct DepositContext
/**
* Check if /deposit is already in the database. 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. We do return a "hard" error also if we found the deposit in the
* database and generated a regular response.
* Execute database transaction for /deposit. Runs the transaction
* logic; IF it returns a non-error code, the transaction logic MUST
* NOT queue a MHD response. IF it returns an hard error, the
* transaction logic MUST queue a MHD response and set @a mhd_ret. IF
* it returns the soft error code, the function MAY be called again to
* retry and MUST not queue a MHD response.
*
* @param cls a `struct DepositContext`
* @param connection MHD request context
@ -151,15 +152,24 @@ struct DepositContext
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
deposit_precheck (void *cls,
struct MHD_Connection *connection,
MHD_RESULT *mhd_ret)
deposit_transaction (void *cls,
struct MHD_Connection *connection,
MHD_RESULT *mhd_ret)
{
struct DepositContext *dc = cls;
const struct TALER_EXCHANGEDB_Deposit *deposit = dc->deposit;
struct TALER_Amount deposit_fee;
struct TALER_Amount spent;
enum GNUNET_DB_QueryStatus qs;
struct TALER_Amount deposit_fee;
/* make sure coin is 'known' in database */
qs = TEH_make_coin_known (&deposit->coin,
connection,
mhd_ret);
if (qs < 0)
return qs;
/* Check for idempotency: did we get this request before? */
qs = TEH_plugin->have_deposit (TEH_plugin->cls,
deposit,
&deposit_fee,
@ -196,51 +206,8 @@ deposit_precheck (void *cls,
deposit->wire_deadline,
&deposit->merchant_pub,
&amount_without_fee);
/* Treat as 'hard' DB error as we want to rollback and
never try again. */
return GNUNET_DB_STATUS_HARD_ERROR;
}
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
}
/**
* Execute database transaction for /deposit. Runs the transaction
* logic; IF it returns a non-error code, the transaction logic MUST
* NOT queue a MHD response. IF it returns an hard error, the
* transaction logic MUST queue a MHD response and set @a mhd_ret. IF
* it returns the soft error code, the function MAY be called again to
* retry and MUST not queue a MHD response.
*
* @param cls a `struct DepositContext`
* @param connection MHD request context
* @param[out] mhd_ret set to MHD status on error
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
deposit_transaction (void *cls,
struct MHD_Connection *connection,
MHD_RESULT *mhd_ret)
{
struct DepositContext *dc = cls;
const struct TALER_EXCHANGEDB_Deposit *deposit = dc->deposit;
struct TALER_Amount spent;
enum GNUNET_DB_QueryStatus qs;
/* make sure coin is 'known' in database */
qs = TEH_make_coin_known (&deposit->coin,
connection,
mhd_ret);
if (qs < 0)
return qs;
/* Theoretically, someone other threat may have received
and committed the deposit in the meantime. Check now
that we are in the transaction scope. */
qs = deposit_precheck (cls,
connection,
mhd_ret);
if (qs < 0)
return qs;
/* Start with fee for THIS transaction */
spent = deposit->amount_with_fee;
@ -412,22 +379,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
TALER_merchant_wire_signature_hash (dc.payto_uri,
&deposit.wire_salt,
&dc.h_wire);
/* Check for idempotency: did we get this request before? */
dc.deposit = &deposit;
{
MHD_RESULT mhd_ret;
if (GNUNET_OK !=
TEH_DB_run_transaction (connection,
"precheck deposit",
&mhd_ret,
&deposit_precheck,
&dc))
{
GNUNET_JSON_parse_free (spec);
return mhd_ret;
}
}
/* new deposit */
dc.exchange_timestamp = GNUNET_TIME_absolute_get ();