gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnunet] branch master updated: optimize memory consumption


From: gnunet
Subject: [GNUnet-SVN] [gnunet] branch master updated: optimize memory consumption of zoneimporter
Date: Mon, 23 Apr 2018 19:21:51 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository gnunet.

The following commit(s) were added to refs/heads/master by this push:
     new d21a53947 optimize memory consumption of zoneimporter
d21a53947 is described below

commit d21a53947cf1d4fd98234f97b6a4f02b54d9a46a
Author: Christian Grothoff <address@hidden>
AuthorDate: Mon Apr 23 19:20:52 2018 +0200

    optimize memory consumption of zoneimporter
---
 doc/man/gnunet-zoneimport.1       |   2 +-
 src/namestore/gnunet-zoneimport.c | 243 ++++++++++++++++++++++++--------------
 2 files changed, 158 insertions(+), 87 deletions(-)

diff --git a/doc/man/gnunet-zoneimport.1 b/doc/man/gnunet-zoneimport.1
index afe3354e6..687e6f900 100644
--- a/doc/man/gnunet-zoneimport.1
+++ b/doc/man/gnunet-zoneimport.1
@@ -18,7 +18,7 @@ gnunet\-zoneimport will issue many DNS queries in parallel, 
but is rate-limited
 
 gnunet\-zoneimport operates incrementally. It will check if the namestore 
already has (non-expired) records stored for a given name in the respective 
zone and not issue those requests again.  Thus, it is fine to restart 
gnunet\-zoneimport whenever the list of domain names changes.
 
-Finally, gnunet\-zoneimport keeps information for each domain name in memory.  
This consumes about 200 bytes per label, or 2 GB for 10 million labels.
+Finally, gnunet\-zoneimport keeps information for each domain name in memory.  
This consumes about 200 bytes per domain name, or 1 GB for 5 million labels.
 
 .SH OPTIONS
 .B
diff --git a/src/namestore/gnunet-zoneimport.c 
b/src/namestore/gnunet-zoneimport.c
index bcc82607e..d57bb938d 100644
--- a/src/namestore/gnunet-zoneimport.c
+++ b/src/namestore/gnunet-zoneimport.c
@@ -104,7 +104,9 @@ struct Record
 
 
 /**
- * Request we should make.
+ * Request we should make.  We keep this struct in memory per request,
+ * thus optimizing it is crucial for the overall memory consumption of
+ * the zone importer.
  */
 struct Request
 {
@@ -141,21 +143,13 @@ struct Request
   struct GNUNET_DNSSTUB_RequestSocket *rs;
 
   /**
-   * Raw DNS query.
-   */
-  void *raw;
-
-  /**
-   * Hostname we are resolving.
+   * Hostname we are resolving, allocated at the end of
+   * this struct (optimizing memory consumption by reducing
+   * total number of allocations).
    */
   char *hostname;
 
   /**
-   * Label (without TLD) which we are resolving.
-   */
-  char *label;
-
-  /**
    * Namestore operation pending for this record.
    */
   struct GNUNET_NAMESTORE_QueueEntry *qe;
@@ -166,12 +160,6 @@ struct Request
   const struct Zone *zone;
 
   /**
-   * Answer we got back and are currently parsing, or NULL
-   * if not active.
-   */
-  struct GNUNET_DNSPARSER_Packet *p;
-
-  /**
    * At what time does the (earliest) of the returned records
    * for this name expire? At this point, we need to re-fetch
    * the record.
@@ -179,20 +167,10 @@ struct Request
   struct GNUNET_TIME_Absolute expires;
 
   /**
-   * Number of bytes in @e raw.
-   */
-  size_t raw_len;
-
-  /**
-   * When did we last issue this request?
-   */
-  time_t time;
-
-  /**
    * How often did we issue this query? (And failed, reset
    * to zero once we were successful.)
    */
-  int issue_num;
+  unsigned int issue_num;
 
   /**
    * random 16-bit DNS query identifier.
@@ -327,6 +305,96 @@ for_all_records (const struct GNUNET_DNSPARSER_Packet *p,
 
 
 /**
+ * Return just the label of the hostname in @a req.
+ * 
+ * @param req request to process hostname of
+ * @return statically allocated pointer to the label,
+ *         overwritten upon the next request!
+ */
+static const char *
+get_label (struct Request *req)
+{
+  static char label[64];
+  const char *dot;
+  
+  dot = strchr (req->hostname,
+                (unsigned char) '.');
+  if (NULL == dot)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+  if (((size_t) (dot - req->hostname)) >= sizeof (label))
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+  memcpy (label,
+         req->hostname,
+         dot - req->hostname);
+  label[dot - req->hostname] = '\0';
+  return label;
+}
+
+
+/**
+ * Build DNS query for @a hostname.
+ * 
+ * @param hostname host to build query for
+ * @param raw_size[out] number of bytes in the query
+ * @return NULL on error, otherwise pointer to statically (!)
+ *         allocated query buffer
+ */
+static void *
+build_dns_query (struct Request *req,
+                size_t *raw_size)
+{
+  static char raw[512];
+  char *rawp;
+  struct GNUNET_DNSPARSER_Packet p;
+  struct GNUNET_DNSPARSER_Query q;
+
+  q.name = (char *) req->hostname;
+  q.type = GNUNET_DNSPARSER_TYPE_NS;
+  q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
+
+  memset (&p,
+          0,
+          sizeof (p));
+  p.num_queries = 1;
+  p.queries = &q;
+  p.id = req->id;
+  if (GNUNET_OK !=
+      GNUNET_DNSPARSER_pack (&p,
+                             UINT16_MAX,
+                             &rawp,
+                             raw_size))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to pack query for hostname `%s'\n",
+                req->hostname);
+    rejects++;
+    return NULL;
+  }
+  if (*raw_size > sizeof (raw))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to pack query for hostname `%s'\n",
+                req->hostname);
+    rejects++;
+    GNUNET_break (0);
+    GNUNET_free (rawp);
+    return NULL; 
+  }
+  memcpy (raw,
+         rawp,
+         *raw_size);
+  GNUNET_free (rawp);
+  return raw;
+}
+
+
+/**
  * Free @a req and data structures reachable from it.
  *
  * @param req request to free
@@ -343,9 +411,6 @@ free_request (struct Request *req)
                                 rec);
     GNUNET_free (rec);
   }
-  GNUNET_free (req->hostname);
-  GNUNET_free (req->label);
-  GNUNET_free (req->raw);
   GNUNET_free (req);
 }
 
@@ -556,16 +621,35 @@ check_for_glue (void *cls,
 
 
 /**
+ * Closure for #process_record().
+ */
+struct ProcessRecordContext
+{
+  /**
+   * Answer we got back and are currently parsing, or NULL
+   * if not active.
+   */
+  struct GNUNET_DNSPARSER_Packet *p;
+
+  /**
+   * Request we are processing.
+   */
+  struct Request *req;
+};
+
+
+/**
  * We received @a rec for @a req. Remember the answer.
  *
- * @param cls a `struct Request`
+ * @param cls a `struct ProcessRecordContext`
  * @param rec response
  */
 static void
 process_record (void *cls,
                 const struct GNUNET_DNSPARSER_Record *rec)
 {
-  struct Request *req = cls;
+  struct ProcessRecordContext *prc = cls;
+  struct Request *req = prc->req;
   char dst[65536];
   size_t dst_len;
   size_t off;
@@ -602,7 +686,7 @@ process_record (void *cls,
       gc.req = req;
       gc.ns = rec->data.hostname;
       gc.found = GNUNET_NO;
-      for_all_records (req->p,
+      for_all_records (prc->p,
                       &check_for_glue,
                       &gc);
       if ( (GNUNET_NO == gc.found) &&
@@ -803,7 +887,7 @@ store_completed_cb (void *cls,
   {
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                "Stored records under `%s'\n",
-               req->label);
+               req->hostname);
     pdot++;
     if (0 == pdot % 1000)
       fprintf (stderr, ".");
@@ -884,11 +968,16 @@ process_result (void *cls,
   }
   /* import new records */
   req->issue_num = 0; /* success, reset counter! */
-  req->p = p;
-  for_all_records (p,
-                  &process_record,
-                  req);
-  req->p = NULL;
+  {
+    struct ProcessRecordContext prc = {
+      .req = req,
+      .p = p
+    };
+    
+    for_all_records (p,
+                    &process_record,
+                    &prc);
+  }
   GNUNET_DNSPARSER_free_packet (p);
   /* count records found, determine minimum expiration time */
   req->expires = GNUNET_TIME_UNIT_FOREVER_ABS;
@@ -921,7 +1010,7 @@ process_result (void *cls,
       rd[off++] = rec->grd;
     req->qe = GNUNET_NAMESTORE_records_store (ns,
                                              &req->zone->key,
-                                             req->label,
+                                             get_label (req),
                                              rd_count,
                                              rd,
                                              &store_completed_cb,
@@ -945,6 +1034,8 @@ submit_req (struct Request *req)
 {
   static struct GNUNET_TIME_Absolute last_request;
   struct GNUNET_TIME_Absolute now;
+  void *raw;
+  size_t raw_size;
 
   if (NULL != req->qe)
     return GNUNET_NO; /* namestore op still pending */
@@ -964,9 +1055,17 @@ submit_req (struct Request *req)
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
              "Requesting resolution for `%s'\n",
              req->hostname);
+  raw = build_dns_query (req,
+                        &raw_size);
+  if (NULL == raw)
+  {
+    GNUNET_break (0);
+    free_request (req);
+    return GNUNET_SYSERR;
+  }
   req->rs = GNUNET_DNSSTUB_resolve (ctx,
-                                    req->raw,
-                                    req->raw_len,
+                                    raw,
+                                    raw_size,
                                     &process_result,
                                     req);
   GNUNET_assert (NULL != req->rs);
@@ -974,7 +1073,6 @@ submit_req (struct Request *req)
   last_request = now;
   lookups++;
   pending++;
-  req->time = time (NULL);
   return GNUNET_OK;
 }
 
@@ -1137,7 +1235,7 @@ ns_lookup_error_cb (void *cls)
   req->qe = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
              "Failed to load data from namestore for `%s'\n",
-             req->label);
+             req->hostname);
   insert_sorted (req);
   pending--;
   continue_stdin ();
@@ -1168,7 +1266,7 @@ ns_lookup_result_cb (void *cls,
                             &req->zone->key,
                             sizeof (*zone)));
   GNUNET_break (0 == strcasecmp (label,
-                                req->label));
+                                get_label (req)));
   for (unsigned int i=0;i<rd_count;i++)
   {
     struct GNUNET_TIME_Absolute at;
@@ -1184,7 +1282,7 @@ ns_lookup_result_cb (void *cls,
   {
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                "Empty record set in namestore for `%s'\n",
-               req->label);
+               req->hostname);
   }
   else
   {
@@ -1207,7 +1305,7 @@ ns_lookup_result_cb (void *cls,
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                 "Hot-start with %u existing records for `%s'\n",
                pos,
-                req->label);
+                req->hostname);
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Adding `%s' to worklist to start at %s\n",
@@ -1226,13 +1324,10 @@ ns_lookup_result_cb (void *cls,
 static void
 queue (const char *hostname)
 {
-  struct GNUNET_DNSPARSER_Packet p;
-  struct GNUNET_DNSPARSER_Query q;
   struct Request *req;
-  char *raw;
-  size_t raw_size;
   const char *dot;
   struct Zone *zone;
+  size_t hlen;
 
   if (GNUNET_OK !=
       GNUNET_DNSPARSER_check_name (hostname))
@@ -1268,44 +1363,20 @@ queue (const char *hostname)
     continue_stdin ();
     return;
   }
-  q.name = (char *) hostname;
-  q.type = GNUNET_DNSPARSER_TYPE_NS;
-  q.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
-
-  memset (&p,
-          0,
-          sizeof (p));
-  p.num_queries = 1;
-  p.queries = &q;
-  p.id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
-                                              UINT16_MAX);
-
-  if (GNUNET_OK !=
-      GNUNET_DNSPARSER_pack (&p,
-                             UINT16_MAX,
-                             &raw,
-                             &raw_size))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Failed to pack query for hostname `%s'\n",
-                hostname);
-    rejects++;
-    continue_stdin ();
-    return;
-  }
 
   pending++;
-  req = GNUNET_new (struct Request);
+  hlen = strlen (hostname) + 1;
+  req = GNUNET_malloc (sizeof (struct Request) + hlen);
   req->zone = zone;
-  req->hostname = GNUNET_strdup (hostname);
-  req->raw = raw;
-  req->raw_len = raw_size;
-  req->id = p.id;
-  req->label = GNUNET_strndup (hostname,
-                              dot - hostname);
+  req->hostname = (char *) &req[1];
+  memcpy (req->hostname,
+         hostname,
+         hlen);
+  req->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+                                                UINT16_MAX);
   req->qe = GNUNET_NAMESTORE_records_lookup (ns,
                                             &req->zone->key,
-                                            req->label,
+                                            get_label (req),
                                             &ns_lookup_error_cb,
                                             req,
                                             &ns_lookup_result_cb,

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]