root/src/noit_check_tools.c

Revision 899f2d2b74c6a8e1d8fc9a0ede60f226f83d551d, 9.1 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 7 years ago)

Performance enhancement populating check metrics from json in lua.
(as in, don't do it in lua, do it all in C). 1.6x speedup.

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34 #include "dtrace_probes.h"
35 #include "noit_check_tools.h"
36 #include "noit_check_tools_shared.h"
37 #include "utils/noit_str.h"
38 #include "json-lib/json.h"
39
40 #include <assert.h>
41
42 typedef struct {
43   noit_module_t *self;
44   noit_check_t *check;
45   noit_check_t *cause;
46   dispatch_func_t dispatch;
47 } recur_closure_t;
48
49 static int
50 noit_check_recur_handler(eventer_t e, int mask, void *closure,
51                               struct timeval *now) {
52   recur_closure_t *rcl = closure;
53   rcl->check->fire_event = NULL; /* This is us, we get free post-return */
54   noit_check_resolve(rcl->check);
55   noit_check_schedule_next(rcl->self, &e->whence, rcl->check, now,
56                            rcl->dispatch, NULL);
57   if(NOIT_CHECK_RESOLVED(rcl->check)) {
58     if(NOIT_CHECK_DISPATCH_ENABLED()) {
59       char id[UUID_STR_LEN+1];
60       uuid_unparse_lower(rcl->check->checkid, id);
61       NOIT_CHECK_DISPATCH(id, rcl->check->module, rcl->check->name,
62                           rcl->check->target);
63     }
64     rcl->dispatch(rcl->self, rcl->check, rcl->cause);
65   }
66   else
67     noitL(noit_debug, "skipping %s`%s`%s, unresolved\n",
68           rcl->check->target, rcl->check->module, rcl->check->name);
69   free(rcl);
70   return 0;
71 }
72
73 int
74 noit_check_schedule_next(noit_module_t *self,
75                          struct timeval *last_check, noit_check_t *check,
76                          struct timeval *now, dispatch_func_t dispatch,
77                          noit_check_t *cause) {
78   eventer_t newe;
79   struct timeval period, earliest;
80   recur_closure_t *rcl;
81
82   assert(cause == NULL);
83   assert(check->fire_event == NULL);
84   if(check->period == 0) return 0;
85   if(NOIT_CHECK_DISABLED(check) || NOIT_CHECK_KILLED(check)) return 0;
86
87   /* If we have an event, we know when we intended it to fire.  This means
88    * we should schedule that point + period.
89    */
90   if(now)
91     memcpy(&earliest, now, sizeof(earliest));
92   else
93     gettimeofday(&earliest, NULL);
94
95   /* If the check is unconfigured and needs resolving, we'll set the
96    * period down a bit lower so we can pick up the resolution quickly.
97    */
98   if(!NOIT_CHECK_RESOLVED(check) && NOIT_CHECK_SHOULD_RESOLVE(check) &&
99       check->period > 1000) {
100     period.tv_sec = 1;
101     period.tv_usec = 0;
102   }
103   else {
104     period.tv_sec = check->period / 1000;
105     period.tv_usec = (check->period % 1000) * 1000;
106   }
107
108   newe = eventer_alloc();
109   memcpy(&newe->whence, last_check, sizeof(*last_check));
110   add_timeval(newe->whence, period, &newe->whence);
111   if(compare_timeval(newe->whence, earliest) < 0)
112     memcpy(&newe->whence, &earliest, sizeof(earliest));
113   newe->mask = EVENTER_TIMER;
114   newe->callback = noit_check_recur_handler;
115   rcl = calloc(1, sizeof(*rcl));
116   rcl->self = self;
117   rcl->check = check;
118   rcl->cause = cause;
119   rcl->dispatch = dispatch;
120   newe->closure = rcl;
121
122   eventer_add(newe);
123   check->fire_event = newe;
124   return 0;
125 }
126
127 void
128 noit_check_run_full_asynch_opts(noit_check_t *check, eventer_func_t callback,
129                                 int mask) {
130   struct timeval __now, p_int;
131   eventer_t e;
132   e = eventer_alloc();
133   e->fd = -1;
134   e->mask = EVENTER_ASYNCH | mask;
135   gettimeofday(&__now, NULL);
136   memcpy(&e->whence, &__now, sizeof(__now));
137   p_int.tv_sec = check->timeout / 1000;
138   p_int.tv_usec = (check->timeout % 1000) * 1000;
139   add_timeval(e->whence, p_int, &e->whence);
140   e->callback = callback;
141   e->closure =  check->closure;
142   eventer_add(e);
143 }
144 void
145 noit_check_run_full_asynch(noit_check_t *check, eventer_func_t callback) {
146   noit_check_run_full_asynch_opts(check, callback,
147                                   EVENTER_DEFAULT_ASYNCH_ABORT);
148 }
149
150 void
151 noit_check_tools_init() {
152   noit_check_tools_shared_init();
153   eventer_name_callback("noit_check_recur_handler", noit_check_recur_handler);
154 }
155
156 static int
157 populate_stats_from_resmon_formatted_json(stats_t *s, struct json_object *o,
158                                           const char *prefix) {
159   int count = 0;
160   char keybuff[256];
161 #define MKKEY(fmt, arg) do { \
162   if(prefix) snprintf(keybuff, sizeof(keybuff), "%s`" fmt, prefix, arg); \
163   else snprintf(keybuff, sizeof(keybuff), fmt, arg); \
164 } while(0)
165   switch(json_object_get_type(o)) {
166     /* sub callers */
167     case json_type_array:
168     {
169       int i, alen = json_object_array_length(o);
170       for(i=0;i<alen;i++) {
171         struct json_object *item = json_object_array_get_idx(o, i);
172         MKKEY("%d", i);
173         count += populate_stats_from_resmon_formatted_json(s, item, keybuff);
174       }
175     }
176     break;
177     case json_type_object:
178     {
179       struct lh_table *lh;
180       struct lh_entry *el;
181       struct json_object *has_type = NULL, *has_value = NULL;
182       lh = json_object_get_object(o);
183       lh_foreach(lh, el) {
184         if(!strcmp(el->k, "_type")) has_type = (struct json_object *)el->v;
185         else if(!strcmp(el->k, "_value")) has_value = (struct json_object *)el->v;
186         else {
187           struct json_object *item = (struct json_object *)el->v;
188           MKKEY("%s", (const char *)el->k);
189           count += populate_stats_from_resmon_formatted_json(s, item, keybuff);
190         }
191       }
192       if(prefix && has_type && has_value &&
193          json_object_is_type(has_type, json_type_string) &&
194          json_object_is_type(has_value, json_type_string)) {
195         const char *type_str = json_object_get_string(has_type);
196         const char *value_str = json_object_get_string(has_value);
197         switch(*type_str) {
198           case METRIC_INT32:
199           case METRIC_UINT32:
200           case METRIC_INT64:
201           case METRIC_UINT64:
202           case METRIC_DOUBLE:
203           case METRIC_STRING:
204             noit_stats_set_metric_coerce(s, prefix,
205                                          (metric_type_t)*type_str, value_str);
206             count++;
207           default:
208             break;
209         }
210       }
211       break;
212     }
213
214     /* directs */
215     case json_type_string:
216       if(prefix) {
217         noit_stats_set_metric(s, prefix, METRIC_GUESS,
218                               (char *)json_object_get_string(o));
219         count++;
220       }
221       break;
222     case json_type_boolean:
223       if(prefix) {
224         int val = json_object_get_boolean(o) ? 1 : 0;
225         noit_stats_set_metric(s, prefix, METRIC_INT32, &val);
226         count++;
227       }
228       break;
229     case json_type_null:
230       if(prefix) {
231         noit_stats_set_metric(s, prefix, METRIC_STRING, NULL);
232         count++;
233       }
234       break;
235     case json_type_double:
236       if(prefix) {
237         double val = json_object_get_double(o);
238         noit_stats_set_metric(s, prefix, METRIC_DOUBLE, &val);
239         count++;
240       }
241       break;
242     case json_type_int:
243       if(prefix) {
244         int64_t i64;
245         uint64_t u64;
246         switch(json_object_get_int_overflow(o)) {
247           case json_overflow_int:
248             i64 = json_object_get_int(o);
249             noit_stats_set_metric(s, prefix, METRIC_INT64, &i64);
250             count++;
251             break;
252           case json_overflow_int64:
253             i64 = json_object_get_int64(o);
254             noit_stats_set_metric(s, prefix, METRIC_INT64, &i64);
255             count++;
256             break;
257           case json_overflow_uint64:
258             u64 = json_object_get_uint64(o);
259             noit_stats_set_metric(s, prefix, METRIC_UINT64, &u64);
260             count++;
261             break;
262         }
263       }
264   }
265   return count;
266 }
267 int
268 noit_check_stats_from_json_str(stats_t *s, const char *json_str, int len) {
269   int rv = -1;
270   struct json_tokener *tok = NULL;
271   struct json_object *root = NULL;
272   tok = json_tokener_new();
273   root = json_tokener_parse_ex(tok, json_str, len);
274   if(root) rv = populate_stats_from_resmon_formatted_json(s, root, NULL);
275   if(tok) json_tokener_free(tok);
276   if(root) json_object_put(root);
277   return rv;
278 }
Note: See TracBrowser for help on using the browser.