use mmap() instead of malloc, rename heap->flat as database is persisted in flat...
authorChristian Grothoff <christian@grothoff.org>
Sat, 29 Jun 2019 08:18:44 +0000 (10:18 +0200)
committerChristian Grothoff <christian@grothoff.org>
Sat, 29 Jun 2019 08:18:44 +0000 (10:18 +0200)
src/namestore/.gitignore
src/namestore/Makefile.am
src/namestore/perf_namestore_api_flat.conf [new file with mode: 0644]
src/namestore/perf_namestore_api_heap.conf [deleted file]
src/namestore/plugin_namestore_flat.c [new file with mode: 0644]
src/namestore/plugin_namestore_heap.c [deleted file]
src/namestore/test_namestore_api_flat.conf [new file with mode: 0644]
src/namestore/test_namestore_api_heap.conf [deleted file]
src/namestore/test_plugin_namestore_flat.conf [new file with mode: 0644]
src/namestore/test_plugin_namestore_heap.conf [deleted file]
src/util/disk.c

index 5a59afd243106f44651041451455d88cd908ca1f..f159cdaff34283e8c4fd23f381791eff4f244eac 100644 (file)
@@ -68,21 +68,21 @@ test_namestore_api_zone_iteration_stop_sqlite
 test_namestore_api_zone_to_name_flat
 test_namestore_api_zone_to_name_postgres
 test_namestore_api_zone_to_name_sqlite
-test_namestore_api_lookup_nick_heap
-test_namestore_api_lookup_private_heap
-test_namestore_api_lookup_public_heap
-test_namestore_api_lookup_shadow_filter_heap
-test_namestore_api_lookup_shadow_heap
-test_namestore_api_monitoring_existing_heap
-test_namestore_api_monitoring_heap
-test_namestore_api_remove_heap
-test_namestore_api_remove_not_existing_record_heap
-test_namestore_api_store_heap
-test_namestore_api_store_update_heap
-test_namestore_api_zone_iteration_heap
-test_namestore_api_zone_iteration_nick_heap
-test_namestore_api_zone_iteration_specific_zone_heap
-test_namestore_api_zone_iteration_stop_heap
-test_namestore_api_zone_to_name_heap
-test_plugin_namestore_heap
-perf_namestore_api_zone_iteration_heap
+test_namestore_api_lookup_nick_flat
+test_namestore_api_lookup_private_flat
+test_namestore_api_lookup_public_flat
+test_namestore_api_lookup_shadow_filter_flat
+test_namestore_api_lookup_shadow_flat
+test_namestore_api_monitoring_existing_flat
+test_namestore_api_monitoring_flat
+test_namestore_api_remove_flat
+test_namestore_api_remove_not_existing_record_flat
+test_namestore_api_store_flat
+test_namestore_api_store_update_flat
+test_namestore_api_zone_iteration_flat
+test_namestore_api_zone_iteration_nick_flat
+test_namestore_api_zone_iteration_specific_zone_flat
+test_namestore_api_zone_iteration_stop_flat
+test_namestore_api_zone_to_name_flat
+test_plugin_namestore_flat
+perf_namestore_api_zone_iteration_flat
index 25941b4fb078558e381f7ca83c02627b6187a512..e95add6c704a6ef9c048ae873b61f8c741158200 100644 (file)
@@ -20,26 +20,26 @@ if USE_COVERAGE
   XLIBS = -lgcov
 endif
 
-HEAP_PLUGIN = libgnunet_plugin_namestore_heap.la
+HEAP_PLUGIN = libgnunet_plugin_namestore_flat.la
 if HAVE_TESTING
-HEAP_TESTS = test_plugin_namestore_heap \
- test_namestore_api_store_heap \
- test_namestore_api_store_update_heap \
- test_namestore_api_remove_heap \
- test_namestore_api_zone_iteration_heap \
- test_namestore_api_lookup_nick_heap \
- test_namestore_api_monitoring_heap \
- test_namestore_api_lookup_public_heap \
- test_namestore_api_lookup_private_heap \
- test_namestore_api_lookup_shadow_heap \
- test_namestore_api_lookup_shadow_filter_heap \
- test_namestore_api_remove_not_existing_record_heap \
- test_namestore_api_zone_iteration_nick_heap \
- test_namestore_api_zone_iteration_specific_zone_heap \
- test_namestore_api_zone_iteration_stop_heap \
- test_namestore_api_monitoring_existing_heap \
- test_namestore_api_zone_to_name_heap \
- perf_namestore_api_zone_iteration_heap
+HEAP_TESTS = test_plugin_namestore_flat \
+ test_namestore_api_store_flat \
+ test_namestore_api_store_update_flat \
+ test_namestore_api_remove_flat \
+ test_namestore_api_zone_iteration_flat \
+ test_namestore_api_lookup_nick_flat \
+ test_namestore_api_monitoring_flat \
+ test_namestore_api_lookup_public_flat \
+ test_namestore_api_lookup_private_flat \
+ test_namestore_api_lookup_shadow_flat \
+ test_namestore_api_lookup_shadow_filter_flat \
+ test_namestore_api_remove_not_existing_record_flat \
+ test_namestore_api_zone_iteration_nick_flat \
+ test_namestore_api_zone_iteration_specific_zone_flat \
+ test_namestore_api_zone_iteration_stop_flat \
+ test_namestore_api_monitoring_existing_flat \
+ test_namestore_api_zone_to_name_flat \
+ perf_namestore_api_zone_iteration_flat
 endif
 
 if HAVE_SQLITE
@@ -206,14 +206,14 @@ gnunet_service_namestore_LDADD = \
 
 
 
-libgnunet_plugin_namestore_heap_la_SOURCES = \
-  plugin_namestore_heap.c
-libgnunet_plugin_namestore_heap_la_LIBADD = \
+libgnunet_plugin_namestore_flat_la_SOURCES = \
+  plugin_namestore_flat.c
+libgnunet_plugin_namestore_flat_la_LIBADD = \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la  \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
   $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
   $(LTLIBINTL)
-libgnunet_plugin_namestore_heap_la_LDFLAGS = \
+libgnunet_plugin_namestore_flat_la_LDFLAGS = \
  $(GN_PLUGIN_LDFLAGS)
 
 
@@ -239,9 +239,9 @@ libgnunet_plugin_namestore_postgres_la_LIBADD = \
 libgnunet_plugin_namestore_postgres_la_LDFLAGS = \
  $(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS)
 
-test_namestore_api_store_heap_SOURCES = \
+test_namestore_api_store_flat_SOURCES = \
  test_namestore_api_store.c
-test_namestore_api_store_heap_LDADD = \
+test_namestore_api_store_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -263,9 +263,9 @@ test_namestore_api_store_postgres_LDADD = \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
   libgnunetnamestore.la
 
-test_namestore_api_store_update_heap_SOURCES = \
+test_namestore_api_store_update_flat_SOURCES = \
  test_namestore_api_store_update.c
-test_namestore_api_store_update_heap_LDADD = \
+test_namestore_api_store_update_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -290,9 +290,9 @@ test_namestore_api_store_update_postgres_LDADD = \
   $(top_builddir)/src/namecache/libgnunetnamecache.la \
   libgnunetnamestore.la
 
-test_namestore_api_lookup_public_heap_SOURCES = \
+test_namestore_api_lookup_public_flat_SOURCES = \
  test_namestore_api_lookup_public.c
-test_namestore_api_lookup_public_heap_LDADD = \
+test_namestore_api_lookup_public_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -335,18 +335,18 @@ test_namestore_api_lookup_nick_postgres_LDADD = \
   $(top_builddir)/src/namecache/libgnunetnamecache.la \
   libgnunetnamestore.la
 
-test_namestore_api_lookup_nick_heap_SOURCES = \
+test_namestore_api_lookup_nick_flat_SOURCES = \
  test_namestore_api_lookup_nick.c
-test_namestore_api_lookup_nick_heap_LDADD = \
+test_namestore_api_lookup_nick_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
   $(top_builddir)/src/namecache/libgnunetnamecache.la \
   libgnunetnamestore.la
 
-test_namestore_api_lookup_private_heap_SOURCES = \
+test_namestore_api_lookup_private_flat_SOURCES = \
  test_namestore_api_lookup_private.c
-test_namestore_api_lookup_private_heap_LDADD = \
+test_namestore_api_lookup_private_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -371,9 +371,9 @@ test_namestore_api_lookup_private_postgres_LDADD = \
   $(top_builddir)/src/namecache/libgnunetnamecache.la \
   libgnunetnamestore.la
 
-test_namestore_api_lookup_shadow_heap_SOURCES = \
+test_namestore_api_lookup_shadow_flat_SOURCES = \
  test_namestore_api_lookup_shadow.c
-test_namestore_api_lookup_shadow_heap_LDADD = \
+test_namestore_api_lookup_shadow_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -398,9 +398,9 @@ test_namestore_api_lookup_shadow_postgres_LDADD = \
   $(top_builddir)/src/namecache/libgnunetnamecache.la \
   libgnunetnamestore.la
 
-test_namestore_api_lookup_shadow_filter_heap_SOURCES = \
+test_namestore_api_lookup_shadow_filter_flat_SOURCES = \
  test_namestore_api_lookup_shadow_filter.c
-test_namestore_api_lookup_shadow_filter_heap_LDADD = \
+test_namestore_api_lookup_shadow_filter_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -440,17 +440,17 @@ test_namestore_api_remove_postgres_LDADD = \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
   libgnunetnamestore.la
 
-test_namestore_api_remove_heap_SOURCES = \
+test_namestore_api_remove_flat_SOURCES = \
  test_namestore_api_remove.c
-test_namestore_api_remove_heap_LDADD = \
+test_namestore_api_remove_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
   libgnunetnamestore.la
 
-test_namestore_api_remove_not_existing_record_heap_SOURCES = \
+test_namestore_api_remove_not_existing_record_flat_SOURCES = \
  test_namestore_api_remove_not_existing_record.c
-test_namestore_api_remove_not_existing_record_heap_LDADD = \
+test_namestore_api_remove_not_existing_record_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -472,9 +472,9 @@ test_namestore_api_remove_not_existing_record_postgres_LDADD = \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
   libgnunetnamestore.la
 
-test_namestore_api_zone_to_name_heap_SOURCES = \
+test_namestore_api_zone_to_name_flat_SOURCES = \
  test_namestore_api_zone_to_name.c
-test_namestore_api_zone_to_name_heap_LDADD = \
+test_namestore_api_zone_to_name_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   libgnunetnamestore.la
@@ -493,9 +493,9 @@ test_namestore_api_zone_to_name_postgres_LDADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
   libgnunetnamestore.la
 
-test_namestore_api_monitoring_heap_SOURCES = \
+test_namestore_api_monitoring_flat_SOURCES = \
  test_namestore_api_monitoring.c
-test_namestore_api_monitoring_heap_LDADD = \
+test_namestore_api_monitoring_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   libgnunetnamestore.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -517,9 +517,9 @@ test_namestore_api_monitoring_postgres_LDADD = \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
   $(top_builddir)/src/util/libgnunetutil.la
 
-test_namestore_api_monitoring_existing_heap_SOURCES = \
+test_namestore_api_monitoring_existing_flat_SOURCES = \
  test_namestore_api_monitoring_existing.c
-test_namestore_api_monitoring_existing_heap_LDADD = \
+test_namestore_api_monitoring_existing_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   libgnunetnamestore.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -541,9 +541,9 @@ test_namestore_api_monitoring_existing_postgres_LDADD = \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
   $(top_builddir)/src/util/libgnunetutil.la
 
-test_namestore_api_zone_iteration_heap_SOURCES = \
+test_namestore_api_zone_iteration_flat_SOURCES = \
  test_namestore_api_zone_iteration.c
-test_namestore_api_zone_iteration_heap_LDADD = \
+test_namestore_api_zone_iteration_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -581,17 +581,17 @@ perf_namestore_api_zone_iteration_sqlite_LDADD = \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
   libgnunetnamestore.la
 
-perf_namestore_api_zone_iteration_heap_SOURCES = \
+perf_namestore_api_zone_iteration_flat_SOURCES = \
  perf_namestore_api_zone_iteration.c
-perf_namestore_api_zone_iteration_heap_LDADD = \
+perf_namestore_api_zone_iteration_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
   libgnunetnamestore.la
 
-test_namestore_api_zone_iteration_nick_heap_SOURCES = \
+test_namestore_api_zone_iteration_nick_flat_SOURCES = \
  test_namestore_api_zone_iteration_nick.c
-test_namestore_api_zone_iteration_nick_heap_LDADD = \
+test_namestore_api_zone_iteration_nick_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -613,9 +613,9 @@ test_namestore_api_zone_iteration_nick_postgres_LDADD = \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
   libgnunetnamestore.la
 
-test_namestore_api_zone_iteration_specific_zone_heap_SOURCES = \
+test_namestore_api_zone_iteration_specific_zone_flat_SOURCES = \
  test_namestore_api_zone_iteration_specific_zone.c
-test_namestore_api_zone_iteration_specific_zone_heap_LDADD = \
+test_namestore_api_zone_iteration_specific_zone_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -637,9 +637,9 @@ test_namestore_api_zone_iteration_specific_zone_postgres_LDADD = \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
   libgnunetnamestore.la
 
-test_namestore_api_zone_iteration_stop_heap_SOURCES = \
+test_namestore_api_zone_iteration_stop_flat_SOURCES = \
  test_namestore_api_zone_iteration_stop.c
-test_namestore_api_zone_iteration_stop_heap_LDADD = \
+test_namestore_api_zone_iteration_stop_flat_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
@@ -661,9 +661,9 @@ test_namestore_api_zone_iteration_stop_postgres_LDADD = \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
   libgnunetnamestore.la
 
-test_plugin_namestore_heap_SOURCES = \
+test_plugin_namestore_flat_SOURCES = \
  test_plugin_namestore.c
-test_plugin_namestore_heap_LDADD = \
+test_plugin_namestore_flat_LDADD = \
  $(top_builddir)/src/testing/libgnunettesting.la \
  $(top_builddir)/src/util/libgnunetutil.la
 
@@ -689,13 +689,13 @@ EXTRA_DIST = \
   test_namestore_api.conf \
   test_namestore_api_postgres.conf \
   test_namestore_api_sqlite.conf \
-  test_namestore_api_heap.conf \
+  test_namestore_api_flat.conf \
   perf_namestore_api_postgres.conf \
   perf_namestore_api_sqlite.conf \
-  perf_namestore_api_heap.conf \
+  perf_namestore_api_flat.conf \
   test_plugin_namestore_sqlite.conf \
   test_plugin_namestore_postgres.conf \
-  test_plugin_namestore_heap.conf \
+  test_plugin_namestore_flat.conf \
   test_hostkey \
   zonefiles/S5I9DSGQVAB5FVV16T3B3CC5H1B2JGL3Q412JBKURME8EKU0600G.zkey \
   zonefiles/AQ835GVL939H4O8QJQ7GBLPTQC0QAAO91BN7QK01BA63MDSK6I4G.zkey \
diff --git a/src/namestore/perf_namestore_api_flat.conf b/src/namestore/perf_namestore_api_flat.conf
new file mode 100644 (file)
index 0000000..30759ce
--- /dev/null
@@ -0,0 +1,10 @@
+@INLINE@ test_namestore_api.conf
+
+[namestore]
+DATABASE = flat
+
+[namecache]
+DISABLE = YES
+
+[namestore-heap]
+FILENAME = $GNUNET_TEST_HOME/namestore/heap.db
diff --git a/src/namestore/perf_namestore_api_heap.conf b/src/namestore/perf_namestore_api_heap.conf
deleted file mode 100644 (file)
index a12761a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-@INLINE@ test_namestore_api.conf
-
-[namestore]
-DATABASE = heap
-
-[namecache]
-DISABLE = YES
-
-[namestore-heap]
-FILENAME = $GNUNET_TEST_HOME/namestore/heap.db
diff --git a/src/namestore/plugin_namestore_flat.c b/src/namestore/plugin_namestore_flat.c
new file mode 100644 (file)
index 0000000..4e1d339
--- /dev/null
@@ -0,0 +1,815 @@
+ /*
+  * This file is part of GNUnet
+  * Copyright (C) 2009-2015, 2018, 2019 GNUnet e.V.
+  *
+  * GNUnet is free software: you can redistribute it and/or modify it
+  * under the terms of the GNU Affero General Public License as published
+  * by the Free Software Foundation, either version 3 of the License,
+  * or (at your option) any later version.
+  *
+  * GNUnet is distributed in the hope that it will be useful, but
+  * WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Affero General Public License for more details.
+  *
+  * You should have received a copy of the GNU Affero General Public License
+  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
+  */
+/**
+ * @file namestore/plugin_namestore_flat.c
+ * @brief file-based namestore backend
+ * @author Martin Schanzenbach
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_namestore_plugin.h"
+#include "gnunet_namestore_service.h"
+#include "gnunet_gnsrecord_lib.h"
+#include "namestore.h"
+
+/**
+ * Context for all functions in this plugin.
+ */
+struct Plugin
+{
+
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Database filename.
+   */
+  char *fn;
+
+  /**
+   * HashMap
+   */
+  struct GNUNET_CONTAINER_MultiHashMap *hm;
+
+};
+
+
+struct FlatFileEntry
+{
+  /**
+   * Entry zone
+   */
+  struct GNUNET_CRYPTO_EcdsaPrivateKey private_key;
+
+  /**
+   * Record cound
+   */
+  uint32_t record_count;
+
+  /**
+   * Rvalue
+   */
+  uint64_t rvalue;
+
+  /**
+   * Record data
+   */
+  struct GNUNET_GNSRECORD_Data *record_data;
+
+  /**
+   * Label
+   */
+  char *label;
+
+};
+
+
+/**
+ * Hash contactenation of @a pkey and @a label into @a h
+ *
+ * @param pkey a key
+ * @param label a label
+ * @param h[out] initialized hash
+ */
+static void
+hash_pkey_and_label (const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
+                     const char *label,
+                     struct GNUNET_HashCode *h)
+{
+  char *key;
+  size_t label_len;
+  size_t key_len;
+
+  label_len = strlen (label);
+  key_len = label_len + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
+  key = GNUNET_malloc (key_len);
+  GNUNET_memcpy (key,
+                 label,
+                 label_len);
+  GNUNET_memcpy (key + label_len,
+                 pkey,
+                 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
+  GNUNET_CRYPTO_hash (key,
+                      key_len,
+                      h);
+  GNUNET_free (key);
+}
+
+
+/**
+ * Initialize the database connections and associated
+ * data structures (create tables and indices
+ * as needed as well).
+ *
+ * @param plugin the plugin context (state for this module)
+ * @return #GNUNET_OK on success
+ */
+static int
+database_setup (struct Plugin *plugin)
+{
+  char *flatdbfile;
+  char *record_data;
+  char *zone_private_key;
+  char *record_data_b64;
+  char *buffer;
+  char *line;
+  char *label;
+  char *rvalue;
+  char *record_count;
+  size_t record_data_size;
+  uint64_t size;
+  struct GNUNET_HashCode hkey;
+  struct GNUNET_DISK_FileHandle *fh;
+  struct FlatFileEntry *entry;
+  struct GNUNET_DISK_MapHandle *mh;
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
+                                               "namestore-flat",
+                                               "FILENAME",
+                                              &flatdbfile))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "namestore-flat",
+                              "FILENAME");
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK !=
+      GNUNET_DISK_file_test (flatdbfile))
+  {
+    if (GNUNET_OK !=
+       GNUNET_DISK_directory_create_for_file (flatdbfile))
+    {
+      GNUNET_break (0);
+      GNUNET_free (flatdbfile);
+      return GNUNET_SYSERR;
+    }
+  }
+  /* flatdbfile should be UTF-8-encoded. If it isn't, it's a bug */
+  plugin->fn = flatdbfile;
+
+  /* Load data from file into hashmap */
+  plugin->hm = GNUNET_CONTAINER_multihashmap_create (10,
+                                                     GNUNET_NO);
+  fh = GNUNET_DISK_file_open (flatdbfile,
+                              GNUNET_DISK_OPEN_CREATE |
+                              GNUNET_DISK_OPEN_READWRITE,
+                              GNUNET_DISK_PERM_USER_WRITE |
+                              GNUNET_DISK_PERM_USER_READ);
+  if (NULL == fh)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+         _("Unable to initialize file: %s.\n"),
+         flatdbfile);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_SYSERR ==
+      GNUNET_DISK_file_size (flatdbfile,
+                             &size,
+                             GNUNET_YES,
+                             GNUNET_YES))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+         _("Unable to get filesize: %s.\n"),
+         flatdbfile);
+    GNUNET_DISK_file_close (fh);
+    return GNUNET_SYSERR;
+  }
+  if (size > SIZE_MAX)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("File too big to map: %llu bytes.\n"),
+                (unsigned long long) size);
+    GNUNET_DISK_file_close (fh);
+    return GNUNET_SYSERR;
+  }
+  if (0 == size)
+  {
+    GNUNET_DISK_file_close (fh);
+    return GNUNET_OK;
+  }
+  buffer = GNUNET_DISK_file_map (fh,
+                                 &mh,
+                                 GNUNET_DISK_MAP_TYPE_READ,
+                                 size);
+  if (NULL == buffer)
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                         "mmap");
+    GNUNET_DISK_file_close (fh);
+    return GNUNET_SYSERR;
+  }
+  if ('\0' != buffer[size-1])
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("Namestore database file `%s' malformed\n"),
+                flatdbfile);
+    GNUNET_DISK_file_unmap (mh);
+    GNUNET_DISK_file_close (fh);
+    return GNUNET_SYSERR;
+  }
+
+  line = strtok (buffer, "\n");
+  while (NULL != line)
+  {
+    zone_private_key = strtok (line, ",");
+    if (NULL == zone_private_key)
+      break;
+    rvalue = strtok (NULL, ",");
+    if (NULL == rvalue)
+      break;
+    record_count = strtok (NULL, ",");
+    if (NULL == record_count)
+      break;
+    record_data_b64 = strtok (NULL, ",");
+    if (NULL == record_data_b64)
+      break;
+    label = strtok (NULL, ",");
+    if (NULL == label)
+      break;
+    line = strtok (NULL, "\n");
+    entry = GNUNET_new (struct FlatFileEntry);
+    {
+      unsigned long long ll;
+      
+      if (1 != sscanf (rvalue,
+                       "%llu",
+                       &ll))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "Error parsing entry\n");
+        GNUNET_free (entry);
+        break;
+      }
+      entry->rvalue = (uint64_t) ll;
+    }
+    {
+      unsigned int ui;
+
+      if (1 != sscanf (record_count,
+                       "%u",
+                       &ui))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "Error parsing entry\n");
+        GNUNET_free (entry);
+        break;
+      }
+      entry->record_count = (uint32_t) ui;
+    }
+    entry->label = GNUNET_strdup (label);
+    record_data_size
+      = GNUNET_STRINGS_base64_decode (record_data_b64,
+                                      strlen (record_data_b64),
+                                      (void **) &record_data);
+    entry->record_data =
+      GNUNET_new_array (entry->record_count,
+                        struct GNUNET_GNSRECORD_Data);
+    if (GNUNET_OK !=
+        GNUNET_GNSRECORD_records_deserialize (record_data_size,
+                                              record_data,
+                                              entry->record_count,
+                                              entry->record_data))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Unable to deserialize record %s\n",
+                  label);
+      GNUNET_free (entry->label);
+      GNUNET_free (entry);
+      GNUNET_free (record_data);
+      break;
+    }
+    GNUNET_free (record_data);
+    
+    {
+      struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key;
+      
+      GNUNET_STRINGS_base64_decode (zone_private_key,
+                                    strlen (zone_private_key),
+                                    (void**)&private_key);
+      entry->private_key = *private_key;
+      GNUNET_free (private_key);
+    }
+    
+    hash_pkey_and_label (&entry->private_key,
+                         label,
+                         &hkey);
+    if (GNUNET_OK !=
+        GNUNET_CONTAINER_multihashmap_put (plugin->hm,
+                                           &hkey,
+                                           entry,
+                                           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+    {
+      GNUNET_free (entry);
+      GNUNET_break (0);
+    }
+  }
+  GNUNET_DISK_file_unmap (mh);
+  GNUNET_DISK_file_close (fh);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Store values in hashmap in file and free data
+ *
+ * @param plugin the plugin context
+ * @param key key in the map
+ * @param value a `struct FlatFileEntry`
+ */
+static int
+store_and_free_entries (void *cls,
+                        const struct GNUNET_HashCode *key,
+                        void *value)
+{
+  struct GNUNET_DISK_FileHandle *fh = cls;
+  struct FlatFileEntry *entry = value;
+  char *line;
+  char *zone_private_key;
+  char *record_data_b64;
+  ssize_t data_size;
+
+  (void) key;
+  GNUNET_STRINGS_base64_encode (&entry->private_key,
+                                sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
+                                &zone_private_key);
+  data_size = GNUNET_GNSRECORD_records_get_size (entry->record_count,
+                                                 entry->record_data);
+  if (data_size < 0)
+  {
+    GNUNET_break (0);
+    GNUNET_free (zone_private_key);
+    return GNUNET_SYSERR;
+  }
+  if (data_size >= UINT16_MAX)
+  {
+    GNUNET_break (0);
+    GNUNET_free (zone_private_key);
+    return GNUNET_SYSERR;
+  }
+  {
+    char data[data_size];
+    ssize_t ret;
+
+    ret = GNUNET_GNSRECORD_records_serialize (entry->record_count,
+                                             entry->record_data,
+                                             data_size,
+                                             data);
+    if ( (ret < 0) ||
+        (data_size != ret) )
+    {
+      GNUNET_break (0);
+      GNUNET_free (zone_private_key);
+      return GNUNET_SYSERR;
+    }
+    GNUNET_STRINGS_base64_encode (data,
+                                  data_size,
+                                  &record_data_b64);
+  }
+  GNUNET_asprintf (&line,
+                   "%s,%llu,%u,%s,%s\n",
+                   zone_private_key,
+                   (unsigned long long) entry->rvalue,
+                   (unsigned int) entry->record_count,
+                   record_data_b64,
+                   entry->label);
+  GNUNET_free (record_data_b64);
+  GNUNET_free (zone_private_key);
+
+  GNUNET_DISK_file_write (fh,
+                          line,
+                          strlen (line));
+
+  GNUNET_free (line);
+  GNUNET_free (entry->label);
+  GNUNET_free (entry->record_data);
+  GNUNET_free (entry);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Shutdown database connection and associate data
+ * structures.
+ * @param plugin the plugin context (state for this module)
+ */
+static void
+database_shutdown (struct Plugin *plugin)
+{
+  struct GNUNET_DISK_FileHandle *fh;
+
+  fh = GNUNET_DISK_file_open (plugin->fn,
+                              GNUNET_DISK_OPEN_CREATE |
+                              GNUNET_DISK_OPEN_TRUNCATE |
+                              GNUNET_DISK_OPEN_READWRITE,
+                              GNUNET_DISK_PERM_USER_WRITE |
+                              GNUNET_DISK_PERM_USER_READ);
+  if (NULL == fh)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("Unable to initialize file: %s.\n"),
+                plugin->fn);
+    return;
+  }
+
+  GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
+                                         &store_and_free_entries,
+                                         fh);
+  GNUNET_CONTAINER_multihashmap_destroy (plugin->hm);
+  /* append 0-terminator */
+  GNUNET_DISK_file_write (fh,
+                          "",
+                          1);
+  GNUNET_DISK_file_close (fh);
+}
+
+
+/**
+ * Store a record in the datastore.  Removes any existing record in the
+ * same zone with the same name.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param zone_key private key of the zone
+ * @param label name that is being mapped (at most 255 characters long)
+ * @param rd_count number of entries in @a rd array
+ * @param rd array of records with data to store
+ * @return #GNUNET_OK on success, else #GNUNET_SYSERR
+ */
+static int
+namestore_flat_store_records (void *cls,
+                              const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+                              const char *label,
+                              unsigned int rd_count,
+                              const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct Plugin *plugin = cls;
+  uint64_t rvalue;
+  struct GNUNET_HashCode hkey;
+  struct FlatFileEntry *entry;
+
+  rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                    UINT64_MAX);
+  hash_pkey_and_label (zone_key,
+                       label,
+                       &hkey);
+  GNUNET_CONTAINER_multihashmap_remove_all (plugin->hm,
+                                            &hkey);
+  if (0 == rd_count)
+  {
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                     "sqlite",
+                     "Record deleted\n");
+    return GNUNET_OK;
+  }
+  entry = GNUNET_new (struct FlatFileEntry);
+  GNUNET_asprintf (&entry->label,
+                   label,
+                   strlen (label));
+  GNUNET_memcpy (&entry->private_key,
+                 zone_key,
+                 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
+  entry->rvalue = rvalue;
+  entry->record_count = rd_count;
+  entry->record_data = GNUNET_new_array (rd_count,
+                                         struct GNUNET_GNSRECORD_Data);
+  for (unsigned int i = 0; i < rd_count; i++)
+  {
+    entry->record_data[i].expiration_time = rd[i].expiration_time;
+    entry->record_data[i].record_type = rd[i].record_type;
+    entry->record_data[i].flags = rd[i].flags;
+    entry->record_data[i].data_size = rd[i].data_size;
+    entry->record_data[i].data = GNUNET_malloc (rd[i].data_size);
+    GNUNET_memcpy ((char*)entry->record_data[i].data,
+                   rd[i].data,
+                   rd[i].data_size);
+  }
+  return GNUNET_CONTAINER_multihashmap_put (plugin->hm,
+                                            &hkey,
+                                            entry,
+                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+}
+
+
+/**
+ * Lookup records in the datastore for which we are the authority.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param zone private key of the zone
+ * @param label name of the record in the zone
+ * @param iter function to call with the result
+ * @param iter_cls closure for @a iter
+ * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
+ */
+static int
+namestore_flat_lookup_records (void *cls,
+                               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+                               const char *label,
+                               GNUNET_NAMESTORE_RecordIterator iter,
+                               void *iter_cls)
+{
+  struct Plugin *plugin = cls;
+  struct FlatFileEntry *entry;
+  struct GNUNET_HashCode hkey;
+
+  if (NULL == zone)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  hash_pkey_and_label (zone,
+                       label,
+                       &hkey);
+  entry = GNUNET_CONTAINER_multihashmap_get (plugin->hm,
+                                            &hkey);
+
+  if (NULL == entry)
+    return GNUNET_NO;
+  if (NULL != iter)
+    iter (iter_cls,
+         1, /* zero is illegal */
+         &entry->private_key,
+         entry->label,
+         entry->record_count,
+         entry->record_data);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Closure for #iterate_zones.
+ */
+struct IterateContext
+{
+  /**
+   * How many more records should we skip before returning results?
+   */
+  uint64_t offset;
+
+  /**
+   * How many more records should we return?
+   */
+  uint64_t limit;
+
+  /**
+   * What is the position of the current entry, counting
+   * starts from 1.
+   */
+  uint64_t pos;
+
+  /**
+   * Target zone.
+   */
+  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone;
+
+  /**
+   * Function to call on each record.
+   */
+  GNUNET_NAMESTORE_RecordIterator iter;
+
+  /**
+   * Closure for @e iter.
+   */
+  void *iter_cls;
+
+};
+
+
+/**
+ * Helper function for #namestore_flat_iterate_records().
+ *
+ * @param cls a `struct IterateContext`
+ * @param key unused
+ * @param value a `struct FlatFileEntry`
+ * @return #GNUNET_YES to continue the iteration
+ */
+static int
+iterate_zones (void *cls,
+               const struct GNUNET_HashCode *key,
+               void *value)
+{
+  struct IterateContext *ic = cls;
+  struct FlatFileEntry *entry = value;
+
+  (void) key;
+  if (0 == ic->limit)
+    return GNUNET_NO;
+  if ( (NULL != ic->zone) &&
+       (0 != GNUNET_memcmp (&entry->private_key,
+                     ic->zone)) )
+    return GNUNET_YES;
+  ic->pos++;
+  if (ic->offset > 0)
+  {
+    ic->offset--;
+    return GNUNET_YES;
+  }
+  ic->iter (ic->iter_cls,
+           ic->pos,
+            (NULL == ic->zone)
+           ? &entry->private_key
+           : ic->zone,
+            entry->label,
+            entry->record_count,
+            entry->record_data);
+  ic->limit--;
+  if (0 == ic->limit)
+    return GNUNET_NO;
+  return GNUNET_YES;
+}
+
+
+/**
+ * Iterate over the results for a particular key and zone in the
+ * datastore.  Will return at most one result to the iterator.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param zone hash of public key of the zone, NULL to iterate over all zones
+ * @param serial serial number to exclude in the list of all matching records
+ * @param limit maximum number of results to return to @a iter
+ * @param iter function to call with the result
+ * @param iter_cls closure for @a iter
+ * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error
+ */
+static int
+namestore_flat_iterate_records (void *cls,
+                                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+                                uint64_t serial,
+                                uint64_t limit,
+                                GNUNET_NAMESTORE_RecordIterator iter,
+                                void *iter_cls)
+{
+  struct Plugin *plugin = cls;
+  struct IterateContext ic;
+
+  ic.offset = serial;
+  ic.pos = 0;
+  ic.limit = limit;
+  ic.iter = iter;
+  ic.iter_cls = iter_cls;
+  ic.zone = zone;
+  GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
+                                         &iterate_zones,
+                                         &ic);
+  return (0 == ic.limit) ? GNUNET_OK : GNUNET_NO;
+}
+
+
+/**
+ * Closure for #zone_to_name.
+ */
+struct ZoneToNameContext
+{
+  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone;
+  const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone;
+  GNUNET_NAMESTORE_RecordIterator iter;
+  void *iter_cls;
+
+  int result_found;
+};
+
+
+static int
+zone_to_name (void *cls,
+              const struct GNUNET_HashCode *key,
+              void *value)
+{
+  struct ZoneToNameContext *ztn = cls;
+  struct FlatFileEntry *entry = value;
+
+  (void) key;
+  if (0 != GNUNET_memcmp (&entry->private_key,
+                   ztn->zone))
+    return GNUNET_YES;
+
+  for (unsigned int i = 0; i < entry->record_count; i++)
+  {
+    if (GNUNET_GNSRECORD_TYPE_PKEY != entry->record_data[i].record_type)
+      continue;
+    if (0 == memcmp (ztn->value_zone,
+                     entry->record_data[i].data,
+                     sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
+    {
+      ztn->iter (ztn->iter_cls,
+                 i + 1, /* zero is illegal! */
+                 &entry->private_key,
+                 entry->label,
+                 entry->record_count,
+                 entry->record_data);
+      ztn->result_found = GNUNET_YES;
+    }
+  }
+  return GNUNET_YES;
+}
+
+
+/**
+ * Look for an existing PKEY delegation record for a given public key.
+ * Returns at most one result to the iterator.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param zone private key of the zone to look up in, never NULL
+ * @param value_zone public key of the target zone (value), never NULL
+ * @param iter function to call with the result
+ * @param iter_cls closure for @a iter
+ * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
+ */
+static int
+namestore_flat_zone_to_name (void *cls,
+                             const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+                             const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
+                             GNUNET_NAMESTORE_RecordIterator iter,
+                             void *iter_cls)
+{
+  struct Plugin *plugin = cls;
+  struct ZoneToNameContext ztn = {
+    .iter = iter,
+    .iter_cls = iter_cls,
+    .zone = zone,
+    .value_zone = value_zone,
+    .result_found = GNUNET_NO
+  };
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Performing reverse lookup for `%s'\n",
+              GNUNET_GNSRECORD_z2s (value_zone));
+  GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
+                                         &zone_to_name,
+                                         &ztn);
+  return ztn.result_found;
+}
+
+
+/**
+ * Entry point for the plugin.
+ *
+ * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
+ * @return NULL on error, otherwise the plugin context
+ */
+void *
+libgnunet_plugin_namestore_flat_init (void *cls)
+{
+  static 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))
+  {
+    database_shutdown (&plugin);
+    return NULL;
+  }
+  api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
+  api->cls = &plugin;
+  api->store_records = &namestore_flat_store_records;
+  api->iterate_records = &namestore_flat_iterate_records;
+  api->zone_to_name = &namestore_flat_zone_to_name;
+  api->lookup_records = &namestore_flat_lookup_records;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              _("Flat file database running\n"));
+  return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ *
+ * @param cls the plugin context (as returned by "init")
+ * @return always NULL
+ */
+void *
+libgnunet_plugin_namestore_flat_done (void *cls)
+{
+  struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
+  struct Plugin *plugin = api->cls;
+
+  database_shutdown (plugin);
+  plugin->cfg = NULL;
+  GNUNET_free (api);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Flat file plugin is finished\n");
+  return NULL;
+}
+
+/* end of plugin_namestore_flat.c */
diff --git a/src/namestore/plugin_namestore_heap.c b/src/namestore/plugin_namestore_heap.c
deleted file mode 100644 (file)
index 2a72c0e..0000000
+++ /dev/null
@@ -1,796 +0,0 @@
- /*
-  * This file is part of GNUnet
-  * Copyright (C) 2009-2015, 2018 GNUnet e.V.
-  *
-  * GNUnet is free software: you can redistribute it and/or modify it
-  * under the terms of the GNU Affero General Public License as published
-  * by the Free Software Foundation, either version 3 of the License,
-  * or (at your option) any later version.
-  *
-  * GNUnet is distributed in the hope that it will be useful, but
-  * WITHOUT ANY WARRANTY; without even the implied warranty of
-  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  * Affero General Public License for more details.
-  *
-  * You should have received a copy of the GNU Affero General Public License
-  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-     SPDX-License-Identifier: AGPL3.0-or-later
-  */
-
-/**
- * @file namestore/plugin_namestore_heap.c
- * @brief file-based namestore backend
- * @author Martin Schanzenbach
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "gnunet_namestore_plugin.h"
-#include "gnunet_namestore_service.h"
-#include "gnunet_gnsrecord_lib.h"
-#include "namestore.h"
-
-/**
- * Context for all functions in this plugin.
- */
-struct Plugin
-{
-
-  const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-  /**
-   * Database filename.
-   */
-  char *fn;
-
-  /**
-   * HashMap
-   */
-  struct GNUNET_CONTAINER_MultiHashMap *hm;
-
-};
-
-
-struct FlatFileEntry
-{
-  /**
-   * Entry zone
-   */
-  struct GNUNET_CRYPTO_EcdsaPrivateKey private_key;
-
-  /**
-   * Record cound
-   */
-  uint32_t record_count;
-
-  /**
-   * Rvalue
-   */
-  uint64_t rvalue;
-
-  /**
-   * Record data
-   */
-  struct GNUNET_GNSRECORD_Data *record_data;
-
-  /**
-   * Label
-   */
-  char *label;
-
-};
-
-
-/**
- * Hash contactenation of @a pkey and @a label into @a h
- *
- * @param pkey a key
- * @param label a label
- * @param h[out] initialized hash
- */
-static void
-hash_pkey_and_label (const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
-                     const char *label,
-                     struct GNUNET_HashCode *h)
-{
-  char *key;
-  size_t label_len;
-  size_t key_len;
-
-  label_len = strlen (label);
-  key_len = label_len + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
-  key = GNUNET_malloc (key_len);
-  GNUNET_memcpy (key,
-                 label,
-                 label_len);
-  GNUNET_memcpy (key + label_len,
-                 pkey,
-                 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
-  GNUNET_CRYPTO_hash (key,
-                      key_len,
-                      h);
-  GNUNET_free (key);
-}
-
-
-/**
- * Initialize the database connections and associated
- * data structures (create tables and indices
- * as needed as well).
- *
- * @param plugin the plugin context (state for this module)
- * @return #GNUNET_OK on success
- */
-static int
-database_setup (struct Plugin *plugin)
-{
-  char *afsdir;
-  char *record_data;
-  char *zone_private_key;
-  char *record_data_b64;
-  char *buffer;
-  char *line;
-  char *label;
-  char *rvalue;
-  char *record_count;
-  size_t record_data_size;
-  uint64_t size;
-  struct GNUNET_HashCode hkey;
-  struct GNUNET_DISK_FileHandle *fh;
-  struct FlatFileEntry *entry;
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
-                                               "namestore-heap",
-                                               "FILENAME",
-                                              &afsdir))
-  {
-    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-                               "namestore-heap",
-                              "FILENAME");
-    return GNUNET_SYSERR;
-  }
-  if (GNUNET_OK !=
-      GNUNET_DISK_file_test (afsdir))
-  {
-    if (GNUNET_OK !=
-       GNUNET_DISK_directory_create_for_file (afsdir))
-    {
-      GNUNET_break (0);
-      GNUNET_free (afsdir);
-      return GNUNET_SYSERR;
-    }
-  }
-  /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */
-  plugin->fn = afsdir;
-
-  /* Load data from file into hashmap */
-  plugin->hm = GNUNET_CONTAINER_multihashmap_create (10,
-                                                     GNUNET_NO);
-  fh = GNUNET_DISK_file_open (afsdir,
-                              GNUNET_DISK_OPEN_CREATE |
-                              GNUNET_DISK_OPEN_READWRITE,
-                              GNUNET_DISK_PERM_USER_WRITE |
-                              GNUNET_DISK_PERM_USER_READ);
-  if (NULL == fh)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-         _("Unable to initialize file: %s.\n"),
-         afsdir);
-    return GNUNET_SYSERR;
-  }
-  if (GNUNET_SYSERR ==
-      GNUNET_DISK_file_size (afsdir,
-                             &size,
-                             GNUNET_YES,
-                             GNUNET_YES))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-         _("Unable to get filesize: %s.\n"),
-         afsdir);
-    GNUNET_DISK_file_close (fh);
-    return GNUNET_SYSERR;
-  }
-
-  buffer = GNUNET_malloc_large (size + 1);
-  if (GNUNET_SYSERR ==
-      GNUNET_DISK_file_read (fh,
-                             buffer,
-                             size))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-         _("Unable to read file: %s.\n"),
-         afsdir);
-    GNUNET_free (buffer);
-    GNUNET_DISK_file_close (fh);
-    return GNUNET_SYSERR;
-  }
-  buffer[size] = '\0';
-  GNUNET_DISK_file_close (fh);
-
-  if (0 < size)
-  {
-    line = strtok (buffer, "\n");
-    while (line != NULL)
-    {
-      zone_private_key = strtok (line, ",");
-      if (NULL == zone_private_key)
-        break;
-      rvalue = strtok (NULL, ",");
-      if (NULL == rvalue)
-        break;
-      record_count = strtok (NULL, ",");
-      if (NULL == record_count)
-        break;
-      record_data_b64 = strtok (NULL, ",");
-      if (NULL == record_data_b64)
-        break;
-      label = strtok (NULL, ",");
-      if (NULL == label)
-        break;
-      line = strtok (NULL, "\n");
-      entry = GNUNET_new (struct FlatFileEntry);
-      {
-        unsigned long long ll;
-
-        if (1 != sscanf (rvalue,
-                         "%llu",
-                         &ll))
-        {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                      "Error parsing entry\n");
-          GNUNET_free (entry);
-          break;
-        }
-        entry->rvalue = (uint64_t) ll;
-      }
-      {
-        unsigned int ui;
-
-        if (1 != sscanf (record_count,
-                         "%u",
-                         &ui))
-        {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                      "Error parsing entry\n");
-          GNUNET_free (entry);
-          break;
-        }
-        entry->record_count = (uint32_t) ui;
-      }
-      entry->label = GNUNET_strdup (label);
-      record_data_size
-       = GNUNET_STRINGS_base64_decode (record_data_b64,
-                                       strlen (record_data_b64),
-                                       (void **) &record_data);
-      entry->record_data =
-        GNUNET_new_array (entry->record_count,
-                         struct GNUNET_GNSRECORD_Data);
-      if (GNUNET_OK !=
-         GNUNET_GNSRECORD_records_deserialize (record_data_size,
-                                               record_data,
-                                               entry->record_count,
-                                               entry->record_data))
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    "Unable to deserialize record %s\n",
-                   label);
-        GNUNET_free (entry->label);
-        GNUNET_free (entry);
-        GNUNET_free (record_data);
-        break;
-      }
-      GNUNET_free (record_data);
-
-      {
-        struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key;
-
-        GNUNET_STRINGS_base64_decode (zone_private_key,
-                                      strlen (zone_private_key),
-                                      (void**)&private_key);
-        entry->private_key = *private_key;
-        GNUNET_free (private_key);
-      }
-
-      hash_pkey_and_label (&entry->private_key,
-                           label,
-                           &hkey);
-      if (GNUNET_OK !=
-          GNUNET_CONTAINER_multihashmap_put (plugin->hm,
-                                             &hkey,
-                                             entry,
-                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
-      {
-        GNUNET_free (entry);
-        GNUNET_break (0);
-      }
-    }
-  }
-  GNUNET_free (buffer);
-  return GNUNET_OK;
-}
-
-
-/**
- * Store values in hashmap in file and free data
- *
- * @param plugin the plugin context
- * @param key key in the map
- * @param value a `struct FlatFileEntry`
- */
-static int
-store_and_free_entries (void *cls,
-                        const struct GNUNET_HashCode *key,
-                        void *value)
-{
-  struct GNUNET_DISK_FileHandle *fh = cls;
-  struct FlatFileEntry *entry = value;
-  char *line;
-  char *zone_private_key;
-  char *record_data_b64;
-  ssize_t data_size;
-
-  (void) key;
-  GNUNET_STRINGS_base64_encode (&entry->private_key,
-                                sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
-                                &zone_private_key);
-  data_size = GNUNET_GNSRECORD_records_get_size (entry->record_count,
-                                                 entry->record_data);
-  if (data_size < 0)
-  {
-    GNUNET_break (0);
-    GNUNET_free (zone_private_key);
-    return GNUNET_SYSERR;
-  }
-  if (data_size >= UINT16_MAX)
-  {
-    GNUNET_break (0);
-    GNUNET_free (zone_private_key);
-    return GNUNET_SYSERR;
-  }
-  {
-    char data[data_size];
-    ssize_t ret;
-
-    ret = GNUNET_GNSRECORD_records_serialize (entry->record_count,
-                                             entry->record_data,
-                                             data_size,
-                                             data);
-    if ( (ret < 0) ||
-        (data_size != ret) )
-    {
-      GNUNET_break (0);
-      GNUNET_free (zone_private_key);
-      return GNUNET_SYSERR;
-    }
-    GNUNET_STRINGS_base64_encode (data,
-                                  data_size,
-                                  &record_data_b64);
-  }
-  GNUNET_asprintf (&line,
-                   "%s,%llu,%u,%s,%s\n",
-                   zone_private_key,
-                   (unsigned long long) entry->rvalue,
-                   (unsigned int) entry->record_count,
-                   record_data_b64,
-                   entry->label);
-  GNUNET_free (record_data_b64);
-  GNUNET_free (zone_private_key);
-
-  GNUNET_DISK_file_write (fh,
-                          line,
-                          strlen (line));
-
-  GNUNET_free (line);
-  GNUNET_free (entry->label);
-  GNUNET_free (entry->record_data);
-  GNUNET_free (entry);
-  return GNUNET_YES;
-}
-
-
-/**
- * Shutdown database connection and associate data
- * structures.
- * @param plugin the plugin context (state for this module)
- */
-static void
-database_shutdown (struct Plugin *plugin)
-{
-  struct GNUNET_DISK_FileHandle *fh;
-
-  fh = GNUNET_DISK_file_open (plugin->fn,
-                              GNUNET_DISK_OPEN_CREATE |
-                              GNUNET_DISK_OPEN_TRUNCATE |
-                              GNUNET_DISK_OPEN_READWRITE,
-                              GNUNET_DISK_PERM_USER_WRITE |
-                              GNUNET_DISK_PERM_USER_READ);
-  if (NULL == fh)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _("Unable to initialize file: %s.\n"),
-                plugin->fn);
-    return;
-  }
-
-  GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
-                                         &store_and_free_entries,
-                                         fh);
-  GNUNET_CONTAINER_multihashmap_destroy (plugin->hm);
-  GNUNET_DISK_file_close (fh);
-}
-
-
-/**
- * Store a record in the datastore.  Removes any existing record in the
- * same zone with the same name.
- *
- * @param cls closure (internal context for the plugin)
- * @param zone_key private key of the zone
- * @param label name that is being mapped (at most 255 characters long)
- * @param rd_count number of entries in @a rd array
- * @param rd array of records with data to store
- * @return #GNUNET_OK on success, else #GNUNET_SYSERR
- */
-static int
-namestore_heap_store_records (void *cls,
-                              const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
-                              const char *label,
-                              unsigned int rd_count,
-                              const struct GNUNET_GNSRECORD_Data *rd)
-{
-  struct Plugin *plugin = cls;
-  uint64_t rvalue;
-  struct GNUNET_HashCode hkey;
-  struct FlatFileEntry *entry;
-
-  rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                    UINT64_MAX);
-  hash_pkey_and_label (zone_key,
-                       label,
-                       &hkey);
-  GNUNET_CONTAINER_multihashmap_remove_all (plugin->hm,
-                                            &hkey);
-  if (0 == rd_count)
-  {
-    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
-                     "sqlite",
-                     "Record deleted\n");
-    return GNUNET_OK;
-  }
-  entry = GNUNET_new (struct FlatFileEntry);
-  GNUNET_asprintf (&entry->label,
-                   label,
-                   strlen (label));
-  GNUNET_memcpy (&entry->private_key,
-                 zone_key,
-                 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
-  entry->rvalue = rvalue;
-  entry->record_count = rd_count;
-  entry->record_data = GNUNET_new_array (rd_count,
-                                         struct GNUNET_GNSRECORD_Data);
-  for (unsigned int i = 0; i < rd_count; i++)
-  {
-    entry->record_data[i].expiration_time = rd[i].expiration_time;
-    entry->record_data[i].record_type = rd[i].record_type;
-    entry->record_data[i].flags = rd[i].flags;
-    entry->record_data[i].data_size = rd[i].data_size;
-    entry->record_data[i].data = GNUNET_malloc (rd[i].data_size);
-    GNUNET_memcpy ((char*)entry->record_data[i].data,
-                   rd[i].data,
-                   rd[i].data_size);
-  }
-  return GNUNET_CONTAINER_multihashmap_put (plugin->hm,
-                                            &hkey,
-                                            entry,
-                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
-}
-
-
-/**
- * Lookup records in the datastore for which we are the authority.
- *
- * @param cls closure (internal context for the plugin)
- * @param zone private key of the zone
- * @param label name of the record in the zone
- * @param iter function to call with the result
- * @param iter_cls closure for @a iter
- * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
- */
-static int
-namestore_heap_lookup_records (void *cls,
-                               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
-                               const char *label,
-                               GNUNET_NAMESTORE_RecordIterator iter,
-                               void *iter_cls)
-{
-  struct Plugin *plugin = cls;
-  struct FlatFileEntry *entry;
-  struct GNUNET_HashCode hkey;
-
-  if (NULL == zone)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  hash_pkey_and_label (zone,
-                       label,
-                       &hkey);
-  entry = GNUNET_CONTAINER_multihashmap_get (plugin->hm,
-                                            &hkey);
-
-  if (NULL == entry)
-    return GNUNET_NO;
-  if (NULL != iter)
-    iter (iter_cls,
-         1, /* zero is illegal */
-         &entry->private_key,
-         entry->label,
-         entry->record_count,
-         entry->record_data);
-  return GNUNET_YES;
-}
-
-
-/**
- * Closure for #iterate_zones.
- */
-struct IterateContext
-{
-  /**
-   * How many more records should we skip before returning results?
-   */
-  uint64_t offset;
-
-  /**
-   * How many more records should we return?
-   */
-  uint64_t limit;
-
-  /**
-   * What is the position of the current entry, counting
-   * starts from 1.
-   */
-  uint64_t pos;
-
-  /**
-   * Target zone.
-   */
-  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone;
-
-  /**
-   * Function to call on each record.
-   */
-  GNUNET_NAMESTORE_RecordIterator iter;
-
-  /**
-   * Closure for @e iter.
-   */
-  void *iter_cls;
-
-};
-
-
-/**
- * Helper function for #namestore_heap_iterate_records().
- *
- * @param cls a `struct IterateContext`
- * @param key unused
- * @param value a `struct FlatFileEntry`
- * @return #GNUNET_YES to continue the iteration
- */
-static int
-iterate_zones (void *cls,
-               const struct GNUNET_HashCode *key,
-               void *value)
-{
-  struct IterateContext *ic = cls;
-  struct FlatFileEntry *entry = value;
-
-  (void) key;
-  if (0 == ic->limit)
-    return GNUNET_NO;
-  if ( (NULL != ic->zone) &&
-       (0 != GNUNET_memcmp (&entry->private_key,
-                     ic->zone)) )
-    return GNUNET_YES;
-  ic->pos++;
-  if (ic->offset > 0)
-  {
-    ic->offset--;
-    return GNUNET_YES;
-  }
-  ic->iter (ic->iter_cls,
-           ic->pos,
-            (NULL == ic->zone)
-           ? &entry->private_key
-           : ic->zone,
-            entry->label,
-            entry->record_count,
-            entry->record_data);
-  ic->limit--;
-  if (0 == ic->limit)
-    return GNUNET_NO;
-  return GNUNET_YES;
-}
-
-
-/**
- * Iterate over the results for a particular key and zone in the
- * datastore.  Will return at most one result to the iterator.
- *
- * @param cls closure (internal context for the plugin)
- * @param zone hash of public key of the zone, NULL to iterate over all zones
- * @param serial serial number to exclude in the list of all matching records
- * @param limit maximum number of results to return to @a iter
- * @param iter function to call with the result
- * @param iter_cls closure for @a iter
- * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error
- */
-static int
-namestore_heap_iterate_records (void *cls,
-                                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
-                                uint64_t serial,
-                                uint64_t limit,
-                                GNUNET_NAMESTORE_RecordIterator iter,
-                                void *iter_cls)
-{
-  struct Plugin *plugin = cls;
-  struct IterateContext ic;
-
-  ic.offset = serial;
-  ic.pos = 0;
-  ic.limit = limit;
-  ic.iter = iter;
-  ic.iter_cls = iter_cls;
-  ic.zone = zone;
-  GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
-                                         &iterate_zones,
-                                         &ic);
-  return (0 == ic.limit) ? GNUNET_OK : GNUNET_NO;
-}
-
-
-/**
- * Closure for #zone_to_name.
- */
-struct ZoneToNameContext
-{
-  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone;
-  const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone;
-  GNUNET_NAMESTORE_RecordIterator iter;
-  void *iter_cls;
-
-  int result_found;
-};
-
-
-static int
-zone_to_name (void *cls,
-              const struct GNUNET_HashCode *key,
-              void *value)
-{
-  struct ZoneToNameContext *ztn = cls;
-  struct FlatFileEntry *entry = value;
-
-  (void) key;
-  if (0 != GNUNET_memcmp (&entry->private_key,
-                   ztn->zone))
-    return GNUNET_YES;
-
-  for (unsigned int i = 0; i < entry->record_count; i++)
-  {
-    if (GNUNET_GNSRECORD_TYPE_PKEY != entry->record_data[i].record_type)
-      continue;
-    if (0 == memcmp (ztn->value_zone,
-                     entry->record_data[i].data,
-                     sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
-    {
-      ztn->iter (ztn->iter_cls,
-                 i + 1, /* zero is illegal! */
-                 &entry->private_key,
-                 entry->label,
-                 entry->record_count,
-                 entry->record_data);
-      ztn->result_found = GNUNET_YES;
-    }
-  }
-  return GNUNET_YES;
-}
-
-
-/**
- * Look for an existing PKEY delegation record for a given public key.
- * Returns at most one result to the iterator.
- *
- * @param cls closure (internal context for the plugin)
- * @param zone private key of the zone to look up in, never NULL
- * @param value_zone public key of the target zone (value), never NULL
- * @param iter function to call with the result
- * @param iter_cls closure for @a iter
- * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
- */
-static int
-namestore_heap_zone_to_name (void *cls,
-                             const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
-                             const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
-                             GNUNET_NAMESTORE_RecordIterator iter,
-                             void *iter_cls)
-{
-  struct Plugin *plugin = cls;
-  struct ZoneToNameContext ztn = {
-    .iter = iter,
-    .iter_cls = iter_cls,
-    .zone = zone,
-    .value_zone = value_zone,
-    .result_found = GNUNET_NO
-  };
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Performing reverse lookup for `%s'\n",
-              GNUNET_GNSRECORD_z2s (value_zone));
-  GNUNET_CONTAINER_multihashmap_iterate (plugin->hm,
-                                         &zone_to_name,
-                                         &ztn);
-  return ztn.result_found;
-}
-
-
-/**
- * Entry point for the plugin.
- *
- * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
- * @return NULL on error, otherwise the plugin context
- */
-void *
-libgnunet_plugin_namestore_heap_init (void *cls)
-{
-  static 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))
-  {
-    database_shutdown (&plugin);
-    return NULL;
-  }
-  api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
-  api->cls = &plugin;
-  api->store_records = &namestore_heap_store_records;
-  api->iterate_records = &namestore_heap_iterate_records;
-  api->zone_to_name = &namestore_heap_zone_to_name;
-  api->lookup_records = &namestore_heap_lookup_records;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              _("heap file database running\n"));
-  return api;
-}
-
-
-/**
- * Exit point from the plugin.
- *
- * @param cls the plugin context (as returned by "init")
- * @return always NULL
- */
-void *
-libgnunet_plugin_namestore_heap_done (void *cls)
-{
-  struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
-  struct Plugin *plugin = api->cls;
-
-  database_shutdown (plugin);
-  plugin->cfg = NULL;
-  GNUNET_free (api);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "heap file plugin is finished\n");
-  return NULL;
-}
-
-/* end of plugin_namestore_heap.c */
diff --git a/src/namestore/test_namestore_api_flat.conf b/src/namestore/test_namestore_api_flat.conf
new file mode 100644 (file)
index 0000000..8460d14
--- /dev/null
@@ -0,0 +1,7 @@
+@INLINE@ test_namestore_api.conf
+
+[namestore]
+DATABASE = flat
+
+[namestore-heap]
+FILENAME = $GNUNET_TEST_HOME/namestore/flat.db
diff --git a/src/namestore/test_namestore_api_heap.conf b/src/namestore/test_namestore_api_heap.conf
deleted file mode 100644 (file)
index 1d6173e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-@INLINE@ test_namestore_api.conf
-
-[namestore]
-DATABASE = heap
-
-[namestore-heap]
-FILENAME = $GNUNET_TEST_HOME/namestore/flat.db
diff --git a/src/namestore/test_plugin_namestore_flat.conf b/src/namestore/test_plugin_namestore_flat.conf
new file mode 100644 (file)
index 0000000..5c632f0
--- /dev/null
@@ -0,0 +1,2 @@
+[namestore-flat]
+FILENAME = $GNUNET_TMP/gnunet-test-plugin-namestore-flat/flatdb
diff --git a/src/namestore/test_plugin_namestore_heap.conf b/src/namestore/test_plugin_namestore_heap.conf
deleted file mode 100644 (file)
index 94f79b9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-[namestore-heap]
-FILENAME = $GNUNET_TMP/gnunet-test-plugin-namestore-flat/flatdb
index 4f78c77470ee5317c3d7853b3cef161f0794434b..f395a375ea2b533e97c7dcd30ed74d8d69a81b5d 100644 (file)
@@ -2021,7 +2021,7 @@ GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
                       struct GNUNET_DISK_MapHandle **m,
                       enum GNUNET_DISK_MapType access, size_t len)
 {
-  if (h == NULL)
+  if (NULL == h)
   {
     errno = EINVAL;
     return NULL;