Code

src/utils_cache.c: Update GETVAL output when missing state.
[collectd.git] / src / utils_cache.c
index 6d96516900c7f9d03d1cc39a2b3abef8c89a96f8..4d2c554990acc6e2927b784510c796dcd3cc60ef 100644 (file)
@@ -156,13 +156,12 @@ static int uc_send_notification (const char *name)
     return (-1);
   }
 
-  snprintf (n.message, sizeof (n.message),
+  ssnprintf (n.message, sizeof (n.message),
       "%s has not been updated for %i seconds.", name,
       (int) (n.time - ce->last_update));
 
   pthread_mutex_unlock (&cache_lock);
 
-  n.message[sizeof (n.message) - 1] = '\0';
   plugin_dispatch_notification (&n);
 
   return (0);
@@ -187,6 +186,7 @@ static int uc_insert (const data_set_t *ds, const value_list_t *vl,
   ce = cache_alloc (ds->ds_num);
   if (ce == NULL)
   {
+    sfree (key_copy);
     ERROR ("uc_insert: cache_alloc (%i) failed.", ds->ds_num);
     return (-1);
   }
@@ -260,8 +260,10 @@ int uc_check_timeout (void)
          (keys_len + 1) * sizeof (char *));
       if (tmp == NULL)
       {
-       ERROR ("uc_purge: realloc failed.");
+       ERROR ("uc_check_timeout: realloc failed.");
        c_avl_iterator_destroy (iter);
+       sfree (keys);
+       pthread_mutex_unlock (&cache_lock);
        return (-1);
       }
 
@@ -276,6 +278,8 @@ int uc_check_timeout (void)
     }
   } /* while (c_avl_iterator_next) */
 
+  ce = NULL;
+
   for (i = 0; i < keys_len; i++)
   {
     int status;
@@ -286,10 +290,10 @@ int uc_check_timeout (void)
     {
       ERROR ("uc_check_timeout: ut_check_interesting failed.");
       sfree (keys[i]);
+      continue;
     }
     else if (status == 0) /* ``service'' is uninteresting */
     {
-      ce = NULL;
       DEBUG ("uc_check_timeout: %s is missing but ``uninteresting''",
          keys[i]);
       status = c_avl_remove (cache_tree, keys[i],
@@ -301,20 +305,34 @@ int uc_check_timeout (void)
       sfree (keys[i]);
       sfree (key);
       cache_free (ce);
+      continue;
     }
-    else if (status == 1) /* persist */
+
+    /* If we get here, the value is ``interesting''. Query the record from the
+     * cache and update the state field. */
+    if (c_avl_get (cache_tree, keys[i], (void *) &ce) != 0)
+    {
+      ERROR ("uc_check_timeout: cannot get data for %s from cache", keys[i]);
+      /* Do not free `keys[i]' so a notification is sent further down. */
+      continue;
+    }
+    assert (ce != NULL);
+
+    if (status == 2) /* persist */
     {
       DEBUG ("uc_check_timeout: %s is missing, sending notification.",
          keys[i]);
       ce->state = STATE_MISSING;
+      /* Do not free `keys[i]' so a notification is sent further down. */
     }
-    else if (status == 2) /* do not persist */
+    else if (status == 1) /* do not persist */
     {
       if (ce->state == STATE_MISSING)
       {
        DEBUG ("uc_check_timeout: %s is missing but "
            "notification has already been sent.",
            keys[i]);
+       /* Set `keys[i]' to NULL to no notification is sent. */
        sfree (keys[i]);
       }
       else /* (ce->state != STATE_MISSING) */
@@ -322,14 +340,20 @@ int uc_check_timeout (void)
        DEBUG ("uc_check_timeout: %s is missing, sending one notification.",
            keys[i]);
        ce->state = STATE_MISSING;
+       /* Do not free `keys[i]' so a notification is sent further down. */
       }
     }
     else
     {
-      WARNING ("uc_check_timeout: ut_check_interesting (%s) returned ",
+      WARNING ("uc_check_timeout: ut_check_interesting (%s) returned "
          "invalid status %i.",
          keys[i], status);
+      sfree (keys[i]);
     }
+
+    /* Make really sure the next iteration doesn't work with this pointer.
+     * There have been too many bugs in the past.. :/  -- octo */
+    ce = NULL;
   } /* for (keys[i]) */
 
   c_avl_iterator_destroy (iter);
@@ -451,10 +475,9 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
   n.severity = NOTIF_OKAY;
   n.time = vl->time;
 
-  snprintf (n.message, sizeof (n.message),
+  ssnprintf (n.message, sizeof (n.message),
       "Received a value for %s. It was missing for %u seconds.",
       name, (unsigned int) update_delay);
-  n.message[sizeof (n.message) - 1] = '\0';
 
   plugin_dispatch_notification (&n);
 
@@ -474,16 +497,24 @@ int uc_get_rate_by_name (const char *name, gauge_t **ret_values, size_t *ret_val
   {
     assert (ce != NULL);
 
-    ret_num = ce->values_num;
-    ret = (gauge_t *) malloc (ret_num * sizeof (gauge_t));
-    if (ret == NULL)
+    /* remove missing values from getval */
+    if (ce->state == STATE_MISSING)
     {
-      ERROR ("utils_cache: uc_get_rate_by_name: malloc failed.");
       status = -1;
     }
     else
     {
-      memcpy (ret, ce->values_gauge, ret_num * sizeof (gauge_t));
+      ret_num = ce->values_num;
+      ret = (gauge_t *) malloc (ret_num * sizeof (gauge_t));
+      if (ret == NULL)
+      {
+        ERROR ("utils_cache: uc_get_rate_by_name: malloc failed.");
+        status = -1;
+      }
+      else
+      {
+        memcpy (ret, ce->values_gauge, ret_num * sizeof (gauge_t));
+      }
     }
   }
   else
@@ -512,7 +543,7 @@ gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl)
 
   if (FORMAT_VL (name, sizeof (name), vl, ds) != 0)
   {
-    ERROR ("uc_insert: FORMAT_VL failed.");
+    ERROR ("utils_cache: uc_get_rate: FORMAT_VL failed.");
     return (NULL);
   }
 
@@ -522,10 +553,10 @@ gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl)
 
   /* This is important - the caller has no other way of knowing how many
    * values are returned. */
-  if (ret_num != ds->ds_num)
+  if (ret_num != (size_t) ds->ds_num)
   {
     ERROR ("utils_cache: uc_get_rate: ds[%s] has %i values, "
-       "but uc_get_rate_by_name returned %i.",
+       "but uc_get_rate_by_name returned %zu.",
        ds->type, ds->ds_num, ret_num);
     sfree (ret);
     return (NULL);
@@ -556,6 +587,10 @@ int uc_get_names (char ***ret_names, time_t **ret_times, size_t *ret_number)
   {
     char **temp;
 
+    /* remove missing values when list values */
+    if (value->state == STATE_MISSING)
+      continue;
+
     if (ret_times != NULL)
     {
       time_t *tmp_times;