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,
* 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 */
|| ((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)
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);