From cdde19794f49b5b022b0987b1d99edc7910f4d00 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 1 Aug 2021 14:26:07 +0200 Subject: fix #6946: reload merchant instance settings from DB on change --- src/backend/taler-merchant-httpd.c | 196 +++++++++++++++++++++++++++---------- 1 file changed, 146 insertions(+), 50 deletions(-) (limited to 'src/backend/taler-merchant-httpd.c') diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index 104d7435..577672b9 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -22,6 +22,7 @@ * @author Florian Dold */ #include "platform.h" +#include #include #include #include "taler-merchant-httpd_auditors.h" @@ -100,6 +101,11 @@ int TMH_force_audit; */ struct TALER_MERCHANTDB_Plugin *TMH_db; +/** + * Event handler for instance settings changes. + */ +static struct GNUNET_DB_EventHandler *instance_eh; + /** * Hashmap pointing at merchant instances by 'id'. An 'id' is * just a string that identifies a merchant instance. When a frontend @@ -241,22 +247,14 @@ TMH_compute_auth (const char *token, * * @param[in,out] mi merchant instance to update and possibly free */ -void -TMH_instance_decref (struct TMH_MerchantInstance *mi) +static void +instance_decref (struct TMH_MerchantInstance *mi) { struct TMH_WireMethod *wm; - struct GNUNET_HashCode h_instance; mi->rc--; if (0 != mi->rc) return; - GNUNET_CRYPTO_hash (mi->settings.id, - strlen (mi->settings.id), - &h_instance); - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_remove (TMH_by_id_map, - &h_instance, - mi)); TMH_force_get_orders_resume (mi); while (NULL != (wm = (mi->wm_head))) { @@ -277,22 +275,27 @@ TMH_instance_decref (struct TMH_MerchantInstance *mi) /** - * Callback that frees all the instances in the hashmap + * Callback that frees an instances removing + * it from the global hashmap. * * @param cls closure, NULL * @param key current key * @param value a `struct TMH_MerchantInstance` */ -static int -instance_free_cb (void *cls, - const struct GNUNET_HashCode *key, - void *value) +int +TMH_instance_free_cb (void *cls, + const struct GNUNET_HashCode *key, + void *value) { struct TMH_MerchantInstance *mi = value; (void) cls; (void) key; - TMH_instance_decref (mi); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_remove (TMH_by_id_map, + &mi->h_instance, + mi)); + instance_decref (mi); return GNUNET_YES; } @@ -732,6 +735,11 @@ do_shutdown (void *cls) mhd = NULL; } TMH_RESERVES_done (); + if (NULL != instance_eh) + { + TMH_db->event_listen_cancel (instance_eh); + instance_eh = NULL; + } if (NULL != TMH_db) { TALER_MERCHANTDB_plugin_unload (TMH_db); @@ -755,7 +763,7 @@ do_shutdown (void *cls) if (NULL != TMH_by_id_map) { GNUNET_CONTAINER_multihashmap_iterate (TMH_by_id_map, - &instance_free_cb, + &TMH_instance_free_cb, NULL); GNUNET_CONTAINER_multihashmap_destroy (TMH_by_id_map); TMH_by_id_map = NULL; @@ -799,7 +807,7 @@ handle_mhd_completion_callback (void *cls, if (NULL != hc->request_body) json_decref (hc->request_body); if (NULL != hc->instance) - TMH_instance_decref (hc->instance); + instance_decref (hc->instance); memset (&hc->async_scope_id, 0, sizeof (struct GNUNET_AsyncScopeId)); @@ -914,8 +922,6 @@ struct TMH_MerchantInstance * TMH_lookup_instance (const char *instance_id) { struct GNUNET_HashCode h_instance; - struct TMH_MerchantInstance *mi; - struct GNUNET_TIME_Relative age; if (NULL == instance_id) instance_id = "default"; @@ -928,16 +934,8 @@ TMH_lookup_instance (const char *instance_id) instance_id); /* We're fine if that returns NULL, the calling routine knows how to handle that */ - mi = GNUNET_CONTAINER_multihashmap_get (TMH_by_id_map, - &h_instance); - if (NULL == mi) - return mi; - age = GNUNET_TIME_absolute_get_duration (mi->staleness); - if (age.rel_value_us > INSTANCE_STALENESS.rel_value_us) - { - // FIXME: referesh from DB - } - return mi; + return GNUNET_CONTAINER_multihashmap_get (TMH_by_id_map, + &h_instance); } @@ -950,7 +948,6 @@ TMH_lookup_instance (const char *instance_id) int TMH_add_instance (struct TMH_MerchantInstance *mi) { - struct GNUNET_HashCode h_instance; const char *id; int ret; @@ -959,13 +956,13 @@ TMH_add_instance (struct TMH_MerchantInstance *mi) id = "default"; GNUNET_CRYPTO_hash (id, strlen (id), - &h_instance); + &mi->h_instance); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for by-id key %s of `%s' in hashmap\n", - GNUNET_h2s (&h_instance), + GNUNET_h2s (&mi->h_instance), id); ret = GNUNET_CONTAINER_multihashmap_put (TMH_by_id_map, - &h_instance, + &mi->h_instance, mi, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); if (GNUNET_OK == ret) @@ -2043,6 +2040,15 @@ add_instance_cb (void *cls, struct TMH_MerchantInstance *mi; (void) cls; + mi = TMH_lookup_instance (is->id); + if (NULL != mi) + { + /* (outdated) entry exists, remove old entry */ + (void) TMH_instance_free_cb (NULL, + &mi->h_instance, + mi); + } + mi = GNUNET_new (struct TMH_MerchantInstance); mi->settings = *is; mi->auth = *ias; @@ -2055,7 +2061,6 @@ add_instance_cb (void *cls, else mi->deleted = true; mi->merchant_pub = *merchant_pub; - mi->staleness = GNUNET_TIME_absolute_get (); for (unsigned int i = 0; ilookup_instances (TMH_db->cls, + false, + &add_instance_cb, + NULL); + } + else + { + struct TMH_MerchantInstance *mi; + + /* This must be done here to handle instance + purging, as for purged instances, the DB + lookup below will otherwise do nothing */ + mi = TMH_lookup_instance (id); + if (NULL != mi) + { + (void) TMH_instance_free_cb (NULL, + &mi->h_instance, + mi); + } + qs = TMH_db->lookup_instance (TMH_db->cls, + id, + false, + &add_instance_cb, + NULL); + } + if (0 > qs) + { + GNUNET_break (0); + GNUNET_SCHEDULER_shutdown (); + return; + } +} + + +/** + * A transaction modified an instance setting + * (or created/deleted/purged one). Notify all + * backends about the change. + * + * @param id ID of the instance that changed + */ +void +TMH_reload_instances (const char *id) +{ + struct GNUNET_DB_EventHeaderP es = { + es.size = ntohs (sizeof (es)), + es.type = ntohs (sizeof (TALER_DBEVENT_MERCHANT_INSTANCE_SETTINGS)) + }; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Generating instance settings notification: reload `%s'\n", + id); + TMH_db->event_notify (TMH_db->cls, + &es, + id, + (NULL == id) + ? 0 + : strlen (id) + 1); +} + + /** * Main function that will be run by the scheduler. * @@ -2175,8 +2272,8 @@ run (void *cls, return; } if (NULL == - (TMH_by_id_map = GNUNET_CONTAINER_multihashmap_create (1, - GNUNET_NO))) + (TMH_by_id_map = GNUNET_CONTAINER_multihashmap_create (4, + GNUNET_YES))) { GNUNET_SCHEDULER_shutdown (); return; @@ -2195,21 +2292,20 @@ run (void *cls, GNUNET_SCHEDULER_shutdown (); return; } - /* load instances */ { - enum GNUNET_DB_QueryStatus qs; - - qs = TMH_db->lookup_instances (TMH_db->cls, - false, - &add_instance_cb, - NULL); - if (0 > qs) - { - GNUNET_break (0); - GNUNET_SCHEDULER_shutdown (); - return; - } + struct GNUNET_DB_EventHeaderP es = { + es.size = ntohs (sizeof (es)), + es.type = ntohs (sizeof (TALER_DBEVENT_MERCHANT_INSTANCE_SETTINGS)) + }; + + instance_eh = TMH_db->event_listen (TMH_db->cls, + &es, + &load_instances, + NULL); } + load_instances (NULL, + NULL, + 0); /* start watching reserves */ TMH_RESERVES_init (); fh = TALER_MHD_bind (cfg, -- cgit v1.2.3