Code

remove_cache_item() did not check whether a file was in queue before
authoroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Wed, 22 Oct 2008 06:02:23 +0000 (06:02 +0000)
committeroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Wed, 22 Oct 2008 06:02:23 +0000 (06:02 +0000)
modifying the cache head/tail pointers.  Therefore, the process of
flushing old files may perturb the cache_queue_head pointer.  This caused
some nodes with CI_FLAGS_IN_QUEUE to be un-linked from the queue list.

Thereafter, they would not be flushed by any periodic process (although
they could be revived with FLUSH or UPDATE).  This caused a slow memory
leak for files that are no longer updated.  Pending updates for these
"abandoned" files would remain in memory ad infinitum.

With this patch, remove_from_queue() will check that the item is queued
before modifying the head/tail pointers.  This restores the intended
behavior.
--kevin

git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk@1626 a5681a0c-68f1-0310-ab6d-d61299d08faa

program/src/rrd_daemon.c

index d404e04b40fe2029051c605e11c22aa83c19f787..8d26e0a6e86266f3dec0f0f35ce924e15ec7af59 100644 (file)
@@ -564,6 +564,7 @@ static void wipe_ci_values(cache_item_t *ci, time_t when)
 static void remove_from_queue(cache_item_t *ci) /* {{{ */
 {
   if (ci == NULL) return;
+  if ((ci->flags & CI_FLAGS_IN_QUEUE) == 0) return; /* not queued */
 
   if (ci->prev == NULL)
     cache_queue_head = ci->next; /* reset head */
@@ -625,9 +626,8 @@ static int enqueue_cache_item (cache_item_t *ci, /* {{{ */
     if (cache_queue_head == ci)
       return 0;
 
-    /* remove from the double linked list */
-    if (ci->flags & CI_FLAGS_IN_QUEUE)
-      remove_from_queue(ci);
+    /* remove if further down in queue */
+    remove_from_queue(ci);
 
     ci->prev = NULL;
     ci->next = cache_queue_head;
@@ -681,20 +681,20 @@ static gboolean tree_callback_flush (gpointer key, gpointer value, /* {{{ */
   ci = (cache_item_t *) value;
   cfd = (callback_flush_data_t *) data;
 
+  if (ci->flags & CI_FLAGS_IN_QUEUE)
+    return FALSE;
+
   if ((ci->last_flush_time <= cfd->abs_timeout)
-      && ((ci->flags & CI_FLAGS_IN_QUEUE) == 0)
       && (ci->values_num > 0))
   {
     enqueue_cache_item (ci, TAIL);
   }
   else if ((do_shutdown != 0)
-      && ((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;