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