From 127ad07a3abaee00fb206aaf8b980f258d2933c8 Mon Sep 17 00:00:00 2001 From: Martin Schanzenbach Date: Fri, 23 Sep 2022 01:06:59 +0900 Subject: NAMESTORE: Use a per client database connection Each connecting namestore client will now get a new database connection through any of the plugins. This will allow us to properly use locking in databases where available. --- src/namestore/gnunet-service-namestore.c | 146 ++++++++++++++++-------------- src/namestore/plugin_namestore_flat.c | 16 ++-- src/namestore/plugin_namestore_postgres.c | 16 ++-- src/namestore/plugin_namestore_sqlite.c | 32 +++---- 4 files changed, 107 insertions(+), 103 deletions(-) diff --git a/src/namestore/gnunet-service-namestore.c b/src/namestore/gnunet-service-namestore.c index 6d3cc45ec..a173e8927 100644 --- a/src/namestore/gnunet-service-namestore.c +++ b/src/namestore/gnunet-service-namestore.c @@ -131,6 +131,11 @@ struct NamestoreClient */ struct GNUNET_SERVICE_Client *client; + /** + * Database handle + */ + struct GNUNET_NAMESTORE_PluginFunctions *GSN_database; + /** * Message queue for transmission to @e client */ @@ -352,11 +357,6 @@ static struct GNUNET_STATISTICS_Handle *statistics; */ static struct GNUNET_NAMECACHE_Handle *namecache; -/** - * Database handle - */ -static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database; - /** * Name of the database plugin */ @@ -436,7 +436,6 @@ cleanup_task (void *cls) GNUNET_NAMECACHE_disconnect (namecache); namecache = NULL; } - GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database)); GNUNET_free (db_lib_name); db_lib_name = NULL; if (NULL != monitor_nc) @@ -560,11 +559,13 @@ cache_nick (const struct GNUNET_IDENTITY_PrivateKey *zone, /** * Return the NICK record for the zone (if it exists). * + * @param nc the namestore client * @param zone private key for the zone to look for nick * @return NULL if no NICK record was found */ static struct GNUNET_GNSRECORD_Data * -get_nick_record (const struct GNUNET_IDENTITY_PrivateKey *zone) +get_nick_record (const struct NamestoreClient *nc, + const struct GNUNET_IDENTITY_PrivateKey *zone) { struct GNUNET_IDENTITY_PublicKey pub; struct GNUNET_GNSRECORD_Data *nick; @@ -588,11 +589,11 @@ get_nick_record (const struct GNUNET_IDENTITY_PrivateKey *zone) } nick = NULL; - res = GSN_database->lookup_records (GSN_database->cls, - zone, - GNUNET_GNS_EMPTY_LABEL_AT, - &lookup_nick_it, - &nick); + res = nc->GSN_database->lookup_records (nc->GSN_database->cls, + zone, + GNUNET_GNS_EMPTY_LABEL_AT, + &lookup_nick_it, + &nick); if ((GNUNET_OK != res) || (NULL == nick)) { #if ! defined(GNUNET_CULL_LOGGING) @@ -735,7 +736,7 @@ send_lookup_response (struct NamestoreClient *nc, char *name_tmp; char *rd_ser; - nick = get_nick_record (zone_key); + nick = get_nick_record (nc, zone_key); GNUNET_assert (-1 != GNUNET_GNSRECORD_records_get_size (rd_count, rd)); if ((NULL != nick) && (0 != strcmp (name, GNUNET_GNS_EMPTY_LABEL_AT))) @@ -936,7 +937,7 @@ refresh_block (struct NamestoreClient *nc, rd_clean[rd_count_clean++] = rd[i]; } - nick = get_nick_record (zone_key); + nick = get_nick_record (nc, zone_key); res_count = rd_count_clean; res = (struct GNUNET_GNSRECORD_Data *) rd_clean; /* fixme: a bit unclean... */ if ((NULL != nick) && (0 != strcmp (name, GNUNET_GNS_EMPTY_LABEL_AT))) @@ -1168,6 +1169,7 @@ client_disconnect_cb (void *cls, for (cop = cop_head; NULL != cop; cop = cop->next) if (nc == cop->nc) cop->nc = NULL; + GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, nc->GSN_database)); GNUNET_free (nc); } @@ -1186,12 +1188,35 @@ client_connect_cb (void *cls, struct GNUNET_MQ_Handle *mq) { struct NamestoreClient *nc; + char *database; + char *db_lib_name; (void) cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client); nc = GNUNET_new (struct NamestoreClient); nc->client = client; nc->mq = mq; + /* Loading database plugin */ + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (GSN_cfg, + "namestore", + "database", + &database)) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n"); + GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Loading %s\n", db_lib_name); + nc->GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg); + GNUNET_free (database); + if (NULL == nc->GSN_database) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not load database backend `%s'\n", + db_lib_name); + GNUNET_free (db_lib_name); + GNUNET_free (nc); + return NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Loaded %s\n", db_lib_name); + GNUNET_free (db_lib_name); return nc; } @@ -1402,12 +1427,12 @@ handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) rlc.res_rd_count = 0; rlc.res_rd = NULL; rlc.rd_ser_len = 0; - rlc.nick = get_nick_record (&ll_msg->zone); - res = GSN_database->lookup_records (GSN_database->cls, - &ll_msg->zone, - conv_name, - &lookup_it, - &rlc); + rlc.nick = get_nick_record (nc, &ll_msg->zone); + res = nc->GSN_database->lookup_records (nc->GSN_database->cls, + &ll_msg->zone, + conv_name, + &lookup_it, + &rlc); env = GNUNET_MQ_msg_extra (llr_msg, name_len + rlc.rd_ser_len, @@ -1591,11 +1616,11 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg) "Creating %u records for name `%s'\n", (unsigned int) rd_count, conv_name); - if ((GNUNET_NO == GSN_database->lookup_records (GSN_database->cls, - &rp_msg->private_key, - conv_name, - &get_block_exp_existing, - &existing_block_exp)) && + if ((GNUNET_NO == nc->GSN_database->lookup_records (nc->GSN_database->cls, + &rp_msg->private_key, + conv_name, + &get_block_exp_existing, + &existing_block_exp)) && (rd_count == 0)) { /* This name does not exist, so cannot be removed */ @@ -1676,11 +1701,11 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg) /* remove nick record from cache, in case we have one there */ cache_nick (&rp_msg->private_key, NULL); } - res = GSN_database->store_records (GSN_database->cls, - &rp_msg->private_key, - conv_name, - rd_nf_count, - rd_nf); + res = nc->GSN_database->store_records (nc->GSN_database->cls, + &rp_msg->private_key, + conv_name, + rd_nf_count, + rd_nf); } if (GNUNET_OK != res) @@ -1817,11 +1842,11 @@ handle_zone_to_name (void *cls, const struct ZoneToNameMessage *ztn_msg) ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id); ztn_ctx.nc = nc; ztn_ctx.success = GNUNET_NO; - if (GNUNET_SYSERR == GSN_database->zone_to_name (GSN_database->cls, - &ztn_msg->zone, - &ztn_msg->value_zone, - &handle_zone_to_name_it, - &ztn_ctx)) + if (GNUNET_SYSERR == nc->GSN_database->zone_to_name (nc->GSN_database->cls, + &ztn_msg->zone, + &ztn_msg->value_zone, + &handle_zone_to_name_it, + &ztn_ctx)) { /* internal error, hang up instead of signalling something that might be wrong */ @@ -1935,6 +1960,7 @@ run_zone_iteration_round (struct ZoneIteration *zi, uint64_t limit) struct ZoneIterationProcResult proc; struct GNUNET_TIME_Absolute start; struct GNUNET_TIME_Relative duration; + struct NamestoreClient *nc = zi->nc; memset (&proc, 0, sizeof(proc)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -1945,15 +1971,16 @@ run_zone_iteration_round (struct ZoneIteration *zi, uint64_t limit) proc.limit = limit; start = GNUNET_TIME_absolute_get (); GNUNET_break (GNUNET_SYSERR != - GSN_database->iterate_records (GSN_database->cls, - (GNUNET_YES == GNUNET_is_zero ( - &zi->zone)) + nc->GSN_database->iterate_records (nc->GSN_database->cls, + (GNUNET_YES == + GNUNET_is_zero ( + &zi->zone)) ? NULL : &zi->zone, - zi->seq, - limit, - &zone_iterate_proc, - &proc)); + zi->seq, + limit, + &zone_iterate_proc, + &proc)); duration = GNUNET_TIME_absolute_get_duration (start); duration = GNUNET_TIME_relative_divide (duration, limit - proc.limit); GNUNET_STATISTICS_set (statistics, @@ -2212,6 +2239,7 @@ static void monitor_iteration_next (void *cls) { struct ZoneMonitor *zm = cls; + struct NamestoreClient *nc = zm->nc; int ret; zm->task = NULL; @@ -2220,15 +2248,13 @@ monitor_iteration_next (void *cls) zm->iteration_cnt = zm->limit / 2; /* leave half for monitor events */ else zm->iteration_cnt = zm->limit; /* use it all */ - ret = GSN_database->iterate_records (GSN_database->cls, - (GNUNET_YES == GNUNET_is_zero ( - &zm->zone)) - ? NULL - : &zm->zone, - zm->seq, - zm->iteration_cnt, - &monitor_iterate_cb, - zm); + ret = nc->GSN_database->iterate_records (nc->GSN_database->cls, + (GNUNET_YES == GNUNET_is_zero ( + &zm->zone)) ? NULL : &zm->zone, + zm->seq, + zm->iteration_cnt, + &monitor_iterate_cb, + zm); if (GNUNET_SYSERR == ret) { GNUNET_SERVICE_client_drop (zm->nc->client); @@ -2330,26 +2356,8 @@ run (void *cls, namecache = GNUNET_NAMECACHE_connect (cfg); GNUNET_assert (NULL != namecache); } - /* Loading database plugin */ - if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, - "namestore", - "database", - &database)) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n"); - - GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database); - GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg); - GNUNET_free (database); statistics = GNUNET_STATISTICS_create ("namestore", cfg); GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL); - if (NULL == GSN_database) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not load database backend `%s'\n", - db_lib_name); - GNUNET_SCHEDULER_shutdown (); - return; - } } diff --git a/src/namestore/plugin_namestore_flat.c b/src/namestore/plugin_namestore_flat.c index 3576b14e0..3feac60d8 100644 --- a/src/namestore/plugin_namestore_flat.c +++ b/src/namestore/plugin_namestore_flat.c @@ -767,19 +767,16 @@ namestore_flat_zone_to_name (void *cls, void * libgnunet_plugin_namestore_flat_init (void *cls) { - static struct Plugin plugin; + struct Plugin *plugin; const struct GNUNET_CONFIGURATION_Handle *cfg = cls; struct GNUNET_NAMESTORE_PluginFunctions *api; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, - 0, - sizeof(struct Plugin)); - plugin.cfg = cfg; - if (GNUNET_OK != database_setup (&plugin)) + plugin = GNUNET_new (struct Plugin); + plugin->cfg = cfg; + if (GNUNET_OK != database_setup (plugin)) { - database_shutdown (&plugin); + database_shutdown (plugin); + GNUNET_free (plugin); return NULL; } api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions); @@ -808,6 +805,7 @@ libgnunet_plugin_namestore_flat_done (void *cls) database_shutdown (plugin); plugin->cfg = NULL; + GNUNET_free (plugin); GNUNET_free (api); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Flat file plugin is finished\n"); diff --git a/src/namestore/plugin_namestore_postgres.c b/src/namestore/plugin_namestore_postgres.c index bdbaf96b3..54a19794f 100644 --- a/src/namestore/plugin_namestore_postgres.c +++ b/src/namestore/plugin_namestore_postgres.c @@ -577,21 +577,20 @@ database_shutdown (struct Plugin *plugin) void * libgnunet_plugin_namestore_postgres_init (void *cls) { - static struct Plugin plugin; + struct Plugin *plugin; const struct GNUNET_CONFIGURATION_Handle *cfg = cls; struct GNUNET_NAMESTORE_PluginFunctions *api; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof(struct Plugin)); - plugin.cfg = cfg; - if (GNUNET_OK != database_setup (&plugin)) + plugin = GNUNET_new (struct Plugin); + plugin->cfg = cfg; + if (GNUNET_OK != database_setup (plugin)) { - database_shutdown (&plugin); + database_shutdown (plugin); + GNUNET_free (plugin); return NULL; } api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions); - api->cls = &plugin; + api->cls = plugin; api->store_records = &namestore_postgres_store_records; api->iterate_records = &namestore_postgres_iterate_records; api->zone_to_name = &namestore_postgres_zone_to_name; @@ -616,6 +615,7 @@ libgnunet_plugin_namestore_postgres_done (void *cls) database_shutdown (plugin); plugin->cfg = NULL; + GNUNET_free (plugin); GNUNET_free (api); LOG (GNUNET_ERROR_TYPE_DEBUG, "Postgres namestore plugin is finished\n"); diff --git a/src/namestore/plugin_namestore_sqlite.c b/src/namestore/plugin_namestore_sqlite.c index f2017b695..fd81780fb 100644 --- a/src/namestore/plugin_namestore_sqlite.c +++ b/src/namestore/plugin_namestore_sqlite.c @@ -129,7 +129,7 @@ database_setup (struct Plugin *plugin) GNUNET_SQ_make_try_execute ("PRAGMA legacy_file_format=OFF"), GNUNET_SQ_make_try_execute ("PRAGMA auto_vacuum=INCREMENTAL"), GNUNET_SQ_make_try_execute ("PRAGMA encoding=\"UTF-8\""), - GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=EXCLUSIVE"), + GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=NORMAL"), GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"), GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"), GNUNET_SQ_make_execute ("CREATE TABLE IF NOT EXISTS ns098records (" @@ -201,17 +201,16 @@ database_setup (struct Plugin *plugin) return GNUNET_SYSERR; } } - /* sqlite_filename should be UTF-8-encoded. If it isn't, it's a bug */ - plugin->fn = sqlite_filename; /* Open database and precompile statements */ if (SQLITE_OK != - sqlite3_open (plugin->fn, + sqlite3_open (sqlite_filename, &plugin->dbh)) { LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Unable to initialize SQLite: %s.\n"), sqlite3_errmsg (plugin->dbh)); + GNUNET_free (sqlite_filename); return GNUNET_SYSERR; } GNUNET_break (SQLITE_OK == @@ -224,7 +223,8 @@ database_setup (struct Plugin *plugin) GNUNET_break (0); LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Failed to setup database at `%s'\n"), - plugin->fn); + sqlite_filename); + GNUNET_free (sqlite_filename); return GNUNET_SYSERR; } @@ -235,7 +235,8 @@ database_setup (struct Plugin *plugin) GNUNET_break (0); LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Failed to setup database at `%s'\n"), - plugin->fn); + sqlite_filename); + GNUNET_free (sqlite_filename); return GNUNET_SYSERR; } return GNUNET_OK; @@ -296,7 +297,6 @@ database_shutdown (struct Plugin *plugin) GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); - GNUNET_free (plugin->fn); } @@ -802,23 +802,20 @@ namestore_sqlite_transaction_commit (void *cls, void * libgnunet_plugin_namestore_sqlite_init (void *cls) { - static struct Plugin plugin; + struct Plugin *plugin; const struct GNUNET_CONFIGURATION_Handle *cfg = cls; struct GNUNET_NAMESTORE_PluginFunctions *api; - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, - 0, - sizeof(struct Plugin)); - plugin.cfg = cfg; - if (GNUNET_OK != database_setup (&plugin)) + plugin = GNUNET_new (struct Plugin); + plugin->cfg = cfg; + if (GNUNET_OK != database_setup (plugin)) { - database_shutdown (&plugin); + database_shutdown (plugin); + GNUNET_free (plugin); return NULL; } api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions); - api->cls = &plugin; + api->cls = plugin; api->store_records = &namestore_sqlite_store_records; api->iterate_records = &namestore_sqlite_iterate_records; api->zone_to_name = &namestore_sqlite_zone_to_name; @@ -846,6 +843,7 @@ libgnunet_plugin_namestore_sqlite_done (void *cls) database_shutdown (plugin); plugin->cfg = NULL; + GNUNET_free (plugin); GNUNET_free (api); LOG (GNUNET_ERROR_TYPE_DEBUG, "sqlite plugin is finished\n"); -- cgit v1.2.3