src/rrd_daemon.c: Implemented removal of unused tree nodes.
authorFlorian Forster <octo@verplant.org>
Wed, 2 Jul 2008 21:04:54 +0000 (23:04 +0200)
committerFlorian Forster <octo@verplant.org>
Wed, 2 Jul 2008 21:04:54 +0000 (23:04 +0200)
src/rrd_daemon.c

index feb1ce3..3163e18 100644 (file)
@@ -116,6 +116,14 @@ struct cache_item_s
   cache_item_t *next;
 };
 
+struct callback_flush_data_s
+{
+  time_t now;
+  char **keys;
+  size_t keys_num;
+};
+typedef struct callback_flush_data_s callback_flush_data_t;
+
 enum queue_side_e
 {
   HEAD,
@@ -283,21 +291,40 @@ static int enqueue_cache_item (cache_item_t *ci, /* {{{ */
  * Called via `g_tree_foreach' in `queue_thread_main'. `cache_lock' is held
  * while this is in progress.
  */
-static gboolean tree_callback_flush (gpointer key /* {{{ */
-    __attribute__((unused)), gpointer value, gpointer data)
+static gboolean tree_callback_flush (gpointer key, gpointer value, /* {{{ */
+    gpointer data)
 {
   cache_item_t *ci;
-  time_t now;
-
-  key = NULL; /* make compiler happy */
+  callback_flush_data_t *cfd;
 
   ci = (cache_item_t *) value;
-  now = *((time_t *) data);
+  cfd = (callback_flush_data_t *) data;
 
-  if (((now - ci->last_flush_time) >= config_write_interval)
+  if (((cfd->now - ci->last_flush_time) >= config_write_interval)
       && ((ci->flags & CI_FLAGS_IN_QUEUE) == 0)
       && (ci->values_num > 0))
+  {
     enqueue_cache_item (ci, TAIL);
+  }
+  else if (((cfd->now - ci->last_flush_time) >= config_flush_interval)
+      && ((ci->flags & CI_FLAGS_IN_QUEUE) == 0)
+      && (ci->values_num <= 0))
+  {
+    char **temp;
+
+    temp = (char **) realloc (cfd->keys,
+        sizeof (char *) * (cfd->keys_num + 1));
+    if (temp == NULL)
+    {
+      RRDD_LOG (LOG_ERR, "tree_callback_flush: realloc 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);
 } /* }}} gboolean tree_callback_flush */
@@ -327,13 +354,48 @@ static void *queue_thread_main (void *args __attribute__((unused))) /* {{{ */
         || ((now.tv_sec == next_flush.tv_sec)
           && ((1000 * now.tv_usec) > next_flush.tv_nsec)))
     {
-      time_t time_now;
+      callback_flush_data_t cfd;
+      size_t k;
 
+      memset (&cfd, 0, sizeof (cfd));
       /* Pass the current time as user data so that we don't need to call
        * `time' for each node. */
-      time_now = time (NULL);
+      cfd.now = time (NULL);
+      cfd.keys = NULL;
+      cfd.keys_num = 0;
+
+      /* `tree_callback_flush' will return the keys of all values that haven't
+       * been touched in the last `config_flush_interval' seconds in `cfd'.
+       * The char*'s in this array point to the same memory as ci->file, so we
+       * don't need to free them separately. */
+      g_tree_foreach (cache_tree, tree_callback_flush, (gpointer) &cfd);
 
-      g_tree_foreach (cache_tree, tree_callback_flush, (gpointer) &time_now);
+      for (k = 0; k < cfd.keys_num; k++)
+      {
+        /* This must not fail. */
+        ci = (cache_item_t *) g_tree_lookup (cache_tree, cfd.keys[k]);
+        assert (ci != NULL);
+
+        /* If we end up here with values available, something's seriously
+         * messed up. */
+        assert (ci->values_num == 0);
+
+        /* Remove the node from the tree */
+        g_tree_remove (cache_tree, cfd.keys[k]);
+        cfd.keys[k] = NULL;
+
+        /* Now free and clean up `ci'. */
+        free (ci->file);
+        ci->file = NULL;
+        free (ci);
+        ci = NULL;
+      } /* for (k = 0; k < cfd.keys_num; k++) */
+
+      if (cfd.keys != NULL)
+      {
+        free (cfd.keys);
+        cfd.keys = NULL;
+      }
 
       /* Determine the time of the next cache flush. */
       while (next_flush.tv_sec < now.tv_sec)
@@ -474,7 +536,7 @@ static int flush_file (const char *filename) /* {{{ */
 
   pthread_mutex_lock (&cache_lock);
 
-  ci = g_tree_lookup (cache_tree, filename);
+  ci = (cache_item_t *) g_tree_lookup (cache_tree, filename);
   if (ci == NULL)
   {
     pthread_mutex_unlock (&cache_lock);