[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