Merge branch 'collectd-5.7' into collectd-5.8
[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
29 #include "common.h"
30 #include "meta_data.h"
31 #include "plugin.h"
32
33 #define MD_MAX_NONSTRING_CHARS 128
34
35 /*
36  * Data types
37  */
38 union meta_value_u {
39   char *mv_string;
40   int64_t mv_signed_int;
41   uint64_t mv_unsigned_int;
42   double mv_double;
43   _Bool mv_boolean;
44 };
45 typedef union meta_value_u meta_value_t;
46
47 struct meta_entry_s;
48 typedef struct meta_entry_s meta_entry_t;
49 struct meta_entry_s {
50   char *key;
51   meta_value_t value;
52   int type;
53   meta_entry_t *next;
54 };
55
56 struct meta_data_s {
57   meta_entry_t *head;
58   pthread_mutex_t lock;
59 };
60
61 /*
62  * Private functions
63  */
64 static char *md_strdup(const char *orig) /* {{{ */
65 {
66   size_t sz;
67   char *dest;
68
69   if (orig == NULL)
70     return NULL;
71
72   sz = strlen(orig) + 1;
73   dest = malloc(sz);
74   if (dest == NULL)
75     return NULL;
76
77   memcpy(dest, orig, sz);
78
79   return dest;
80 } /* }}} char *md_strdup */
81
82 static meta_entry_t *md_entry_alloc(const char *key) /* {{{ */
83 {
84   meta_entry_t *e;
85
86   e = calloc(1, sizeof(*e));
87   if (e == NULL) {
88     ERROR("md_entry_alloc: calloc failed.");
89     return NULL;
90   }
91
92   e->key = md_strdup(key);
93   if (e->key == NULL) {
94     free(e);
95     ERROR("md_entry_alloc: md_strdup failed.");
96     return NULL;
97   }
98
99   e->type = 0;
100   e->next = NULL;
101
102   return e;
103 } /* }}} meta_entry_t *md_entry_alloc */
104
105 /* XXX: The lock on md must be held while calling this function! */
106 static meta_entry_t *md_entry_clone_contents(const meta_entry_t *orig) /* {{{ */
107 {
108   meta_entry_t *copy;
109
110   /* WARNINGS :
111    *  - we do not check that orig != NULL here. You should have done it before.
112    *  - we do not set copy->next. DO NOT FORGET TO SET copy->next IN YOUR
113    * 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     if (strcasecmp(e->key, this->key) == 0)
171       break;
172
173     prev = this;
174     this = this->next;
175   }
176
177   if (this == NULL) {
178     /* This key does not exist yet. */
179     if (md->head == NULL)
180       md->head = e;
181     else {
182       assert(prev != NULL);
183       prev->next = e;
184     }
185
186     e->next = NULL;
187   } else /* (this != NULL) */
188   {
189     if (prev == NULL)
190       md->head = e;
191     else
192       prev->next = e;
193
194     e->next = this->next;
195   }
196
197   pthread_mutex_unlock(&md->lock);
198
199   if (this != NULL) {
200     this->next = NULL;
201     md_entry_free(this);
202   }
203
204   return 0;
205 } /* }}} int md_entry_insert */
206
207 /* XXX: The lock on md must be held while calling this function! */
208 static int md_entry_insert_clone(meta_data_t *md, meta_entry_t *orig) /* {{{ */
209 {
210   meta_entry_t *e;
211   meta_entry_t *this;
212   meta_entry_t *prev;
213
214   /* WARNINGS :
215    *  - we do not check that md and e != NULL here. You should have done it
216    * before.
217    *  - we do not use the lock. You should have set it before.
218    */
219
220   e = md_entry_clone_contents(orig);
221
222   prev = NULL;
223   this = md->head;
224   while (this != NULL) {
225     if (strcasecmp(e->key, this->key) == 0)
226       break;
227
228     prev = this;
229     this = this->next;
230   }
231
232   if (this == NULL) {
233     /* This key does not exist yet. */
234     if (md->head == NULL)
235       md->head = e;
236     else {
237       assert(prev != NULL);
238       prev->next = e;
239     }
240
241     e->next = NULL;
242   } else /* (this != NULL) */
243   {
244     if (prev == NULL)
245       md->head = e;
246     else
247       prev->next = e;
248
249     e->next = this->next;
250   }
251
252   if (this != NULL) {
253     this->next = NULL;
254     md_entry_free(this);
255   }
256
257   return 0;
258 } /* }}} int md_entry_insert_clone */
259
260 /* XXX: The lock on md must be held while calling this function! */
261 static meta_entry_t *md_entry_lookup(meta_data_t *md, /* {{{ */
262                                      const char *key) {
263   meta_entry_t *e;
264
265   if ((md == NULL) || (key == NULL))
266     return NULL;
267
268   for (e = md->head; e != NULL; e = e->next)
269     if (strcasecmp(key, e->key) == 0)
270       break;
271
272   return e;
273 } /* }}} meta_entry_t *md_entry_lookup */
274
275 /*
276  * Each value_list_t*, as it is going through the system, is handled by exactly
277  * one thread. Plugins which pass a value_list_t* to another thread, e.g. the
278  * rrdtool plugin, must create a copy first. The meta data within a
279  * value_list_t* is not thread safe and doesn't need to be.
280  *
281  * The meta data associated with cache entries are a different story. There, we
282  * need to ensure exclusive locking to prevent leaks and other funky business.
283  * This is ensured by the uc_meta_data_get_*() functions.
284  */
285
286 /*
287  * Public functions
288  */
289 meta_data_t *meta_data_create(void) /* {{{ */
290 {
291   meta_data_t *md;
292
293   md = calloc(1, sizeof(*md));
294   if (md == NULL) {
295     ERROR("meta_data_create: calloc failed.");
296     return NULL;
297   }
298
299   pthread_mutex_init(&md->lock, /* attr = */ NULL);
300
301   return md;
302 } /* }}} meta_data_t *meta_data_create */
303
304 meta_data_t *meta_data_clone(meta_data_t *orig) /* {{{ */
305 {
306   meta_data_t *copy;
307
308   if (orig == NULL)
309     return NULL;
310
311   copy = meta_data_create();
312   if (copy == NULL)
313     return NULL;
314
315   pthread_mutex_lock(&orig->lock);
316   copy->head = md_entry_clone(orig->head);
317   pthread_mutex_unlock(&orig->lock);
318
319   return copy;
320 } /* }}} meta_data_t *meta_data_clone */
321
322 int meta_data_clone_merge(meta_data_t **dest, meta_data_t *orig) /* {{{ */
323 {
324   if (orig == NULL)
325     return 0;
326
327   if (*dest == NULL) {
328     *dest = meta_data_clone(orig);
329     return 0;
330   }
331
332   pthread_mutex_lock(&orig->lock);
333   for (meta_entry_t *e = orig->head; e != NULL; e = e->next) {
334     md_entry_insert_clone((*dest), e);
335   }
336   pthread_mutex_unlock(&orig->lock);
337
338   return 0;
339 } /* }}} int meta_data_clone_merge */
340
341 void meta_data_destroy(meta_data_t *md) /* {{{ */
342 {
343   if (md == NULL)
344     return;
345
346   md_entry_free(md->head);
347   pthread_mutex_destroy(&md->lock);
348   free(md);
349 } /* }}} void meta_data_destroy */
350
351 int meta_data_exists(meta_data_t *md, const char *key) /* {{{ */
352 {
353   if ((md == NULL) || (key == NULL))
354     return -EINVAL;
355
356   pthread_mutex_lock(&md->lock);
357
358   for (meta_entry_t *e = md->head; e != NULL; e = e->next) {
359     if (strcasecmp(key, e->key) == 0) {
360       pthread_mutex_unlock(&md->lock);
361       return 1;
362     }
363   }
364
365   pthread_mutex_unlock(&md->lock);
366   return 0;
367 } /* }}} int meta_data_exists */
368
369 int meta_data_type(meta_data_t *md, const char *key) /* {{{ */
370 {
371   if ((md == NULL) || (key == NULL))
372     return -EINVAL;
373
374   pthread_mutex_lock(&md->lock);
375
376   for (meta_entry_t *e = md->head; e != NULL; e = e->next) {
377     if (strcasecmp(key, e->key) == 0) {
378       pthread_mutex_unlock(&md->lock);
379       return e->type;
380     }
381   }
382
383   pthread_mutex_unlock(&md->lock);
384   return 0;
385 } /* }}} int meta_data_type */
386
387 int meta_data_toc(meta_data_t *md, char ***toc) /* {{{ */
388 {
389   int i = 0, count = 0;
390
391   if ((md == NULL) || (toc == NULL))
392     return -EINVAL;
393
394   pthread_mutex_lock(&md->lock);
395
396   for (meta_entry_t *e = md->head; e != NULL; e = e->next)
397     ++count;
398
399   if (count == 0) {
400     pthread_mutex_unlock(&md->lock);
401     return count;
402   }
403
404   *toc = calloc(count, sizeof(**toc));
405   for (meta_entry_t *e = md->head; e != NULL; e = e->next)
406     (*toc)[i++] = strdup(e->key);
407
408   pthread_mutex_unlock(&md->lock);
409   return count;
410 } /* }}} int meta_data_toc */
411
412 int meta_data_delete(meta_data_t *md, const char *key) /* {{{ */
413 {
414   meta_entry_t *this;
415   meta_entry_t *prev;
416
417   if ((md == NULL) || (key == NULL))
418     return -EINVAL;
419
420   pthread_mutex_lock(&md->lock);
421
422   prev = NULL;
423   this = md->head;
424   while (this != NULL) {
425     if (strcasecmp(key, this->key) == 0)
426       break;
427
428     prev = this;
429     this = this->next;
430   }
431
432   if (this == NULL) {
433     pthread_mutex_unlock(&md->lock);
434     return -ENOENT;
435   }
436
437   if (prev == NULL)
438     md->head = this->next;
439   else
440     prev->next = this->next;
441
442   pthread_mutex_unlock(&md->lock);
443
444   this->next = NULL;
445   md_entry_free(this);
446
447   return 0;
448 } /* }}} int meta_data_delete */
449
450 /*
451  * Add functions
452  */
453 int meta_data_add_string(meta_data_t *md, /* {{{ */
454                          const char *key, const char *value) {
455   meta_entry_t *e;
456
457   if ((md == NULL) || (key == NULL) || (value == NULL))
458     return -EINVAL;
459
460   e = md_entry_alloc(key);
461   if (e == NULL)
462     return -ENOMEM;
463
464   e->value.mv_string = md_strdup(value);
465   if (e->value.mv_string == NULL) {
466     ERROR("meta_data_add_string: md_strdup failed.");
467     md_entry_free(e);
468     return -ENOMEM;
469   }
470   e->type = MD_TYPE_STRING;
471
472   return md_entry_insert(md, e);
473 } /* }}} int meta_data_add_string */
474
475 int meta_data_add_signed_int(meta_data_t *md, /* {{{ */
476                              const char *key, int64_t value) {
477   meta_entry_t *e;
478
479   if ((md == NULL) || (key == NULL))
480     return -EINVAL;
481
482   e = md_entry_alloc(key);
483   if (e == NULL)
484     return -ENOMEM;
485
486   e->value.mv_signed_int = value;
487   e->type = MD_TYPE_SIGNED_INT;
488
489   return md_entry_insert(md, e);
490 } /* }}} int meta_data_add_signed_int */
491
492 int meta_data_add_unsigned_int(meta_data_t *md, /* {{{ */
493                                const char *key, uint64_t value) {
494   meta_entry_t *e;
495
496   if ((md == NULL) || (key == NULL))
497     return -EINVAL;
498
499   e = md_entry_alloc(key);
500   if (e == NULL)
501     return -ENOMEM;
502
503   e->value.mv_unsigned_int = value;
504   e->type = MD_TYPE_UNSIGNED_INT;
505
506   return md_entry_insert(md, e);
507 } /* }}} int meta_data_add_unsigned_int */
508
509 int meta_data_add_double(meta_data_t *md, /* {{{ */
510                          const char *key, double value) {
511   meta_entry_t *e;
512
513   if ((md == NULL) || (key == NULL))
514     return -EINVAL;
515
516   e = md_entry_alloc(key);
517   if (e == NULL)
518     return -ENOMEM;
519
520   e->value.mv_double = value;
521   e->type = MD_TYPE_DOUBLE;
522
523   return md_entry_insert(md, e);
524 } /* }}} int meta_data_add_double */
525
526 int meta_data_add_boolean(meta_data_t *md, /* {{{ */
527                           const char *key, _Bool value) {
528   meta_entry_t *e;
529
530   if ((md == NULL) || (key == NULL))
531     return -EINVAL;
532
533   e = md_entry_alloc(key);
534   if (e == NULL)
535     return -ENOMEM;
536
537   e->value.mv_boolean = value;
538   e->type = MD_TYPE_BOOLEAN;
539
540   return md_entry_insert(md, e);
541 } /* }}} int meta_data_add_boolean */
542
543 /*
544  * Get functions
545  */
546 int meta_data_get_string(meta_data_t *md, /* {{{ */
547                          const char *key, char **value) {
548   meta_entry_t *e;
549   char *temp;
550
551   if ((md == NULL) || (key == NULL) || (value == NULL))
552     return -EINVAL;
553
554   pthread_mutex_lock(&md->lock);
555
556   e = md_entry_lookup(md, key);
557   if (e == NULL) {
558     pthread_mutex_unlock(&md->lock);
559     return -ENOENT;
560   }
561
562   if (e->type != MD_TYPE_STRING) {
563     ERROR("meta_data_get_string: Type mismatch for key `%s'", e->key);
564     pthread_mutex_unlock(&md->lock);
565     return -ENOENT;
566   }
567
568   temp = md_strdup(e->value.mv_string);
569   if (temp == NULL) {
570     pthread_mutex_unlock(&md->lock);
571     ERROR("meta_data_get_string: md_strdup failed.");
572     return -ENOMEM;
573   }
574
575   pthread_mutex_unlock(&md->lock);
576
577   *value = temp;
578
579   return 0;
580 } /* }}} int meta_data_get_string */
581
582 int meta_data_get_signed_int(meta_data_t *md, /* {{{ */
583                              const char *key, int64_t *value) {
584   meta_entry_t *e;
585
586   if ((md == NULL) || (key == NULL) || (value == NULL))
587     return -EINVAL;
588
589   pthread_mutex_lock(&md->lock);
590
591   e = md_entry_lookup(md, key);
592   if (e == NULL) {
593     pthread_mutex_unlock(&md->lock);
594     return -ENOENT;
595   }
596
597   if (e->type != MD_TYPE_SIGNED_INT) {
598     ERROR("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
599     pthread_mutex_unlock(&md->lock);
600     return -ENOENT;
601   }
602
603   *value = e->value.mv_signed_int;
604
605   pthread_mutex_unlock(&md->lock);
606   return 0;
607 } /* }}} int meta_data_get_signed_int */
608
609 int meta_data_get_unsigned_int(meta_data_t *md, /* {{{ */
610                                const char *key, uint64_t *value) {
611   meta_entry_t *e;
612
613   if ((md == NULL) || (key == NULL) || (value == NULL))
614     return -EINVAL;
615
616   pthread_mutex_lock(&md->lock);
617
618   e = md_entry_lookup(md, key);
619   if (e == NULL) {
620     pthread_mutex_unlock(&md->lock);
621     return -ENOENT;
622   }
623
624   if (e->type != MD_TYPE_UNSIGNED_INT) {
625     ERROR("meta_data_get_unsigned_int: Type mismatch for key `%s'", e->key);
626     pthread_mutex_unlock(&md->lock);
627     return -ENOENT;
628   }
629
630   *value = e->value.mv_unsigned_int;
631
632   pthread_mutex_unlock(&md->lock);
633   return 0;
634 } /* }}} int meta_data_get_unsigned_int */
635
636 int meta_data_get_double(meta_data_t *md, /* {{{ */
637                          const char *key, double *value) {
638   meta_entry_t *e;
639
640   if ((md == NULL) || (key == NULL) || (value == NULL))
641     return -EINVAL;
642
643   pthread_mutex_lock(&md->lock);
644
645   e = md_entry_lookup(md, key);
646   if (e == NULL) {
647     pthread_mutex_unlock(&md->lock);
648     return -ENOENT;
649   }
650
651   if (e->type != MD_TYPE_DOUBLE) {
652     ERROR("meta_data_get_double: Type mismatch for key `%s'", e->key);
653     pthread_mutex_unlock(&md->lock);
654     return -ENOENT;
655   }
656
657   *value = e->value.mv_double;
658
659   pthread_mutex_unlock(&md->lock);
660   return 0;
661 } /* }}} int meta_data_get_double */
662
663 int meta_data_get_boolean(meta_data_t *md, /* {{{ */
664                           const char *key, _Bool *value) {
665   meta_entry_t *e;
666
667   if ((md == NULL) || (key == NULL) || (value == NULL))
668     return -EINVAL;
669
670   pthread_mutex_lock(&md->lock);
671
672   e = md_entry_lookup(md, key);
673   if (e == NULL) {
674     pthread_mutex_unlock(&md->lock);
675     return -ENOENT;
676   }
677
678   if (e->type != MD_TYPE_BOOLEAN) {
679     ERROR("meta_data_get_boolean: Type mismatch for key `%s'", e->key);
680     pthread_mutex_unlock(&md->lock);
681     return -ENOENT;
682   }
683
684   *value = e->value.mv_boolean;
685
686   pthread_mutex_unlock(&md->lock);
687   return 0;
688 } /* }}} int meta_data_get_boolean */
689
690 int meta_data_as_string(meta_data_t *md, /* {{{ */
691                         const char *key, char **value) {
692   meta_entry_t *e;
693   const char *actual;
694   char buffer[MD_MAX_NONSTRING_CHARS]; /* For non-string types. */
695   char *temp;
696   int type;
697
698   if ((md == NULL) || (key == NULL) || (value == NULL))
699     return -EINVAL;
700
701   pthread_mutex_lock(&md->lock);
702
703   e = md_entry_lookup(md, key);
704   if (e == NULL) {
705     pthread_mutex_unlock(&md->lock);
706     return -ENOENT;
707   }
708
709   type = e->type;
710
711   switch (type) {
712   case MD_TYPE_STRING:
713     actual = e->value.mv_string;
714     break;
715   case MD_TYPE_SIGNED_INT:
716     snprintf(buffer, sizeof(buffer), "%" PRIi64, e->value.mv_signed_int);
717     actual = buffer;
718     break;
719   case MD_TYPE_UNSIGNED_INT:
720     snprintf(buffer, sizeof(buffer), "%" PRIu64, e->value.mv_unsigned_int);
721     actual = buffer;
722     break;
723   case MD_TYPE_DOUBLE:
724     snprintf(buffer, sizeof(buffer), GAUGE_FORMAT, e->value.mv_double);
725     actual = buffer;
726     break;
727   case MD_TYPE_BOOLEAN:
728     actual = e->value.mv_boolean ? "true" : "false";
729     break;
730   default:
731     pthread_mutex_unlock(&md->lock);
732     ERROR("meta_data_as_string: unknown type %d for key `%s'", type, key);
733     return -ENOENT;
734   }
735
736   pthread_mutex_unlock(&md->lock);
737
738   temp = md_strdup(actual);
739   if (temp == NULL) {
740     ERROR("meta_data_as_string: md_strdup failed for key `%s'.", key);
741     return -ENOMEM;
742   }
743
744   *value = temp;
745
746   return 0;
747 } /* }}} int meta_data_as_string */