Example #1
0
static int statsd_read(void) /* {{{ */
{
  c_avl_iterator_t *iter;
  char *name;
  statsd_metric_t *metric;

  char **to_be_deleted = NULL;
  size_t to_be_deleted_num = 0;

  pthread_mutex_lock(&metrics_lock);

  if (metrics_tree == NULL) {
    pthread_mutex_unlock(&metrics_lock);
    return 0;
  }

  iter = c_avl_get_iterator(metrics_tree);
  while (c_avl_iterator_next(iter, (void *)&name, (void *)&metric) == 0) {
    if ((metric->updates_num == 0) &&
        ((conf_delete_counters && (metric->type == STATSD_COUNTER)) ||
         (conf_delete_timers && (metric->type == STATSD_TIMER)) ||
         (conf_delete_gauges && (metric->type == STATSD_GAUGE)) ||
         (conf_delete_sets && (metric->type == STATSD_SET)))) {
      DEBUG("statsd plugin: Deleting metric \"%s\".", name);
      strarray_add(&to_be_deleted, &to_be_deleted_num, name);
      continue;
    }

    /* Names have a prefix, e.g. "c:", which determines the (statsd) type.
     * Remove this here. */
    statsd_metric_submit_unsafe(name + 2, metric);

    /* Reset the metric. */
    metric->updates_num = 0;
    if (metric->type == STATSD_SET)
      statsd_metric_clear_set_unsafe(metric);
  }
  c_avl_iterator_destroy(iter);

  for (size_t i = 0; i < to_be_deleted_num; i++) {
    int status;

    status = c_avl_remove(metrics_tree, to_be_deleted[i], (void *)&name,
                          (void *)&metric);
    if (status != 0) {
      ERROR("stats plugin: c_avl_remove (\"%s\") failed with status %i.",
            to_be_deleted[i], status);
      continue;
    }

    sfree(name);
    statsd_metric_free(metric);
  }

  pthread_mutex_unlock(&metrics_lock);

  strarray_free(to_be_deleted, to_be_deleted_num);

  return 0;
} /* }}} int statsd_read */
Example #2
0
int uc_check_timeout (void)
{
  time_t now;
  cache_entry_t *ce;

  char **keys = NULL;
  int keys_len = 0;

  char *key;
  c_avl_iterator_t *iter;
  int i;
  
  pthread_mutex_lock (&cache_lock);

  now = time (NULL);

  /* Build a list of entries to be flushed */
  iter = c_avl_get_iterator (cache_tree);
  while (c_avl_iterator_next (iter, (void *) &key, (void *) &ce) == 0)
  {
    /* If entry has not been updated, add to `keys' array */
    /* FIXME: Remove macro once "ce->interval" is of type cdtime_t. */
    if ((now - ce->last_update) >= TIME_T_TO_CDTIME_T (timeout_g * ce->interval))
    {
      char **tmp;

      tmp = (char **) realloc ((void *) keys,
	  (keys_len + 1) * sizeof (char *));
      if (tmp == NULL)
      {
	ERROR ("uc_check_timeout: realloc failed.");
	c_avl_iterator_destroy (iter);
	sfree (keys);
	pthread_mutex_unlock (&cache_lock);
	return (-1);
      }

      keys = tmp;
      keys[keys_len] = strdup (key);
      if (keys[keys_len] == NULL)
      {
	ERROR ("uc_check_timeout: strdup failed.");
	continue;
      }
      keys_len++;
    }
  } /* while (c_avl_iterator_next) */

  ce = NULL;

  for (i = 0; i < keys_len; i++)
  {
    int status;

    status = ut_check_interesting (keys[i]);

    if (status < 0)
    {
      ERROR ("uc_check_timeout: ut_check_interesting failed.");
      sfree (keys[i]);
      continue;
    }
    else if (status == 0) /* ``service'' is uninteresting */
    {
      DEBUG ("uc_check_timeout: %s is missing but ``uninteresting''",
	  keys[i]);
      ce = NULL;
      status = c_avl_remove (cache_tree, keys[i],
	  (void *) &key, (void *) &ce);
      if (status != 0)
      {
	ERROR ("uc_check_timeout: c_avl_remove (%s) failed.", keys[i]);
      }
      sfree (keys[i]);
      sfree (key);
      if (ce != NULL)
        cache_free (ce);
      continue;
    }

    /* 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 == 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) */
      {
	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 "
	  "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);

  pthread_mutex_unlock (&cache_lock);

  for (i = 0; i < keys_len; i++)
  {
    if (keys[i] == NULL)
      continue;

    uc_send_notification (keys[i]);
    sfree (keys[i]);
  }

  sfree (keys);

  return (0);
} /* int uc_check_timeout */
Example #3
0
int uc_check_timeout (void)
{
    cdtime_t now;
    cache_entry_t *ce;

    char **keys = NULL;
    cdtime_t *keys_time = NULL;
    cdtime_t *keys_interval = NULL;
    int keys_len = 0;

    char *key;
    c_avl_iterator_t *iter;

    int status;
    int i;

    pthread_mutex_lock (&cache_lock);

    now = cdtime ();

    /* Build a list of entries to be flushed */
    iter = c_avl_get_iterator (cache_tree);
    while (c_avl_iterator_next (iter, (void *) &key, (void *) &ce) == 0)
    {
        char **tmp;
        cdtime_t *tmp_time;

        /* If the entry is fresh enough, continue. */
        if ((now - ce->last_update) < (ce->interval * timeout_g))
            continue;

        /* If entry has not been updated, add to `keys' array */
        tmp = realloc ((void *) keys,
                       (keys_len + 1) * sizeof (char *));
        if (tmp == NULL)
        {
            ERROR ("uc_check_timeout: realloc failed.");
            continue;
        }
        keys = tmp;

        tmp_time = realloc (keys_time, (keys_len + 1) * sizeof (*keys_time));
        if (tmp_time == NULL)
        {
            ERROR ("uc_check_timeout: realloc failed.");
            continue;
        }
        keys_time = tmp_time;

        tmp_time = realloc (keys_interval, (keys_len + 1) * sizeof (*keys_interval));
        if (tmp_time == NULL)
        {
            ERROR ("uc_check_timeout: realloc failed.");
            continue;
        }
        keys_interval = tmp_time;

        keys[keys_len] = strdup (key);
        if (keys[keys_len] == NULL)
        {
            ERROR ("uc_check_timeout: strdup failed.");
            continue;
        }
        keys_time[keys_len] = ce->last_time;
        keys_interval[keys_len] = ce->interval;

        keys_len++;
    } /* while (c_avl_iterator_next) */

    c_avl_iterator_destroy (iter);
    pthread_mutex_unlock (&cache_lock);

    if (keys_len == 0)
    {
        /* realloc() may have been called for these. */
        sfree (keys);
        sfree (keys_time);
        sfree (keys_interval);
        return (0);
    }

    /* Call the "missing" callback for each value. Do this before removing the
     * value from the cache, so that callbacks can still access the data stored,
     * including plugin specific meta data, rates, history, …. This must be done
     * without holding the lock, otherwise we will run into a deadlock if a
     * plugin calls the cache interface. */
    for (i = 0; i < keys_len; i++)
    {
        value_list_t vl = VALUE_LIST_INIT;

        vl.values = NULL;
        vl.values_len = 0;
        vl.meta = NULL;

        status = parse_identifier_vl (keys[i], &vl);
        if (status != 0)
        {
            ERROR ("uc_check_timeout: parse_identifier_vl (\"%s\") failed.", keys[i]);
            continue;
        }

        vl.time = keys_time[i];
        vl.interval = keys_interval[i];

        plugin_dispatch_missing (&vl);
    } /* for (i = 0; i < keys_len; i++) */

    /* Now actually remove all the values from the cache. We don't re-evaluate
     * the timestamp again, so in theory it is possible we remove a value after
     * it is updated here. */
    pthread_mutex_lock (&cache_lock);
    for (i = 0; i < keys_len; i++)
    {
        key = NULL;
        ce = NULL;

        status = c_avl_remove (cache_tree, keys[i],
                               (void *) &key, (void *) &ce);
        if (status != 0)
        {
            ERROR ("uc_check_timeout: c_avl_remove (\"%s\") failed.", keys[i]);
            sfree (keys[i]);
            continue;
        }

        sfree (keys[i]);
        sfree (key);
        cache_free (ce);
    } /* for (i = 0; i < keys_len; i++) */
    pthread_mutex_unlock (&cache_lock);

    sfree (keys);
    sfree (keys_time);
    sfree (keys_interval);

    return (0);
} /* int uc_check_timeout */