1 /*
2 * Copyright (c) 2002-2013 Balabit
3 * Copyright (c) 1998-2013 Balázs Scheidler
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * As an additional exemption you are allowed to compile & link against the
20 * OpenSSL libraries as published by the OpenSSL project. See the file
21 * COPYING for details.
22 *
23 */
24 #include "stats/stats-cluster.h"
25 #include "mainloop.h"
26
27 #include <assert.h>
28 #include <string.h>
29
30 GPtrArray *stats_types;
31
32 void
stats_cluster_init(void)33 stats_cluster_init(void)
34 {
35 g_assert(!stats_types);
36 stats_types = g_ptr_array_new_with_free_func(g_free);
37
38 g_assert(stats_register_type("none") == 0);
39 g_assert(stats_register_type("group") == SCS_GROUP);
40 g_assert(stats_register_type("global") == SCS_GLOBAL);
41 g_assert(stats_register_type("center") == SCS_CENTER);
42 g_assert(stats_register_type("host") == SCS_HOST);
43 g_assert(stats_register_type("sender") == SCS_SENDER);
44 g_assert(stats_register_type("program") == SCS_PROGRAM);
45 g_assert(stats_register_type("severity") == SCS_SEVERITY);
46 g_assert(stats_register_type("facility") == SCS_FACILITY);
47 g_assert(stats_register_type("tag") == SCS_TAG);
48 g_assert(stats_register_type("filter") == SCS_FILTER);
49 g_assert(stats_register_type("parser") == SCS_PARSER);
50 }
51
52 gboolean
_types_equal(const gchar * a,const gchar * b)53 _types_equal(const gchar *a, const gchar *b)
54 {
55 return !strcmp(a, b);
56 };
57
58 guint
stats_register_type(const gchar * type_name)59 stats_register_type(const gchar *type_name)
60 {
61 main_loop_assert_main_thread();
62 guint index_ = 0;
63 gboolean result = g_ptr_array_find_with_equal_func(stats_types, type_name, (GEqualFunc)_types_equal, &index_);
64 if (result)
65 return index_;
66
67 g_ptr_array_add(stats_types, g_strdup(type_name));
68
69 guint registered_number = stats_types->len - 1;
70 g_assert(registered_number <= SCS_SOURCE_MASK);
71 return registered_number;
72 };
73
74 void
stats_cluster_deinit(void)75 stats_cluster_deinit(void)
76 {
77 g_ptr_array_free(stats_types, TRUE);
78 stats_types = NULL;
79 }
80
81 StatsClusterKey *
stats_cluster_key_clone(StatsClusterKey * dst,const StatsClusterKey * src)82 stats_cluster_key_clone(StatsClusterKey *dst, const StatsClusterKey *src)
83 {
84 dst->component = src->component;
85 dst->id = g_strdup(src->id ? : "");
86 dst->instance = g_strdup(src->instance ? : "");
87
88 if (src->counter_group_init.clone)
89 src->counter_group_init.clone(&dst->counter_group_init, &src->counter_group_init);
90 else
91 dst->counter_group_init = src->counter_group_init;
92
93 return dst;
94 }
95
96 void
stats_cluster_key_set(StatsClusterKey * self,guint16 component,const gchar * id,const gchar * instance,StatsCounterGroupInit counter_group_init)97 stats_cluster_key_set(StatsClusterKey *self, guint16 component, const gchar *id, const gchar *instance,
98 StatsCounterGroupInit counter_group_init)
99 {
100 self->component = component;
101 self->id = (id?id:"");
102 self->instance = (instance?instance:"");
103 self->counter_group_init = counter_group_init;
104 }
105
106 void
stats_cluster_key_cloned_free(StatsClusterKey * self)107 stats_cluster_key_cloned_free(StatsClusterKey *self)
108 {
109 g_free((gchar *)(self->id));
110 g_free((gchar *)(self->instance));
111
112 if (self->counter_group_init.cloned_free)
113 self->counter_group_init.cloned_free(&self->counter_group_init);
114 }
115
116 void
stats_cluster_foreach_counter(StatsCluster * self,StatsForeachCounterFunc func,gpointer user_data)117 stats_cluster_foreach_counter(StatsCluster *self, StatsForeachCounterFunc func, gpointer user_data)
118 {
119 gint type;
120
121 for (type = 0; type < self->counter_group.capacity; type++)
122 {
123 if (self->live_mask & (1 << type))
124 {
125 func(self, type, &self->counter_group.counters[type], user_data);
126 }
127 }
128 }
129
130 const gchar *
stats_cluster_get_type_name(StatsCluster * self,gint type)131 stats_cluster_get_type_name(StatsCluster *self, gint type)
132 {
133 if (type < self->counter_group.capacity)
134 return self->counter_group.counter_names[type];
135
136 return "";
137 }
138
139 static const gchar *
_get_module_name(gint source)140 _get_module_name(gint source)
141 {
142 gint type = source & SCS_SOURCE_MASK;
143 g_assert(type < stats_types->len);
144 return g_ptr_array_index(stats_types, type);
145 }
146
147
148 static const gchar *
_get_component_prefix(gint source)149 _get_component_prefix(gint source)
150 {
151 return (source & SCS_SOURCE ? "src." : (source & SCS_DESTINATION ? "dst." : ""));
152 }
153
154 /* buf is a scratch area which is not always used, the return value is
155 * either a locally managed string or points to @buf. */
156 const gchar *
stats_cluster_get_component_name(StatsCluster * self,gchar * buf,gsize buf_len)157 stats_cluster_get_component_name(StatsCluster *self, gchar *buf, gsize buf_len)
158 {
159 if ((self->key.component & SCS_SOURCE_MASK) == SCS_GROUP)
160 {
161 if (self->key.component & SCS_SOURCE)
162 return "source";
163 else if (self->key.component & SCS_DESTINATION)
164 return "destination";
165 else
166 g_assert_not_reached();
167 }
168 else
169 {
170 g_snprintf(buf, buf_len, "%s%s",
171 _get_component_prefix(self->key.component),
172 _get_module_name(self->key.component));
173 return buf;
174 }
175 }
176
177 gboolean
stats_counter_group_init_equals(const StatsCounterGroupInit * self,const StatsCounterGroupInit * other)178 stats_counter_group_init_equals(const StatsCounterGroupInit *self, const StatsCounterGroupInit *other)
179 {
180 if (!self || !other)
181 return FALSE;
182
183 if (self == other)
184 return TRUE;
185
186 if (self->equals)
187 return self->equals(self, other);
188
189 return (self->init == other->init) && (self->counter.names == other->counter.names);
190 }
191
192 gboolean
stats_cluster_key_equal(const StatsClusterKey * key1,const StatsClusterKey * key2)193 stats_cluster_key_equal(const StatsClusterKey *key1, const StatsClusterKey *key2)
194 {
195 return key1->component == key2->component
196 && strcmp(key1->id, key2->id) == 0
197 && strcmp(key1->instance, key2->instance) == 0
198 && stats_counter_group_init_equals(&key1->counter_group_init, &key2->counter_group_init);
199 }
200
201 gboolean
stats_cluster_equal(const StatsCluster * sc1,const StatsCluster * sc2)202 stats_cluster_equal(const StatsCluster *sc1, const StatsCluster *sc2)
203 {
204 return stats_cluster_key_equal(&sc1->key, &sc2->key);
205 }
206
207 guint
stats_cluster_hash(const StatsCluster * self)208 stats_cluster_hash(const StatsCluster *self)
209 {
210 return g_str_hash(self->key.id) + g_str_hash(self->key.instance) + self->key.component;
211 }
212
213 StatsCounterItem *
stats_cluster_track_counter(StatsCluster * self,gint type)214 stats_cluster_track_counter(StatsCluster *self, gint type)
215 {
216 gint type_mask = 1 << type;
217
218 g_assert(type < self->counter_group.capacity);
219
220 self->live_mask |= type_mask;
221 self->use_count++;
222 return &self->counter_group.counters[type];
223 }
224
225 StatsCounterItem *
stats_cluster_get_counter(StatsCluster * self,gint type)226 stats_cluster_get_counter(StatsCluster *self, gint type)
227 {
228 gint type_mask = 1 << type;
229
230 g_assert(type < self->counter_group.capacity);
231
232 if (!(self->live_mask & type_mask))
233 return NULL;
234
235 return &self->counter_group.counters[type];
236 }
237
238 void
stats_cluster_untrack_counter(StatsCluster * self,gint type,StatsCounterItem ** counter)239 stats_cluster_untrack_counter(StatsCluster *self, gint type, StatsCounterItem **counter)
240 {
241 g_assert(self && (self->live_mask & (1 << type)) && &self->counter_group.counters[type] == (*counter));
242 g_assert(self->use_count > 0);
243 self->use_count--;
244
245 if (self->use_count == 0 && (*counter)->external)
246 {
247 (*counter)->external = FALSE;
248 (*counter)->value_ref = NULL;
249 gint type_mask = 1 << type;
250 self->live_mask &= ~type_mask;
251 }
252
253 *counter = NULL;
254 }
255
256 static gchar *
_stats_build_query_key(StatsCluster * self)257 _stats_build_query_key(StatsCluster *self)
258 {
259 GString *key = g_string_new("");
260 gchar buffer[64] = {0};
261 const gchar *component_name = stats_cluster_get_component_name(self, buffer, sizeof(buffer));
262
263 g_string_append(key, component_name);
264
265 if (self->key.id && self->key.id[0])
266 {
267 g_string_append_printf(key, ".%s", self->key.id);
268 }
269 if (self->key.instance && self->key.instance[0])
270 {
271 g_string_append_printf(key, ".%s", self->key.instance);
272 }
273
274 return g_string_free(key, FALSE);
275 }
276
277 gboolean
stats_cluster_is_alive(StatsCluster * self,gint type)278 stats_cluster_is_alive(StatsCluster *self, gint type)
279 {
280 g_assert(type < self->counter_group.capacity);
281
282 return !!((1<<type) & self->live_mask);
283 }
284
285 gboolean
stats_cluster_is_indexed(StatsCluster * self,gint type)286 stats_cluster_is_indexed(StatsCluster *self, gint type)
287 {
288 g_assert(type < self->counter_group.capacity);
289
290 return !!((1<<type) & self->indexed_mask);
291 }
292
293 StatsCluster *
stats_cluster_new(const StatsClusterKey * key)294 stats_cluster_new(const StatsClusterKey *key)
295 {
296 StatsCluster *self = g_new0(StatsCluster, 1);
297
298 stats_cluster_key_clone(&self->key, key);
299 self->use_count = 0;
300 self->query_key = _stats_build_query_key(self);
301 key->counter_group_init.init(&self->key.counter_group_init, &self->counter_group);
302 g_assert(self->counter_group.capacity <= sizeof(self->live_mask)*8);
303 return self;
304 }
305
306 StatsCluster *
stats_cluster_dynamic_new(const StatsClusterKey * key)307 stats_cluster_dynamic_new(const StatsClusterKey *key)
308 {
309 StatsCluster *sc = stats_cluster_new(key);
310 sc->dynamic = TRUE;
311
312 return sc;
313 }
314
315 void
stats_counter_group_free(StatsCounterGroup * self)316 stats_counter_group_free(StatsCounterGroup *self)
317 {
318 if (self->free_fn)
319 self->free_fn(self);
320 }
321
322
323 static void
stats_cluster_free_counter(StatsCluster * self,gint type,StatsCounterItem * item,gpointer user_data)324 stats_cluster_free_counter(StatsCluster *self, gint type, StatsCounterItem *item, gpointer user_data)
325 {
326 stats_counter_free(item);
327 }
328
329 void
stats_cluster_free(StatsCluster * self)330 stats_cluster_free(StatsCluster *self)
331 {
332 stats_cluster_foreach_counter(self, stats_cluster_free_counter, NULL);
333 stats_cluster_key_cloned_free(&self->key);
334 g_free(self->query_key);
335 stats_counter_group_free(&self->counter_group);
336 g_free(self);
337 }
338