[rrd-developers] [PATCH] pointer manipulation utility functions

kevin brintnall kbrint at rufus.net
Fri Apr 17 21:20:33 CEST 2009


This patch includes utility functions to support dynamically sized arrays.
This simplifies the code that manages some of the dynamic structures
inside rrdcached.

Per Tobi's request, I started a "librrd.pod" where we'll document the
external facing librrd API.

A few data types have been changed to size_t.

---
diff --git a/doc/Makefile.am b/doc/Makefile.am
index f5f2cb1..74a5455 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -13,7 +13,7 @@ POD = bin_dec_hex.pod        rrddump.pod            rrdgraph_examples.pod  rrdre
       rpntutorial.pod        rrdfirst.pod           rrdgraph_rpn.pod       rrdtool.pod            rrdcached.pod  \
       rrd-beginners.pod      rrdinfo.pod            rrdtune.pod            rrdbuild.pod           rrdflush.pod   \
       rrdcgi.pod             rrdgraph.pod           rrdlast.pod            rrdlastupdate.pod                     \
-      rrdcreate.pod          rrdgraph_data.pod      rrdresize.pod          rrdtutorial.pod
+      rrdcreate.pod          rrdgraph_data.pod      rrdresize.pod          rrdtutorial.pod        librrd.pod

 if BUILD_LIBDBI
   POD += rrdgraph_libdbi.pod
diff --git a/doc/librrd.pod b/doc/librrd.pod
new file mode 100644
index 0000000..52cf18e
--- /dev/null
+++ b/doc/librrd.pod
@@ -0,0 +1,61 @@
+=pod
+
+=head1 NAME
+
+librrd - RRD library functions
+
+=head1 DESCRIPTION
+
+B<librrd> contains most of the functionality in B<RRDTool>.  The command
+line utilities and language bindings are often just wrappers around the
+code contained in B<librrd>.
+
+This manual page documents the B<librrd> API.
+
+B<NOTE:> This document is a work in progress, and should be considered
+incomplete as long as this warning persists.  For more information about
+the B<librrd> functions, always consult the source code.
+
+=head1 UTILITY FUNCTIONS
+
+=over
+
+=item B<rrd_random()>
+
+Generates random numbers just like random().  This further ensures that
+the random number generator is seeded exactly once per process.
+
+=item B<rrd_add_ptr(void ***dest, size_t *dest_size, void *src)>
+
+Dynamically resize the array pointed to by C<dest>.  C<dest_size> is a
+pointer to the current size of C<dest>.  Upon successful realloc(), the
+C<dest_size> is incremented by 1 and the C<src> pointer is stored at the
+end of the new C<dest>.  Returns 1 on success, 0 on failure.
+
+    type **arr = NULL;
+    type *elem = "whatever";
+    size_t arr_size = 0;
+    if (!rrd_add_ptr(&arr, &arr_size, elem))
+        handle_failure();
+
+=item B<rrd_add_strdup(char ***dest, size_t *dest_size, char *src)>
+
+Like C<rrd_add_ptr>, except adds a C<strdup> of the source string.
+
+    char **arr = NULL;
+    size_t arr_size = NULL;
+    char *str  = "example text";
+    if (!rrd_add_strdup(&arr, &arr_size, str))
+        handle_failure();
+
+=item B<rrd_free_ptrs(void ***src, size_t *cnt)>
+
+Free an array of pointers allocated by C<rrd_add_ptr> or
+C<rrd_add_strdup>.  Also frees the array pointer itself.  On return, the
+source pointer will be NULL and the count will be zero.
+
+    /* created as above */
+    rrd_free_ptrs(&arr, &arr_size);
+    /* here, arr == NULL && arr_size == 0 */
+
+=back
diff --git a/src/librrd.sym.in.in b/src/librrd.sym.in.in
index 0a7a699..f947fe5 100644
--- a/src/librrd.sym.in.in
+++ b/src/librrd.sym.in.in
@@ -1,3 +1,5 @@
+rrd_add_ptr
+rrd_add_strdup
 rrd_clear_error
 rrd_close
 rrd_cmd_flush
@@ -12,6 +14,7 @@ rrd_first
 rrd_first_r
 rrd_free
 rrd_free_context
+rrd_free_ptrs
 rrd_freemem
 rrd_get_context
 rrd_get_error
diff --git a/src/rrd.h b/src/rrd.h
index fd506d9..0227ed4 100644
--- a/src/rrd.h
+++ b/src/rrd.h
@@ -323,6 +323,10 @@ int       rrd_proc_start_end(

     long rrd_random(void);

+    int rrd_add_ptr(void ***dest, size_t *dest_size, void *src);
+    int rrd_add_strdup(char ***dest, size_t *dest_size, char *src);
+    void rrd_free_ptrs(void ***src, size_t *cnt);
+
 /*
  * The following functions are _internal_ functions needed to read the raw RRD
  * files. Since they are _internal_ they may change with the file format and
diff --git a/src/rrd_daemon.c b/src/rrd_daemon.c
index 7a7ae88..53904a3 100644
--- a/src/rrd_daemon.c
+++ b/src/rrd_daemon.c
@@ -175,7 +175,7 @@ struct cache_item_s
 {
   char *file;
   char **values;
-  int values_num;
+  size_t values_num;
   time_t last_flush_time;
   time_t last_update_stamp;
 #define CI_FLAGS_IN_TREE  (1<<0)
@@ -244,7 +244,7 @@ static size_t _config_base_dir_len = 0;
 static int config_write_base_only = 0;

 static listen_socket_t **config_listen_address_list = NULL;
-static int config_listen_address_list_len = 0;
+static size_t config_listen_address_list_len = 0;

 static uint64_t stats_queue_length = 0;
 static uint64_t stats_updates_received = 0;
@@ -642,7 +642,7 @@ static void *free_cache_item(cache_item_t *ci) /* {{{ */

   remove_from_queue(ci);

-  for (int i=0; i < ci->values_num; i++)
+  for (size_t i=0; i < ci->values_num; i++)
     free(ci->values[i]);

   free (ci->values);
@@ -745,20 +745,12 @@ static gboolean tree_callback_flush (gpointer key, gpointer value, /* {{{ */
   else if (((cfd->now - ci->last_flush_time) >= config_flush_interval)
       && (ci->values_num <= 0))
   {
-    char **temp;
-
-    temp = (char **) rrd_realloc (cfd->keys,
-        sizeof (char *) * (cfd->keys_num + 1));
-    if (temp == NULL)
+    assert ((char *) key == ci->file);
+    if (!rrd_add_ptr((void ***)&cfd->keys, &cfd->keys_num, (void *)key))
     {
-      RRDD_LOG (LOG_ERR, "tree_callback_flush: realloc failed.");
+      RRDD_LOG (LOG_ERR, "tree_callback_flush: rrd_add_ptrs failed.");
       return (FALSE);
     }
-    cfd->keys = temp;
-    /* Make really sure this points to the _same_ place */
-    assert ((char *) key == ci->file);
-    cfd->keys[cfd->keys_num] = (char *) key;
-    cfd->keys_num++;
   }

   return (FALSE);
@@ -863,9 +855,8 @@ static void *queue_thread_main (void *args __attribute__((unused))) /* {{{ */
     cache_item_t *ci;
     char *file;
     char **values;
-    int values_num;
+    size_t values_num;
     int status;
-    int i;

     /* Now, check if there's something to store away. If not, wait until
      * something comes in.  if we are shutting down, do not wait around.  */
@@ -906,7 +897,7 @@ static void *queue_thread_main (void *args __attribute__((unused))) /* {{{ */
     pthread_mutex_unlock (&cache_lock);

     rrd_clear_error ();
-    status = rrd_update_r (file, NULL, values_num, (void *) values);
+    status = rrd_update_r (file, NULL, (int) values_num, (void *) values);
     if (status != 0)
     {
       RRDD_LOG (LOG_NOTICE, "queue_thread_main: "
@@ -917,10 +908,7 @@ static void *queue_thread_main (void *args __attribute__((unused))) /* {{{ */
     journal_write("wrote", file);
     pthread_cond_broadcast(&ci->flushed);

-    for (i = 0; i < values_num; i++)
-      free (values[i]);
-
-    free(values);
+    rrd_free_ptrs((void ***) &values, &values_num);
     free(file);

     if (status == 0)
@@ -1227,7 +1215,7 @@ static int handle_request_pending(HANDLER_PROTO) /* {{{ */
     return send_response(sock, RESP_ERR, "%s\n", rrd_strerror(ENOENT));
   }

-  for (int i=0; i < ci->values_num; i++)
+  for (size_t i=0; i < ci->values_num; i++)
     add_response_info(sock, "%s\n", ci->values[i]);

   pthread_mutex_unlock(&cache_lock);
@@ -1369,7 +1357,6 @@ static int handle_request_update (HANDLER_PROTO) /* {{{ */

   while (buffer_size > 0)
   {
-    char **temp;
     char *value;
     time_t stamp;
     char *eostamp;
@@ -1400,22 +1387,11 @@ static int handle_request_update (HANDLER_PROTO) /* {{{ */
     else
       ci->last_update_stamp = stamp;

-    temp = (char **) rrd_realloc (ci->values,
-        sizeof (char *) * (ci->values_num + 1));
-    if (temp == NULL)
-    {
-      RRDD_LOG (LOG_ERR, "handle_request_update: realloc failed.");
-      continue;
-    }
-    ci->values = temp;
-
-    ci->values[ci->values_num] = strdup (value);
-    if (ci->values[ci->values_num] == NULL)
+    if (!rrd_add_strdup(&ci->values, &ci->values_num, value))
     {
-      RRDD_LOG (LOG_ERR, "handle_request_update: strdup failed.");
+      RRDD_LOG (LOG_ERR, "handle_request_update: rrd_add_strdup failed.");
       continue;
     }
-    ci->values_num++;

     values_num++;
   }
@@ -1445,7 +1421,6 @@ static int handle_request_update (HANDLER_PROTO) /* {{{ */
  */
 static int handle_request_wrote (HANDLER_PROTO) /* {{{ */
 {
-  int i;
   cache_item_t *ci;
   const char *file = buffer;

@@ -1459,12 +1434,7 @@ static int handle_request_wrote (HANDLER_PROTO) /* {{{ */
   }

   if (ci->values)
-  {
-    for (i=0; i < ci->values_num; i++)
-      free(ci->values[i]);
-
-    free(ci->values);
-  }
+    rrd_free_ptrs((void ***) &ci->values, &ci->values_num);

   wipe_ci_values(ci, now);
   remove_from_queue(ci);
@@ -2434,13 +2404,11 @@ static int daemonize (void) /* {{{ */
   /* open all the listen sockets */
   if (config_listen_address_list_len > 0)
   {
-    for (int i = 0; i < config_listen_address_list_len; i++)
-    {
+    for (size_t i = 0; i < config_listen_address_list_len; i++)
       open_listen_socket (config_listen_address_list[i]);
-      free_listen_socket (config_listen_address_list[i]);
-    }

-    free(config_listen_address_list);
+    rrd_free_ptrs((void ***) &config_listen_address_list,
+                  &config_listen_address_list_len);
   }
   else
   {
@@ -2564,7 +2532,6 @@ static int read_options (int argc, char **argv) /* {{{ */
       case 'L':
       case 'l':
       {
-        listen_socket_t **temp;
         listen_socket_t *new;

         new = malloc(sizeof(listen_socket_t));
@@ -2575,20 +2542,15 @@ static int read_options (int argc, char **argv) /* {{{ */
         }
         memset(new, 0, sizeof(listen_socket_t));

-        temp = (listen_socket_t **) rrd_realloc (config_listen_address_list,
-            sizeof (listen_socket_t *) * (config_listen_address_list_len + 1));
-        if (temp == NULL)
-        {
-          fprintf (stderr, "read_options: realloc failed.\n");
-          return (2);
-        }
-        config_listen_address_list = temp;
-
         strncpy(new->addr, optarg, sizeof(new->addr)-1);
         new->privilege = (option == 'l') ? PRIV_HIGH : PRIV_LOW;

-        temp[config_listen_address_list_len] = new;
-        config_listen_address_list_len++;
+        if (!rrd_add_ptr((void ***)&config_listen_address_list,
+                         &config_listen_address_list_len, new))
+        {
+          fprintf(stderr, "read_options: rrd_add_ptr failed.\n");
+          return (2);
+        }
       }
       break;

diff --git a/src/rrd_utils.c b/src/rrd_utils.c
index 39d2aca..9ac3e8a 100644
--- a/src/rrd_utils.c
+++ b/src/rrd_utils.c
@@ -16,6 +16,7 @@
 #include "rrd_tool.h"

 #include <stdlib.h>
+#include <assert.h>

 #ifdef WIN32
 #	define random() rand()
@@ -34,3 +35,63 @@ long rrd_random(void)

     return random();
 }
+
+/* rrd_add_ptr: add a pointer to a dynamically sized array of pointers,
+ * realloc as necessary.  returns 1 on success, 0 on failure.
+ */
+
+int rrd_add_ptr(void ***dest, size_t *dest_size, void *src)
+{
+    void **temp;
+
+    assert(dest != NULL);
+
+    temp = (void **) rrd_realloc(*dest, (*dest_size+1) * sizeof(*dest));
+    if (!temp)
+        return 0;
+
+    *dest = temp;
+    temp[*dest_size] = src;
+    (*dest_size)++;
+
+    return 1;
+}
+
+/* like rrd_add_ptr, but calls strdup() on a string first. */
+int rrd_add_strdup(char ***dest, size_t *dest_size, char *src)
+{
+    char *dup_src;
+    int add_ok;
+
+    assert(dest != NULL);
+    assert(src  != NULL);
+
+    dup_src = strdup(src);
+    if (!dup_src)
+        return 0;
+
+    add_ok = rrd_add_ptr((void ***)dest, dest_size, (void *)dup_src);
+    if (!add_ok)
+        free(dup_src);
+
+    return add_ok;
+}
+
+void rrd_free_ptrs(void ***src, size_t *cnt)
+{
+    void **sp;
+
+    assert(src != NULL);
+    sp = *src;
+
+    if (sp == NULL)
+        return;
+
+    while (*cnt > 0) {
+        (*cnt)--;
+        free(sp[*cnt]);
+    }
+
+    free (sp);
+    *src = NULL;
+}



More information about the rrd-developers mailing list