From: Florian Forster Date: Wed, 2 Jul 2008 21:04:54 +0000 (+0200) Subject: src/rrd_daemon.c: Implemented removal of unused tree nodes. X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=commitdiff_plain;h=28e399e75eb5a26a5ab1b65b7b18b4cfd69e263d src/rrd_daemon.c: Implemented removal of unused tree nodes. --- diff --git a/src/rrd_daemon.c b/src/rrd_daemon.c index feb1ce3..3163e18 100644 --- a/src/rrd_daemon.c +++ b/src/rrd_daemon.c @@ -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);