Merge branch 'collectd-5.5'
[collectd.git] / src / daemon / meta_data.c
1 /**
2  * collectd - src/meta_data.c
3  * Copyright (C) 2008-2011  Florian octo Forster
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Florian octo Forster <octo at collectd.org>
25  **/
26
27 #include "collectd.h"
28 #include "plugin.h"
29 #include "meta_data.h"
30
31 /*
32  * Data types
33  */
34 union meta_value_u
35 {
36   char    *mv_string;
37   int64_t  mv_signed_int;
38   uint64_t mv_unsigned_int;
39   double   mv_double;
40   _Bool    mv_boolean;
41 };
42 typedef union meta_value_u meta_value_t;
43
44 struct meta_entry_s;
45 typedef struct meta_entry_s meta_entry_t;
46 struct meta_entry_s
47 {
48   char         *key;
49   meta_value_t  value;
50   int           type;
51   meta_entry_t *next;
52 };
53
54 struct meta_data_s
55 {
56   meta_entry_t   *head;
57   pthread_mutex_t lock;
58 };
59
60 /*
61  * Private functions
62  */
63 static char *md_strdup (const char *orig) /* {{{ */
64 {
65   size_t sz;
66   char *dest;
67
68   if (orig == NULL)
69     return (NULL);
70
71   sz = strlen (orig) + 1;
72   dest = malloc (sz);
73   if (dest == NULL)
74     return (NULL);
75
76   memcpy (dest, orig, sz);
77
78   return (dest);
79 } /* }}} char *md_strdup */
80
81 static meta_entry_t *md_entry_alloc (const char *key) /* {{{ */
82 {
83   meta_entry_t *e;
84
85   e = calloc (1, sizeof (*e));
86   if (e == NULL)
87   {
88     ERROR ("md_entry_alloc: calloc failed.");
89     return (NULL);
90   }
91
92   e->key = md_strdup (key);
93   if (e->key == NULL)
94   {
95     free (e);
96     ERROR ("md_entry_alloc: md_strdup failed.");
97     return (NULL);
98   }
99
100   e->type = 0;
101   e->next = NULL;
102
103   return (e);
104 } /* }}} meta_entry_t *md_entry_alloc */
105
106 /* XXX: The lock on md must be held while calling this function! */
107 static meta_entry_t *md_entry_clone_contents (const meta_entry_t *orig) /* {{{ */
108 {
109   meta_entry_t *copy;
110
111   /* WARNINGS :
112    *  - we do not check that orig != NULL here. You should have done it before.
113    *  - we do not set copy->next. DO NOT FORGET TO SET copy->next IN YOUR FUNCTION
114    */
115
116   copy = md_entry_alloc (orig->key);
117   if (copy == NULL)
118     return (NULL);
119   copy->type = orig->type;
120   if (copy->type == MD_TYPE_STRING)
121     copy->value.mv_string = strdup (orig->value.mv_string);
122   else
123     copy->value = orig->value;
124
125   return (copy);
126 } /* }}} meta_entry_t *md_entry_clone_contents */
127
128 static meta_entry_t *md_entry_clone (const meta_entry_t *orig) /* {{{ */
129 {
130   meta_entry_t *copy;
131
132   if (orig == NULL)
133     return (NULL);
134
135   copy = md_entry_clone_contents(orig);
136
137   copy->next = md_entry_clone (orig->next);
138   return (copy);
139 } /* }}} meta_entry_t *md_entry_clone */
140
141 static void md_entry_free (meta_entry_t *e) /* {{{ */
142 {
143   if (e == NULL)
144     return;
145
146   free (e->key);
147
148   if (e->type == MD_TYPE_STRING)
149     free (e->value.mv_string);
150
151   if (e->next != NULL)
152     md_entry_free (e->next);
153
154   free (e);
155 } /* }}} void md_entry_free */
156
157 static int md_entry_insert (meta_data_t *md, meta_entry_t *e) /* {{{ */
158 {
159   meta_entry_t *this;
160   meta_entry_t *prev;
161
162   if ((md == NULL) || (e == NULL))
163     return (-EINVAL);
164
165   pthread_mutex_lock (&md->lock);
166
167   prev = NULL;
168   this = md->head;
169   while (this != NULL)
170   {
171     if (strcasecmp (e->key, this->key) == 0)
172       break;
173
174     prev = this;
175     this = this->next;
176   }
177
178   if (this == NULL)
179   {
180     /* This key does not exist yet. */
181     if (md->head == NULL)
182       md->head = e;
183     else
184     {
185       assert (prev != NULL);
186       prev->next = e;
187     }
188
189     e->next = NULL;
190   }
191   else /* (this != NULL) */
192   {
193     if (prev == NULL)
194       md->head = e;
195     else
196       prev->next = e;
197
198     e->next = this->next;
199   }
200
201   pthread_mutex_unlock (&md->lock);
202
203   if (this != NULL)
204   {
205     this->next = NULL;
206     md_entry_free (this);
207   }
208
209   return (0);
210 } /* }}} int md_entry_insert */
211
212 /* XXX: The lock on md must be held while calling this function! */
213 static int md_entry_insert_clone (meta_data_t *md, meta_entry_t *orig) /* {{{ */
214 {
215   meta_entry_t *e;
216   meta_entry_t *this;
217   meta_entry_t *prev;
218
219   /* WARNINGS :
220    *  - we do not check that md and e != NULL here. You should have done it before.
221    *  - we do not use the lock. You should have set it before.
222    */
223
224   e = md_entry_clone_contents(orig);
225
226   prev = NULL;
227   this = md->head;
228   while (this != NULL)
229   {
230     if (strcasecmp (e->key, this->key) == 0)
231       break;
232
233     prev = this;
234     this = this->next;
235   }
236
237   if (this == NULL)
238   {
239     /* This key does not exist yet. */
240     if (md->head == NULL)
241       md->head = e;
242     else
243     {
244       assert (prev != NULL);
245       prev->next = e;
246     }
247
248     e->next = NULL;
249   }
250   else /* (this != NULL) */
251   {
252     if (prev == NULL)
253       md->head = e;
254     else
255       prev->next = e;
256
257     e->next = this->next;
258   }
259
260   if (this != NULL)
261   {
262     this->next = NULL;
263     md_entry_free (this);
264   }
265
266   return (0);
267 } /* }}} int md_entry_insert_clone */
268
269 /* XXX: The lock on md must be held while calling this function! */
270 static meta_entry_t *md_entry_lookup (meta_data_t *md, /* {{{ */
271     const char *key)
272 {
273   meta_entry_t *e;
274
275   if ((md == NULL) || (key == NULL))
276     return (NULL);
277
278   for (e = md->head; e != NULL; e = e->next)
279     if (strcasecmp (key, e->key) == 0)
280       break;
281
282   return (e);
283 } /* }}} meta_entry_t *md_entry_lookup */
284
285 /*
286  * Each value_list_t*, as it is going through the system, is handled by exactly
287  * one thread. Plugins which pass a value_list_t* to another thread, e.g. the
288  * rrdtool plugin, must create a copy first. The meta data within a
289  * value_list_t* is not thread safe and doesn't need to be.
290  *
291  * The meta data associated with cache entries are a different story. There, we
292  * need to ensure exclusive locking to prevent leaks and other funky business.
293  * This is ensured by the uc_meta_data_get_*() functions.
294  */
295
296 /*
297  * Public functions
298  */
299 meta_data_t *meta_data_create (void) /* {{{ */
300 {
301   meta_data_t *md;
302
303   md = calloc (1, sizeof (*md));
304   if (md == NULL)
305   {
306     ERROR ("meta_data_create: calloc failed.");
307     return (NULL);
308   }
309
310   pthread_mutex_init (&md->lock, /* attr = */ NULL);
311
312   return (md);
313 } /* }}} meta_data_t *meta_data_create */
314
315 meta_data_t *meta_data_clone (meta_data_t *orig) /* {{{ */
316 {
317   meta_data_t *copy;
318
319   if (orig == NULL)
320     return (NULL);
321
322   copy = meta_data_create ();
323   if (copy == NULL)
324     return (NULL);
325
326   pthread_mutex_lock (&orig->lock);
327   copy->head = md_entry_clone (orig->head);
328   pthread_mutex_unlock (&orig->lock);
329
330   return (copy);
331 } /* }}} meta_data_t *meta_data_clone */
332
333 int meta_data_clone_merge (meta_data_t **dest, meta_data_t *orig) /* {{{ */
334 {
335   meta_entry_t *e;
336
337   if (orig == NULL)
338     return (0);
339
340   if (*dest == NULL) {
341     *dest = meta_data_clone(orig);
342     return(0);
343   }
344
345   pthread_mutex_lock (&orig->lock);
346   for (e=orig->head; e != NULL; e = e->next)
347   {
348     md_entry_insert_clone((*dest), e);
349   }
350   pthread_mutex_unlock (&orig->lock);
351
352   return (0);
353 } /* }}} int meta_data_clone_merge */
354
355 void meta_data_destroy (meta_data_t *md) /* {{{ */
356 {
357   if (md == NULL)
358     return;
359
360   md_entry_free (md->head);
361   pthread_mutex_destroy (&md->lock);
362   free (md);
363 } /* }}} void meta_data_destroy */
364
365 int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */
366 {
367   meta_entry_t *e;
368
369   if ((md == NULL) || (key == NULL))
370     return (-EINVAL);
371
372   pthread_mutex_lock (&md->lock);
373
374   for (e = md->head; e != NULL; e = e->next)
375   {
376     if (strcasecmp (key, e->key) == 0)
377     {
378       pthread_mutex_unlock (&md->lock);
379       return (1);
380     }
381   }
382
383   pthread_mutex_unlock (&md->lock);
384   return (0);
385 } /* }}} int meta_data_exists */
386
387 int meta_data_type (meta_data_t *md, const char *key) /* {{{ */
388 {
389   meta_entry_t *e;
390
391   if ((md == NULL) || (key == NULL))
392     return -EINVAL;
393
394   pthread_mutex_lock (&md->lock);
395
396   for (e = md->head; e != NULL; e = e->next)
397   {
398     if (strcasecmp (key, e->key) == 0)
399     {
400       pthread_mutex_unlock (&md->lock);
401       return e->type;
402     }
403   }
404
405   pthread_mutex_unlock (&md->lock);
406   return 0;
407 } /* }}} int meta_data_type */
408
409 int meta_data_toc (meta_data_t *md, char ***toc) /* {{{ */
410 {
411   int i = 0, count = 0;
412   meta_entry_t *e;
413
414   if ((md == NULL) || (toc == NULL))
415     return -EINVAL;
416
417   pthread_mutex_lock (&md->lock);
418
419   for (e = md->head; e != NULL; e = e->next)
420     ++count;
421
422   if (count == 0)
423   {
424     pthread_mutex_unlock (&md->lock);
425     return (count);
426   }
427
428   *toc = calloc(count, sizeof(**toc));
429   for (e = md->head; e != NULL; e = e->next)
430     (*toc)[i++] = strdup(e->key);
431
432   pthread_mutex_unlock (&md->lock);
433   return count;
434 } /* }}} int meta_data_toc */
435
436 int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
437 {
438   meta_entry_t *this;
439   meta_entry_t *prev;
440
441   if ((md == NULL) || (key == NULL))
442     return (-EINVAL);
443
444   pthread_mutex_lock (&md->lock);
445
446   prev = NULL;
447   this = md->head;
448   while (this != NULL)
449   {
450     if (strcasecmp (key, this->key) == 0)
451       break;
452
453     prev = this;
454     this = this->next;
455   }
456
457   if (this == NULL)
458   {
459     pthread_mutex_unlock (&md->lock);
460     return (-ENOENT);
461   }
462
463   if (prev == NULL)
464     md->head = this->next;
465   else
466     prev->next = this->next;
467
468   pthread_mutex_unlock (&md->lock);
469
470   this->next = NULL;
471   md_entry_free (this);
472
473   return (0);
474 } /* }}} int meta_data_delete */
475
476 /*
477  * Add functions
478  */
479 int meta_data_add_string (meta_data_t *md, /* {{{ */
480     const char *key, const char *value)
481 {
482   meta_entry_t *e;
483
484   if ((md == NULL) || (key == NULL) || (value == NULL))
485     return (-EINVAL);
486
487   e = md_entry_alloc (key);
488   if (e == NULL)
489     return (-ENOMEM);
490
491   e->value.mv_string = md_strdup (value);
492   if (e->value.mv_string == NULL)
493   {
494     ERROR ("meta_data_add_string: md_strdup failed.");
495     md_entry_free (e);
496     return (-ENOMEM);
497   }
498   e->type = MD_TYPE_STRING;
499
500   return (md_entry_insert (md, e));
501 } /* }}} int meta_data_add_string */
502
503 int meta_data_add_signed_int (meta_data_t *md, /* {{{ */
504     const char *key, int64_t value)
505 {
506   meta_entry_t *e;
507
508   if ((md == NULL) || (key == NULL))
509     return (-EINVAL);
510
511   e = md_entry_alloc (key);
512   if (e == NULL)
513     return (-ENOMEM);
514
515   e->value.mv_signed_int = value;
516   e->type = MD_TYPE_SIGNED_INT;
517
518   return (md_entry_insert (md, e));
519 } /* }}} int meta_data_add_signed_int */
520
521 int meta_data_add_unsigned_int (meta_data_t *md, /* {{{ */
522     const char *key, uint64_t value)
523 {
524   meta_entry_t *e;
525
526   if ((md == NULL) || (key == NULL))
527     return (-EINVAL);
528
529   e = md_entry_alloc (key);
530   if (e == NULL)
531     return (-ENOMEM);
532
533   e->value.mv_unsigned_int = value;
534   e->type = MD_TYPE_UNSIGNED_INT;
535
536   return (md_entry_insert (md, e));
537 } /* }}} int meta_data_add_unsigned_int */
538
539 int meta_data_add_double (meta_data_t *md, /* {{{ */
540     const char *key, double value)
541 {
542   meta_entry_t *e;
543
544   if ((md == NULL) || (key == NULL))
545     return (-EINVAL);
546
547   e = md_entry_alloc (key);
548   if (e == NULL)
549     return (-ENOMEM);
550
551   e->value.mv_double = value;
552   e->type = MD_TYPE_DOUBLE;
553
554   return (md_entry_insert (md, e));
555 } /* }}} int meta_data_add_double */
556
557 int meta_data_add_boolean (meta_data_t *md, /* {{{ */
558     const char *key, _Bool value)
559 {
560   meta_entry_t *e;
561
562   if ((md == NULL) || (key == NULL))
563     return (-EINVAL);
564
565   e = md_entry_alloc (key);
566   if (e == NULL)
567     return (-ENOMEM);
568
569   e->value.mv_boolean = value;
570   e->type = MD_TYPE_BOOLEAN;
571
572   return (md_entry_insert (md, e));
573 } /* }}} int meta_data_add_boolean */
574
575 /*
576  * Get functions
577  */
578 int meta_data_get_string (meta_data_t *md, /* {{{ */
579     const char *key, char **value)
580 {
581   meta_entry_t *e;
582   char *temp;
583
584   if ((md == NULL) || (key == NULL) || (value == NULL))
585     return (-EINVAL);
586
587   pthread_mutex_lock (&md->lock);
588
589   e = md_entry_lookup (md, key);
590   if (e == NULL)
591   {
592     pthread_mutex_unlock (&md->lock);
593     return (-ENOENT);
594   }
595
596   if (e->type != MD_TYPE_STRING)
597   {
598     ERROR ("meta_data_get_string: Type mismatch for key `%s'", e->key);
599     pthread_mutex_unlock (&md->lock);
600     return (-ENOENT);
601   }
602
603   temp = md_strdup (e->value.mv_string);
604   if (temp == NULL)
605   {
606     pthread_mutex_unlock (&md->lock);
607     ERROR ("meta_data_get_string: md_strdup failed.");
608     return (-ENOMEM);
609   }
610
611   pthread_mutex_unlock (&md->lock);
612
613   *value = temp;
614
615   return (0);
616 } /* }}} int meta_data_get_string */
617
618 int meta_data_get_signed_int (meta_data_t *md, /* {{{ */
619     const char *key, int64_t *value)
620 {
621   meta_entry_t *e;
622
623   if ((md == NULL) || (key == NULL) || (value == NULL))
624     return (-EINVAL);
625
626   pthread_mutex_lock (&md->lock);
627
628   e = md_entry_lookup (md, key);
629   if (e == NULL)
630   {
631     pthread_mutex_unlock (&md->lock);
632     return (-ENOENT);
633   }
634
635   if (e->type != MD_TYPE_SIGNED_INT)
636   {
637     ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
638     pthread_mutex_unlock (&md->lock);
639     return (-ENOENT);
640   }
641
642   *value = e->value.mv_signed_int;
643
644   pthread_mutex_unlock (&md->lock);
645   return (0);
646 } /* }}} int meta_data_get_signed_int */
647
648 int meta_data_get_unsigned_int (meta_data_t *md, /* {{{ */
649     const char *key, uint64_t *value)
650 {
651   meta_entry_t *e;
652
653   if ((md == NULL) || (key == NULL) || (value == NULL))
654     return (-EINVAL);
655
656   pthread_mutex_lock (&md->lock);
657
658   e = md_entry_lookup (md, key);
659   if (e == NULL)
660   {
661     pthread_mutex_unlock (&md->lock);
662     return (-ENOENT);
663   }
664
665   if (e->type != MD_TYPE_UNSIGNED_INT)
666   {
667     ERROR ("meta_data_get_unsigned_int: Type mismatch for key `%s'", e->key);
668     pthread_mutex_unlock (&md->lock);
669     return (-ENOENT);
670   }
671
672   *value = e->value.mv_unsigned_int;
673
674   pthread_mutex_unlock (&md->lock);
675   return (0);
676 } /* }}} int meta_data_get_unsigned_int */
677
678 int meta_data_get_double (meta_data_t *md, /* {{{ */
679     const char *key, double *value)
680 {
681   meta_entry_t *e;
682
683   if ((md == NULL) || (key == NULL) || (value == NULL))
684     return (-EINVAL);
685
686   pthread_mutex_lock (&md->lock);
687
688   e = md_entry_lookup (md, key);
689   if (e == NULL)
690   {
691     pthread_mutex_unlock (&md->lock);
692     return (-ENOENT);
693   }
694
695   if (e->type != MD_TYPE_DOUBLE)
696   {
697     ERROR ("meta_data_get_double: Type mismatch for key `%s'", e->key);
698     pthread_mutex_unlock (&md->lock);
699     return (-ENOENT);
700   }
701
702   *value = e->value.mv_double;
703
704   pthread_mutex_unlock (&md->lock);
705   return (0);
706 } /* }}} int meta_data_get_double */
707
708 int meta_data_get_boolean (meta_data_t *md, /* {{{ */
709     const char *key, _Bool *value)
710 {
711   meta_entry_t *e;
712
713   if ((md == NULL) || (key == NULL) || (value == NULL))
714     return (-EINVAL);
715
716   pthread_mutex_lock (&md->lock);
717
718   e = md_entry_lookup (md, key);
719   if (e == NULL)
720   {
721     pthread_mutex_unlock (&md->lock);
722     return (-ENOENT);
723   }
724
725   if (e->type != MD_TYPE_BOOLEAN)
726   {
727     ERROR ("meta_data_get_boolean: Type mismatch for key `%s'", e->key);
728     pthread_mutex_unlock (&md->lock);
729     return (-ENOENT);
730   }
731
732   *value = e->value.mv_boolean;
733
734   pthread_mutex_unlock (&md->lock);
735   return (0);
736 } /* }}} int meta_data_get_boolean */
737
738 /* vim: set sw=2 sts=2 et fdm=marker : */