コード例 #1
0
ファイル: curl_json.c プロジェクト: Altiscale/collectd
/* Queries the key-tree of the parent context for "in_name" and, if found,
 * updates the "key" field of the current context. Otherwise, "key" is set to
 * NULL. */
static int cj_cb_map_key (void *ctx,
    unsigned char const *in_name, yajl_len_t in_name_len)
{
  cj_t *db = (cj_t *)ctx;
  c_avl_tree_t *tree;

  tree = db->state[db->depth-1].tree;

  if (tree != NULL)
  {
    cj_key_t *value = NULL;
    char *name;
    size_t name_len;

    /* Create a null-terminated version of the name. */
    name = db->state[db->depth].name;
    name_len = COUCH_MIN ((size_t) in_name_len,
        sizeof (db->state[db->depth].name) - 1);
    memcpy (name, in_name, name_len);
    name[name_len] = 0;

    if (c_avl_get (tree, name, (void *) &value) == 0)
      db->state[db->depth].key = value;
    else if (c_avl_get (tree, CJ_ANY, (void *) &value) == 0)
      db->state[db->depth].key = value;
    else
      db->state[db->depth].key = NULL;
  }

  return (CJ_CB_CONTINUE);
}
コード例 #2
0
ファイル: curl_json.c プロジェクト: gnosek/collectd
static int cj_cb_map_key (void *ctx, const unsigned char *val,
                            unsigned int len)
{
  cj_t *db = (cj_t *)ctx;
  c_avl_tree_t *tree;

  tree = db->state[db->depth-1].tree;

  if (tree != NULL)
  {
    cj_key_t *value;
    char *name;

    name = db->state[db->depth].name;
    len = COUCH_MIN(len, sizeof (db->state[db->depth].name)-1);
    sstrncpy (name, (char *)val, len+1);

    if (c_avl_get (tree, name, (void *) &value) == 0)
      db->state[db->depth].key = value;
    else if (c_avl_get (tree, CJ_ANY, (void *) &value) == 0)
      db->state[db->depth].key = value;
    else
      db->state[db->depth].key = NULL;
  }

  return (CJ_CB_CONTINUE);
}
コード例 #3
0
ファイル: utils_cache.c プロジェクト: tabletcorry/collectd
int uc_inc_hits (const data_set_t *ds, const value_list_t *vl, int step)
{
  char name[6 * DATA_MAX_NAME_LEN];
  cache_entry_t *ce = NULL;
  int ret = -1;

  if (FORMAT_VL (name, sizeof (name), vl) != 0)
  {
    ERROR ("uc_get_state: FORMAT_VL failed.");
    return (STATE_ERROR);
  }

  pthread_mutex_lock (&cache_lock);

  if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
  {
    assert (ce != NULL);
    ret = ce->hits;
    ce->hits = ret + step;
  }

  pthread_mutex_unlock (&cache_lock);

  return (ret);
} /* int uc_inc_hits */
コード例 #4
0
ファイル: ethstat.c プロジェクト: Feandil/collectd
static void ethstat_submit_value(const char *device, const char *type_instance,
                                 derive_t value) {
  static c_complain_t complain_no_map = C_COMPLAIN_INIT_STATIC;

  value_list_t vl = VALUE_LIST_INIT;
  value_map_t *map = NULL;

  if (value_map != NULL)
    c_avl_get(value_map, type_instance, (void *)&map);

  /* If the "MappedOnly" option is specified, ignore unmapped values. */
  if (collect_mapped_only && (map == NULL)) {
    if (value_map == NULL)
      c_complain(
          LOG_WARNING, &complain_no_map,
          "ethstat plugin: The \"MappedOnly\" option has been set to true, "
          "but no mapping has been configured. All values will be ignored!");
    return;
  }

  vl.values = &(value_t){.derive = value};
  vl.values_len = 1;

  sstrncpy(vl.plugin, "ethstat", sizeof(vl.plugin));
  sstrncpy(vl.plugin_instance, device, sizeof(vl.plugin_instance));
  if (map != NULL) {
    sstrncpy(vl.type, map->type, sizeof(vl.type));
    sstrncpy(vl.type_instance, map->type_instance, sizeof(vl.type_instance));
  } else {
    sstrncpy(vl.type, "derive", sizeof(vl.type));
    sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
  }

  plugin_dispatch_values(&vl);
}
コード例 #5
0
ファイル: utils_cache.c プロジェクト: tabletcorry/collectd
/* XXX: This function will acquire `cache_lock' but will not free it! */
static meta_data_t *uc_get_meta (const value_list_t *vl) /* {{{ */
{
  char name[6 * DATA_MAX_NAME_LEN];
  cache_entry_t *ce = NULL;
  int status;

  status = FORMAT_VL (name, sizeof (name), vl);
  if (status != 0)
  {
    ERROR ("utils_cache: uc_get_meta: FORMAT_VL failed.");
    return (NULL);
  }

  pthread_mutex_lock (&cache_lock);

  status = c_avl_get (cache_tree, name, (void *) &ce);
  if (status != 0)
  {
    pthread_mutex_unlock (&cache_lock);
    return (NULL);
  }
  assert (ce != NULL);

  if (ce->meta == NULL)
    ce->meta = meta_data_create ();

  if (ce->meta == NULL)
    pthread_mutex_unlock (&cache_lock);

  return (ce->meta);
} /* }}} meta_data_t *uc_get_meta */
コード例 #6
0
ファイル: utils_fbhash.c プロジェクト: Mindera/collectd
char *fbh_get (fbhash_t *h, const char *key) /* {{{ */
{
  char *value;
  char *value_copy;
  int status;

  if ((h == NULL) || (key == NULL))
    return (NULL);

  value = NULL;
  value_copy = NULL;

  pthread_mutex_lock (&h->lock);

  /* TODO: Checking this every time may be a bit much..? */
  fbh_check_file (h);

  status = c_avl_get (h->tree, key, (void *) &value);
  if (status == 0)
  {
    assert (value != NULL);
    value_copy = strdup (value);
  }

  pthread_mutex_unlock (&h->lock);

  return (value_copy);
} /* }}} char *fbh_get */
コード例 #7
0
ファイル: utils_vl_lookup.c プロジェクト: ajdiaz/collectd
/* returns the number of successful calls to the callback function */
int lookup_search(lookup_t *obj, /* {{{ */
                  data_set_t const *ds, value_list_t const *vl) {
  by_type_entry_t *by_type = NULL;
  user_class_list_t *user_class_list = NULL;
  int retval = 0;
  int status;

  if ((obj == NULL) || (ds == NULL) || (vl == NULL))
    return (-EINVAL);

  by_type = lu_search_by_type(obj, vl->type, /* allocate = */ 0);
  if (by_type == NULL)
    return (0);

  status =
      c_avl_get(by_type->by_plugin_tree, vl->plugin, (void *)&user_class_list);
  if (status == 0) {
    status = lu_handle_user_class_list(obj, ds, vl, user_class_list);
    if (status < 0)
      return (status);
    retval += status;
  }

  if (by_type->wildcard_plugin_list != NULL) {
    status =
        lu_handle_user_class_list(obj, ds, vl, by_type->wildcard_plugin_list);
    if (status < 0)
      return (status);
    retval += status;
  }

  return (retval);
} /* }}} lookup_search */
コード例 #8
0
ファイル: statsd.c プロジェクト: EMSL-MSC/collectd
/* Must hold metrics_lock when calling this function. */
static statsd_metric_t *statsd_metric_lookup_unsafe(char const *name, /* {{{ */
                                                    metric_type_t type) {
  char key[DATA_MAX_NAME_LEN + 2];
  char *key_copy;
  statsd_metric_t *metric;
  int status;

  switch (type) {
  case STATSD_COUNTER:
    key[0] = 'c';
    break;
  case STATSD_TIMER:
    key[0] = 't';
    break;
  case STATSD_GAUGE:
    key[0] = 'g';
    break;
  case STATSD_SET:
    key[0] = 's';
    break;
  default:
    return NULL;
  }

  key[1] = ':';
  sstrncpy(&key[2], name, sizeof(key) - 2);

  status = c_avl_get(metrics_tree, key, (void *)&metric);
  if (status == 0)
    return metric;

  key_copy = strdup(key);
  if (key_copy == NULL) {
    ERROR("statsd plugin: strdup failed.");
    return NULL;
  }

  metric = calloc(1, sizeof(*metric));
  if (metric == NULL) {
    ERROR("statsd plugin: calloc failed.");
    sfree(key_copy);
    return NULL;
  }

  metric->type = type;
  metric->latency = NULL;
  metric->set = NULL;

  status = c_avl_insert(metrics_tree, key_copy, metric);
  if (status != 0) {
    ERROR("statsd plugin: c_avl_insert failed.");
    sfree(key_copy);
    sfree(metric);
    return NULL;
  }

  return metric;
} /* }}} statsd_metric_lookup_unsafe */
コード例 #9
0
ファイル: gmond.c プロジェクト: QualityUnit/collectd
static staging_entry_t *staging_entry_get (const char *host, /* {{{ */
    const char *name,
    const char *type, const char *type_instance,
    int values_len)
{
  char key[2 * DATA_MAX_NAME_LEN];
  staging_entry_t *se;
  int status;

  if (staging_tree == NULL)
    return (NULL);

  ssnprintf (key, sizeof (key), "%s/%s/%s", host, type,
      (type_instance != NULL) ? type_instance : "");

  se = NULL;
  status = c_avl_get (staging_tree, key, (void *) &se);
  if (status == 0)
    return (se);

  /* insert new entry */
  se = (staging_entry_t *) malloc (sizeof (*se));
  if (se == NULL)
    return (NULL);
  memset (se, 0, sizeof (*se));

  sstrncpy (se->key, key, sizeof (se->key));
  se->flags = 0;

  se->vl.values = (value_t *) calloc (values_len, sizeof (*se->vl.values));
  if (se->vl.values == NULL)
  {
    sfree (se);
    return (NULL);
  }
  se->vl.values_len = values_len;

  se->vl.time = 0;
  se->vl.interval = 0;
  sstrncpy (se->vl.host, host, sizeof (se->vl.host));
  sstrncpy (se->vl.plugin, "gmond", sizeof (se->vl.plugin));
  sstrncpy (se->vl.type, type, sizeof (se->vl.type));
  if (type_instance != NULL)
    sstrncpy (se->vl.type_instance, type_instance,
        sizeof (se->vl.type_instance));

  status = c_avl_insert (staging_tree, se->key, se);
  if (status != 0)
  {
    ERROR ("gmond plugin: c_avl_insert failed.");
    sfree (se->vl.values);
    sfree (se);
    return (NULL);
  }

  return (se);
} /* }}} staging_entry_t *staging_entry_get */
コード例 #10
0
ファイル: utils_vl_lookup.c プロジェクト: ajdiaz/collectd
static int lu_add_by_plugin(by_type_entry_t *by_type, /* {{{ */
                            user_class_list_t *user_class_list) {
  user_class_list_t *ptr = NULL;
  identifier_match_t const *match = &user_class_list->entry.match;

  /* Lookup user_class_list from the per-plugin structure. If this is the first
   * user_class to be added, the block returns immediately. Otherwise they will
   * set "ptr" to non-NULL. */
  if (match->plugin.is_regex) {
    if (by_type->wildcard_plugin_list == NULL) {
      by_type->wildcard_plugin_list = user_class_list;
      return (0);
    }

    ptr = by_type->wildcard_plugin_list;
  }    /* if (plugin is wildcard) */
  else /* (plugin is not wildcard) */
  {
    int status;

    status =
        c_avl_get(by_type->by_plugin_tree, match->plugin.str, (void *)&ptr);

    if (status != 0) /* plugin not yet in tree */
    {
      char *plugin_copy = strdup(match->plugin.str);

      if (plugin_copy == NULL) {
        ERROR("utils_vl_lookup: strdup failed.");
        sfree(user_class_list);
        return (ENOMEM);
      }

      status =
          c_avl_insert(by_type->by_plugin_tree, plugin_copy, user_class_list);
      if (status != 0) {
        ERROR("utils_vl_lookup: c_avl_insert(\"%s\") failed with status %i.",
              plugin_copy, status);
        sfree(plugin_copy);
        sfree(user_class_list);
        return (status);
      } else {
        return (0);
      }
    } /* if (plugin not yet in tree) */
  }   /* if (plugin is not wildcard) */

  assert(ptr != NULL);

  while (ptr->next != NULL)
    ptr = ptr->next;
  ptr->next = user_class_list;

  return (0);
} /* }}} int lu_add_by_plugin */
コード例 #11
0
ファイル: utils_vl_lookup.c プロジェクト: Altiscale/collectd
static by_type_entry_t *lu_search_by_type (lookup_t *obj, /* {{{ */
    char const *type, _Bool allocate_if_missing)
{
  by_type_entry_t *by_type;
  char *type_copy;
  int status;

  status = c_avl_get (obj->by_type_tree, type, (void *) &by_type);
  if (status == 0)
    return (by_type);

  if (!allocate_if_missing)
    return (NULL);

  type_copy = strdup (type);
  if (type_copy == NULL)
  {
    ERROR ("utils_vl_lookup: strdup failed.");
    return (NULL);
  }

  by_type = malloc (sizeof (*by_type));
  if (by_type == NULL)
  {
    ERROR ("utils_vl_lookup: malloc failed.");
    sfree (type_copy);
    return (NULL);
  }
  memset (by_type, 0, sizeof (*by_type));
  by_type->wildcard_plugin_list = NULL;
  
  by_type->by_plugin_tree = c_avl_create ((void *) strcmp);
  if (by_type->by_plugin_tree == NULL)
  {
    ERROR ("utils_vl_lookup: c_avl_create failed.");
    sfree (by_type);
    sfree (type_copy);
    return (NULL);
  }

  status = c_avl_insert (obj->by_type_tree,
      /* key = */ type_copy, /* value = */ by_type);
  assert (status <= 0); /* >0 => entry exists => race condition. */
  if (status != 0)
  {
    ERROR ("utils_vl_lookup: c_avl_insert failed.");
    c_avl_destroy (by_type->by_plugin_tree);
    sfree (by_type);
    sfree (type_copy);
    return (NULL);
  }
  
  return (by_type);
} /* }}} by_type_entry_t *lu_search_by_type */
コード例 #12
0
static int
basic_aggregator_config_aggregator_get_all_instances_of_type(char ***type_instances, char*type) {
	char **names = NULL;
	char *subtype;
	int l;
	int pos = 0;
	instances_list_t *v;
	int i;
	int typelen;
	*type_instances = NULL;

	for(l=0; type[l] && (pos < 2); l++) {
		if(type[l] == '/') pos++;
	}
	if(type[l] == '\0') {
		return(-1);
	}
	subtype = type+l;

	pthread_mutex_lock (&instances_of_types_mutex);
	if(0 != c_avl_get(instances_of_types_tree, subtype,(void*)&v)) {
		pthread_mutex_unlock (&instances_of_types_mutex);
		return(0);
	}
	for(i=0; v->instance[i]; i++); /* Count how many instances the type has */
	if(NULL == (names = malloc((i+1)*sizeof(*type_instances)))) {
		ERROR(OUTPUT_PREFIX_STRING "Could not allocate memory");
		pthread_mutex_unlock (&instances_of_types_mutex);
		return(-1);
	}
	typelen = strlen(type);
	for(i=0; v->instance[i]; i++) {
		int li;
		li = strlen(v->instance[i]);
		if(NULL == (names[i] = malloc((typelen+2+li)*sizeof(**names)))) {
			int j;
			ERROR(OUTPUT_PREFIX_STRING "Could not allocate memory");
			for(j=0; j<i; j++) free(names[j]);
			free(names);
			pthread_mutex_unlock (&instances_of_types_mutex);
			return(-1);
		}
		memcpy(names[i], type, typelen);
		names[i][typelen] = '-';
		memcpy(names[i]+typelen+1, v->instance[i],li+1);
	}
	names[i] = NULL;
	pthread_mutex_unlock (&instances_of_types_mutex);
	*type_instances = names;
		
	return(0);
}
コード例 #13
0
ファイル: utils_cache.c プロジェクト: tabletcorry/collectd
int uc_get_rate_by_name (const char *name, gauge_t **ret_values, size_t *ret_values_num)
{
  gauge_t *ret = NULL;
  size_t ret_num = 0;
  cache_entry_t *ce = NULL;
  int status = 0;

  pthread_mutex_lock (&cache_lock);

  if (c_avl_get (cache_tree, name, (void *) &ce) == 0)
  {
    assert (ce != NULL);

    /* remove missing values from getval */
    if (ce->state == STATE_MISSING)
    {
      status = -1;
    }
    else
    {
      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
  {
    DEBUG ("utils_cache: uc_get_rate_by_name: No such value: %s", name);
    status = -1;
  }

  pthread_mutex_unlock (&cache_lock);

  if (status == 0)
  {
    *ret_values = ret;
    *ret_values_num = ret_num;
  }

  return (status);
} /* gauge_t *uc_get_rate_by_name */
コード例 #14
0
ファイル: utils_threshold.c プロジェクト: hasso/collectd
/*
 * threshold_t *threshold_get
 *
 * Retrieve one specific threshold configuration. For looking up a threshold
 * matching a value_list_t, see "threshold_search" below. Returns NULL if the
 * specified threshold doesn't exist.
 */
threshold_t *threshold_get(const char *hostname, const char *plugin,
                           const char *plugin_instance, const char *type,
                           const char *type_instance) { /* {{{ */
    char name[6 * DATA_MAX_NAME_LEN];
    threshold_t *th = NULL;

    format_name(name, sizeof(name), (hostname == NULL) ? "" : hostname,
                (plugin == NULL) ? "" : plugin, plugin_instance,
                (type == NULL) ? "" : type, type_instance);
    name[sizeof(name) - 1] = '\0';

    if (c_avl_get(threshold_tree, name, (void *)&th) == 0)
        return (th);
    else
        return (NULL);
} /* }}} threshold_t *threshold_get */
コード例 #15
0
ファイル: zone.c プロジェクト: ajdiaz/collectd
static zone_stats_t *zone_find_stats(c_avl_tree_t *tree, zoneid_t zoneid) {
  zone_stats_t *ret = NULL;
  zoneid_t *key = NULL;

  if (c_avl_get(tree, (void **)&zoneid, (void **)&ret)) {
    if (!(ret = malloc(sizeof(*ret)))) {
      WARNING("zone plugin: no memory");
      return (NULL);
    }
    if (!(key = malloc(sizeof(*key)))) {
      WARNING("zone plugin: no memory");
      free(ret);
      return (NULL);
    }
    *key = zoneid;
    if (c_avl_insert(tree, key, ret)) {
      WARNING("zone plugin: error inserting into tree");
      return (NULL);
    }
  }
  return (ret);
}
コード例 #16
0
static int
instances_of_types_tree_update (void) {
	char **names = NULL;
	cdtime_t *times = NULL;
	size_t number = 0;
	int i;
	int status = 0;

	if(NULL == instances_of_types_tree) {
		instances_of_types_tree = c_avl_create ((void *) strcmp);
	}

	status = uc_get_names (&names, &times, &number);
	if (status != 0)
	{
			size_t j; 
			DEBUG (OUTPUT_PREFIX_STRING "uc_get_names failed with status %i", status);
			for (j = 0; j < number; j++) { 
					sfree(names[j]); 
			} 
			sfree(names); 
			sfree(times); 
			return(status);
	}

	if(number == 0) {
		return(0);
	}
	pthread_mutex_lock (&instances_of_types_mutex);
	for(i=0; i<number; i++) {
		char *type;
		int l1,l2;
		int pos =0;
		instances_list_t *v;
		char *type_instance;
		int type_instance_is_missing = 1;

		for(l1=0; names[i][l1] && (pos < 2); l1++) {
			if(names[i][l1] == '/') pos++;
		}
		if(names[i][l1] == '\0') {
			sfree(names[i]);
			continue;
		}
		l2 = l1;
		while(names[i][l2] && (names[i][l2] != '-')) l2++;
		if(names[i][l2] == '\0') {
			sfree(names[i]);
			continue;
		}
		type = names[i]+l1;
		names[i][l2] = '\0';
		type_instance = names[i]+l2+1;


		if(0 == c_avl_get(instances_of_types_tree, type,(void*)&v)) {
			int i;
			for(i=0; v->instance[i]; i++) {
				if(0 == strcmp(v->instance[i], type_instance)) {
					type_instance_is_missing = 0;
					break;
				}
			}
			if(type_instance_is_missing) {
				if(i >= v->nb) {
					v->nb += 128;
					if(NULL == (v->instance = realloc(v->instance, v->nb*sizeof(*(v->instance))))) {
						ERROR(OUTPUT_PREFIX_STRING "Could not allocate memory");
						pthread_mutex_unlock (&instances_of_types_mutex);
						return(-1);
					}
					}
				v->instance[i+1] = NULL;
				if(NULL == (v->instance[i] = sstrdup(type_instance))) {
					ERROR(OUTPUT_PREFIX_STRING "Could not allocate memory");
					pthread_mutex_unlock (&instances_of_types_mutex);
					return(-1);
				}
			}
		} else {
			char *k;
			if(NULL == (v = malloc(sizeof(*v)))) {
				ERROR(OUTPUT_PREFIX_STRING "Could not allocate memory");
				pthread_mutex_unlock (&instances_of_types_mutex);
				return(-1);
			}
			v->nb = 128;
			if(NULL == (v->instance = malloc(v->nb*sizeof(*(v->instance))))) {
				ERROR(OUTPUT_PREFIX_STRING "Could not allocate memory");
				sfree(v);
				pthread_mutex_unlock (&instances_of_types_mutex);
				return(-1);
			}
			if(NULL == (k = sstrdup(type))) {
				ERROR(OUTPUT_PREFIX_STRING "Could not allocate memory");
				sfree(v);
				pthread_mutex_unlock (&instances_of_types_mutex);
				return(-1);
			}
			if(NULL == (v->instance[0] = sstrdup(type_instance))) {
				ERROR(OUTPUT_PREFIX_STRING "Could not allocate memory");
				sfree(v);
				pthread_mutex_unlock (&instances_of_types_mutex);
				return(-1);
			}
			v->instance[1] = NULL;
			if(0 != c_avl_insert(instances_of_types_tree, k,v)) {
				ERROR (OUTPUT_PREFIX_STRING "Could insert data into AVL tree");
				sfree(v->instance[0]);
				sfree(v);
				pthread_mutex_unlock (&instances_of_types_mutex);
				return(-1);
			}
		}
		sfree(names[i]); 
	}
	pthread_mutex_unlock (&instances_of_types_mutex);
	sfree(names); 
	sfree(times); 
	return(0);
}
コード例 #17
0
ファイル: utils_cache.c プロジェクト: beorn-/collectd
int uc_update (const data_set_t *ds, const value_list_t *vl)
{
    char name[6 * DATA_MAX_NAME_LEN];
    cache_entry_t *ce = NULL;
    int status;
    size_t i;

    if (FORMAT_VL (name, sizeof (name), vl) != 0)
    {
        ERROR ("uc_update: FORMAT_VL failed.");
        return (-1);
    }

    pthread_mutex_lock (&cache_lock);

    status = c_avl_get (cache_tree, name, (void *) &ce);
    if (status != 0) /* entry does not yet exist */
    {
        status = uc_insert (ds, vl, name);
        pthread_mutex_unlock (&cache_lock);
        return (status);
    }

    assert (ce != NULL);
    assert (ce->values_num == ds->ds_num);

    if (ce->last_time >= vl->time)
    {
        pthread_mutex_unlock (&cache_lock);
        NOTICE ("uc_update: Value too old: name = %s; value time = %.3f; "
                "last cache update = %.3f;",
                name,
                CDTIME_T_TO_DOUBLE (vl->time),
                CDTIME_T_TO_DOUBLE (ce->last_time));
        return (-1);
    }

    for (i = 0; i < ds->ds_num; i++)
    {
        switch (ds->ds[i].type)
        {
        case DS_TYPE_COUNTER:
        {
            counter_t diff = counter_diff (ce->values_raw[i].counter, vl->values[i].counter);
            ce->values_gauge[i] = ((double) diff)
                                  / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
            ce->values_raw[i].counter = vl->values[i].counter;
        }
        break;

        case DS_TYPE_GAUGE:
            ce->values_raw[i].gauge = vl->values[i].gauge;
            ce->values_gauge[i] = vl->values[i].gauge;
            break;

        case DS_TYPE_DERIVE:
        {
            derive_t diff = vl->values[i].derive - ce->values_raw[i].derive;

            ce->values_gauge[i] = ((double) diff)
                                  / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
            ce->values_raw[i].derive = vl->values[i].derive;
        }
        break;

        case DS_TYPE_ABSOLUTE:
            ce->values_gauge[i] = ((double) vl->values[i].absolute)
                                  / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
            ce->values_raw[i].absolute = vl->values[i].absolute;
            break;

        default:
            /* This shouldn't happen. */
            pthread_mutex_unlock (&cache_lock);
            ERROR ("uc_update: Don't know how to handle data source type %i.",
                   ds->ds[i].type);
            return (-1);
        } /* switch (ds->ds[i].type) */

        DEBUG ("uc_update: %s: ds[%zu] = %lf", name, i, ce->values_gauge[i]);
    } /* for (i) */

    /* Update the history if it exists. */
    if (ce->history != NULL)
    {
        assert (ce->history_index < ce->history_length);
        for (i = 0; i < ce->values_num; i++)
        {
            size_t hist_idx = (ce->values_num * ce->history_index) + i;
            ce->history[hist_idx] = ce->values_gauge[i];
        }

        assert (ce->history_length > 0);
        ce->history_index = (ce->history_index + 1) % ce->history_length;
    }

    /* Prune invalid gauge data */
    uc_check_range (ds, ce);

    ce->last_time = vl->time;
    ce->last_update = cdtime ();
    ce->interval = vl->interval;

    pthread_mutex_unlock (&cache_lock);

    return (0);
} /* int uc_update */
コード例 #18
0
static int basic_aggregator_submit_resultvalue (
	const aggregator_definition_t *agg,
	c_avl_tree_t *ds_data
	)
{
	value_t *values;
	value_list_t vl = VALUE_LIST_INIT;
	const data_set_t *ds;
	char *identifier;
	char *hostname;
	char *plugin;
	char *plugin_instance;
	char *type;
	char *type_instance;
	int  status;
	int i;
	int submit_ok;
	aggregator_operation_e operation;
	c_avl_iterator_t *iter;
	char *key_instance;
	c_avl_tree_t *ds_tree;

	identifier = sstrdup (agg->resultvalue);

	status = parse_identifier (identifier, &hostname,
					&plugin, &plugin_instance,
					&type, &type_instance);
	if (status != 0)
	{
		ERROR (OUTPUT_PREFIX_STRING "Cannot parse value `%s'.", agg->resultvalue);
		sfree (identifier);
		return (-1);
	}

	if((NULL == type) || (type[0] == '\0')) {
		ERROR (OUTPUT_PREFIX_STRING "parse_identifier() : type == NULL or is empty (identifier='%s')", identifier);
		sfree (identifier);
		return (-1);
	}

	ds = plugin_get_ds (type);
	if (ds == NULL)
	{
		ERROR (OUTPUT_PREFIX_STRING "plugin_get_ds (%s) == NULL", type);
		sfree (identifier);
		return (-1);
	}
	
	if(NULL == (values = malloc(ds->ds_num* sizeof(*values)))) {
		ERROR (OUTPUT_PREFIX_STRING "Could not allocate memory");
		sfree (identifier);
		return (-1);
	}
	
	iter = c_avl_get_iterator (ds_data);
	while (c_avl_iterator_next (iter, (void *) &key_instance, (void *) &ds_tree) == 0) {
	
		for (operation=0; operation < nb_enum_in_aggregator_operation_e; operation++) {
			if(0 == agg->operation[operation]) continue;
			memset(values, '\0', ds->ds_num*sizeof(*values));
			submit_ok = 1;
			for(i=0; i<ds->ds_num; i++) {
				value_and_nb_t *v;
				if(0 == c_avl_get(ds_tree, ds->ds[i].name,(void*)&v)) {
					switch(operation) {
						case operation_SUM : values[i].gauge = v->val; break;
						case operation_AVG : values[i].gauge = v->val/v->nb; break;
						default : assert (11 == 12); /* this should never happen */
					}
				} else {
						submit_ok = 0;
				}
	
			}
			if(submit_ok) {
				int l = 0;
				int pos = 0;
	
				vl.values = values;
				vl.values_len = ds->ds_num;
				
				if(plugin_instance) {
					l = strlen(plugin_instance);
				}
				if(l) {
					sstrncpy (vl.plugin_instance, plugin_instance, l+1);
					pos += l;
					sstrncpy (vl.plugin_instance + pos, "_", DATA_MAX_NAME_LEN - pos);
					pos += 1;
				}
				switch(operation) {
						case operation_SUM : sstrncpy (vl.plugin_instance + pos, "sum", DATA_MAX_NAME_LEN - pos); break;
						case operation_AVG : sstrncpy (vl.plugin_instance + pos, "avg", DATA_MAX_NAME_LEN - pos); break;
						default : assert (11 == 12); /* this should never happen */
				}
	
				sstrncpy (vl.host, hostname, sizeof (vl.host));
				sstrncpy (vl.plugin, plugin, sizeof (vl.plugin));
				sstrncpy (vl.type, type, sizeof (vl.type));
				if(key_instance[0]) sstrncpy (vl.type_instance, key_instance, sizeof (vl.type_instance));
	
#ifdef DEBUG_THIS
INFO(OUTPUT_PREFIX_STRING "DEBUG : dispatch '%s/%s-%s/%s%s%s'", vl.host, vl.plugin, vl.plugin_instance, vl.type,
	                                                               (vl.type_instance && vl.type_instance[0])?"-":"",
																   vl.type_instance?vl.type_instance:"(null)");
#endif
#ifdef DEBUG_THIS
do {
	int i;
	if(strcmp(vl.host, "aggregator_2")) break;
	for(i=0; i<vl.values_len; i++) {
INFO(OUTPUT_PREFIX_STRING "DEBUG : dispatch '%s/%s-%s/%s%s%s DS '%s'=%12e", vl.host, vl.plugin, vl.plugin_instance, vl.type,
	                                                               (vl.type_instance && vl.type_instance[0])?"-":"",
																   vl.type_instance?vl.type_instance:"(null)",
																   ds->ds[i].name, values[i].gauge
																   );
	}
} while(0);
#endif
				plugin_dispatch_values (&vl);
			}
		}
	} /* while (c_avl_iterator_next) */
	c_avl_iterator_destroy (iter);
	sfree (identifier);
	return(0);
} /* void basic_aggregator_submit_resultvalue */
コード例 #19
0
ファイル: utils_cache.c プロジェクト: tabletcorry/collectd
int uc_get_history_by_name (const char *name,
    gauge_t *ret_history, size_t num_steps, size_t num_ds)
{
  cache_entry_t *ce = NULL;
  size_t i;
  int status = 0;

  pthread_mutex_lock (&cache_lock);

  status = c_avl_get (cache_tree, name, (void *) &ce);
  if (status != 0)
  {
    pthread_mutex_unlock (&cache_lock);
    return (-ENOENT);
  }

  if (((size_t) ce->values_num) != num_ds)
  {
    pthread_mutex_unlock (&cache_lock);
    return (-EINVAL);
  }

  /* Check if there are enough values available. If not, increase the buffer
   * size. */
  if (ce->history_length < num_steps)
  {
    gauge_t *tmp;
    size_t i;

    tmp = realloc (ce->history, sizeof (*ce->history)
	* num_steps * ce->values_num);
    if (tmp == NULL)
    {
      pthread_mutex_unlock (&cache_lock);
      return (-ENOMEM);
    }

    for (i = ce->history_length * ce->values_num;
	i < (num_steps * ce->values_num);
	i++)
      tmp[i] = NAN;

    ce->history = tmp;
    ce->history_length = num_steps;
  } /* if (ce->history_length < num_steps) */

  /* Copy the values to the output buffer. */
  for (i = 0; i < num_steps; i++)
  {
    size_t src_index;
    size_t dst_index;

    if (i < ce->history_index)
      src_index = ce->history_index - (i + 1);
    else
      src_index = ce->history_length + ce->history_index - (i + 1);
    src_index = src_index * num_ds;

    dst_index = i * num_ds;

    memcpy (ret_history + dst_index, ce->history + src_index,
	sizeof (*ret_history) * num_ds);
  }

  pthread_mutex_unlock (&cache_lock);

  return (0);
} /* int uc_get_history_by_name */
コード例 #20
0
ファイル: utils_cache.c プロジェクト: tabletcorry/collectd
int uc_update (const data_set_t *ds, const value_list_t *vl)
{
  char name[6 * DATA_MAX_NAME_LEN];
  cache_entry_t *ce = NULL;
  int send_okay_notification = 0;
  time_t update_delay = 0;
  notification_t n;
  int status;
  int i;

  if (FORMAT_VL (name, sizeof (name), vl) != 0)
  {
    ERROR ("uc_update: FORMAT_VL failed.");
    return (-1);
  }

  pthread_mutex_lock (&cache_lock);

  status = c_avl_get (cache_tree, name, (void *) &ce);
  if (status != 0) /* entry does not yet exist */
  {
    status = uc_insert (ds, vl, name);
    pthread_mutex_unlock (&cache_lock);
    return (status);
  }

  assert (ce != NULL);
  assert (ce->values_num == ds->ds_num);

  if (ce->last_time >= vl->time)
  {
    pthread_mutex_unlock (&cache_lock);
    NOTICE ("uc_update: Value too old: name = %s; value time = %u; "
	"last cache update = %u;",
	name, (unsigned int) vl->time, (unsigned int) ce->last_time);
    return (-1);
  }

  /* Send a notification (after the lock has been released) if we switch the
   * state from something else to `okay'. */
  if (ce->state == STATE_MISSING)
  {
    send_okay_notification = 1;
    ce->state = STATE_OKAY;
    update_delay = time (NULL) - ce->last_update;
  }

  for (i = 0; i < ds->ds_num; i++)
  {
    switch (ds->ds[i].type)
    {
      case DS_TYPE_COUNTER:
	{
	  counter_t diff;

	  /* check if the counter has wrapped around */
	  if (vl->values[i].counter < ce->values_raw[i].counter)
	  {
	    if (ce->values_raw[i].counter <= 4294967295U)
	      diff = (4294967295U - ce->values_raw[i].counter)
		+ vl->values[i].counter;
	    else
	      diff = (18446744073709551615ULL - ce->values_raw[i].counter)
		+ vl->values[i].counter;
	  }
	  else /* counter has NOT wrapped around */
	  {
	    diff = vl->values[i].counter - ce->values_raw[i].counter;
	  }

	  ce->values_gauge[i] = ((double) diff)
	    / ((double) (vl->time - ce->last_time));
	  ce->values_raw[i].counter = vl->values[i].counter;
	}
	break;

      case DS_TYPE_GAUGE:
	ce->values_raw[i].gauge = vl->values[i].gauge;
	ce->values_gauge[i] = vl->values[i].gauge;
	break;

      case DS_TYPE_DERIVE:
	{
	  derive_t diff;

	  diff = vl->values[i].derive - ce->values_raw[i].derive;

	  ce->values_gauge[i] = ((double) diff)
	    / ((double) (vl->time - ce->last_time));
	  ce->values_raw[i].derive = vl->values[i].derive;
	}
	break;

      case DS_TYPE_ABSOLUTE:
	ce->values_gauge[i] = ((double) vl->values[i].absolute)
	  / ((double) (vl->time - ce->last_time));
	ce->values_raw[i].absolute = vl->values[i].absolute;
	break;

      default:
	/* This shouldn't happen. */
	pthread_mutex_unlock (&cache_lock);
	ERROR ("uc_update: Don't know how to handle data source type %i.",
	    ds->ds[i].type);
	return (-1);
    } /* switch (ds->ds[i].type) */

    DEBUG ("uc_update: %s: ds[%i] = %lf", name, i, ce->values_gauge[i]);
  } /* for (i) */

  /* Update the history if it exists. */
  if (ce->history != NULL)
  {
    assert (ce->history_index < ce->history_length);
    for (i = 0; i < ce->values_num; i++)
    {
      size_t hist_idx = (ce->values_num * ce->history_index) + i;
      ce->history[hist_idx] = ce->values_gauge[i];
    }

    assert (ce->history_length > 0);
    ce->history_index = (ce->history_index + 1) % ce->history_length;
  }

  /* Prune invalid gauge data */
  uc_check_range (ds, ce);

  ce->last_time = vl->time;
  ce->last_update = time (NULL);
  ce->interval = vl->interval;

  pthread_mutex_unlock (&cache_lock);

  if (send_okay_notification == 0)
    return (0);

  /* Do not send okay notifications for uninteresting values, i. e. values for
   * which no threshold is configured. */
  status = ut_check_interesting (name);
  if (status <= 0)
    return (0);

  /* Initialize the notification */
  memset (&n, '\0', sizeof (n));
  NOTIFICATION_INIT_VL (&n, vl, ds);

  n.severity = NOTIF_OKAY;
  n.time = vl->time;

  ssnprintf (n.message, sizeof (n.message),
      "Received a value for %s. It was missing for %u seconds.",
      name, (unsigned int) update_delay);

  plugin_dispatch_notification (&n);

  return (0);
} /* int uc_update */
コード例 #21
0
static int
basic_aggregator_update_aggregator(char *identifier, c_avl_tree_t *ds_data, aggregator_definition_t *agg) {
		char *identifier_copy;
		char *hostname;
		char *plugin;
		char *plugin_instance;
		char *type;
		char *type_instance;
		gauge_t *values;
		size_t values_num;
		int status;
		size_t i;
		const data_set_t *ds;

		/* parse_identifier() modifies its first argument,
		 * returning pointers into it */
		identifier_copy = sstrdup (identifier);

		status = parse_identifier (identifier_copy, &hostname,
						&plugin, &plugin_instance,
						&type, &type_instance);
		if (status != 0)
		{
			WARNING (OUTPUT_PREFIX_STRING "Cannot parse value `%s'.", identifier);
			WARNING (OUTPUT_PREFIX_STRING "Value `%s' is removed from the aggregator '%s'.", identifier, agg->resultvalue);
			sfree (identifier_copy);
			return(1);
		}

		ds = plugin_get_ds (type);
		if (ds == NULL)
		{
			WARNING (OUTPUT_PREFIX_STRING "plugin_get_ds (%s) == NULL;", type);
			WARNING (OUTPUT_PREFIX_STRING "Value `%s' is removed from the aggregator '%s'.", identifier, agg->resultvalue);
			sfree (identifier_copy);
			return(1);
		}

		values = NULL;
		values_num = 0;
		status = uc_get_rate_by_name (identifier, &values, &values_num);
		if (status != 0)
		{
			DEBUG(OUTPUT_PREFIX_STRING "uc_get_rate_by_name failed for %s", identifier);
			sfree (identifier_copy);
			return(2);
		}

		if ((size_t) ds->ds_num != values_num)
		{
			ERROR ("ds[%s]->ds_num = %i, "
							"but uc_get_rate_by_name returned %u values.",
							ds->type, ds->ds_num, (unsigned int) values_num);
			sfree (values);
			sfree (identifier_copy);
			return (-1);
		}

		for (i = 0; i < values_num; i++)
		{
			if ( ! isnan (values[i]))
			{
				char *k;
				c_avl_tree_t *t;
				value_and_nb_t *v;

				if(0 != c_avl_get(ds_data, type_instance?type_instance:"",(void*)&t)) {
					if(NULL == (t = c_avl_create((void *) strcmp))) {
						ERROR (OUTPUT_PREFIX_STRING "Could not allocate memory for tree");
						sfree (identifier_copy);
						return(-1);

					}
					if(NULL == (k=strdup(type_instance?type_instance:""))) {
						ERROR (OUTPUT_PREFIX_STRING "Could not allocate memory");
						c_avl_destroy(t);
						sfree (identifier_copy);
						return(-1);
					}
					if(0 != c_avl_insert(ds_data, k,t)) {
						ERROR (OUTPUT_PREFIX_STRING "Could insert data into AVL tree");
						c_avl_destroy(t);
						sfree (identifier_copy);
						return(-1);
					}
				}
				if(0 != c_avl_get(t, ds->ds[i].name,(void*)&v)) {
					if(NULL == (k=strdup(ds->ds[i].name))) {
						ERROR (OUTPUT_PREFIX_STRING "Could not allocate memory");
						sfree (identifier_copy);
						return(-1);
					}
					if(NULL == (v=malloc(sizeof(*v)))) {
						ERROR (OUTPUT_PREFIX_STRING "Could not allocate memory");
						sfree (identifier_copy);
						return(-1);
					}
					v->val=0;
					v->nb=0;
					if(0 != c_avl_insert(t, k,v)) {
						ERROR (OUTPUT_PREFIX_STRING "Could insert data into AVL tree");
						sfree (identifier_copy);
						return(-1);
					}
				}
				v->val += values[i];
				v->nb +=1;
#ifdef DEBUG_THIS
				if(values[i] > 1000) {

INFO(OUTPUT_PREFIX_STRING "DEBUG : ATTENTION '%s/%s-%s/%s%s%s DS '%s'=%12e", hostname, plugin, plugin_instance, type,
	                                                               (type_instance && type_instance[0])?"-":"",
																   type_instance?type_instance:"(null)",
																   ds->ds[i].name, values[i]
																   );
				}
#endif

			}
		}

		sfree (values);
		sfree (identifier_copy);
		return(status);
}
コード例 #22
0
ファイル: utils_cache.c プロジェクト: tabletcorry/collectd
static int uc_send_notification (const char *name)
{
  cache_entry_t *ce = NULL;
  int status;

  char *name_copy;
  char *host;
  char *plugin;
  char *plugin_instance;
  char *type;
  char *type_instance;

  notification_t n;

  name_copy = strdup (name);
  if (name_copy == NULL)
  {
    ERROR ("uc_send_notification: strdup failed.");
    return (-1);
  }

  status = parse_identifier (name_copy, &host,
      &plugin, &plugin_instance,
      &type, &type_instance);
  if (status != 0)
  {
    ERROR ("uc_send_notification: Cannot parse name `%s'", name);
    return (-1);
  }

  /* Copy the associative members */
  notification_init (&n, NOTIF_FAILURE, /* host = */ NULL,
      host, plugin, plugin_instance, type, type_instance);

  sfree (name_copy);
  name_copy = host = plugin = plugin_instance = type = type_instance = NULL;

  pthread_mutex_lock (&cache_lock);

  /*
   * Set the time _after_ getting the lock because we don't know how long
   * acquiring the lock takes and we will use this time later to decide
   * whether or not the state is OKAY.
   */
  n.time = time (NULL);

  status = c_avl_get (cache_tree, name, (void *) &ce);
  if (status != 0)
  {
    pthread_mutex_unlock (&cache_lock);
    sfree (name_copy);
    return (-1);
  }
    
  /* Check if the entry has been updated in the meantime */
  if ((n.time - ce->last_update) < (2 * ce->interval))
  {
    ce->state = STATE_OKAY;
    pthread_mutex_unlock (&cache_lock);
    sfree (name_copy);
    return (-1);
  }

  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);

  plugin_dispatch_notification (&n);

  return (0);
} /* int uc_send_notification */
コード例 #23
0
ファイル: curl_json.c プロジェクト: karcaw/collectd
static int cj_config_add_key (cj_t *db, /* {{{ */
                              oconfig_item_t *ci)
{
    cj_key_t *key;
    int status;
    int i;

    if ((ci->values_num != 1)
            || (ci->values[0].type != OCONFIG_TYPE_STRING))
    {
        WARNING ("curl_json plugin: The `Key' block "
                 "needs exactly one string argument.");
        return (-1);
    }

    key = (cj_key_t *) malloc (sizeof (*key));
    if (key == NULL)
    {
        ERROR ("curl_json plugin: malloc failed.");
        return (-1);
    }
    memset (key, 0, sizeof (*key));
    key->magic = CJ_KEY_MAGIC;

    if (strcasecmp ("Key", ci->key) == 0)
    {
        status = cf_util_get_string (ci, &key->path);
        if (status != 0)
        {
            sfree (key);
            return (status);
        }
    }
    else
    {
        ERROR ("curl_json plugin: cj_config: "
               "Invalid key: %s", ci->key);
        return (-1);
    }

    status = 0;
    for (i = 0; i < ci->children_num; i++)
    {
        oconfig_item_t *child = ci->children + i;

        if (strcasecmp ("Type", child->key) == 0)
            status = cf_util_get_string (child, &key->type);
        else if (strcasecmp ("Instance", child->key) == 0)
            status = cf_util_get_string (child, &key->instance);
        else
        {
            WARNING ("curl_json plugin: Option `%s' not allowed here.", child->key);
            status = -1;
        }

        if (status != 0)
            break;
    } /* for (i = 0; i < ci->children_num; i++) */

    while (status == 0)
    {
        if (key->type == NULL)
        {
            WARNING ("curl_json plugin: `Type' missing in `Key' block.");
            status = -1;
        }

        break;
    } /* while (status == 0) */

    /* store path in a tree that will match the json map structure, example:
     * "httpd/requests/count",
     * "httpd/requests/current" ->
     * { "httpd": { "requests": { "count": $key, "current": $key } } }
     */
    if (status == 0)
    {
        char *ptr;
        char *name;
        char ent[PATH_MAX];
        c_avl_tree_t *tree;

        if (db->tree == NULL)
            db->tree = cj_avl_create();

        tree = db->tree;
        name = key->path;
        ptr = key->path;
        if (*ptr == '/')
            ++ptr;

        name = ptr;
        while (*ptr)
        {
            if (*ptr == '/')
            {
                c_avl_tree_t *value;
                int len;

                len = ptr-name;
                if (len == 0)
                    break;
                len = COUCH_MIN(len, sizeof (ent)-1);
                sstrncpy (ent, name, len+1);

                if (c_avl_get (tree, ent, (void *) &value) != 0)
                {
                    value = cj_avl_create ();
                    c_avl_insert (tree, strdup (ent), value);
                }

                tree = value;
                name = ptr+1;
            }
            ++ptr;
        }
        if (*name)
            c_avl_insert (tree, strdup(name), key);
        else
        {
            ERROR ("curl_json plugin: invalid key: %s", key->path);
            status = -1;
        }
    }

    return (status);
} /* }}} int cj_config_add_key */
コード例 #24
0
ファイル: utils_cache.c プロジェクト: tabletcorry/collectd
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 */