Handle race condition for "UPDATE" with new files. Problem found by Sebastian Harl...
[rrdtool.git] / src / rrd_daemon.c
index 53904a3..8b1fc9e 100644 (file)
@@ -379,7 +379,13 @@ static int check_pidfile(void)
   }
 
   lseek(pid_fd, 0, SEEK_SET);
-  ftruncate(pid_fd, 0);
+  if (ftruncate(pid_fd, 0) == -1)
+  {
+    fprintf(stderr,
+            "FATAL: Faild to truncate stale PID file. (pid %d)\n", pid);
+    close(pid_fd);
+    return -1;
+  }
 
   fprintf(stderr,
           "rrdcached: removed stale PID file (no rrdcached on pid %d)\n"
@@ -650,6 +656,7 @@ static void *free_cache_item(cache_item_t *ci) /* {{{ */
 
   /* in case anyone is waiting */
   pthread_cond_broadcast(&ci->flushed);
+  pthread_cond_destroy(&ci->flushed);
 
   free (ci);
 
@@ -906,7 +913,14 @@ static void *queue_thread_main (void *args __attribute__((unused))) /* {{{ */
     }
 
     journal_write("wrote", file);
-    pthread_cond_broadcast(&ci->flushed);
+
+    /* Search again in the tree.  It's possible someone issued a "FORGET"
+     * while we were writing the update values. */
+    pthread_mutex_lock(&cache_lock);
+    ci = (cache_item_t *) g_tree_lookup(cache_tree, file);
+    if (ci)
+      pthread_cond_broadcast(&ci->flushed);
+    pthread_mutex_unlock(&cache_lock);
 
     rrd_free_ptrs((void ***) &values, &values_num);
     free(file);
@@ -1300,6 +1314,7 @@ static int handle_request_update (HANDLER_PROTO) /* {{{ */
   if (ci == NULL) /* {{{ */
   {
     struct stat statbuf;
+    cache_item_t *tmp;
 
     /* don't hold the lock while we setup; stat(2) might block */
     pthread_mutex_unlock(&cache_lock);
@@ -1347,7 +1362,16 @@ static int handle_request_update (HANDLER_PROTO) /* {{{ */
     pthread_cond_init(&ci->flushed, NULL);
 
     pthread_mutex_lock(&cache_lock);
-    g_tree_replace (cache_tree, (void *) ci->file, (void *) ci);
+
+    /* another UPDATE might have added this entry in the meantime */
+    tmp = g_tree_lookup (cache_tree, file);
+    if (tmp == NULL)
+      g_tree_replace (cache_tree, (void *) ci->file, (void *) ci);
+    else
+    {
+      free_cache_item (ci);
+      ci = tmp;
+    }
   } /* }}} */
   assert (ci != NULL);
 
@@ -2446,8 +2470,9 @@ static int daemonize (void) /* {{{ */
     close (0);
 
     open ("/dev/null", O_RDWR);
-    dup (0);
-    dup (0);
+    if (dup(0) == -1 || dup(0) == -1){
+        RRDD_LOG (LOG_ERR, "faild to run dup.\n");
+    }
   } /* if (!stay_foreground) */
 
   /* Change into the /tmp directory. */