exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit 09dc2f98a23a3fe0fdd0405f62ad4fe49c88cbea
parent 767ef1d06b2de26559d370bd26d398bedc18f554
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu, 13 Aug 2026 20:15:05 +0200

ensure au cleanup on shutdown

Diffstat:
Msrc/exchange/taler-exchange-aggregator.c | 41+++++++++++++++++++++++++++++++++++------
1 file changed, 35 insertions(+), 6 deletions(-)

diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c @@ -244,6 +244,15 @@ static struct TALER_EXCHANGEDB_PostgresContext *pg; static struct GNUNET_SCHEDULER_Task *task; /** + * The aggregation we are currently working on, NULL if none. There is at most + * one at any point in time, as the next one is only started once the previous + * one was cleaned up. Needed so that we can cancel an asynchronous rule + * update and free the aggregation on shutdown, as the rule update outlives + * the task that started it and keeps a reference to @e pg. + */ +static struct AggregationUnit *au_active; + +/** * How long should we sleep when idle before trying to find more work? */ static struct GNUNET_TIME_Relative aggregator_idle_sleep_interval; @@ -294,6 +303,8 @@ static void cleanup_au (struct AggregationUnit *au) { GNUNET_assert (NULL != au); + if (au == au_active) + au_active = NULL; GNUNET_free (au->extra_wire_subject_metadata); if (NULL != au->ru) { @@ -439,6 +450,20 @@ shutdown_task (void *cls) GNUNET_SCHEDULER_cancel (task); task = NULL; } + if (NULL != au_active) + { + struct AggregationUnit *au = au_active; + + /* An asynchronous rule update is not a shutdown task and would thus + still run (on the freed database context) after we return; stop it + while the KYC logic and the database are still around. */ + if (NULL != au->ru) + { + TALER_EXCHANGEDB_begin_rule_update_cancel (au->ru); + au->ru = NULL; + } + cleanup_au (au); + } TALER_KYCLOGIC_kyc_done (); TALER_EXCHANGEDB_disconnect (pg); pg = NULL; @@ -1300,6 +1325,8 @@ run_aggregation (void *cls) "Checking for ready deposits to aggregate\n"); /* make sure we have current fees */ au = GNUNET_new (struct AggregationUnit); + GNUNET_assert (NULL == au_active); + au_active = au; au->execution_time = GNUNET_TIME_timestamp_get (); au->shard = s; if (GNUNET_OK != @@ -1450,13 +1477,15 @@ drain_kyc_alerts (void *cls) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Draining KYC alerts\n"); au = GNUNET_new (struct AggregationUnit); + GNUNET_assert (NULL == au_active); + au_active = au; au->execution_time = GNUNET_TIME_timestamp_get (); if (GNUNET_SYSERR == TALER_EXCHANGEDB_preflight (pg)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to obtain database connection!\n"); - GNUNET_free (au); + cleanup_au (au); global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); return; @@ -1467,7 +1496,7 @@ drain_kyc_alerts (void *cls) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start database transaction!\n"); - GNUNET_free (au); + cleanup_au (au); global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); return; @@ -1485,7 +1514,7 @@ drain_kyc_alerts (void *cls) case GNUNET_DB_STATUS_HARD_ERROR: GNUNET_break (0); TALER_EXCHANGEDB_rollback (pg); - GNUNET_free (au); + cleanup_au (au); GNUNET_assert (NULL == task); global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); @@ -1493,12 +1522,12 @@ drain_kyc_alerts (void *cls) case GNUNET_DB_STATUS_SOFT_ERROR: TALER_EXCHANGEDB_rollback (pg); GNUNET_assert (NULL == task); - GNUNET_free (au); + cleanup_au (au); task = GNUNET_SCHEDULER_add_now (&drain_kyc_alerts, NULL); return; case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - GNUNET_free (au); + cleanup_au (au); TALER_EXCHANGEDB_rollback (pg); GNUNET_assert (NULL == task); task = GNUNET_SCHEDULER_add_now (&run_shard, @@ -1522,7 +1551,7 @@ drain_kyc_alerts (void *cls) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to lookup transient aggregates!\n"); TALER_EXCHANGEDB_rollback (pg); - GNUNET_free (au); + cleanup_au (au); global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); return;