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