Code

rrdtool plugin: Assure that values, that are older then the newest value in the cache...
[collectd.git] / src / rrdtool.c
1 /**
2  * collectd - src/rrdtool.c
3  * Copyright (C) 2006,2007  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Florian octo Forster <octo at verplant.org>
20  **/
22 #include "collectd.h"
23 #include "plugin.h"
24 #include "common.h"
25 #include "utils_avltree.h"
27 #if HAVE_PTHREAD_H
28 # include <pthread.h>
29 #endif
31 /*
32  * Private types
33  */
34 struct rrd_cache_s
35 {
36         int    values_num;
37         char **values;
38         time_t first_value;
39         time_t last_value;
40 };
41 typedef struct rrd_cache_s rrd_cache_t;
43 /*
44  * Private variables
45  */
46 static int rra_timespans[] =
47 {
48         3600,
49         86400,
50         604800,
51         2678400,
52         31622400
53 };
54 static int rra_timespans_num = STATIC_ARRAY_SIZE (rra_timespans);
56 static int *rra_timespans_custom = NULL;
57 static int rra_timespans_custom_num = 0;
59 static char *rra_types[] =
60 {
61         "AVERAGE",
62         "MIN",
63         "MAX"
64 };
65 static int rra_types_num = STATIC_ARRAY_SIZE (rra_types);
67 static const char *config_keys[] =
68 {
69         "CacheTimeout",
70         "CacheFlush",
71         "DataDir",
72         "StepSize",
73         "HeartBeat",
74         "RRARows",
75         "RRATimespan",
76         "XFF"
77 };
78 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
80 static char   *datadir   = NULL;
81 static int     stepsize  = 0;
82 static int     heartbeat = 0;
83 static int     rrarows   = 1200;
84 static double  xff       = 0.1;
86 static int         cache_timeout = 0;
87 static int         cache_flush_timeout = 0;
88 static time_t      cache_flush_last;
89 static avl_tree_t *cache = NULL;
90 static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
92 /* * * * * * * * * *
93  * WARNING:  Magic *
94  * * * * * * * * * */
95 static int rra_get (char ***ret)
96 {
97         static char **rra_def = NULL;
98         static int rra_num = 0;
100         int *rts;
101         int  rts_num;
103         int rra_max;
105         int span;
107         int cdp_num;
108         int cdp_len;
109         int i, j;
111         char buffer[64];
113         if ((rra_num != 0) && (rra_def != NULL))
114         {
115                 *ret = rra_def;
116                 return (rra_num);
117         }
119         /* Use the configured timespans or fall back to the built-in defaults */
120         if (rra_timespans_custom_num != 0)
121         {
122                 rts = rra_timespans_custom;
123                 rts_num = rra_timespans_custom_num;
124         }
125         else
126         {
127                 rts = rra_timespans;
128                 rts_num = rra_timespans_num;
129         }
131         rra_max = rts_num * rra_types_num;
133         if ((rra_def = (char **) malloc ((rra_max + 1) * sizeof (char *))) == NULL)
134                 return (-1);
135         memset (rra_def, '\0', (rra_max + 1) * sizeof (char *));
137         if ((stepsize <= 0) || (rrarows <= 0))
138         {
139                 *ret = NULL;
140                 return (-1);
141         }
143         cdp_len = 0;
144         for (i = 0; i < rts_num; i++)
145         {
146                 span = rts[i];
148                 if ((span / stepsize) < rrarows)
149                         continue;
151                 if (cdp_len == 0)
152                         cdp_len = 1;
153                 else
154                         cdp_len = (int) floor (((double) span)
155                                         / ((double) (rrarows * stepsize)));
157                 cdp_num = (int) ceil (((double) span)
158                                 / ((double) (cdp_len * stepsize)));
160                 for (j = 0; j < rra_types_num; j++)
161                 {
162                         if (rra_num >= rra_max)
163                                 break;
165                         if (snprintf (buffer, sizeof (buffer), "RRA:%s:%3.1f:%u:%u",
166                                                 rra_types[j], xff,
167                                                 cdp_len, cdp_num) >= sizeof (buffer))
168                         {
169                                 ERROR ("rra_get: Buffer would have been truncated.");
170                                 continue;
171                         }
173                         rra_def[rra_num++] = sstrdup (buffer);
174                 }
175         }
177 #if COLLECT_DEBUG
178         DEBUG ("rra_num = %i", rra_num);
179         for (i = 0; i < rra_num; i++)
180                 DEBUG ("  %s", rra_def[i]);
181 #endif
183         *ret = rra_def;
184         return (rra_num);
187 static void ds_free (int ds_num, char **ds_def)
189         int i;
191         for (i = 0; i < ds_num; i++)
192                 if (ds_def[i] != NULL)
193                         free (ds_def[i]);
194         free (ds_def);
197 static int ds_get (char ***ret, const data_set_t *ds)
199         char **ds_def;
200         int ds_num;
202         char min[32];
203         char max[32];
204         char buffer[128];
206         DEBUG ("ds->ds_num = %i", ds->ds_num);
208         ds_def = (char **) malloc (ds->ds_num * sizeof (char *));
209         if (ds_def == NULL)
210         {
211                 char errbuf[1024];
212                 ERROR ("rrdtool plugin: malloc failed: %s",
213                                 sstrerror (errno, errbuf, sizeof (errbuf)));
214                 return (-1);
215         }
216         memset (ds_def, '\0', ds->ds_num * sizeof (char *));
218         for (ds_num = 0; ds_num < ds->ds_num; ds_num++)
219         {
220                 data_source_t *d = ds->ds + ds_num;
221                 char *type;
222                 int status;
224                 ds_def[ds_num] = NULL;
226                 if (d->type == DS_TYPE_COUNTER)
227                         type = "COUNTER";
228                 else if (d->type == DS_TYPE_GAUGE)
229                         type = "GAUGE";
230                 else
231                 {
232                         ERROR ("rrdtool plugin: Unknown DS type: %i",
233                                         d->type);
234                         break;
235                 }
237                 if (isnan (d->min))
238                 {
239                         strcpy (min, "U");
240                 }
241                 else
242                 {
243                         snprintf (min, sizeof (min), "%lf", d->min);
244                         min[sizeof (min) - 1] = '\0';
245                 }
247                 if (isnan (d->max))
248                 {
249                         strcpy (max, "U");
250                 }
251                 else
252                 {
253                         snprintf (max, sizeof (max), "%lf", d->max);
254                         max[sizeof (max) - 1] = '\0';
255                 }
257                 status = snprintf (buffer, sizeof (buffer),
258                                 "DS:%s:%s:%i:%s:%s",
259                                 d->name, type, heartbeat,
260                                 min, max);
261                 if ((status < 1) || (status >= sizeof (buffer)))
262                         break;
264                 ds_def[ds_num] = sstrdup (buffer);
265         } /* for ds_num = 0 .. ds->ds_num */
267 #if COLLECT_DEBUG
269         int i;
270         DEBUG ("ds_num = %i", ds_num);
271         for (i = 0; i < ds_num; i++)
272                 DEBUG ("  %s", ds_def[i]);
274 #endif
276         if (ds_num != ds->ds_num)
277         {
278                 ds_free (ds_num, ds_def);
279                 return (-1);
280         }
282         *ret = ds_def;
283         return (ds_num);
286 static int rrd_create_file (char *filename, const data_set_t *ds)
288         char **argv;
289         int argc;
290         char **rra_def;
291         int rra_num;
292         char **ds_def;
293         int ds_num;
294         int i, j;
295         char stepsize_str[16];
296         int status = 0;
298         if (check_create_dir (filename))
299                 return (-1);
301         if ((rra_num = rra_get (&rra_def)) < 1)
302         {
303                 ERROR ("rrd_create_file failed: Could not calculate RRAs");
304                 return (-1);
305         }
307         if ((ds_num = ds_get (&ds_def, ds)) < 1)
308         {
309                 ERROR ("rrd_create_file failed: Could not calculate DSes");
310                 return (-1);
311         }
313         argc = ds_num + rra_num + 4;
315         if ((argv = (char **) malloc (sizeof (char *) * (argc + 1))) == NULL)
316         {
317                 char errbuf[1024];
318                 ERROR ("rrd_create failed: %s",
319                                 sstrerror (errno, errbuf, sizeof (errbuf)));
320                 return (-1);
321         }
323         status = snprintf (stepsize_str, sizeof (stepsize_str),
324                         "%i", stepsize);
325         if ((status < 1) || (status >= sizeof (stepsize_str)))
326         {
327                 ERROR ("rrdtool plugin: snprintf failed.");
328                 return (-1);
329         }
331         argv[0] = "create";
332         argv[1] = filename;
333         argv[2] = "-s";
334         argv[3] = stepsize_str;
336         j = 4;
337         for (i = 0; i < ds_num; i++)
338                 argv[j++] = ds_def[i];
339         for (i = 0; i < rra_num; i++)
340                 argv[j++] = rra_def[i];
341         argv[j] = NULL;
343         optind = 0; /* bug in librrd? */
344         rrd_clear_error ();
345         if (rrd_create (argc, argv) == -1)
346         {
347                 ERROR ("rrd_create failed: %s: %s", filename, rrd_get_error ());
348                 status = -1;
349         }
351         free (argv);
352         ds_free (ds_num, ds_def);
354         return (status);
357 static int value_list_to_string (char *buffer, int buffer_len,
358                 const data_set_t *ds, const value_list_t *vl)
360         int offset;
361         int status;
362         int i;
364         memset (buffer, '\0', sizeof (buffer_len));
366         status = snprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
367         if ((status < 1) || (status >= buffer_len))
368                 return (-1);
369         offset = status;
371         for (i = 0; i < ds->ds_num; i++)
372         {
373                 if ((ds->ds[i].type != DS_TYPE_COUNTER)
374                                 && (ds->ds[i].type != DS_TYPE_GAUGE))
375                         return (-1);
377                 if (ds->ds[i].type == DS_TYPE_COUNTER)
378                         status = snprintf (buffer + offset, buffer_len - offset,
379                                         ":%llu", vl->values[i].counter);
380                 else
381                         status = snprintf (buffer + offset, buffer_len - offset,
382                                         ":%lf", vl->values[i].gauge);
384                 if ((status < 1) || (status >= (buffer_len - offset)))
385                         return (-1);
387                 offset += status;
388         } /* for ds->ds_num */
390         return (0);
391 } /* int value_list_to_string */
393 static int value_list_to_filename (char *buffer, int buffer_len,
394                 const data_set_t *ds, const value_list_t *vl)
396         int offset = 0;
397         int status;
399         if (datadir != NULL)
400         {
401                 status = snprintf (buffer + offset, buffer_len - offset,
402                                 "%s/", datadir);
403                 if ((status < 1) || (status >= buffer_len - offset))
404                         return (-1);
405                 offset += status;
406         }
408         status = snprintf (buffer + offset, buffer_len - offset,
409                         "%s/", vl->host);
410         if ((status < 1) || (status >= buffer_len - offset))
411                 return (-1);
412         offset += status;
414         if (strlen (vl->plugin_instance) > 0)
415                 status = snprintf (buffer + offset, buffer_len - offset,
416                                 "%s-%s/", vl->plugin, vl->plugin_instance);
417         else
418                 status = snprintf (buffer + offset, buffer_len - offset,
419                                 "%s/", vl->plugin);
420         if ((status < 1) || (status >= buffer_len - offset))
421                 return (-1);
422         offset += status;
424         if (strlen (vl->type_instance) > 0)
425                 status = snprintf (buffer + offset, buffer_len - offset,
426                                 "%s-%s.rrd", ds->type, vl->type_instance);
427         else
428                 status = snprintf (buffer + offset, buffer_len - offset,
429                                 "%s.rrd", ds->type);
430         if ((status < 1) || (status >= buffer_len - offset))
431                 return (-1);
432         offset += status;
434         return (0);
435 } /* int value_list_to_filename */
437 static rrd_cache_t *rrd_cache_insert (const char *filename,
438                 const char *value, time_t value_time)
440         rrd_cache_t *rc = NULL;
441         int new_rc = 0;
443         if (cache != NULL)
444                 avl_get (cache, filename, (void *) &rc);
446         if (rc == NULL)
447         {
448                 rc = (rrd_cache_t *) malloc (sizeof (rrd_cache_t));
449                 if (rc == NULL)
450                         return (NULL);
451                 rc->values_num = 0;
452                 rc->values = NULL;
453                 rc->first_value = 0;
454                 rc->last_value = 0;
455                 new_rc = 1;
456         }
458         if (rc->last_value >= value_time)
459         {
460                 WARNING ("rrdtool plugin: (rc->last_value = %u) >= (value_time = %u)",
461                                 (unsigned int) rc->last_value,
462                                 (unsigned int) value_time);
463                 return (NULL);
464         }
466         rc->values = (char **) realloc ((void *) rc->values,
467                         (rc->values_num + 1) * sizeof (char *));
468         if (rc->values == NULL)
469         {
470                 char errbuf[1024];
471                 ERROR ("rrdtool plugin: realloc failed: %s",
472                                 sstrerror (errno, errbuf, sizeof (errbuf)));
473                 if (cache != NULL)
474                 {
475                         void *cache_key = NULL;
476                         avl_remove (cache, filename, &cache_key, NULL);
477                         sfree (cache_key);
478                 }
479                 free (rc);
480                 return (NULL);
481         }
483         rc->values[rc->values_num] = strdup (value);
484         if (rc->values[rc->values_num] != NULL)
485                 rc->values_num++;
487         if (rc->values_num == 1)
488                 rc->first_value = value_time;
489         rc->last_value = value_time;
491         /* Insert if this is the first value */
492         if ((cache != NULL) && (new_rc == 1))
493         {
494                 void *cache_key = strdup (filename);
496                 if (cache_key == NULL)
497                 {
498                         char errbuf[1024];
499                         ERROR ("rrdtool plugin: strdup failed: %s",
500                                         sstrerror (errno, errbuf, sizeof (errbuf)));
501                         sfree (rc->values[0]);
502                         sfree (rc->values);
503                         sfree (rc);
504                         return (NULL);
505                 }
507                 avl_insert (cache, cache_key, rc);
508         }
510         DEBUG ("rrd_cache_insert (%s, %s, %u) = %p", filename, value,
511                         (unsigned int) value_time, (void *) rc);
513         return (rc);
514 } /* rrd_cache_t *rrd_cache_insert */
516 static int rrd_write_cache_entry (const char *filename, rrd_cache_t *rc)
518         char **argv;
519         int    argc;
521         char *fn;
522         int status;
524         int i;
526         if (rc->values_num < 1)
527                 return (0);
529         argc = rc->values_num + 2;
530         argv = (char **) malloc ((argc + 1) * sizeof (char *));
531         if (argv == NULL)
532                 return (-1);
534         fn = strdup (filename);
535         if (fn == NULL)
536         {
537                 free (argv);
538                 return (-1);
539         }
541         argv[0] = "update";
542         argv[1] = fn;
543         memcpy (argv + 2, rc->values, rc->values_num * sizeof (char *));
544         argv[argc] = NULL;
546         DEBUG ("rrd_update (argc = %i, argv = %p)", argc, (void *) argv);
548         optind = 0; /* bug in librrd? */
549         rrd_clear_error ();
550         status = rrd_update (argc, argv);
551         if (status != 0)
552         {
553                 WARNING ("rrd_update failed: %s: %s",
554                                 filename, rrd_get_error ());
555                 status = -1;
556         }
558         free (argv);
559         free (fn);
560         /* Free the value list of `rc' */
561         for (i = 0; i < rc->values_num; i++)
562                 free (rc->values[i]);
563         free (rc->values);
564         rc->values = NULL;
565         rc->values_num = 0;
567         return (status);
568 } /* int rrd_write_cache_entry */
570 static void rrd_cache_flush (int timeout)
572         rrd_cache_t *rc;
573         time_t       now;
575         char **keys = NULL;
576         int    keys_num = 0;
578         char *key;
579         avl_iterator_t *iter;
580         int i;
582         if (cache == NULL)
583                 return;
585         DEBUG ("Flushing cache, timeout = %i", timeout);
587         now = time (NULL);
589         /* Build a list of entries to be flushed */
590         iter = avl_get_iterator (cache);
591         while (avl_iterator_next (iter, (void *) &key, (void *) &rc) == 0)
592         {
593                 DEBUG ("key = %s; age = %i;", key, now - rc->first_value);
594                 if ((now - rc->first_value) >= timeout)
595                 {
596                         keys = (char **) realloc ((void *) keys,
597                                         (keys_num + 1) * sizeof (char *));
598                         if (keys == NULL)
599                         {
600                                 char errbuf[1024];
601                                 ERROR ("rrdtool plugin: "
602                                                 "realloc failed: %s",
603                                                 sstrerror (errno, errbuf,
604                                                         sizeof (errbuf)));
605                                 avl_iterator_destroy (iter);
606                                 return;
607                         }
608                         keys[keys_num] = key;
609                         keys_num++;
610                 }
611         } /* while (avl_iterator_next) */
612         avl_iterator_destroy (iter);
613         
614         for (i = 0; i < keys_num; i++)
615         {
616                 if (avl_remove (cache, keys[i], (void *) &key, (void *) &rc) != 0)
617                 {
618                         DEBUG ("avl_remove (%s) failed.", keys[i]);
619                         continue;
620                 }
622                 rrd_write_cache_entry (keys[i], rc);
623                 /* rc's value-list is free's by `rrd_write_cache_entry' */
624                 sfree (rc);
625                 sfree (key);
626                 keys[i] = NULL;
627         } /* for (i = 0..keys_num) */
629         free (keys);
630         DEBUG ("Flushed %i value(s)", keys_num);
632         cache_flush_last = now;
633 } /* void rrd_cache_flush */
635 static int rrd_write (const data_set_t *ds, const value_list_t *vl)
637         struct stat  statbuf;
638         char         filename[512];
639         char         values[512];
640         rrd_cache_t *rc;
641         time_t       now;
643         if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
644                 return (-1);
646         if (value_list_to_string (values, sizeof (values), ds, vl) != 0)
647                 return (-1);
649         if (stat (filename, &statbuf) == -1)
650         {
651                 if (errno == ENOENT)
652                 {
653                         if (rrd_create_file (filename, ds))
654                                 return (-1);
655                 }
656                 else
657                 {
658                         char errbuf[1024];
659                         ERROR ("stat(%s) failed: %s", filename,
660                                         sstrerror (errno, errbuf,
661                                                 sizeof (errbuf)));
662                         return (-1);
663                 }
664         }
665         else if (!S_ISREG (statbuf.st_mode))
666         {
667                 ERROR ("stat(%s): Not a regular file!",
668                                 filename);
669                 return (-1);
670         }
672         pthread_mutex_lock (&cache_lock);
673         rc = rrd_cache_insert (filename, values, vl->time);
674         if (rc == NULL)
675         {
676                 pthread_mutex_unlock (&cache_lock);
677                 return (-1);
678         }
680         if (cache == NULL)
681         {
682                 rrd_write_cache_entry (filename, rc);
683                 /* rc's value-list is free's by `rrd_write_cache_entry' */
684                 sfree (rc);
685                 pthread_mutex_unlock (&cache_lock);
686                 return (0);
687         }
689         now = time (NULL);
691         DEBUG ("age (%s) = %i", filename, now - rc->first_value);
693         /* `rc' is not free'd here, because we'll likely reuse it. If not, then
694          * the next flush will remove this entry.  */
695         if ((now - rc->first_value) >= cache_timeout)
696                 rrd_write_cache_entry (filename, rc);
698         if ((now - cache_flush_last) >= cache_flush_timeout)
699                 rrd_cache_flush (cache_flush_timeout);
701         pthread_mutex_unlock (&cache_lock);
702         return (0);
703 } /* int rrd_write */
705 static int rrd_config (const char *key, const char *value)
707         if (strcasecmp ("CacheTimeout", key) == 0)
708         {
709                 int tmp = atoi (value);
710                 if (tmp < 0)
711                 {
712                         fprintf (stderr, "rrdtool: `CacheTimeout' must "
713                                         "be greater than 0.\n");
714                         return (1);
715                 }
716                 cache_timeout = tmp;
717         }
718         else if (strcasecmp ("CacheFlush", key) == 0)
719         {
720                 int tmp = atoi (value);
721                 if (tmp < 0)
722                 {
723                         fprintf (stderr, "rrdtool: `CacheFlush' must "
724                                         "be greater than 0.\n");
725                         return (1);
726                 }
727                 cache_flush_timeout = tmp;
728         }
729         else if (strcasecmp ("DataDir", key) == 0)
730         {
731                 if (datadir != NULL)
732                         free (datadir);
733                 datadir = strdup (value);
734                 if (datadir != NULL)
735                 {
736                         int len = strlen (datadir);
737                         while ((len > 0) && (datadir[len - 1] == '/'))
738                         {
739                                 len--;
740                                 datadir[len] = '\0';
741                         }
742                         if (len <= 0)
743                         {
744                                 free (datadir);
745                                 datadir = NULL;
746                         }
747                 }
748         }
749         else if (strcasecmp ("StepSize", key) == 0)
750         {
751                 int tmp = atoi (value);
752                 if (tmp <= 0)
753                 {
754                         fprintf (stderr, "rrdtool: `StepSize' must "
755                                         "be greater than 0.\n");
756                         return (1);
757                 }
758                 stepsize = tmp;
759         }
760         else if (strcasecmp ("HeartBeat", key) == 0)
761         {
762                 int tmp = atoi (value);
763                 if (tmp <= 0)
764                 {
765                         fprintf (stderr, "rrdtool: `HeartBeat' must "
766                                         "be greater than 0.\n");
767                         return (1);
768                 }
769                 heartbeat = tmp;
770         }
771         else if (strcasecmp ("RRARows", key) == 0)
772         {
773                 int tmp = atoi (value);
774                 if (tmp <= 0)
775                 {
776                         fprintf (stderr, "rrdtool: `RRARows' must "
777                                         "be greater than 0.\n");
778                         return (1);
779                 }
780                 rrarows = tmp;
781         }
782         else if (strcasecmp ("RRATimespan", key) == 0)
783         {
784                 char *saveptr = NULL;
785                 char *dummy;
786                 char *ptr;
787                 char *value_copy;
788                 int *tmp_alloc;
790                 value_copy = strdup (value);
791                 if (value_copy == NULL)
792                         return (1);
794                 dummy = value_copy;
795                 while ((ptr = strtok_r (dummy, ", \t", &saveptr)) != NULL)
796                 {
797                         dummy = NULL;
798                         
799                         tmp_alloc = realloc (rra_timespans_custom,
800                                         sizeof (int) * (rra_timespans_custom_num + 1));
801                         if (tmp_alloc == NULL)
802                         {
803                                 fprintf (stderr, "rrdtool: realloc failed.\n");
804                                 free (value_copy);
805                                 return (1);
806                         }
807                         rra_timespans_custom = tmp_alloc;
808                         rra_timespans_custom[rra_timespans_custom_num] = atoi (ptr);
809                         if (rra_timespans_custom[rra_timespans_custom_num] != 0)
810                                 rra_timespans_custom_num++;
811                 } /* while (strtok_r) */
812                 free (value_copy);
813         }
814         else if (strcasecmp ("XFF", key) == 0)
815         {
816                 double tmp = atof (value);
817                 if ((tmp < 0.0) || (tmp >= 1.0))
818                 {
819                         fprintf (stderr, "rrdtool: `XFF' must "
820                                         "be in the range 0 to 1 (exclusive).");
821                         return (1);
822                 }
823                 xff = tmp;
824         }
825         else
826         {
827                 return (-1);
828         }
829         return (0);
830 } /* int rrd_config */
832 static int rrd_shutdown (void)
834         pthread_mutex_lock (&cache_lock);
835         rrd_cache_flush (-1);
836         if (cache != NULL)
837                 avl_destroy (cache);
838         cache = NULL;
839         pthread_mutex_unlock (&cache_lock);
841         return (0);
842 } /* int rrd_shutdown */
844 static int rrd_init (void)
846         if (stepsize <= 0)
847                 stepsize = interval_g;
848         if (heartbeat <= 0)
849                 heartbeat = 2 * interval_g;
851         if (heartbeat < interval_g)
852                 WARNING ("rrdtool plugin: Your `heartbeat' is "
853                                 "smaller than your `interval'. This will "
854                                 "likely cause problems.");
855         else if (stepsize < interval_g)
856                 WARNING ("rrdtool plugin: Your `stepsize' is "
857                                 "smaller than your `interval'. This will "
858                                 "create needlessly big RRD-files.");
860         pthread_mutex_lock (&cache_lock);
861         if (cache_timeout < 2)
862         {
863                 cache_timeout = 0;
864                 cache_flush_timeout = 0;
865         }
866         else
867         {
868                 if (cache_flush_timeout < cache_timeout)
869                         cache_flush_timeout = 10 * cache_timeout;
871                 cache = avl_create ((int (*) (const void *, const void *)) strcmp);
872                 cache_flush_last = time (NULL);
873                 plugin_register_shutdown ("rrdtool", rrd_shutdown);
874         }
875         pthread_mutex_unlock (&cache_lock);
877         DEBUG ("rrdtool plugin: rrd_init: datadir = %s; stepsize = %i;"
878                         " heartbeat = %i; rrarows = %i; xff = %lf;",
879                         (datadir == NULL) ? "(null)" : datadir,
880                         stepsize, heartbeat, rrarows, xff);
882         return (0);
883 } /* int rrd_init */
885 void module_register (void)
887         plugin_register_config ("rrdtool", rrd_config,
888                         config_keys, config_keys_num);
889         plugin_register_init ("rrdtool", rrd_init);
890         plugin_register_write ("rrdtool", rrd_write);