diff options
22 files changed, 157 insertions, 40 deletions
diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c index e807378fe..b8f6c624c 100644 --- a/src/auditor/taler-auditor.c +++ b/src/auditor/taler-auditor.c @@ -1890,7 +1890,7 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Detected applicable deposit of %s\n", TALER_amount2s (&amount_without_fee)); - deposit_fee = fee; + deposit_fee = fee; } /* Check that the fees given in the transaction list and in dki match */ TALER_amount_ntoh (&tmp, @@ -2006,7 +2006,7 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub, merchant_gain, deposit_fee)); } - + /* Calculate total balance change, i.e. expenditures minus refunds */ if (GNUNET_SYSERR == TALER_amount_subtract (&spent, @@ -3906,8 +3906,11 @@ transact (Analysis analysis, GNUNET_break (0); return GNUNET_SYSERR; } + edb->preflight (edb->cls, + esession); ret = edb->start (edb->cls, - esession); + esession, + "auditor"); if (GNUNET_OK != ret) { GNUNET_break (0); @@ -3918,7 +3921,7 @@ transact (Analysis analysis, if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) { qs = edb->commit (edb->cls, - esession); + esession); if (0 > qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); diff --git a/src/auditor/taler-wire-auditor.c b/src/auditor/taler-wire-auditor.c index 8ba38d39c..55a2a05fb 100644 --- a/src/auditor/taler-wire-auditor.c +++ b/src/auditor/taler-wire-auditor.c @@ -1412,8 +1412,11 @@ run (void *cls, GNUNET_SCHEDULER_shutdown (); return; } + edb->preflight (edb->cls, + esession); ret = edb->start (edb->cls, - esession); + esession, + "wire auditor"); if (GNUNET_OK != ret) { GNUNET_break (0); diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c index d5d43052d..49cbb2b93 100644 --- a/src/exchange/taler-exchange-aggregator.c +++ b/src/exchange/taler-exchange-aggregator.c @@ -618,7 +618,7 @@ refund_by_coin_cb (void *cls, } return GNUNET_OK; } - + /** * Function called with details about deposits that have been made, @@ -675,7 +675,7 @@ deposit_cb (void *cls, GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); return qs; } - + GNUNET_assert (NULL == au->wire); au->wire = json_incref ((json_t *) wire); if (GNUNET_OK != @@ -810,7 +810,7 @@ aggregate_cb (void *cls, GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); return qs; } - + if (au->rows_offset >= aggregation_limit) { /* Bug: we asked for at most #aggregation_limit results! */ @@ -1203,9 +1203,12 @@ run_reserve_closures (void *cls) GNUNET_SCHEDULER_shutdown (); return; } + db_plugin->preflight (db_plugin->cls, + session); if (GNUNET_OK != db_plugin->start (db_plugin->cls, - session)) + session, + "aggregator reserve closures")) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start database transaction!\n"); @@ -1413,7 +1416,8 @@ run_aggregation (void *cls) transaction to mark all* of the selected deposits as minor! */ if (GNUNET_OK != db_plugin->start (db_plugin->cls, - session)) + session, + "aggregator mark tiny transactions")) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start database transaction!\n"); @@ -1767,9 +1771,12 @@ run_transfers (void *cls) GNUNET_SCHEDULER_shutdown (); return; } + db_plugin->preflight (db_plugin->cls, + session); if (GNUNET_OK != db_plugin->start (db_plugin->cls, - session)) + session, + "aggregator run transfer")) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start database transaction!\n"); diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c index bd7777ce3..7817de990 100644 --- a/src/exchange/taler-exchange-httpd_db.c +++ b/src/exchange/taler-exchange-httpd_db.c @@ -41,6 +41,7 @@ * errors, generates an error message for @a connection. * * @param connection MHD connection to run @a cb for + * @param name name of the transaction (for debugging) * @param[out] set to MHD response code, if transaction failed * @param cb callback implementing transaction logic * @param cb_cls closure for @a cb, must be read-only! @@ -48,6 +49,7 @@ */ int TEH_DB_run_transaction (struct MHD_Connection *connection, + const char *name, int *mhd_ret, TEH_DB_TransactionCallback cb, void *cb_cls) @@ -64,13 +66,16 @@ TEH_DB_run_transaction (struct MHD_Connection *connection, TALER_EC_DB_SETUP_FAILED); return GNUNET_SYSERR; } + TEH_plugin->preflight (TEH_plugin->cls, + session); for (unsigned int retries = 0;retries < MAX_TRANSACTION_COMMIT_RETRIES; retries++) { enum GNUNET_DB_QueryStatus qs; if (GNUNET_OK != TEH_plugin->start (TEH_plugin->cls, - session)) + session, + name)) { GNUNET_break (0); if (NULL != mhd_ret) diff --git a/src/exchange/taler-exchange-httpd_db.h b/src/exchange/taler-exchange-httpd_db.h index 7e342c842..2a42bcd85 100644 --- a/src/exchange/taler-exchange-httpd_db.h +++ b/src/exchange/taler-exchange-httpd_db.h @@ -52,8 +52,9 @@ typedef enum GNUNET_DB_QueryStatus * attempts to commit the transaction. Upon soft failures, * retries @a cb a few times. Upon hard or persistent soft * errors, generates an error message for @a connection. - * + * * @param connection MHD connection to run @a cb for + * @param name name of the transaction (for debugging) * @param[out] set to MHD response code, if transaction failed * @param cb callback implementing transaction logic * @param cb_cls closure for @a cb, must be read-only! @@ -61,6 +62,7 @@ typedef enum GNUNET_DB_QueryStatus */ int TEH_DB_run_transaction (struct MHD_Connection *connection, + const char *name, int *mhd_ret, TEH_DB_TransactionCallback cb, void *cb_cls); diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c index 542c56c9c..277430b2d 100644 --- a/src/exchange/taler-exchange-httpd_deposit.c +++ b/src/exchange/taler-exchange-httpd_deposit.c @@ -289,6 +289,7 @@ verify_and_execute_deposit (struct MHD_Connection *connection, dc.deposit = deposit; if (GNUNET_OK != TEH_DB_run_transaction (connection, + "execute deposit", &mhd_ret, &deposit_transaction, &dc)) diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c index 0428b1016..042773bf9 100644 --- a/src/exchange/taler-exchange-httpd_keystate.c +++ b/src/exchange/taler-exchange-httpd_keystate.c @@ -711,6 +711,7 @@ reload_keys_denom_iter (void *cls, arc.revocation_master_sig = revocation_master_sig; if (GNUNET_OK != TEH_DB_run_transaction (NULL, + "add denomination key revocations", NULL, &add_revocations_transaction, &arc)) @@ -739,6 +740,7 @@ reload_keys_denom_iter (void *cls, if (GNUNET_OK != TEH_DB_run_transaction (NULL, + "add denomination key", NULL, &add_denomination_transaction, (void *) dki)) diff --git a/src/exchange/taler-exchange-httpd_payback.c b/src/exchange/taler-exchange-httpd_payback.c index e6fade49e..6f910b55b 100644 --- a/src/exchange/taler-exchange-httpd_payback.c +++ b/src/exchange/taler-exchange-httpd_payback.c @@ -396,6 +396,7 @@ verify_and_execute_payback (struct MHD_Connection *connection, pc.coin = coin; if (GNUNET_OK != TEH_DB_run_transaction (connection, + "run payback", &mhd_ret, &payback_transaction, &pc)) diff --git a/src/exchange/taler-exchange-httpd_refresh_link.c b/src/exchange/taler-exchange-httpd_refresh_link.c index aee23369c..0ec505a84 100644 --- a/src/exchange/taler-exchange-httpd_refresh_link.c +++ b/src/exchange/taler-exchange-httpd_refresh_link.c @@ -203,6 +203,7 @@ TEH_REFRESH_handler_refresh_link (struct TEH_RequestHandler *rh, ctx.mlist = json_array (); if (GNUNET_OK != TEH_DB_run_transaction (connection, + "run link", &mhd_ret, &refresh_link_transaction, &ctx)) diff --git a/src/exchange/taler-exchange-httpd_refresh_melt.c b/src/exchange/taler-exchange-httpd_refresh_melt.c index 400d2bb8c..384589df1 100644 --- a/src/exchange/taler-exchange-httpd_refresh_melt.c +++ b/src/exchange/taler-exchange-httpd_refresh_melt.c @@ -364,6 +364,7 @@ handle_refresh_melt (struct MHD_Connection *connection, if (GNUNET_OK != TEH_DB_run_transaction (connection, + "run melt", &mhd_ret, &refresh_melt_transaction, rmc)) diff --git a/src/exchange/taler-exchange-httpd_refresh_reveal.c b/src/exchange/taler-exchange-httpd_refresh_reveal.c index 4a7cd33db..b0451842d 100644 --- a/src/exchange/taler-exchange-httpd_refresh_reveal.c +++ b/src/exchange/taler-exchange-httpd_refresh_reveal.c @@ -587,6 +587,7 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, /* do transactional work */ if (GNUNET_OK == TEH_DB_run_transaction (connection, + "run reveal", &res, &refresh_reveal_transaction, rctx)) diff --git a/src/exchange/taler-exchange-httpd_refund.c b/src/exchange/taler-exchange-httpd_refund.c index 986c9d312..97cd9351f 100644 --- a/src/exchange/taler-exchange-httpd_refund.c +++ b/src/exchange/taler-exchange-httpd_refund.c @@ -452,6 +452,7 @@ verify_and_execute_refund (struct MHD_Connection *connection, } if (GNUNET_OK != TEH_DB_run_transaction (connection, + "run refund", &mhd_ret, &refund_transaction, (void *) refund)) diff --git a/src/exchange/taler-exchange-httpd_reserve_status.c b/src/exchange/taler-exchange-httpd_reserve_status.c index f87afa5ae..998460da7 100644 --- a/src/exchange/taler-exchange-httpd_reserve_status.c +++ b/src/exchange/taler-exchange-httpd_reserve_status.c @@ -78,7 +78,7 @@ struct ReserveStatusContext /** - * Function implementing /reserve/status transaction. + * Function implementing /reserve/status transaction. * Execute a /reserve/status. Given the public key of a reserve, * return the associated transaction history. Runs the * transaction logic; IF it returns a non-error code, the transaction @@ -144,6 +144,7 @@ TEH_RESERVE_handler_reserve_status (struct TEH_RequestHandler *rh, rsc.rh = NULL; if (GNUNET_OK != TEH_DB_run_transaction (connection, + "get reserve status", &mhd_ret, &reserve_status_transaction, &rsc)) diff --git a/src/exchange/taler-exchange-httpd_reserve_withdraw.c b/src/exchange/taler-exchange-httpd_reserve_withdraw.c index 11265b43c..3f2bc3173 100644 --- a/src/exchange/taler-exchange-httpd_reserve_withdraw.c +++ b/src/exchange/taler-exchange-httpd_reserve_withdraw.c @@ -492,6 +492,7 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh, if (GNUNET_OK != TEH_DB_run_transaction (connection, + "run reserve withdraw", &mhd_ret, &withdraw_transaction, &wc)) diff --git a/src/exchange/taler-exchange-httpd_track_transaction.c b/src/exchange/taler-exchange-httpd_track_transaction.c index 13a106621..fdda22b8d 100644 --- a/src/exchange/taler-exchange-httpd_track_transaction.c +++ b/src/exchange/taler-exchange-httpd_track_transaction.c @@ -120,25 +120,25 @@ struct DepositWtidContext * Public key of the merchant. */ const struct TALER_MerchantPublicKeyP *merchant_pub; - + /** * Set by #handle_wtid data to the wire transfer ID. - */ + */ struct TALER_WireTransferIdentifierRawP wtid; - + /** * Set by #handle_wtid data to the coin's contribution to the wire transfer. - */ + */ struct TALER_Amount coin_contribution; - + /** * Set by #handle_wtid data to the fee charged to the coin. - */ + */ struct TALER_Amount coin_fee; /** * Set by #handle_wtid data to the wire transfer execution time. - */ + */ struct GNUNET_TIME_Absolute execution_time; /** @@ -289,9 +289,10 @@ check_and_handle_track_transaction_request (struct MHD_Connection *connection, ctx.pending = GNUNET_NO; ctx.tps = tps; ctx.merchant_pub = merchant_pub; - + if (GNUNET_OK != TEH_DB_run_transaction (connection, + "handle track transaction", &mhd_ret, &track_transaction_transaction, &ctx)) diff --git a/src/exchange/taler-exchange-httpd_track_transfer.c b/src/exchange/taler-exchange-httpd_track_transfer.c index 38c6c29e3..493febc21 100644 --- a/src/exchange/taler-exchange-httpd_track_transfer.c +++ b/src/exchange/taler-exchange-httpd_track_transfer.c @@ -141,7 +141,7 @@ reply_track_transfer_details (struct MHD_Connection *connection, TALER_EC_EXCHANGE_BAD_CONFIGURATION, "no keys"); } - + return TEH_RESPONSE_reply_json_pack (connection, MHD_HTTP_OK, "{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}", @@ -327,7 +327,7 @@ handle_transaction_data (void *cls, /** * Execute a "/track/transfer". Returns the transaction information * associated with the given wire transfer identifier. - * + * * 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 @@ -474,6 +474,7 @@ TEH_TRACKING_handler_track_transfer (struct TEH_RequestHandler *rh, return MHD_YES; /* parse error */ if (GNUNET_OK != TEH_DB_run_transaction (connection, + "run track transfer", &mhd_ret, &track_transfer_transaction, &ctx)) diff --git a/src/exchange/taler-exchange-wirewatch.c b/src/exchange/taler-exchange-wirewatch.c index 856a62019..e9f9276ca 100644 --- a/src/exchange/taler-exchange-wirewatch.c +++ b/src/exchange/taler-exchange-wirewatch.c @@ -422,9 +422,12 @@ find_transfers (void *cls) GNUNET_SCHEDULER_shutdown (); return; } + db_plugin->preflight (db_plugin->cls, + session); if (GNUNET_OK != db_plugin->start (db_plugin->cls, - session)) + session, + "wirewatch check for incoming wire transfers")) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start database transaction!\n"); diff --git a/src/exchange/test_taler_exchange_aggregator.c b/src/exchange/test_taler_exchange_aggregator.c index 3265bf2a1..0335bcd44 100644 --- a/src/exchange/test_taler_exchange_aggregator.c +++ b/src/exchange/test_taler_exchange_aggregator.c @@ -447,7 +447,8 @@ do_deposit (struct Command *cmd) /* finally, actually perform the DB operation */ if ( (GNUNET_OK != plugin->start (plugin->cls, - session)) || + session, + "aggregator-test-1")) || (GNUNET_OK != plugin->insert_deposit (plugin->cls, session, @@ -1150,7 +1151,8 @@ run (void *cls) &issue.properties.denom_hash); if ( (GNUNET_OK != plugin->start (plugin->cls, - session)) || + session, + "aggregator-test-2")) || (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->insert_denomination_info (plugin->cls, session, diff --git a/src/exchangedb/perf_taler_exchangedb_interpreter.c b/src/exchangedb/perf_taler_exchangedb_interpreter.c index b9bf9c32e..8a81befdb 100644 --- a/src/exchangedb/perf_taler_exchangedb_interpreter.c +++ b/src/exchangedb/perf_taler_exchangedb_interpreter.c @@ -1159,7 +1159,8 @@ interpret (struct PERF_TALER_EXCHANGEDB_interpreter_state *state) case PERF_TALER_EXCHANGEDB_CMD_START_TRANSACTION: GNUNET_break (GNUNET_OK == state->plugin->start (state->plugin->cls, - state->session)); + state->session, + "perf-interpreter")); break; case PERF_TALER_EXCHANGEDB_CMD_COMMIT_TRANSACTION: diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index a4f32cdc4..d6a9b2838 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015, 2016, 2017 GNUnet e.V. + Copyright (C) 2014, 2015, 2016, 2017, 2018 GNUnet e.V. 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 @@ -60,6 +60,11 @@ struct TALER_EXCHANGEDB_Session */ PGconn *conn; + /** + * Name of the current transaction, for debugging. + */ + const char *transaction_name; + }; @@ -1533,11 +1538,14 @@ postgres_get_session (void *cls) * * @param cls the `struct PostgresClosure` with the plugin-specific state * @param session the database connection + * @param name unique name identifying the transaction (for debugging) + * must point to a constant * @return #GNUNET_OK on success */ static int postgres_start (void *cls, - struct TALER_EXCHANGEDB_Session *session) + struct TALER_EXCHANGEDB_Session *session, + const char *name) { PGresult *result; ExecStatusType ex; @@ -1552,9 +1560,11 @@ postgres_start (void *cls, PQerrorMessage (session->conn)); GNUNET_break (0); PQclear (result); + session->transaction_name = NULL; return GNUNET_SYSERR; } PQclear (result); + session->transaction_name = name; return GNUNET_OK; } @@ -1577,6 +1587,7 @@ postgres_rollback (void *cls, GNUNET_break (PGRES_COMMAND_OK == PQresultStatus (result)); PQclear (result); + session->transaction_name = NULL; } @@ -1594,10 +1605,50 @@ postgres_commit (void *cls, struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_end }; + enum GNUNET_DB_QueryStatus qs; - return GNUNET_PQ_eval_prepared_non_select (session->conn, - "do_commit", - params); + qs = GNUNET_PQ_eval_prepared_non_select (session->conn, + "do_commit", + params); + session->transaction_name = NULL; + return qs; +} + + +/** + * Do a pre-flight check that we are not in an uncommitted transaction. + * If we are, try to commit the previous transaction and output a warning. + * Does not return anything, as we will continue regardless of the outcome. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session the database connection + */ +static void +postgres_preflight (void *cls, + struct TALER_EXCHANGEDB_Session *session) +{ + PGresult *result; + ExecStatusType status; + + if (NULL == session->transaction_name) + return; /* all good */ + result = PQexec (session->conn, + "COMMIT"); + status = PQresultStatus (result); + if (PGRES_COMMAND_OK == status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "BUG: Preflight check committed transaction `%s'!\n", + session->transaction_name); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "BUG: Preflight check failed to commit transaction `%s'!\n", + session->transaction_name); + } + session->transaction_name = NULL; + PQclear (result); } @@ -6363,6 +6414,7 @@ libtaler_plugin_exchangedb_postgres_init (void *cls) plugin->create_tables = &postgres_create_tables; plugin->start = &postgres_start; plugin->commit = &postgres_commit; + plugin->preflight = &postgres_preflight; plugin->rollback = &postgres_rollback; plugin->insert_denomination_info = &postgres_insert_denomination_info; plugin->get_denomination_info = &postgres_get_denomination_info; diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index a0eb50f08..36f0cce4e 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -1545,7 +1545,8 @@ run (void *cls) FAILIF (GNUNET_OK != plugin->start (plugin->cls, - session)); + session, + "test-1")); /* test DB is empty */ FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != @@ -1909,7 +1910,8 @@ run (void *cls) session)); FAILIF (GNUNET_OK != plugin->start (plugin->cls, - session)); + session, + "test-2")); FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->mark_deposit_tiny (plugin->cls, session, @@ -1928,7 +1930,8 @@ run (void *cls) &deposit)); FAILIF (GNUNET_OK != plugin->start (plugin->cls, - session)); + session, + "test-3")); FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != plugin->test_deposit_done (plugin->cls, session, @@ -1992,9 +1995,12 @@ run (void *cls) FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != plugin->commit (plugin->cls, session)); + plugin->preflight (plugin->cls, + session); FAILIF (GNUNET_OK != plugin->start (plugin->cls, - session)); + session, + "test-4")); FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != plugin->insert_denomination_revocation (plugin->cls, session, @@ -2002,9 +2008,12 @@ run (void *cls) &master_sig)); plugin->rollback (plugin->cls, session); + plugin->preflight (plugin->cls, + session); FAILIF (GNUNET_OK != plugin->start (plugin->cls, - session)); + session, + "test-5")); { struct TALER_MasterSignatureP msig; uint64_t rev_rowid; @@ -2164,6 +2173,8 @@ run (void *cls) FAILIF (GNUNET_OK != test_wire_fees (session)); + plugin->preflight (plugin->cls, + session); result = 0; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index ae38856a3..33677559a 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -1152,11 +1152,14 @@ struct TALER_EXCHANGEDB_Plugin * * @param cls the @e cls of this struct with the plugin-specific state * @param session connection to use + * @param name unique name identifying the transaction (for debugging), + * must point to a constant * @return #GNUNET_OK on success */ int (*start) (void *cls, - struct TALER_EXCHANGEDB_Session *session); + struct TALER_EXCHANGEDB_Session *session, + const char *name); /** @@ -1172,6 +1175,19 @@ struct TALER_EXCHANGEDB_Plugin /** + * Do a pre-flight check that we are not in an uncommitted transaction. + * If we are, try to commit the previous transaction and output a warning. + * Does not return anything, as we will continue regardless of the outcome. + * + * @param cls the `struct PostgresClosure` with the plugin-specific state + * @param session the database connection + */ + void + (*preflight) (void *cls, + struct TALER_EXCHANGEDB_Session *session); + + + /** * Abort/rollback a transaction. * * @param cls the @e cls of this struct with the plugin-specific state @@ -1397,7 +1413,7 @@ struct TALER_EXCHANGEDB_Plugin const struct TALER_CoinSpendPublicKeyP *coin_pub, TALER_EXCHANGEDB_RefundCoinCallback cb, void *cb_cls); - + /** * Mark a deposit as tiny, thereby declaring that it cannot be |