# HG changeset patch
# User Peter Stamfest <pe...@stamfest.at>
# Date 1299524364 -3600
# Node ID 2e1ec35bef337eee041078d583cfe5aaa7068509
# Parent  4fcecd56ec3b1091c9fd649d3d52aa86a679eb02
* Introduce rrdc_connection_t
  - bundles all the data needed for a rrdcached connection
  - remove global variables used until now
* Use rrdc_connection_t throughout rrdtool
  - sematic changes:
    - The last connection to a rrdcached is not kept open, thus multiple
      requests to the same rrdcached use different connections.

diff --git a/src/rrd_client.c b/src/rrd_client.c
--- a/src/rrd_client.c
+++ b/src/rrd_client.c
@@ -25,6 +25,7 @@
  *   Sebastian tokkee Harl <sh at tokkee.org>
  **/
 
+
 #include "rrd.h"
 #include "rrd_tool.h"
 #include "rrd_client.h"
@@ -55,10 +56,6 @@
 };
 typedef struct rrdc_response_s rrdc_response_t;
 
-static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-static int sd = -1;
-static FILE *sh = NULL;
-static char *sd_path = NULL; /* cache the path for sd */
 
 /* get_path: Return a path name appropriate to be sent to the daemon.
  *
@@ -68,16 +65,16 @@
  * are not allowed, since path name translation is done by the server.
  *
  * One must hold `lock' when calling this function. */
-static const char *get_path (const char *path, char *resolved_path) /* {{{ */
+static const char *get_path (rrdc_connection_t *conn, const char *path, char 
*resolved_path) /* {{{ */
 {
   const char *ret = path;
   int is_unix = 0;
 
-  if ((path == NULL) || (resolved_path == NULL) || (sd_path == NULL))
+  if ((conn == NULL) || (path == NULL) || (resolved_path == NULL) || 
(conn->sd_path == NULL))
     return (NULL);
 
-  if ((*sd_path == '/')
-      || (strncmp ("unix:", sd_path, strlen ("unix:")) == 0))
+  if ((*(conn->sd_path) == '/')
+      || (strncmp ("unix:", conn->sd_path, strlen ("unix:")) == 0))
     is_unix = 1;
 
   if (is_unix)
@@ -232,23 +229,23 @@
 } /* }}} int parse_value_array_header */
 
 /* One must hold `lock' when calling `close_connection'. */
-static void close_connection (void) /* {{{ */
+static void close_connection (rrdc_connection_t *conn) /* {{{ */
 {
-  if (sh != NULL)
+  if (conn->sh != NULL)
   {
-    fclose (sh);
-    sh = NULL;
-    sd = -1;
+    fclose (conn->sh);
+    conn->sh = NULL;
+    conn->sd = -1;
   }
-  else if (sd >= 0)
+  else if (conn->sd >= 0)
   {
-    close (sd);
-    sd = -1;
+    close (conn->sd);
+    conn->sd = -1;
   }
 
-  if (sd_path != NULL)
-    free (sd_path);
-  sd_path = NULL;
+  if (conn->sd_path != NULL)
+    free (conn->sd_path);
+  conn->sd_path = NULL;
 } /* }}} void close_connection */
 
 static int buffer_add_string (const char *str, /* {{{ */
@@ -367,7 +364,7 @@
   free (res);
 } /* }}} void response_free */
 
-static int response_read (rrdc_response_t **ret_response) /* {{{ */
+static int response_read (rrdc_connection_t *conn, rrdc_response_t 
**ret_response) /* {{{ */
 {
   rrdc_response_t *ret = NULL;
   int status = 0;
@@ -379,7 +376,7 @@
 
 #define DIE(code) do { status = code; goto err_out; } while(0)
 
-  if (sh == NULL)
+  if (conn == NULL || conn->sh == NULL)
     DIE(-1);
 
   ret = (rrdc_response_t *) malloc (sizeof (rrdc_response_t));
@@ -389,7 +386,7 @@
   ret->lines = NULL;
   ret->lines_num = 0;
 
-  buffer_ptr = fgets (buffer, sizeof (buffer), sh);
+  buffer_ptr = fgets (buffer, sizeof (buffer), conn->sh);
   if (buffer_ptr == NULL)
     DIE(-3);
 
@@ -418,7 +415,7 @@
 
   for (i = 0; i < ret->lines_num; i++)
   {
-    buffer_ptr = fgets (buffer, sizeof (buffer), sh);
+    buffer_ptr = fgets (buffer, sizeof (buffer), conn->sh);
     if (buffer_ptr == NULL)
       DIE(-6);
 
@@ -431,39 +428,39 @@
 
 out:
   *ret_response = ret;
-  fflush(sh);
+  fflush(conn->sh);
   return (status);
 
 err_out:
   response_free(ret);
-  close_connection();
+  close_connection(conn);
   return (status);
 
 #undef DIE
 
 } /* }}} rrdc_response_t *response_read */
 
-static int request (const char *buffer, size_t buffer_size, /* {{{ */
+static int request (rrdc_connection_t *conn, const char *buffer, size_t 
buffer_size, /* {{{ */
     rrdc_response_t **ret_response)
 {
   int status;
   rrdc_response_t *res;
 
-  if (sh == NULL)
+  if (conn == NULL || conn->sh == NULL)
     return (ENOTCONN);
 
-  status = (int) fwrite (buffer, buffer_size, /* nmemb = */ 1, sh);
+  status = (int) fwrite (buffer, buffer_size, /* nmemb = */ 1, conn->sh);
   if (status != 1)
   {
-    close_connection ();
+    close_connection (conn);
     rrd_set_error("request: socket error (%d) while talking to rrdcached",
                   status);
     return (-1);
   }
-  fflush (sh);
+  fflush (conn->sh);
 
   res = NULL;
-  status = response_read (&res);
+  status = response_read (conn, &res);
 
   if (status != 0)
   {
@@ -479,9 +476,9 @@
 /* determine whether we are connected to the specified daemon_addr if
  * NULL, return whether we are connected at all
  */
-int rrdc_is_connected(const char *daemon_addr) /* {{{ */
+int rrdc_is_connected(rrdc_connection_t *conn, const char *daemon_addr) /* {{{ 
*/
 {
-  if (sd < 0)
+  if (conn->sd < 0)
     return 0;
   else if (daemon_addr == NULL)
   {
@@ -496,23 +493,23 @@
     else
       return 0;
   }
-  else if (strcmp(daemon_addr, sd_path) == 0)
+  else if (strcmp(daemon_addr, conn->sd_path) == 0)
     return 1;
   else
     return 0;
 
 } /* }}} int rrdc_is_connected */
 
-static int rrdc_connect_unix (const char *path) /* {{{ */
+static int rrdc_connect_unix (rrdc_connection_t *conn, const char *path) /* 
{{{ */
 {
   struct sockaddr_un sa;
   int status;
 
   assert (path != NULL);
-  assert (sd == -1);
+  assert (conn->sd == -1);
 
-  sd = socket (PF_UNIX, SOCK_STREAM, /* protocol = */ 0);
-  if (sd < 0)
+  conn->sd = socket (PF_UNIX, SOCK_STREAM, /* protocol = */ 0);
+  if (conn->sd < 0)
   {
     status = errno;
     return (status);
@@ -522,26 +519,26 @@
   sa.sun_family = AF_UNIX;
   strncpy (sa.sun_path, path, sizeof (sa.sun_path) - 1);
 
-  status = connect (sd, (struct sockaddr *) &sa, sizeof (sa));
+  status = connect (conn->sd, (struct sockaddr *) &sa, sizeof (sa));
   if (status != 0)
   {
     status = errno;
-    close_connection ();
+    close_connection (conn);
     return (status);
   }
 
-  sh = fdopen (sd, "r+");
-  if (sh == NULL)
+  conn->sh = fdopen (conn->sd, "r+");
+  if (conn->sh == NULL)
   {
     status = errno;
-    close_connection ();
+    close_connection (conn);
     return (status);
   }
 
   return (0);
 } /* }}} int rrdc_connect_unix */
 
-static int rrdc_connect_network (const char *addr_orig) /* {{{ */
+static int rrdc_connect_network (rrdc_connection_t *conn, const char 
*addr_orig) /* {{{ */
 {
   struct addrinfo ai_hints;
   struct addrinfo *ai_res;
@@ -550,8 +547,9 @@
   char *addr;
   char *port;
 
+  assert (conn != NULL);
   assert (addr_orig != NULL);
-  assert (sd == -1);
+  assert (conn->sd == -1);
 
   strncpy(addr_copy, addr_orig, sizeof(addr_copy));
   addr_copy[sizeof(addr_copy) - 1] = '\0';
@@ -615,27 +613,27 @@
 
   for (ai_ptr = ai_res; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
   {
-    sd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
-    if (sd < 0)
+    conn->sd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, 
ai_ptr->ai_protocol);
+    if (conn->sd < 0)
     {
       status = errno;
-      sd = -1;
+      conn->sd = -1;
       continue;
     }
 
-    status = connect (sd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+    status = connect (conn->sd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
     if (status != 0)
     {
       status = errno;
-      close_connection();
+      close_connection(conn);
       continue;
     }
 
-    sh = fdopen (sd, "r+");
-    if (sh == NULL)
+    conn->sh = fdopen (conn->sd, "r+");
+    if (conn->sh == NULL)
     {
       status = errno;
-      close_connection ();
+      close_connection (conn);
       continue;
     }
 
@@ -648,7 +646,7 @@
   return (status);
 } /* }}} int rrdc_connect_network */
 
-int rrdc_connect (const char *addr) /* {{{ */
+int rrdc_connect (rrdc_connection_t *conn, const char *addr) /* {{{ */
 {
   int status = 0;
 
@@ -658,29 +656,31 @@
   if (addr == NULL)
     return 0;
 
-  pthread_mutex_lock(&lock);
+  assert (conn != NULL);
 
-  if (sd >= 0 && sd_path != NULL && strcmp(addr, sd_path) == 0)
+  pthread_mutex_lock(&conn->lock);
+
+  if (conn->sd >= 0 && conn->sd_path != NULL && strcmp(addr, conn->sd_path) == 
0)
   {
     /* connection to the same daemon; use cached connection */
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     return (0);
   }
   else
   {
-    close_connection();
+    close_connection(conn);
   }
 
   rrd_clear_error ();
   if (strncmp ("unix:", addr, strlen ("unix:")) == 0)
-    status = rrdc_connect_unix (addr + strlen ("unix:"));
+    status = rrdc_connect_unix (conn, addr + strlen ("unix:"));
   else if (addr[0] == '/')
-    status = rrdc_connect_unix (addr);
+    status = rrdc_connect_unix (conn, addr);
   else
-    status = rrdc_connect_network(addr);
+    status = rrdc_connect_network(conn, addr);
 
-  if (status == 0 && sd >= 0)
-    sd_path = strdup(addr);
+  if (status == 0 && conn->sd >= 0)
+    conn->sd_path = strdup(addr);
   else
   {
     char *err = rrd_test_error () ? rrd_get_error () : "Internal error";
@@ -695,22 +695,23 @@
       free (err);
   }
 
-  pthread_mutex_unlock (&lock);
+  pthread_mutex_unlock (&conn->lock);
   return (status);
 } /* }}} int rrdc_connect */
 
-int rrdc_disconnect (void) /* {{{ */
+int rrdc_disconnect (rrdc_connection_t *conn) /* {{{ */
 {
-  pthread_mutex_lock (&lock);
+  pthread_mutex_lock (&conn->lock);
 
-  close_connection();
+  close_connection(conn);
 
-  pthread_mutex_unlock (&lock);
+  pthread_mutex_unlock (&conn->lock);
 
   return (0);
 } /* }}} int rrdc_disconnect */
 
-int rrdc_update (const char *filename, int values_num, /* {{{ */
+int rrdc_update (rrdc_connection_t *conn,
+                 const char *filename, int values_num, /* {{{ */
                const char * const *values)
 {
   char buffer[RRD_CMD_MAX];
@@ -730,18 +731,18 @@
   if (status != 0)
     return (ENOBUFS);
 
-  pthread_mutex_lock (&lock);
-  filename = get_path (filename, file_path);
+  pthread_mutex_lock (&conn->lock);
+  filename = get_path (conn, filename, file_path);
   if (filename == NULL)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     return (-1);
   }
 
   status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
   if (status != 0)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     return (ENOBUFS);
   }
 
@@ -750,7 +751,7 @@
     status = buffer_add_value (values[i], &buffer_ptr, &buffer_free);
     if (status != 0)
     {
-      pthread_mutex_unlock (&lock);
+      pthread_mutex_unlock (&conn->lock);
       return (ENOBUFS);
     }
   }
@@ -761,8 +762,8 @@
   buffer[buffer_size - 1] = '\n';
 
   res = NULL;
-  status = request (buffer, buffer_size, &res);
-  pthread_mutex_unlock (&lock);
+  status = request (conn, buffer, buffer_size, &res);
+  pthread_mutex_unlock (&conn->lock);
 
   if (status != 0)
     return (status);
@@ -773,7 +774,7 @@
   return (status);
 } /* }}} int rrdc_update */
 
-int rrdc_flush (const char *filename) /* {{{ */
+int rrdc_flush (rrdc_connection_t *conn, const char *filename) /* {{{ */
 {
   char buffer[RRD_CMD_MAX];
   char *buffer_ptr;
@@ -794,18 +795,18 @@
   if (status != 0)
     return (ENOBUFS);
 
-  pthread_mutex_lock (&lock);
-  filename = get_path (filename, file_path);
+  pthread_mutex_lock (&conn->lock);
+  filename = get_path (conn, filename, file_path);
   if (filename == NULL)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     return (-1);
   }
 
   status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
   if (status != 0)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     return (ENOBUFS);
   }
 
@@ -815,8 +816,8 @@
   buffer[buffer_size - 1] = '\n';
 
   res = NULL;
-  status = request (buffer, buffer_size, &res);
-  pthread_mutex_unlock (&lock);
+  status = request (conn, buffer, buffer_size, &res);
+  pthread_mutex_unlock (&conn->lock);
 
   if (status != 0)
     return (status);
@@ -827,7 +828,7 @@
   return (status);
 } /* }}} int rrdc_flush */
 
-rrd_info_t * rrdc_info (const char *filename) /* {{{ */
+rrd_info_t * rrdc_info (rrdc_connection_t *conn, const char *filename) /* {{{ 
*/
 {
   char buffer[RRD_CMD_MAX];
   char *buffer_ptr;
@@ -857,18 +858,18 @@
     return (NULL);
   }
 
-  pthread_mutex_lock (&lock);
-  filename = get_path (filename, file_path);
+  pthread_mutex_lock (&conn->lock);
+  filename = get_path (conn, filename, file_path);
   if (filename == NULL)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     return (NULL);
   }
 
   status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
   if (status != 0)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     rrd_set_error ("rrdc_info: out of memory");
     return (NULL);
   }
@@ -879,8 +880,8 @@
   buffer[buffer_size - 1] = '\n';
 
   res = NULL;
-  status = request (buffer, buffer_size, &res);
-  pthread_mutex_unlock (&lock);
+  status = request (conn, buffer, buffer_size, &res);
+  pthread_mutex_unlock (&conn->lock);
 
   if (status != 0) {
     rrd_set_error ("rrdcached: %s", res->message);
@@ -928,7 +929,7 @@
   return (data);
 } /* }}} int rrdc_info */
 
-time_t rrdc_last (const char *filename) /* {{{ */
+time_t rrdc_last (rrdc_connection_t *conn, const char *filename) /* {{{ */
 {
   char buffer[RRD_CMD_MAX];
   char *buffer_ptr;
@@ -954,18 +955,18 @@
     return (-1);
   }
 
-  pthread_mutex_lock (&lock);
-  filename = get_path (filename, file_path);
+  pthread_mutex_lock (&conn->lock);
+  filename = get_path (conn, filename, file_path);
   if (filename == NULL)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     return (-1);
   }
 
   status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
   if (status != 0)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     rrd_set_error ("rrdc_last: out of memory");
     return (-1);
   }
@@ -976,8 +977,8 @@
   buffer[buffer_size - 1] = '\n';
 
   res = NULL;
-  status = request (buffer, buffer_size, &res);
-  pthread_mutex_unlock (&lock);
+  status = request (conn, buffer, buffer_size, &res);
+  pthread_mutex_unlock (&conn->lock);
 
   if (status != 0) {
     rrd_set_error ("rrdcached: %s", res->message);
@@ -989,7 +990,7 @@
   return (lastup);
 } /* }}} int rrdc_last */
 
-time_t rrdc_first (const char *filename, int rraindex) /* {{{ */
+time_t rrdc_first (rrdc_connection_t *conn, const char *filename, int 
rraindex) /* {{{ */
 {
   char buffer[RRD_CMD_MAX];
   char *buffer_ptr;
@@ -1015,25 +1016,25 @@
     return (-1);
   }
 
-  pthread_mutex_lock (&lock);
-  filename = get_path (filename, file_path);
+  pthread_mutex_lock (&conn->lock);
+  filename = get_path (conn, filename, file_path);
   if (filename == NULL)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     return (-1);
   }
 
   status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
   if (status != 0)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     rrd_set_error ("rrdc_first: out of memory");
     return (-1);
   }
   status = buffer_add_ulong (rraindex, &buffer_ptr, &buffer_free);
   if (status != 0)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     rrd_set_error ("rrdc_first: out of memory");
     return (-1);
   }
@@ -1044,8 +1045,8 @@
   buffer[buffer_size - 1] = '\n';
 
   res = NULL;
-  status = request (buffer, buffer_size, &res);
-  pthread_mutex_unlock (&lock);
+  status = request (conn, buffer, buffer_size, &res);
+  pthread_mutex_unlock (&conn->lock);
 
   if (status != 0) {
     rrd_set_error ("rrdcached: %s", res->message);
@@ -1057,7 +1058,7 @@
   return (firstup);
 } /* }}} int rrdc_first */
 
-int rrdc_create (const char *filename, /* {{{ */
+int rrdc_create (rrdc_connection_t *conn, const char *filename, /* {{{ */
     unsigned long pdp_step,
     time_t last_up,
     int no_overwrite,
@@ -1088,11 +1089,11 @@
     return (-1);
   }
 
-  pthread_mutex_lock (&lock);
-  filename = get_path (filename, file_path);
+  pthread_mutex_lock (&conn->lock);
+  filename = get_path (conn, filename, file_path);
   if (filename == NULL)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     return (-1);
   }
 
@@ -1106,7 +1107,7 @@
   }
   if (status != 0)
   {
-    pthread_mutex_unlock (&lock);
+    pthread_mutex_unlock (&conn->lock);
     rrd_set_error ("rrdc_create: out of memory");
     return (-1);
   }
@@ -1116,7 +1117,7 @@
       status = buffer_add_string (argv[i], &buffer_ptr, &buffer_free);
       if (status != 0)
       {
-        pthread_mutex_unlock (&lock);
+        pthread_mutex_unlock (&conn->lock);
         rrd_set_error ("rrdc_create: out of memory");
         return (-1);
       }
@@ -1130,8 +1131,8 @@
   buffer[buffer_size - 1] = '\n';
 
   res = NULL;
-  status = request (buffer, buffer_size, &res);
-  pthread_mutex_unlock (&lock);
+  status = request (conn, buffer, buffer_size, &res);
+  pthread_mutex_unlock (&conn->lock);
 
   if (status != 0) {
     rrd_set_error ("rrdcached: %s", res->message);
@@ -1141,7 +1142,7 @@
   return(0);
 } /* }}} int rrdc_create */
 
-int rrdc_fetch (const char *filename, /* {{{ */
+int rrdc_fetch (rrdc_connection_t *conn, const char *filename, /* {{{ */
     const char *cf,
     time_t *ret_start, time_t *ret_end,
     unsigned long *ret_step,
@@ -1187,7 +1188,7 @@
     return (ENOBUFS);
 
   /* change to path for rrdcached */
-  path_ptr = get_path (filename, path_buffer);
+  path_ptr = get_path (conn, filename, path_buffer);
   if (path_ptr == NULL)
     return (EINVAL);
 
@@ -1224,7 +1225,7 @@
   buffer[buffer_size - 1] = '\n';
 
   res = NULL;
-  status = request (buffer, buffer_size, &res);
+  status = request (conn, buffer, buffer_size, &res);
   if (status != 0)
     return (status);
 
@@ -1354,16 +1355,16 @@
 /* convenience function; if there is a daemon specified, or if we can
  * detect one from the environment, then flush the file.  Otherwise, no-op
  */
-int rrdc_flush_if_daemon (const char *opt_daemon, const char *filename) /* {{{ 
*/
+int rrdc_flush_if_daemon (rrdc_connection_t *conn, const char *opt_daemon, 
const char *filename) /* {{{ */
 {
   int status = 0;
 
-  rrdc_connect(opt_daemon);
+  rrdc_connect(conn, opt_daemon);
 
-  if (rrdc_is_connected(opt_daemon))
+  if (rrdc_is_connected(conn, opt_daemon))
   {
     rrd_clear_error();
-    status = rrdc_flush (filename);
+    status = rrdc_flush (conn, filename);
 
     if (status != 0 && !rrd_test_error())
     {
@@ -1384,7 +1385,7 @@
 } /* }}} int rrdc_flush_if_daemon */
 
 
-int rrdc_stats_get (rrdc_stats_t **ret_stats) /* {{{ */
+int rrdc_stats_get (rrdc_connection_t *conn, rrdc_stats_t **ret_stats) /* {{{ 
*/
 {
   rrdc_stats_t *head;
   rrdc_stats_t *tail;
@@ -1405,9 +1406,9 @@
    * }}} */
 
   res = NULL;
-  pthread_mutex_lock (&lock);
-  status = request ("STATS\n", strlen ("STATS\n"), &res);
-  pthread_mutex_unlock (&lock);
+  pthread_mutex_lock (&conn->lock);
+  status = request (conn, "STATS\n", strlen ("STATS\n"), &res);
+  pthread_mutex_unlock (&conn->lock);
 
   if (status != 0)
     return (status);
@@ -1519,6 +1520,82 @@
   } /* while (this != NULL) */
 } /* }}} void rrdc_stats_free */
 
+rrdc_connection_t *new_rrdc_connection(const char *addr) {
+  rrdc_connection_t *c = malloc(sizeof(rrdc_connection_t));
+  if (c == NULL) {
+    rrd_set_error("out of memory");
+    return NULL;
+  }
+
+  pthread_mutex_init(&c->lock, NULL);
+  c->sd = -1;
+  c->sh = NULL;
+  c->sd_path = NULL;
+
+  if (addr != NULL) {
+    int status = rrdc_connect(c, addr);
+    if (status != 0) {
+      rrd_set_error("Cannot connect to rrdcached '%s'. Please use an "
+          "appropriate daemon address for the desired operation. "
+          "This might involve using the --daemon option, setting "
+          "the environment option '%s' or using a proper "
+          "rrdfile specification", addr, ENV_RRDCACHED_ADDRESS);
+      delete_rrdc_connection(c);
+      return NULL;
+    }
+  }
+
+  return c;
+}
+
+void delete_rrdc_connection(rrdc_connection_t *conn) {
+  if (conn == NULL) return;
+  rrdc_disconnect(conn);
+  free(conn);
+}
+
+
+const char *want_rrdc_connection(const char *addr) {
+  if (addr != NULL) return addr;
+  return getenv(ENV_RRDCACHED_ADDRESS);
+}
+
+
+static rrdc_connection_t *global = NULL;
+
+int setup_global_rrdc_connection(const char *addr) {
+  if (addr == NULL) {
+    rrd_set_error("Need proper rrdcached address");
+    return -1;
+  }
+
+  if (global != NULL) {
+    /* special case: if addr is the same as during the last invocation, reuse
+     * connection, otherwise close old and create new connection.
+     */
+    if (global->sd >= 0 && global->sd_path != NULL &&
+        strcmp(addr, global->sd_path) == 0) {
+      return 0;
+    }
+
+    delete_rrdc_connection(global);
+    global = NULL;
+  }
+
+  global = new_rrdc_connection(addr);
+  if (global == NULL) {
+    // error already set by new_rrdc_connection
+    return -1;
+  }
+
+  return 0;
+}
+
+rrdc_connection_t *get_global_rrdc_connection(void) {
+  return global;
+}
+
+
 /*
  * vim: set sw=2 sts=2 ts=8 et fdm=marker :
  */
diff --git a/src/rrd_client.h b/src/rrd_client.h
--- a/src/rrd_client.h
+++ b/src/rrd_client.h
@@ -63,17 +63,28 @@
 // Windows version has no daemon/client support
 
 #ifndef WIN32
-int rrdc_connect (const char *addr);
-int rrdc_is_connected(const char *daemon_addr);
-int rrdc_disconnect (void);
 
-int rrdc_update (const char *filename, int values_num,
+struct rrdc_connection_s {
+       pthread_mutex_t lock;
+       int sd;
+       FILE *sh;
+       char *sd_path; /* cache the path for sd */
+};
+
+typedef struct rrdc_connection_s rrdc_connection_t;
+
+
+int rrdc_connect (rrdc_connection_t *conn, const char *addr);
+int rrdc_is_connected(rrdc_connection_t *conn, const char *daemon_addr);
+int rrdc_disconnect (rrdc_connection_t *conn);
+
+int rrdc_update (rrdc_connection_t *conn, const char *filename, int values_num,
         const char * const *values);
 
-rrd_info_t * rrdc_info (const char *filename);
-time_t rrdc_last (const char *filename);
-time_t rrdc_first (const char *filename, int rraindex);
-int rrdc_create (const char *filename,
+rrd_info_t * rrdc_info (rrdc_connection_t *conn, const char *filename);
+time_t rrdc_last (rrdc_connection_t *conn, const char *filename);
+time_t rrdc_first (rrdc_connection_t *conn, const char *filename, int 
rraindex);
+int rrdc_create (rrdc_connection_t *conn, const char *filename,
     unsigned long pdp_step,
     time_t last_up,
     int no_overwrite,
@@ -81,10 +92,10 @@
     const char **argv);
 
 
-int rrdc_flush (const char *filename);
-int rrdc_flush_if_daemon (const char *opt_daemon, const char *filename);
+int rrdc_flush (rrdc_connection_t *conn, const char *filename);
+int rrdc_flush_if_daemon (rrdc_connection_t *conn, const char *opt_daemon, 
const char *filename);
 
-int rrdc_fetch (const char *filename,
+int rrdc_fetch (rrdc_connection_t *conn, const char *filename,
     const char *cf,
     time_t *ret_start, time_t *ret_end,
     unsigned long *ret_step,
@@ -92,12 +103,24 @@
     char ***ret_ds_names,
     rrd_value_t **ret_data);
 
+
+rrdc_connection_t * new_rrdc_connection(const char *addr);
+void delete_rrdc_connection(rrdc_connection_t *conn);
+
+const char *want_rrdc_connection(const char *addr);
+
+int setup_global_rrdc_connection(const char *addr);
+rrdc_connection_t *get_global_rrdc_connection(void);
+
 #else
-#      define rrdc_flush_if_daemon(a,b) 0
-#      define rrdc_connect(a) 0
+#      define rrdc_flush_if_daemon(a,b,c) 0
+#      define rrdc_connect(a,b) 0
 #      define rrdc_is_connected(a) 0
 #      define rrdc_flush(a) 0
-#      define rrdc_update(a,b,c) 0
+#      define rrdc_update(a,b,c,d) 0
+#      define new_rrdc_connection() 0
+#      define delete_rrdc_connection(a) 0
+#       define want_rrdc_connection(a) NULL
 #endif
 
 struct rrdc_stats_s
@@ -116,7 +139,7 @@
 };
 typedef struct rrdc_stats_s rrdc_stats_t;
 
-int rrdc_stats_get (rrdc_stats_t **ret_stats);
+int rrdc_stats_get (rrdc_connection_t *conn, rrdc_stats_t **ret_stats);
 void rrdc_stats_free (rrdc_stats_t *ret_stats);
 
 #endif /* __RRD_CLIENT_H */
diff --git a/src/rrd_create.c b/src/rrd_create.c
--- a/src/rrd_create.c
+++ b/src/rrd_create.c
@@ -123,17 +123,26 @@
         return -1;
     }
 
-    rrdc_connect (opt_daemon);
-    if (rrdc_is_connected (opt_daemon)) {
-        rc = rrdc_create (argv[optind],
-                      pdp_step, last_up, opt_no_overwrite,
-                      argc - optind - 1, (const char **) (argv + optind + 1));
-       } else {
-        rc = rrd_create_r2(argv[optind],
-                      pdp_step, last_up, opt_no_overwrite,
-                      argc - optind - 1, (const char **) (argv + optind + 1));
-       }
+    const char *addr = want_rrdc_connection(opt_daemon);
+    if (addr != NULL) {
+      rrdc_connection_t *conn = new_rrdc_connection(addr);
+      if (conn == NULL) {
+        rc = -1;
+        goto done;
+      }
+      rc = rrdc_create (conn, argv[optind],
+                        pdp_step, last_up, opt_no_overwrite,
+                        argc - optind - 1, (const char **) (argv + optind + 
1));
 
+      delete_rrdc_connection(conn);
+      goto done;
+    }
+
+    rc = rrd_create_r2(argv[optind],
+                       pdp_step, last_up, opt_no_overwrite,
+                       argc - optind - 1, (const char **) (argv + optind + 1));
+done:
+    if (opt_daemon != NULL) free(opt_daemon);
     return rc;
 }
 
diff --git a/src/rrd_dump.c b/src/rrd_dump.c
--- a/src/rrd_dump.c
+++ b/src/rrd_dump.c
@@ -576,9 +576,15 @@
         return (-1);
     }
 
-    rc = rrdc_flush_if_daemon(opt_daemon, argv[optind]);
-    if (opt_daemon) free(opt_daemon);
-    if (rc) return (rc);
+    const char *addr = want_rrdc_connection(opt_daemon);
+    if (addr != NULL) {
+        rrdc_connection_t *conn = new_rrdc_connection(addr);
+        if (conn != NULL) {
+            rc = rrdc_flush(conn, argv[optind]);
+            delete_rrdc_connection(conn);
+            if (rc) goto done;
+        }
+    }
 
     if ((argc - optind) == 2) {
         rc = rrd_dump_opt_r(argv[optind], argv[optind + 1], opt_header);
@@ -586,5 +592,7 @@
         rc = rrd_dump_opt_r(argv[optind], NULL, opt_header);
     }
 
+done:
+    if (opt_daemon) free(opt_daemon);
     return rc;
 }
diff --git a/src/rrd_fetch.c b/src/rrd_fetch.c
--- a/src/rrd_fetch.c
+++ b/src/rrd_fetch.c
@@ -3,7 +3,7 @@
  *****************************************************************************
  * rrd_fetch.c  read date from an rrd to use for further processing
  *****************************************************************************
- * $Id: rrd_fetch.c 2176 2011-03-03 06:53:05Z oetiker $
+ * $Id: rrd_fetch.c 2060 2010-03-29 17:05:33Z oetiker $
  * $Log$
  * Revision 1.8  2004/05/18 18:53:03  oetiker
  * big spell checking patch -- s...@bellsouth.net
@@ -74,7 +74,7 @@
     time_t    start_tmp = 0, end_tmp = 0;
     const char *cf;
     char *opt_daemon = NULL;
-    int status;
+    int status = -1;
 
     rrd_time_value_t start_tv, end_tv;
     char     *parsetime_error = NULL;
@@ -169,14 +169,22 @@
 
     cf = argv[optind + 1];
 
-    rrdc_connect (opt_daemon);
-    if (rrdc_is_connected (opt_daemon))
-           status = rrdc_fetch (argv[optind], cf, start, end, step,
-                           ds_cnt, ds_namv, data);
+    const char *addr = want_rrdc_connection(opt_daemon);
+    if (addr != NULL) {
+        rrdc_connection_t *conn = new_rrdc_connection(addr);
+        if (conn != NULL) {
+            status = rrdc_fetch (conn, argv[optind], cf, start, end, step,
+                                 ds_cnt, ds_namv, data);
+            delete_rrdc_connection(conn);
+        }
+    }
+    else
+    {
+      status = rrd_fetch_r(argv[optind], cf, start, end, step,
+                           ds_cnt, ds_namv, data);
+    }
 
-    else
-           status = rrd_fetch_r(argv[optind], cf, start, end, step,
-                           ds_cnt, ds_namv, data);
+    if (opt_daemon != NULL) free(opt_daemon);
 
     if (status != 0)
         return (-1);
diff --git a/src/rrd_first.c b/src/rrd_first.c
--- a/src/rrd_first.c
+++ b/src/rrd_first.c
@@ -23,6 +23,7 @@
         {"daemon", required_argument, 0, 'd'},
         {0, 0, 0, 0}
     };
+    time_t result = -1;
 
     optind = 0;
     opterr = 0;         /* initialize getopt */
@@ -67,12 +68,19 @@
         return -1;
     }
 
-    rrdc_connect (opt_daemon);
-    if (rrdc_is_connected (opt_daemon)) {
-      return (rrdc_first (argv[optind], target_rraindex));
-    } else {
-    return (rrd_first_r(argv[optind], target_rraindex));
-       }
+    const char *addr = want_rrdc_connection(opt_daemon);
+    if (addr != NULL) {
+      rrdc_connection_t *conn = new_rrdc_connection(addr);
+      if (conn != NULL) {
+        result = rrdc_first (conn, argv[optind], target_rraindex);
+        delete_rrdc_connection(conn);
+      }
+      goto done;
+    }
+    result = rrd_first_r(argv[optind], target_rraindex);
+done:
+    if (opt_daemon != NULL) free(opt_daemon);
+    return result;
 }
 
 
diff --git a/src/rrd_flushcached.c b/src/rrd_flushcached.c
--- a/src/rrd_flushcached.c
+++ b/src/rrd_flushcached.c
@@ -73,15 +73,8 @@
     }
 
     /* try to connect to rrdcached */
-    status = rrdc_connect(opt_daemon);
-    if (status != 0) goto out;
-
-    if (! rrdc_is_connected(opt_daemon))
-    {
-        rrd_set_error ("Daemon address unknown. Please use the \"--daemon\" "
-                "option to set an address on the command line or set the "
-                "\"%s\" environment variable.",
-                ENV_RRDCACHED_ADDRESS);
+    rrdc_connection_t *conn = new_rrdc_connection(opt_daemon);
+    if (conn == NULL) {
         status = -1;
         goto out;
     }
@@ -89,7 +82,7 @@
     status = 0;
     for (i = optind; i < argc; i++)
     {
-        status = rrdc_flush(argv[i]);
+        status = rrdc_flush(conn, argv[i]);
         if (status)
         {
             char *error;
@@ -108,6 +101,7 @@
     }
 
 out:
+    if (conn != NULL) delete_rrdc_connection(conn);
     if (opt_daemon) free(opt_daemon);
 
     return status;
diff --git a/src/rrd_graph.c b/src/rrd_graph.c
--- a/src/rrd_graph.c
+++ b/src/rrd_graph.c
@@ -862,41 +862,40 @@
             else
                 rrd_daemon = im->daemon_addr;
 
-            /* "daemon" may be NULL. ENV_RRDCACHED_ADDRESS is evaluated in that
-             * case. If "daemon" holds the same value as in the previous
-             * iteration, no actual new connection is established - the
-             * existing connection is re-used. */
-            rrdc_connect (rrd_daemon);
-
-            /* If connecting was successfull, use the daemon to query the data.
-             * If there is no connection, for example because no daemon address
-             * was specified, (try to) use the local file directly. */
-            if (rrdc_is_connected (rrd_daemon))
-            {
-                status = rrdc_fetch (im->gdes[i].rrd,
-                        cf_to_string (im->gdes[i].cf),
-                        &im->gdes[i].start,
-                        &im->gdes[i].end,
-                        &ft_step,
-                        &im->gdes[i].ds_cnt,
-                        &im->gdes[i].ds_namv,
-                        &im->gdes[i].data);
-                if (status != 0)
-                    return (status);
-            }
-            else
-            {
-                if ((rrd_fetch_fn(im->gdes[i].rrd,
-                                im->gdes[i].cf,
-                                &im->gdes[i].start,
-                                &im->gdes[i].end,
-                                &ft_step,
-                                &im->gdes[i].ds_cnt,
-                                &im->gdes[i].ds_namv,
-                                &im->gdes[i].data)) == -1) {
-                    return -1;
+            const char *addr = want_rrdc_connection(rrd_daemon);
+            if (addr != NULL) {
+                rrdc_connection_t *conn = new_rrdc_connection(addr);
+                if (conn != NULL) {
+                    status = rrdc_fetch (conn, im->gdes[i].rrd,
+                                         cf_to_string (im->gdes[i].cf),
+                                         &im->gdes[i].start,
+                                         &im->gdes[i].end,
+                                         &ft_step,
+                                         &im->gdes[i].ds_cnt,
+                                         &im->gdes[i].ds_namv,
+                                         &im->gdes[i].data);
+
+                    delete_rrdc_connection(conn);
+
+                    if (status != 0)
+                        return (status);
+
+                } else {
+                    // try to read data locally
                 }
             }
+
+            if ((rrd_fetch_fn(im->gdes[i].rrd,
+                              im->gdes[i].cf,
+                              &im->gdes[i].start,
+                              &im->gdes[i].end,
+                              &ft_step,
+                              &im->gdes[i].ds_cnt,
+                              &im->gdes[i].ds_namv,
+                              &im->gdes[i].data)) == -1) {
+                return -1;
+            }
+
             im->gdes[i].data_first = 1;
 
             if (ft_step < im->gdes[i].step) {
diff --git a/src/rrd_info.c b/src/rrd_info.c
--- a/src/rrd_info.c
+++ b/src/rrd_info.c
@@ -141,18 +141,31 @@
         return (NULL);
     }
 
-    if( flushfirst ) {
-    status = rrdc_flush_if_daemon(opt_daemon, argv[optind]);
-    if (status) return (NULL);
+    const char *addr = want_rrdc_connection(opt_daemon);
+    rrdc_connection_t *conn = NULL;
+
+    if (addr != NULL) {
+        conn = new_rrdc_connection(addr);
+        if (conn == NULL) {
+            return NULL;
+        }
     }
 
-    rrdc_connect (opt_daemon);
-    if (rrdc_is_connected (opt_daemon))
-        info = rrdc_info (argv[optind]);
+    if( flushfirst && conn != NULL) {
+        status = rrdc_flush(conn, argv[optind]);
+        if (status) return (NULL);
+    }
+
+    if (conn != NULL) {
+        info = rrdc_info (conn, argv[optind]);
+    }
     else
-    info = rrd_info_r(argv[optind]);
+        info = rrd_info_r(argv[optind]);
 
     if (opt_daemon) free(opt_daemon);
+    if (conn != NULL) {
+        delete_rrdc_connection(conn);
+    }
     return (info);
 } /* rrd_info_t *rrd_info */
 
diff --git a/src/rrd_last.c b/src/rrd_last.c
--- a/src/rrd_last.c
+++ b/src/rrd_last.c
@@ -14,7 +14,7 @@
     char **argv)
 {
     char *opt_daemon = NULL;
-    time_t lastupdate;
+    time_t lastupdate = -1;
 
     optind = 0;
     opterr = 0;         /* initialize getopt */
@@ -58,10 +58,14 @@
         return (-1);
     }
 
-    rrdc_connect (opt_daemon);
-    if (rrdc_is_connected (opt_daemon))
-        lastupdate = rrdc_last (argv[optind]);
-
+    const char *addr = want_rrdc_connection(opt_daemon);
+    if (addr != NULL) {
+      rrdc_connection_t *conn = new_rrdc_connection(addr);
+      if (conn != NULL) {
+        lastupdate = rrdc_last (conn, argv[optind]);
+        delete_rrdc_connection(conn);
+      }
+    }
     else
         lastupdate = rrd_last_r(argv[optind]);
 
diff --git a/src/rrd_lastupdate.c b/src/rrd_lastupdate.c
--- a/src/rrd_lastupdate.c
+++ b/src/rrd_lastupdate.c
@@ -16,7 +16,7 @@
     char    **ds_names;
     char    **last_ds;
     unsigned long ds_count, i;
-    int status;
+    int status = 0;
 
     char *opt_daemon = NULL;
 
@@ -62,7 +62,14 @@
         return (-1);
     }
 
-    status = rrdc_flush_if_daemon(opt_daemon, argv[optind]);
+    const char *addr = want_rrdc_connection(opt_daemon);
+    if (addr != NULL) {
+      rrdc_connection_t *conn = new_rrdc_connection(addr);
+      if (conn != NULL) {
+        status = rrdc_flush (conn, argv[optind]);
+        delete_rrdc_connection(conn);
+      }
+    }
     if (opt_daemon) free (opt_daemon);
     if (status) return (-1);
 
diff --git a/src/rrd_update.c b/src/rrd_update.c
--- a/src/rrd_update.c
+++ b/src/rrd_update.c
@@ -389,6 +389,8 @@
     char     *tmplt = NULL;
     int       rc = -1;
     char     *opt_daemon = NULL;
+    rrdc_connection_t *conn = NULL;
+    const char *addr = NULL;
 
     optind = 0;
     opterr = 0;         /* initialize getopt */
@@ -427,29 +429,32 @@
         goto out;
     }
 
-    {   /* try to connect to rrdcached */
-        int status = rrdc_connect(opt_daemon);
-        if (status != 0) {        
-             rc = status;           
-             goto out;           
-        }        
+
+    addr = want_rrdc_connection(opt_daemon);
+
+    if (addr != NULL) {
+        conn = new_rrdc_connection(addr);
+        if (conn == NULL) {
+            rc = -1;
+            goto out;
+        }
     }
 
-    if ((tmplt != NULL) && rrdc_is_connected(opt_daemon))
+    if ((tmplt != NULL) && conn != NULL)
     {
         rrd_set_error("The caching daemon cannot be used together with "
                 "templates yet.");
         goto out;
     }
 
-    if (! rrdc_is_connected(opt_daemon))
+    if (conn == NULL)
     {
       rc = rrd_update_r(argv[optind], tmplt,
                         argc - optind - 1, (const char **) (argv + optind + 
1));
     }
     else /* we are connected */
     {
-        rc = rrdc_update (argv[optind], /* file */
+        rc = rrdc_update (conn, argv[optind], /* file */
                           argc - optind - 1, /* values_num */
                           (const char *const *) (argv + optind + 1)); /* 
values */
         if (rc > 0)
@@ -468,6 +473,10 @@
         free (opt_daemon);
         opt_daemon = NULL;
     }
+    if (conn != NULL) {
+        delete_rrdc_connection(conn);
+        conn = NULL;
+    }
     return rc;
 }
 
diff --git a/src/rrd_xport.c b/src/rrd_xport.c
--- a/src/rrd_xport.c
+++ b/src/rrd_xport.c
@@ -167,9 +167,12 @@
         return (-1);
     }
 
-    {   /* try to connect to rrdcached */
-        int status = rrdc_connect(im.daemon_addr);
-        if (status != 0) return status;
+    const char *addr = want_rrdc_connection(im.daemon_addr);
+    if (addr != NULL) {   /* try to connect to rrdcached */
+        rrdc_connection_t *conn = new_rrdc_connection(addr);
+        if (conn == NULL) {
+            return -1;
+        }
     }
 
     if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data) == -1) {

_______________________________________________
rrd-developers mailing list
rrd-developers@lists.oetiker.ch
https://lists.oetiker.ch/cgi-bin/listinfo/rrd-developers

Reply via email to