fix flush race in rrdcached -- Christian Hitz
[rrdtool.git] / src / rrd_daemon.c
index 0586a8d..2c81424 100644 (file)
  * Now for some includes..
  */
 /* {{{ */
-#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) && !defined(HAVE_CONFIG_H)
-#include "../win32/config.h"
-#else
-#ifdef HAVE_CONFIG_H
-#include "../rrd_config.h"
-#endif
-#endif
 
 #include "rrd_tool.h"
 #include "rrd_client.h"
@@ -188,7 +181,7 @@ struct cache_item_s
   size_t values_num;           /* number of valid pointers */
   size_t values_alloc;         /* number of allocated pointers */
   time_t last_flush_time;
-  time_t last_update_stamp;
+  double last_update_stamp;
 #define CI_FLAGS_IN_TREE  (1<<0)
 #define CI_FLAGS_IN_QUEUE (1<<1)
   int flags;
@@ -219,9 +212,7 @@ typedef struct {
   size_t files_num;
 } journal_set;
 
-/* max length of socket command or response */
-#define CMD_MAX 4096
-#define RBUF_SIZE (CMD_MAX*2)
+#define RBUF_SIZE (RRD_CMD_MAX*2)
 
 /*
  * Variables
@@ -304,7 +295,9 @@ static int handle_request_help (HANDLER_PROTO);
 static void sig_common (const char *sig) /* {{{ */
 {
   RRDD_LOG(LOG_NOTICE, "caught SIG%s", sig);
-  state = FLUSHING;
+  if (state == RUNNING) {
+      state = FLUSHING;
+  }
   pthread_cond_broadcast(&flush_cond);
   pthread_cond_broadcast(&queue_cond);
 } /* }}} void sig_common */
@@ -543,7 +536,7 @@ static int add_to_wbuf(listen_socket_t *sock, char *str, size_t len) /* {{{ */
 static int add_response_info(listen_socket_t *sock, char *fmt, ...) /* {{{ */
 {
   va_list argp;
-  char buffer[CMD_MAX];
+  char buffer[RRD_CMD_MAX];
   int len;
 
   if (JOURNAL_REPLAY(sock)) return 0;
@@ -588,7 +581,7 @@ static int send_response (listen_socket_t *sock, response_code rc,
                           char *fmt, ...) /* {{{ */
 {
   va_list argp;
-  char buffer[CMD_MAX];
+  char buffer[RRD_CMD_MAX];
   int lines;
   ssize_t wrote;
   int rclen, len;
@@ -1327,13 +1320,13 @@ static int handle_request_update (HANDLER_PROTO) /* {{{ */
   char *file, file_tmp[PATH_MAX];
   int values_num = 0;
   int status;
-  char orig_buf[CMD_MAX];
+  char orig_buf[RRD_CMD_MAX];
 
   cache_item_t *ci;
 
   /* save it for the journal later */
   if (!JOURNAL_REPLAY(sock))
-    strncpy(orig_buf, buffer, buffer_size);
+    strncpy(orig_buf, buffer, min(RRD_CMD_MAX,buffer_size));
 
   status = buffer_get_field (&buffer, &buffer_size, &file);
   if (status != 0)
@@ -1424,7 +1417,7 @@ static int handle_request_update (HANDLER_PROTO) /* {{{ */
   while (buffer_size > 0)
   {
     char *value;
-    time_t stamp;
+    double stamp;
     char *eostamp;
 
     status = buffer_get_field (&buffer, &buffer_size, &value);
@@ -1434,8 +1427,9 @@ static int handle_request_update (HANDLER_PROTO) /* {{{ */
       break;
     }
 
-    /* make sure update time is always moving forward */
-    stamp = strtol(value, &eostamp, 10);
+    /* make sure update time is always moving forward. We use double here since
+       update does support subsecond precision for timestamps ... */
+    stamp = strtod(value, &eostamp);
     if (eostamp == value || eostamp == NULL || *eostamp != ':')
     {
       pthread_mutex_unlock(&cache_lock);
@@ -1446,8 +1440,8 @@ static int handle_request_update (HANDLER_PROTO) /* {{{ */
     {
       pthread_mutex_unlock(&cache_lock);
       return send_response(sock, RESP_ERR,
-                           "illegal attempt to update using time %ld when last"
-                           " update time is %ld (minimum one second step)\n",
+                           "illegal attempt to update using time %lf when last"
+                           " update time is %lf (minimum one second step)\n",
                            stamp, ci->last_update_stamp);
     }
     else
@@ -2168,6 +2162,15 @@ static void socket_permission_copy (listen_socket_t *dest, /* {{{ */
   dest->permissions = src->permissions;
 } /* }}} socket_permission_copy */
 
+static void socket_permission_set_all (listen_socket_t *sock) /* {{{ */
+{
+  size_t i;
+
+  sock->permissions = 0;
+  for (i = 0; i < list_of_commands_len; i++)
+    sock->permissions |= (1 << i);
+} /* }}} void socket_permission_set_all */
+
 /* check whether commands are received in the expected context */
 static int command_check_context(listen_socket_t *sock, command_t *cmd)
 {
@@ -2195,7 +2198,7 @@ static int handle_request_help (HANDLER_PROTO) /* {{{ */
 
   if (help && (help->syntax || help->help))
   {
-    char tmp[CMD_MAX];
+    char tmp[RRD_CMD_MAX];
 
     snprintf(tmp, sizeof(tmp)-1, "Help for %s\n", help->cmd);
     resp_txt = tmp;
@@ -2430,7 +2433,7 @@ static int journal_replay (const char *file) /* {{{ */
   int entry_cnt = 0;
   int fail_cnt = 0;
   uint64_t line = 0;
-  char entry[CMD_MAX];
+  char entry[RRD_CMD_MAX];
   time_t now;
 
   if (file == NULL) return 0;
@@ -2646,7 +2649,7 @@ static void *connection_thread_main (void *args) /* {{{ */
      getting overwritten by another thread.
   */
   struct request_info req;
-  request_init(&req, RQ_DAEMON, "rrdcache\0", RQ_FILE, fd, NULL );
+  request_init(&req, RQ_DAEMON, "rrdcached\0", RQ_FILE, fd, NULL );
   fromhost(&req);
   if(!hosts_access(&req)) {
     RRDD_LOG(LOG_INFO, "refused connection from %s", eval_client(&req));
@@ -3131,6 +3134,10 @@ static int daemonize (void) /* {{{ */
     strncpy(default_socket.addr, RRDCACHED_DEFAULT_ADDRESS,
         sizeof(default_socket.addr) - 1);
     default_socket.addr[sizeof(default_socket.addr) - 1] = '\0';
+
+    if (default_socket.permissions == 0)
+      socket_permission_set_all (&default_socket);
+
     open_listen_socket (&default_socket);
   }
 
@@ -3275,18 +3282,7 @@ static int read_options (int argc, char **argv) /* {{{ */
         else /* if (default_socket.permissions == 0) */
         {
           /* Add permission for ALL commands to the socket. */
-          size_t i;
-          for (i = 0; i < list_of_commands_len; i++)
-          {
-            status = socket_permission_add (new, list_of_commands[i].cmd);
-            if (status != 0)
-            {
-              fprintf (stderr, "read_options: Adding permission \"%s\" to "
-                  "socket failed. This should never happen, ever! Sorry.\n",
-                  list_of_commands[i].cmd);
-              status = 4;
-            }
-          }
+          socket_permission_set_all (new);
         }
         /* }}} Done adding permissions. */
 
@@ -3531,23 +3527,30 @@ static int read_options (int argc, char **argv) /* {{{ */
       case 'j':
       {
         char journal_dir_actual[PATH_MAX];
-        const char *dir;
-        dir = journal_dir = strdup(realpath((const char *)optarg, journal_dir_actual));
-
-        status = rrd_mkdir_p(dir, 0777);
-        if (status != 0)
-        {
-          fprintf(stderr, "Failed to create journal directory '%s': %s\n",
-              dir, rrd_strerror(errno));
-          return 6;
-        }
-
-        if (access(dir, R_OK|W_OK|X_OK) != 0)
-        {
-          fprintf(stderr, "Must specify a writable directory with -j! (%s)\n",
-                  errno ? rrd_strerror(errno) : "");
-          return 6;
-        }
+        journal_dir = realpath((const char *)optarg, journal_dir_actual);
+       if (journal_dir)
+       {
+          // if we were able to properly resolve the path, lets have a copy
+          // for use outside this block.
+          journal_dir = strdup(journal_dir);           
+         status = rrd_mkdir_p(journal_dir, 0777);
+         if (status != 0)
+         {
+           fprintf(stderr, "Failed to create journal directory '%s': %s\n",
+                   journal_dir, rrd_strerror(errno));
+           return 6;
+         }
+         if (access(journal_dir, R_OK|W_OK|X_OK) != 0)
+         {
+           fprintf(stderr, "Must specify a writable directory with -j! (%s)\n",
+                   errno ? rrd_strerror(errno) : "");
+           return 6;
+         }
+       } else {
+         fprintf(stderr, "Unable to resolve journal path (%s,%s)\n", optarg,
+                 errno ? rrd_strerror(errno) : "");
+         return 6;
+       }
       }
       break;
 
@@ -3573,6 +3576,7 @@ static int read_options (int argc, char **argv) /* {{{ */
             "\n"
             "Valid options are:\n"
             "  -l <address>  Socket address to listen to.\n"
+            "                Default: "RRDCACHED_DEFAULT_ADDRESS"\n"
             "  -P <perms>    Sets the permissions to assign to all following "
                             "sockets\n"
             "  -w <seconds>  Interval in which to write data.\n"