varnish-cache/lib/libvarnishapi/vsc.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 * Author: Martin Blix Grydeland <martin@varnish-software.com>
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30
31
#include "config.h"
32
33
#include <sys/stat.h>
34
35
#include <fnmatch.h>
36
#include <stdint.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <unistd.h>
41
42
#include "vdef.h"
43
#include "vas.h"
44
#include "miniobj.h"
45
#include "vqueue.h"
46
#include "vjsn.h"
47
#include "vsb.h"
48
#include "vend.h"
49
#include "vmb.h"
50
51
#include "vapi/vsc.h"
52
#include "vapi/vsm.h"
53
54
struct vsc_sf {
55
        unsigned                magic;
56
#define VSC_SF_MAGIC            0x558478dd
57
        VTAILQ_ENTRY(vsc_sf)    list;
58
        char                    *pattern;
59
};
60
VTAILQ_HEAD(vsc_sf_head, vsc_sf);
61
62
struct vsc_pt {
63
        struct VSC_point        point;
64
        char                    *name;
65
};
66
67
struct vsc_seg {
68
        unsigned                magic;
69
#define VSC_SEG_MAGIC           0x801177d4
70
        VTAILQ_ENTRY(vsc_seg)   list;
71
        struct vsm_fantom       fantom[1];
72
        struct vjsn             *vj;
73
        unsigned                npoints;
74
        struct vsc_pt           *points;
75
};
76
77
struct vsc {
78
        unsigned                magic;
79
#define VSC_MAGIC               0x3373554a
80
81
        struct vsc_sf_head      sf_list_include;
82
        struct vsc_sf_head      sf_list_exclude;
83
        VTAILQ_HEAD(,vsc_seg)   segs;
84
85
        VSC_new_f               *fnew;
86
        VSC_destroy_f           *fdestroy;
87
        void                    *priv;
88
};
89
90
/*--------------------------------------------------------------------
91
 * Build the static level, type and point descriptions
92
 */
93
94
#define VSC_LEVEL_F(v,l,e,d) \
95
    static const struct VSC_level_desc level_##v = {#v, l, e, d};
96
#include "tbl/vsc_levels.h"
97
98
static const struct VSC_level_desc * const levels[] = {
99
#define VSC_LEVEL_F(v,l,e,d) &level_##v,
100
#include "tbl/vsc_levels.h"
101
#undef VSC_LEVEL_F
102
};
103
104
static const size_t nlevels = sizeof(levels)/sizeof(*levels);
105
106
/*--------------------------------------------------------------------*/
107
108
struct vsc *
109 1272
VSC_New(void)
110
{
111
        struct vsc *vsc;
112
113 1272
        ALLOC_OBJ(vsc, VSC_MAGIC);
114 1272
        if (vsc == NULL)
115 0
                return (vsc);
116 1272
        VTAILQ_INIT(&vsc->sf_list_include);
117 1272
        VTAILQ_INIT(&vsc->sf_list_exclude);
118 1272
        VTAILQ_INIT(&vsc->segs);
119 1272
        return (vsc);
120
}
121
122
/*--------------------------------------------------------------------*/
123
124
static int
125 16
vsc_f_arg(struct vsc *vsc, const char *opt)
126
{
127
        struct vsc_sf *sf;
128 16
        unsigned exclude = 0;
129
130 16
        AN(opt);
131
132 16
        ALLOC_OBJ(sf, VSC_SF_MAGIC);
133 16
        AN(sf);
134
135 16
        if (opt[0] == '^') {
136 8
                exclude = 1;
137 8
                opt++;
138
        }
139
140 16
        sf->pattern = strdup(opt);
141 16
        AN(sf->pattern);
142
143 16
        if (exclude)
144 8
                VTAILQ_INSERT_TAIL(&vsc->sf_list_exclude, sf, list);
145
        else
146 8
                VTAILQ_INSERT_TAIL(&vsc->sf_list_include, sf, list);
147
148 16
        return (1);
149
}
150
151
/*--------------------------------------------------------------------*/
152
153
int
154 16
VSC_Arg(struct vsc *vsc, char arg, const char *opt)
155
{
156
157 16
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
158
159 16
        switch (arg) {
160 16
        case 'f': return (vsc_f_arg(vsc, opt));
161 0
        default: return (0);
162
        }
163
}
164
165
/*--------------------------------------------------------------------
166
 */
167
void
168 0
VSC_State(struct vsc *vsc, VSC_new_f *fn, VSC_destroy_f *fd, void *priv)
169
{
170
171 0
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
172 0
        vsc->fnew = fn;
173 0
        vsc->fdestroy = fd;
174 0
        vsc->priv = priv;
175 0
}
176
177
/*--------------------------------------------------------------------
178
 */
179
180
static int
181 48247
vsc_filter(const struct vsc *vsc, const char *nm)
182
{
183
        struct vsc_sf *sf;
184
185 48247
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
186 50167
        VTAILQ_FOREACH(sf, &vsc->sf_list_exclude, list)
187 2176
                if (!fnmatch(sf->pattern, nm, 0))
188 256
                        return (1);
189 47991
        if (VTAILQ_EMPTY(&vsc->sf_list_include))
190 46907
                return (0);
191 3232
        VTAILQ_FOREACH(sf, &vsc->sf_list_include, list)
192 2160
                if (!fnmatch(sf->pattern, nm, 0))
193 12
                        return (0);
194 1072
        return (1);
195
}
196
197
/*--------------------------------------------------------------------
198
 */
199
200
static void
201 43895
vsc_clean_point(struct vsc_pt *point)
202
{
203 43895
        REPLACE(point->name, NULL);
204 43895
}
205
206
static int
207 48247
vsc_fill_point(const struct vsc *vsc, const struct vsm_fantom *fantom,
208
    const struct vjsn_val *vv, struct vsb *vsb, struct vsc_pt *point)
209
{
210
        struct vjsn_val *vt;
211
212 48247
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
213 48247
        memset(point, 0, sizeof *point);
214
215 48247
        vt = vjsn_child(vv, "name");
216 48247
        AN(vt);
217 48247
        assert(vt->type == VJSN_STRING);
218
219 48247
        VSB_clear(vsb);
220 48247
        VSB_printf(vsb, "%s.%s", fantom->ident, vt->value);
221 48247
        AZ(VSB_finish(vsb));
222
223 48247
        if (vsc_filter(vsc, VSB_data(vsb)))
224 1328
                return (0);
225
226 46919
        point->name = strdup(VSB_data(vsb));
227 46919
        AN(point->name);
228 46919
        point->point.name = point->name;
229
230
#define DOF(n, k)                               \
231
        vt = vjsn_child(vv, k);                 \
232
        AN(vt);                                 \
233
        assert(vt->type == VJSN_STRING);        \
234
        point->point.n = vt->value;
235
236 46919
        DOF(ctype, "ctype");
237 46919
        DOF(sdesc, "oneliner");
238 46919
        DOF(ldesc, "docs");
239
#undef DOF
240 46919
        vt = vjsn_child(vv, "type");
241 46919
        AN(vt);
242 46919
        assert(vt->type == VJSN_STRING);
243
244 46919
        if (!strcmp(vt->value, "counter")) {
245 38145
                point->point.semantics = 'c';
246 8774
        } else if (!strcmp(vt->value, "gauge")) {
247 8736
                point->point.semantics = 'g';
248 38
        } else if (!strcmp(vt->value, "bitmap")) {
249 38
                point->point.semantics = 'b';
250
        } else {
251 0
                point->point.semantics = '?';
252
        }
253
254 46919
        vt = vjsn_child(vv, "format");
255 46919
        AN(vt);
256 46919
        assert(vt->type == VJSN_STRING);
257
258 46919
        if (!strcmp(vt->value, "integer")) {
259 41645
                point->point.format = 'i';
260 5274
        } else if (!strcmp(vt->value, "bytes")) {
261 4710
                point->point.format = 'B';
262 564
        } else if (!strcmp(vt->value, "bitmap")) {
263 38
                point->point.format = 'b';
264 526
        } else if (!strcmp(vt->value, "duration")) {
265 526
                point->point.format = 'd';
266
        } else {
267 0
                point->point.format = '?';
268
        }
269
270 46919
        vt = vjsn_child(vv, "level");
271 46919
        AN(vt);
272 46919
        assert(vt->type == VJSN_STRING);
273
274 46919
        if (!strcmp(vt->value, "info"))  {
275 22718
                point->point.level = &level_info;
276 24201
        } else if (!strcmp(vt->value, "diag")) {
277 14062
                point->point.level = &level_diag;
278 10139
        } else if (!strcmp(vt->value, "debug")) {
279 10139
                point->point.level = &level_debug;
280
        } else {
281 0
                WRONG("Illegal level");
282
        }
283
284 46919
        vt = vjsn_child(vv, "index");
285 46919
        AN(vt);
286
287 46919
        point->point.ptr = (volatile void*)
288 46919
            ((volatile char*)fantom->b + atoi(vt->value));
289 46919
        return (1);
290
}
291
292
static void
293 2419
vsc_del_seg(const struct vsc *vsc, struct vsm *vsm, struct vsc_seg *sp)
294
{
295
        unsigned u;
296
        struct vsc_pt *pp;
297
298 2419
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
299 2419
        AN(vsm);
300 2419
        CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC);
301 2419
        AZ(VSM_Unmap(vsm, sp->fantom));
302 2419
        vjsn_delete(&sp->vj);
303 2419
        pp = sp->points;
304 46314
        for (u = 0; u < sp->npoints; u++, pp++) {
305 43895
                if (vsc->fdestroy != NULL)
306 0
                        vsc->fdestroy(vsc->priv, &pp->point);
307 43895
                vsc_clean_point(pp);
308
        }
309 2419
        free(sp->points);
310 2419
        FREE_OBJ(sp);
311 2419
}
312
313
static struct vsc_seg *
314 2899
vsc_add_seg(const struct vsc *vsc, struct vsm *vsm, const struct vsm_fantom *fp)
315
{
316
        struct vsc_seg *sp;
317
        uint64_t u;
318
        const char *p;
319
        const char *e;
320
        struct vjsn_val *vv, *vve;
321
        struct vsb *vsb;
322
        struct vsc_pt *pp;
323
324 2899
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
325 2899
        AN(vsm);
326
327 2899
        ALLOC_OBJ(sp, VSC_SEG_MAGIC);
328 2899
        AN(sp);
329 2899
        *sp->fantom = *fp;
330 2899
        if (VSM_Map(vsm, sp->fantom)) {
331
                /*
332
                 * If the seg was removed between our call to VSM_Status()
333
                 * and now, we won't be able to map it.
334
                 */
335 0
                FREE_OBJ(sp);
336 0
                return (NULL);
337
        }
338
        // AZ(VSM_Map(vsm, sp->fantom));
339
340 2899
        u = vbe64dec(sp->fantom->b);
341 2899
        if (u == 0) {
342 0
                VRMB();
343 0
                usleep(100000);
344 0
                u = vbe64dec(sp->fantom->b);
345
        }
346 2899
        assert(u > 0);
347 2899
        p = (char*)sp->fantom->b + 8 + u;
348 2899
        assert (p < (char*)sp->fantom->e);
349 2899
        sp->vj = vjsn_parse(p, &e);
350 2899
        XXXAZ(e);
351 2899
        vve = vjsn_child(sp->vj->value, "elements");
352 2899
        AN(vve);
353 2899
        sp->npoints = strtoul(vve->value, NULL, 0);
354 2899
        sp->points = calloc(sp->npoints, sizeof *sp->points);
355 2899
        AN(sp->points);
356 2899
        vsb = VSB_new_auto();
357 2899
        AN(vsb);
358 2899
        vve = vjsn_child(sp->vj->value, "elem");
359 2899
        AN(vve);
360 2899
        pp = sp->points;
361 51146
        VTAILQ_FOREACH(vv, &vve->children, list) {
362 95166
                if (vsc_fill_point(vsc, sp->fantom, vv, vsb, pp) &&
363 46919
                        vsc->fnew != NULL)
364 0
                        pp->point.priv = vsc->fnew(vsc->priv, &pp->point);
365 48247
                pp++;
366
        }
367 2899
        VSB_destroy(&vsb);
368 2899
        AN(sp->vj);
369 2899
        return (sp);
370
}
371
372
static int
373 30508
vsc_iter_seg(const struct vsc *vsc, const struct vsc_seg *sp,
374
    VSC_iter_f *fiter, void *priv)
375
{
376
        unsigned u;
377 30508
        int i = 0;
378
        struct vsc_pt *pp;
379
380 30508
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
381 30508
        CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC);
382 30508
        AN(fiter);
383 30508
        pp = sp->points;
384 346624
        for (u = 0; u < sp->npoints && i == 0; u++, pp++) {
385 316116
                if (pp->name != NULL)
386 313460
                        i = fiter(priv, &pp->point);
387
        }
388 30508
        return (i);
389
}
390
391
int
392 1740
VSC_Iter(struct vsc *vsc, struct vsm *vsm, VSC_iter_f *fiter, void *priv)
393
{
394
        struct vsm_fantom ifantom;
395
        struct vsc_seg *sp, *sp2;
396 1740
        int i = 0;
397
398 1740
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
399 1740
        AN(vsm);
400 1740
        sp = VTAILQ_FIRST(&vsc->segs);
401 42636
        VSM_FOREACH(&ifantom, vsm) {
402 40260
                if (strcmp(ifantom.class, VSC_CLASS))
403 9752
                        continue;
404 88657
                while (sp != NULL &&
405 55244
                    (strcmp(ifantom.ident, sp->fantom->ident) ||
406 27619
                    VSM_StillValid(vsm, sp->fantom) != VSM_valid)) {
407 16
                        sp2 = sp;
408 16
                        sp = VTAILQ_NEXT(sp, list);
409 16
                        VTAILQ_REMOVE(&vsc->segs, sp2, list);
410 16
                        vsc_del_seg(vsc, vsm, sp2);
411
                }
412 30508
                if (sp != NULL) {
413 27609
                        if (fiter != NULL)
414 27609
                                i = vsc_iter_seg(vsc, sp, fiter, priv);
415 27609
                        sp = VTAILQ_NEXT(sp, list);
416
                } else {
417 2899
                        sp = vsc_add_seg(vsc, vsm, &ifantom);
418 2899
                        if (sp != NULL) {
419 2899
                                VTAILQ_INSERT_TAIL(&vsc->segs, sp, list);
420 2899
                                if (fiter != NULL)
421 2899
                                        i = vsc_iter_seg(vsc, sp, fiter, priv);
422 2899
                                sp = NULL;
423
                        }
424
                }
425 30508
                if (i)
426 1104
                        break;
427
        }
428 4465
        while (sp != NULL) {
429 985
                sp2 = sp;
430 985
                sp = VTAILQ_NEXT(sp, list);
431 985
                VTAILQ_REMOVE(&vsc->segs, sp2, list);
432 985
                vsc_del_seg(vsc, vsm, sp2);
433
        }
434 1740
        return (i);
435
}
436
437
438
/*--------------------------------------------------------------------
439
 */
440
441
const struct VSC_level_desc *
442 0
VSC_ChangeLevel(const struct VSC_level_desc *old, int chg)
443
{
444
        int i;
445
446 0
        if (old == NULL)
447 0
                old = levels[0];
448 0
        for (i = 0; i < nlevels; i++)
449 0
                if (old == levels[i])
450 0
                        break;
451 0
        if (i == nlevels)
452 0
                i = 0;
453
        else
454 0
                i += chg;
455 0
        if (i >= nlevels)
456 0
                i = nlevels - 1;
457 0
        if (i < 0)
458 0
                i = 0;
459 0
        return (levels[i]);
460
}
461
462
/*--------------------------------------------------------------------*/
463
464
static void
465 2484
vsc_delete_sf_list(struct vsc_sf_head *head)
466
{
467
        struct vsc_sf *sf;
468
469 4968
        while (!VTAILQ_EMPTY(head)) {
470 0
                sf = VTAILQ_FIRST(head);
471 0
                CHECK_OBJ_NOTNULL(sf, VSC_SF_MAGIC);
472 0
                VTAILQ_REMOVE(head, sf, list);
473 0
                free(sf->pattern);
474 0
                FREE_OBJ(sf);
475
        }
476 2484
}
477
478
void
479 1242
VSC_Destroy(struct vsc **vscp, struct vsm *vsm)
480
{
481
        struct vsc *vsc;
482
        struct vsc_seg *sp, *sp2;
483
484 1242
        TAKE_OBJ_NOTNULL(vsc, vscp, VSC_MAGIC);
485 1242
        vsc_delete_sf_list(&vsc->sf_list_include);
486 1242
        vsc_delete_sf_list(&vsc->sf_list_exclude);
487 2660
        VTAILQ_FOREACH_SAFE(sp, &vsc->segs, list, sp2) {
488 1418
                VTAILQ_REMOVE(&vsc->segs, sp, list);
489 1418
                vsc_del_seg(vsc, vsm, sp);
490
        }
491 1242
        FREE_OBJ(vsc);
492 1242
}
493