| | varnish-cache/lib/libvarnishapi/vsc.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2006 Verdens Gang AS |
2 |
|
* Copyright (c) 2006-2015 Varnish Software AS |
3 |
|
* All rights reserved. |
4 |
|
* |
5 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
6 |
|
* Author: Martin Blix Grydeland <martin@varnish-software.com> |
7 |
|
* |
8 |
|
* SPDX-License-Identifier: BSD-2-Clause |
9 |
|
* |
10 |
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
* modification, are permitted provided that the following conditions |
12 |
|
* are met: |
13 |
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
* documentation and/or other materials provided with the distribution. |
18 |
|
* |
19 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
20 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
23 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 |
|
* SUCH DAMAGE. |
30 |
|
*/ |
31 |
|
|
32 |
|
#include "config.h" |
33 |
|
|
34 |
|
#include <sys/stat.h> |
35 |
|
|
36 |
|
#include <fnmatch.h> |
37 |
|
#include <stdint.h> |
38 |
|
#include <stdio.h> |
39 |
|
#include <stdlib.h> |
40 |
|
#include <string.h> |
41 |
|
#include <unistd.h> |
42 |
|
|
43 |
|
#include "vdef.h" |
44 |
|
#include "vas.h" |
45 |
|
#include "miniobj.h" |
46 |
|
#include "vqueue.h" |
47 |
|
#include "vjsn.h" |
48 |
|
#include "vsb.h" |
49 |
|
#include "vsc_priv.h" |
50 |
|
#include "vtim.h" |
51 |
|
|
52 |
|
#include "vapi/vsc.h" |
53 |
|
#include "vapi/vsm.h" |
54 |
|
|
55 |
|
struct vsc_sf_mode { |
56 |
|
const char *name; |
57 |
|
unsigned include; |
58 |
|
unsigned fail; |
59 |
|
unsigned append; |
60 |
|
}; |
61 |
|
|
62 |
|
static const struct vsc_sf_mode VSC_SF_INCLUDE[1] = {{"include", 1, 1, 1}}; |
63 |
|
static const struct vsc_sf_mode VSC_SF_EXCLUDE[1] = {{"exclude", 0, 0, 1}}; |
64 |
|
static const struct vsc_sf_mode VSC_SF_REQUIRE[1] = {{"require", 1, 0, 0}}; |
65 |
|
|
66 |
|
struct vsc_sf { |
67 |
|
unsigned magic; |
68 |
|
#define VSC_SF_MAGIC 0x558478dd |
69 |
|
VTAILQ_ENTRY(vsc_sf) list; |
70 |
|
char *pattern; |
71 |
|
const struct vsc_sf_mode *mode; |
72 |
|
}; |
73 |
|
|
74 |
|
VTAILQ_HEAD(vsc_sf_head, vsc_sf); |
75 |
|
|
76 |
|
struct vsc_pt { |
77 |
|
struct VSC_point point; |
78 |
|
char *name; |
79 |
|
}; |
80 |
|
|
81 |
|
enum vsc_seg_type { |
82 |
|
VSC_SEG_COUNTERS = 1, |
83 |
|
VSC_SEG_DOCS, |
84 |
|
}; |
85 |
|
|
86 |
|
struct vsc_seg { |
87 |
|
unsigned magic; |
88 |
|
#define VSC_SEG_MAGIC 0x801177d4 |
89 |
|
enum vsc_seg_type type; |
90 |
|
VTAILQ_ENTRY(vsc_seg) list; |
91 |
|
VTAILQ_ENTRY(vsc_seg) doc_list; |
92 |
|
struct vsm_fantom fantom[1]; |
93 |
|
const struct vsc_head *head; |
94 |
|
const char *body; |
95 |
|
|
96 |
|
struct vjsn *vj; |
97 |
|
|
98 |
|
unsigned npoints; |
99 |
|
struct vsc_pt *points; |
100 |
|
|
101 |
|
int mapped; |
102 |
|
int exposed; |
103 |
|
}; |
104 |
|
VTAILQ_HEAD(vsc_seg_head, vsc_seg); |
105 |
|
|
106 |
|
struct vsc { |
107 |
|
unsigned magic; |
108 |
|
#define VSC_MAGIC 0x3373554a |
109 |
|
|
110 |
|
unsigned raw; |
111 |
|
struct vsc_sf_head sf_list; |
112 |
|
struct vsc_seg_head segs; |
113 |
|
struct vsc_seg_head docs; |
114 |
|
|
115 |
|
VSC_new_f *fnew; |
116 |
|
VSC_destroy_f *fdestroy; |
117 |
|
void *priv; |
118 |
|
}; |
119 |
|
|
120 |
|
/*-------------------------------------------------------------------- |
121 |
|
* Build the static level, type and point descriptions |
122 |
|
*/ |
123 |
|
|
124 |
|
enum vsc_levels { |
125 |
|
#define VSC_LEVEL_F(v,l,e,d) v, |
126 |
|
#include "tbl/vsc_levels.h" |
127 |
|
}; |
128 |
|
|
129 |
|
static const struct VSC_level_desc levels[] = { |
130 |
|
#define VSC_LEVEL_F(v,l,e,d) [v] = {#v, l, e, d}, |
131 |
|
#include "tbl/vsc_levels.h" |
132 |
|
}; |
133 |
|
|
134 |
|
static const ssize_t nlevels = sizeof(levels)/sizeof(*levels); |
135 |
|
|
136 |
|
/*--------------------------------------------------------------------*/ |
137 |
|
|
138 |
|
struct vsc * |
139 |
16660 |
VSC_New(void) |
140 |
|
{ |
141 |
|
struct vsc *vsc; |
142 |
|
|
143 |
16660 |
ALLOC_OBJ(vsc, VSC_MAGIC); |
144 |
16660 |
if (vsc == NULL) |
145 |
0 |
return (vsc); |
146 |
16660 |
VTAILQ_INIT(&vsc->sf_list); |
147 |
16660 |
VTAILQ_INIT(&vsc->segs); |
148 |
16660 |
VTAILQ_INIT(&vsc->docs); |
149 |
16660 |
return (vsc); |
150 |
16660 |
} |
151 |
|
|
152 |
|
/*--------------------------------------------------------------------*/ |
153 |
|
|
154 |
|
static int |
155 |
629 |
vsc_sf_arg(struct vsc *vsc, const char *glob, const struct vsc_sf_mode *mode) |
156 |
|
{ |
157 |
|
struct vsc_sf *sf; |
158 |
|
|
159 |
629 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
160 |
629 |
AN(glob); |
161 |
629 |
AN(mode); |
162 |
|
|
163 |
629 |
ALLOC_OBJ(sf, VSC_SF_MAGIC); |
164 |
629 |
AN(sf); |
165 |
629 |
REPLACE(sf->pattern, glob); |
166 |
629 |
sf->mode = mode; |
167 |
629 |
AN(mode->name); |
168 |
629 |
if (mode->append) |
169 |
493 |
VTAILQ_INSERT_TAIL(&vsc->sf_list, sf, list); |
170 |
|
else |
171 |
136 |
VTAILQ_INSERT_HEAD(&vsc->sf_list, sf, list); |
172 |
629 |
return (1); |
173 |
|
} |
174 |
|
|
175 |
|
static int |
176 |
357 |
vsc_f_arg(struct vsc *vsc, const char *opt) |
177 |
|
{ |
178 |
|
|
179 |
357 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
180 |
357 |
AN(opt); |
181 |
|
|
182 |
357 |
if (opt[0] == '^') |
183 |
85 |
return (vsc_sf_arg(vsc, opt + 1, VSC_SF_EXCLUDE)); |
184 |
272 |
return (vsc_sf_arg(vsc, opt, VSC_SF_INCLUDE)); |
185 |
357 |
} |
186 |
|
|
187 |
|
/*--------------------------------------------------------------------*/ |
188 |
|
|
189 |
|
int |
190 |
629 |
VSC_Arg(struct vsc *vsc, char arg, const char *opt) |
191 |
|
{ |
192 |
|
|
193 |
629 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
194 |
|
|
195 |
629 |
switch (arg) { |
196 |
119 |
case 'I': return (vsc_sf_arg(vsc, opt, VSC_SF_INCLUDE)); |
197 |
17 |
case 'X': return (vsc_sf_arg(vsc, opt, VSC_SF_EXCLUDE)); |
198 |
136 |
case 'R': return (vsc_sf_arg(vsc, opt, VSC_SF_REQUIRE)); |
199 |
357 |
case 'f': return (vsc_f_arg(vsc, opt)); |
200 |
0 |
case 'r': vsc->raw = !vsc->raw; return (1); |
201 |
0 |
default: return (0); |
202 |
|
} |
203 |
629 |
} |
204 |
|
|
205 |
|
unsigned |
206 |
119 |
VSC_IsRaw(const struct vsc *vsc) |
207 |
|
{ |
208 |
|
|
209 |
119 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
210 |
119 |
return (vsc->raw); |
211 |
|
} |
212 |
|
|
213 |
|
/*-------------------------------------------------------------------- |
214 |
|
*/ |
215 |
|
|
216 |
|
static int |
217 |
928871 |
vsc_filter(const struct vsc *vsc, const char *nm) |
218 |
|
{ |
219 |
|
struct vsc_sf *sf; |
220 |
928871 |
unsigned res = 0; |
221 |
|
|
222 |
928871 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
223 |
1120155 |
VTAILQ_FOREACH(sf, &vsc->sf_list, list) { |
224 |
194735 |
if (!fnmatch(sf->pattern, nm, 0)) |
225 |
3451 |
return (!sf->mode->include); |
226 |
191284 |
res |= sf->mode->fail; |
227 |
191284 |
} |
228 |
925420 |
return (res); |
229 |
928871 |
} |
230 |
|
|
231 |
|
/*-------------------------------------------------------------------- |
232 |
|
*/ |
233 |
|
|
234 |
|
static void |
235 |
794299 |
vsc_clean_point(struct vsc_pt *point) |
236 |
|
{ |
237 |
794299 |
REPLACE(point->name, NULL); |
238 |
794299 |
} |
239 |
|
|
240 |
|
static void |
241 |
928871 |
vsc_fill_point(const struct vsc *vsc, const struct vsc_seg *seg, |
242 |
|
const struct vjsn_val *vv, struct vsb *vsb, struct vsc_pt *point) |
243 |
|
{ |
244 |
|
struct vjsn_val *vt; |
245 |
|
|
246 |
928871 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
247 |
928871 |
memset(point, 0, sizeof *point); |
248 |
|
|
249 |
928871 |
vt = vjsn_child(vv, "name"); |
250 |
928871 |
AN(vt); |
251 |
928871 |
assert(vjsn_is_string(vt)); |
252 |
|
|
253 |
928871 |
VSB_clear(vsb); |
254 |
928871 |
VSB_printf(vsb, "%s.%s", seg->fantom->ident, vt->value); |
255 |
928871 |
AZ(VSB_finish(vsb)); |
256 |
|
|
257 |
928871 |
if (vsc_filter(vsc, VSB_data(vsb))) |
258 |
66368 |
return; |
259 |
|
|
260 |
862503 |
point->name = strdup(VSB_data(vsb)); |
261 |
862503 |
AN(point->name); |
262 |
862503 |
point->point.name = point->name; |
263 |
|
|
264 |
|
#define DOF(n, k) \ |
265 |
|
vt = vjsn_child(vv, k); \ |
266 |
|
AN(vt); \ |
267 |
|
assert(vjsn_is_string(vt)); \ |
268 |
|
point->point.n = vt->value; |
269 |
|
|
270 |
862503 |
DOF(ctype, "ctype"); |
271 |
862503 |
DOF(sdesc, "oneliner"); |
272 |
862503 |
DOF(ldesc, "docs"); |
273 |
|
#undef DOF |
274 |
862503 |
vt = vjsn_child(vv, "type"); |
275 |
862503 |
AN(vt); |
276 |
862503 |
assert(vjsn_is_string(vt)); |
277 |
|
|
278 |
862503 |
if (!strcmp(vt->value, "counter")) { |
279 |
758735 |
point->point.semantics = 'c'; |
280 |
862503 |
} else if (!strcmp(vt->value, "gauge")) { |
281 |
101398 |
point->point.semantics = 'g'; |
282 |
103768 |
} else if (!strcmp(vt->value, "bitmap")) { |
283 |
2370 |
point->point.semantics = 'b'; |
284 |
2370 |
} else { |
285 |
0 |
point->point.semantics = '?'; |
286 |
|
} |
287 |
|
|
288 |
862503 |
vt = vjsn_child(vv, "format"); |
289 |
862503 |
AN(vt); |
290 |
862503 |
assert(vjsn_is_string(vt)); |
291 |
|
|
292 |
862503 |
if (!strcmp(vt->value, "integer")) { |
293 |
780140 |
point->point.format = 'i'; |
294 |
862503 |
} else if (!strcmp(vt->value, "bytes")) { |
295 |
72122 |
point->point.format = 'B'; |
296 |
82363 |
} else if (!strcmp(vt->value, "bitmap")) { |
297 |
2370 |
point->point.format = 'b'; |
298 |
10241 |
} else if (!strcmp(vt->value, "duration")) { |
299 |
7871 |
point->point.format = 'd'; |
300 |
7871 |
} else { |
301 |
0 |
point->point.format = '?'; |
302 |
|
} |
303 |
|
|
304 |
862503 |
vt = vjsn_child(vv, "level"); |
305 |
862503 |
AN(vt); |
306 |
862503 |
assert(vjsn_is_string(vt)); |
307 |
|
|
308 |
862503 |
if (!strcmp(vt->value, "info")) { |
309 |
405830 |
point->point.level = &levels[info]; |
310 |
862503 |
} else if (!strcmp(vt->value, "diag")) { |
311 |
262886 |
point->point.level = &levels[diag]; |
312 |
456673 |
} else if (!strcmp(vt->value, "debug")) { |
313 |
193787 |
point->point.level = &levels[debug]; |
314 |
193787 |
} else { |
315 |
0 |
WRONG("Illegal level"); |
316 |
|
} |
317 |
|
|
318 |
862503 |
vt = vjsn_child(vv, "index"); |
319 |
862503 |
AN(vt); |
320 |
|
|
321 |
862503 |
point->point.ptr = (volatile const void*)(seg->body + atoi(vt->value)); |
322 |
862503 |
point->point.raw = vsc->raw; |
323 |
928871 |
} |
324 |
|
|
325 |
|
static struct vsc_seg * |
326 |
183046 |
vsc_new_seg(const struct vsm_fantom *fp, enum vsc_seg_type type) |
327 |
|
{ |
328 |
|
struct vsc_seg *sp; |
329 |
|
|
330 |
183046 |
ALLOC_OBJ(sp, VSC_SEG_MAGIC); |
331 |
183046 |
AN(sp); |
332 |
183046 |
*sp->fantom = *fp; |
333 |
183046 |
sp->type = type; |
334 |
|
|
335 |
183046 |
return (sp); |
336 |
|
} |
337 |
|
|
338 |
|
static void |
339 |
169939 |
vsc_unmap_seg(const struct vsc *vsc, struct vsm *vsm, struct vsc_seg *sp) |
340 |
|
{ |
341 |
|
unsigned u; |
342 |
|
struct vsc_pt *pp; |
343 |
|
|
344 |
169939 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
345 |
169939 |
AN(vsm); |
346 |
169939 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
347 |
|
|
348 |
169939 |
AZ(sp->exposed); |
349 |
169939 |
if (!sp->mapped) |
350 |
122864 |
return; |
351 |
|
|
352 |
47075 |
if (sp->type == VSC_SEG_COUNTERS) { |
353 |
35389 |
pp = sp->points; |
354 |
829688 |
for (u = 0; u < sp->npoints; u++, pp++) |
355 |
794299 |
vsc_clean_point(pp); |
356 |
35389 |
free(sp->points); |
357 |
35389 |
sp->points = NULL; |
358 |
35389 |
sp->npoints = 0; |
359 |
35389 |
AZ(sp->vj); |
360 |
47075 |
} else if (sp->type == VSC_SEG_DOCS) { |
361 |
11686 |
if (sp->vj != NULL) |
362 |
11686 |
vjsn_delete(&sp->vj); |
363 |
11686 |
AZ(sp->vj); |
364 |
11686 |
AZ(sp->points); |
365 |
11686 |
} else { |
366 |
0 |
WRONG("Invalid segment type"); |
367 |
|
} |
368 |
|
|
369 |
47075 |
AZ(VSM_Unmap(vsm, sp->fantom)); |
370 |
47075 |
sp->head = NULL; |
371 |
47075 |
sp->body = NULL; |
372 |
47075 |
sp->mapped = 0; |
373 |
169939 |
} |
374 |
|
|
375 |
|
static int |
376 |
410104 |
vsc_map_seg(const struct vsc *vsc, struct vsm *vsm, struct vsc_seg *sp) |
377 |
|
{ |
378 |
|
const struct vsc_head *head; |
379 |
|
struct vsc_seg *spd; |
380 |
|
const char *e; |
381 |
|
struct vjsn_val *vv, *vve; |
382 |
|
struct vsb *vsb; |
383 |
|
struct vsc_pt *pp; |
384 |
|
int retry; |
385 |
|
|
386 |
410104 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
387 |
410104 |
AN(vsm); |
388 |
410104 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
389 |
|
|
390 |
410104 |
if (sp->mapped) |
391 |
349922 |
return (0); |
392 |
|
|
393 |
60182 |
AZ(sp->exposed); |
394 |
|
|
395 |
60182 |
if (VSM_Map(vsm, sp->fantom)) |
396 |
0 |
return (-1); |
397 |
60182 |
head = sp->fantom->b; |
398 |
|
|
399 |
|
/* It isn't ready yet. Sleep and try again. If it still |
400 |
|
* isn't ready, fail the mapping. The transitions inside |
401 |
|
* varnishd that we are waiting for are just some memcpy() |
402 |
|
* operations, so there is no reason to allow a long retry |
403 |
|
* time. */ |
404 |
60182 |
for (retry = 10; retry > 0 && head->ready == 0; retry--) |
405 |
0 |
VTIM_sleep(0.01); |
406 |
|
|
407 |
60182 |
if (head->ready == 0) { |
408 |
0 |
AZ(VSM_Unmap(vsm, sp->fantom)); |
409 |
0 |
return (-1); |
410 |
|
} |
411 |
|
|
412 |
60182 |
sp->head = head; |
413 |
60182 |
sp->body = (char*)sp->fantom->b + sp->head->body_offset; |
414 |
60182 |
sp->mapped = 1; |
415 |
|
|
416 |
60182 |
if (sp->type == VSC_SEG_DOCS) { |
417 |
|
/* Parse the DOCS json */ |
418 |
13590 |
sp->vj = vjsn_parse(sp->body, &e); |
419 |
13590 |
XXXAZ(e); |
420 |
13590 |
AN(sp->vj); |
421 |
13590 |
return (0); |
422 |
|
} |
423 |
|
|
424 |
46592 |
assert(sp->type == VSC_SEG_COUNTERS); |
425 |
|
|
426 |
|
/* Find the corresponding DOCS seg. We are not able to |
427 |
|
* read and match on the doc_id until the DOCS section is |
428 |
|
* mapped. Iterate over all the DOCS sections, attempt to |
429 |
|
* map if needed, and then check the doc_id. */ |
430 |
151947 |
VTAILQ_FOREACH(spd, &vsc->docs, doc_list) { |
431 |
151947 |
CHECK_OBJ_NOTNULL(spd, VSC_SEG_MAGIC); |
432 |
151947 |
assert(spd->type == VSC_SEG_DOCS); |
433 |
151947 |
if (!spd->mapped && vsc_map_seg(vsc, vsm, spd)) |
434 |
0 |
continue; /* Failed to map it */ |
435 |
151947 |
AN(spd->mapped); |
436 |
151947 |
if (spd->head->doc_id == sp->head->doc_id) |
437 |
46592 |
break; /* We have a match */ |
438 |
105355 |
} |
439 |
46592 |
if (spd == NULL) { |
440 |
|
/* Could not find the right DOCS seg. Leave this |
441 |
|
* seg as unmapped. */ |
442 |
0 |
vsc_unmap_seg(vsc, vsm, sp); |
443 |
0 |
return (-1); |
444 |
|
} |
445 |
|
|
446 |
|
/* Create the VSC points list */ |
447 |
46592 |
vve = vjsn_child(spd->vj->value, "elements"); |
448 |
46592 |
AN(vve); |
449 |
46592 |
sp->npoints = strtoul(vve->value, NULL, 0); |
450 |
46592 |
sp->points = calloc(sp->npoints, sizeof *sp->points); |
451 |
46592 |
AN(sp->points); |
452 |
46592 |
vsb = VSB_new_auto(); |
453 |
46592 |
AN(vsb); |
454 |
46592 |
vve = vjsn_child(spd->vj->value, "elem"); |
455 |
46592 |
AN(vve); |
456 |
46592 |
pp = sp->points; |
457 |
975463 |
VTAILQ_FOREACH(vv, &vve->children, list) { |
458 |
928871 |
vsc_fill_point(vsc, sp, vv, vsb, pp); |
459 |
928871 |
pp++; |
460 |
928871 |
} |
461 |
46592 |
VSB_destroy(&vsb); |
462 |
46592 |
return (0); |
463 |
410104 |
} |
464 |
|
|
465 |
|
/*-------------------------------------------------------------------- |
466 |
|
*/ |
467 |
|
|
468 |
|
static void |
469 |
566453 |
vsc_expose(const struct vsc *vsc, struct vsc_seg *sp, int del) |
470 |
|
{ |
471 |
|
struct vsc_pt *pp; |
472 |
|
unsigned u; |
473 |
|
int expose; |
474 |
|
|
475 |
566453 |
if (!sp->mapped) { |
476 |
122864 |
AZ(sp->exposed); |
477 |
122864 |
return; |
478 |
|
} |
479 |
|
|
480 |
447720 |
if (vsc->fnew != NULL && !sp->exposed && |
481 |
4930 |
!del && sp->head->ready == 1) |
482 |
4131 |
expose = 1; |
483 |
470838 |
else if (vsc->fdestroy != NULL && sp->exposed && |
484 |
35511 |
(del || sp->head->ready == 2)) |
485 |
4131 |
expose = 0; |
486 |
|
else |
487 |
435327 |
return; |
488 |
|
|
489 |
8262 |
pp = sp->points; |
490 |
95200 |
for (u = 0; u < sp->npoints; u++, pp++) { |
491 |
86938 |
if (pp->name == NULL) |
492 |
11764 |
continue; |
493 |
75174 |
if (expose) |
494 |
37587 |
pp->point.priv = vsc->fnew(vsc->priv, &pp->point); |
495 |
|
else |
496 |
37587 |
vsc->fdestroy(vsc->priv, &pp->point); |
497 |
75174 |
} |
498 |
8262 |
sp->exposed = expose; |
499 |
566453 |
} |
500 |
|
|
501 |
|
/*-------------------------------------------------------------------- |
502 |
|
*/ |
503 |
|
|
504 |
|
static void |
505 |
38348 |
vsc_del_segs(struct vsc *vsc, struct vsm *vsm, struct vsc_seg_head *head) |
506 |
|
{ |
507 |
|
struct vsc_seg *sp, *sp2; |
508 |
|
|
509 |
208287 |
VTAILQ_FOREACH_SAFE(sp, head, list, sp2) { |
510 |
169939 |
CHECK_OBJ(sp, VSC_SEG_MAGIC); |
511 |
169939 |
VTAILQ_REMOVE(head, sp, list); |
512 |
169939 |
if (sp->type == VSC_SEG_DOCS) |
513 |
27676 |
VTAILQ_REMOVE(&vsc->docs, sp, doc_list); |
514 |
169939 |
vsc_expose(vsc, sp, 1); |
515 |
169939 |
vsc_unmap_seg(vsc, vsm, sp); |
516 |
169939 |
FREE_OBJ(sp); |
517 |
169939 |
} |
518 |
38348 |
} |
519 |
|
|
520 |
|
/*-------------------------------------------------------------------- |
521 |
|
*/ |
522 |
|
|
523 |
|
static int |
524 |
355886 |
vsc_iter_seg(const struct vsc *vsc, const struct vsc_seg *sp, |
525 |
|
VSC_iter_f *fiter, void *priv) |
526 |
|
{ |
527 |
|
unsigned u; |
528 |
355886 |
int i = 0; |
529 |
|
struct vsc_pt *pp; |
530 |
|
|
531 |
355886 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
532 |
355886 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
533 |
355886 |
AN(fiter); |
534 |
355886 |
pp = sp->points; |
535 |
4895785 |
for (u = 0; u < sp->npoints && i == 0; u++, pp++) { |
536 |
4539899 |
if (pp->name != NULL) |
537 |
4504913 |
i = fiter(priv, &pp->point); |
538 |
4539899 |
} |
539 |
355886 |
return (i); |
540 |
|
} |
541 |
|
|
542 |
|
int |
543 |
22096 |
VSC_Iter(struct vsc *vsc, struct vsm *vsm, VSC_iter_f *fiter, void *priv) |
544 |
|
{ |
545 |
|
enum vsc_seg_type type; |
546 |
|
struct vsm_fantom ifantom; |
547 |
|
struct vsc_seg *sp, *sp2; |
548 |
|
struct vsc_seg_head removed; |
549 |
22096 |
int i = 0; |
550 |
|
|
551 |
22096 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
552 |
22096 |
AN(vsm); |
553 |
|
|
554 |
|
/* First walk the VSM segment list and consolidate with the shadow |
555 |
|
* VSC seg list. We avoid calling any of the callback functions |
556 |
|
* while iterating the VSMs. This removes any headaches wrt to |
557 |
|
* callbacks calling VSM_Status(). */ |
558 |
22096 |
VTAILQ_INIT(&removed); |
559 |
22096 |
sp = VTAILQ_FIRST(&vsc->segs); |
560 |
1090037 |
VSM_FOREACH(&ifantom, vsm) { |
561 |
1067941 |
AN(ifantom.category); |
562 |
1067941 |
if (!strcmp(ifantom.category, VSC_CLASS)) |
563 |
781895 |
type = VSC_SEG_COUNTERS; |
564 |
286046 |
else if (!strcmp(ifantom.category, VSC_DOC_CLASS)) |
565 |
154018 |
type = VSC_SEG_DOCS; |
566 |
|
else { |
567 |
|
/* Not one of the categories we care about */ |
568 |
132028 |
continue; |
569 |
|
} |
570 |
|
|
571 |
947116 |
while (sp != NULL) { |
572 |
764070 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
573 |
764070 |
if (VSM_StillValid(vsm, sp->fantom) == VSM_valid && |
574 |
752867 |
!strcmp(ifantom.ident, sp->fantom->ident)) { |
575 |
|
/* sp matches the expected value */ |
576 |
752867 |
break; |
577 |
|
} |
578 |
|
|
579 |
|
/* sp is no longer in the VSM list. Remove it from |
580 |
|
* our list. */ |
581 |
11203 |
sp2 = sp; |
582 |
11203 |
sp = VTAILQ_NEXT(sp, list); |
583 |
11203 |
VTAILQ_REMOVE(&vsc->segs, sp2, list); |
584 |
11203 |
VTAILQ_INSERT_TAIL(&removed, sp2, list); |
585 |
|
} |
586 |
|
|
587 |
935913 |
if (sp == NULL) { |
588 |
|
/* New entries are always appended last in the VSM |
589 |
|
* list. Since we have iterated past all the |
590 |
|
* entries in our shadow list, the VSM entry is a |
591 |
|
* new entry we have not seen before. */ |
592 |
183046 |
sp = vsc_new_seg(&ifantom, type); |
593 |
183046 |
AN(sp); |
594 |
183046 |
VTAILQ_INSERT_TAIL(&vsc->segs, sp, list); |
595 |
183046 |
if (type == VSC_SEG_DOCS) |
596 |
29580 |
VTAILQ_INSERT_TAIL(&vsc->docs, sp, doc_list); |
597 |
183046 |
} |
598 |
|
|
599 |
935913 |
assert(sp->type == type); |
600 |
935913 |
sp = VTAILQ_NEXT(sp, list); |
601 |
|
} |
602 |
22096 |
while (sp != NULL) { |
603 |
|
/* Clean up the tail end of the shadow list. */ |
604 |
0 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
605 |
0 |
sp2 = sp; |
606 |
0 |
sp = VTAILQ_NEXT(sp, list); |
607 |
|
|
608 |
0 |
VTAILQ_REMOVE(&vsc->segs, sp2, list); |
609 |
0 |
VTAILQ_INSERT_TAIL(&removed, sp2, list); |
610 |
|
} |
611 |
|
|
612 |
22096 |
vsc_del_segs(vsc, vsm, &removed); |
613 |
|
|
614 |
|
/* Iterate our shadow list, reporting on each pointer value */ |
615 |
494991 |
VTAILQ_FOREACH(sp, &vsc->segs, list) { |
616 |
489281 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
617 |
|
|
618 |
489281 |
if (sp->type != VSC_SEG_COUNTERS) |
619 |
92767 |
continue; |
620 |
|
|
621 |
|
/* Attempt to map the VSM. This is a noop if it was |
622 |
|
* already mapped. If we fail we skip this seg on this |
623 |
|
* call to VSC_Iter(), but will attempt again the next |
624 |
|
* time VSC_Iter() is called. */ |
625 |
396514 |
if (vsc_map_seg(vsc, vsm, sp)) |
626 |
0 |
continue; |
627 |
|
|
628 |
|
/* Expose the counters if necessary */ |
629 |
396514 |
vsc_expose(vsc, sp, 0); |
630 |
|
|
631 |
396514 |
if (fiter != NULL && sp->head->ready == 1) |
632 |
355886 |
i = vsc_iter_seg(vsc, sp, fiter, priv); |
633 |
396514 |
if (i) |
634 |
16386 |
break; |
635 |
380128 |
} |
636 |
|
|
637 |
22096 |
return (i); |
638 |
|
} |
639 |
|
|
640 |
|
/*-------------------------------------------------------------------- |
641 |
|
*/ |
642 |
|
|
643 |
|
void |
644 |
119 |
VSC_State(struct vsc *vsc, VSC_new_f *fn, VSC_destroy_f *fd, void *priv) |
645 |
|
{ |
646 |
|
struct vsc_seg *sp; |
647 |
|
|
648 |
119 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
649 |
119 |
assert((fn == NULL && fd == NULL) || (fn != NULL && fd != NULL)); |
650 |
119 |
if (fd == NULL) { |
651 |
0 |
VTAILQ_FOREACH(sp, &vsc->segs, list) |
652 |
0 |
vsc_expose(vsc, sp, 1); |
653 |
0 |
} |
654 |
119 |
vsc->fnew = fn; |
655 |
119 |
vsc->fdestroy = fd; |
656 |
119 |
vsc->priv = priv; |
657 |
119 |
} |
658 |
|
|
659 |
|
/*-------------------------------------------------------------------- |
660 |
|
*/ |
661 |
|
|
662 |
|
const struct VSC_level_desc * |
663 |
187 |
VSC_ChangeLevel(const struct VSC_level_desc *old, int chg) |
664 |
|
{ |
665 |
|
int i; |
666 |
|
|
667 |
187 |
if (old == NULL) |
668 |
119 |
old = &levels[0]; |
669 |
204 |
for (i = 0; i < nlevels; i++) |
670 |
204 |
if (old == &levels[i]) |
671 |
187 |
break; |
672 |
187 |
if (i == nlevels) |
673 |
0 |
i = 0; |
674 |
|
|
675 |
187 |
i += chg; |
676 |
187 |
if (i >= nlevels) |
677 |
0 |
i = nlevels - 1; |
678 |
187 |
if (i < 0) |
679 |
0 |
i = 0; |
680 |
187 |
return (&levels[i]); |
681 |
|
} |
682 |
|
|
683 |
|
/*--------------------------------------------------------------------*/ |
684 |
|
|
685 |
|
void |
686 |
16252 |
VSC_Destroy(struct vsc **vscp, struct vsm *vsm) |
687 |
|
{ |
688 |
|
struct vsc *vsc; |
689 |
|
struct vsc_sf *sf, *sf2; |
690 |
|
|
691 |
16252 |
TAKE_OBJ_NOTNULL(vsc, vscp, VSC_MAGIC); |
692 |
|
|
693 |
16592 |
VTAILQ_FOREACH_SAFE(sf, &vsc->sf_list, list, sf2) { |
694 |
340 |
CHECK_OBJ_NOTNULL(sf, VSC_SF_MAGIC); |
695 |
340 |
VTAILQ_REMOVE(&vsc->sf_list, sf, list); |
696 |
340 |
free(sf->pattern); |
697 |
340 |
FREE_OBJ(sf); |
698 |
340 |
} |
699 |
|
|
700 |
16252 |
vsc_del_segs(vsc, vsm, &vsc->segs); |
701 |
16252 |
assert(VTAILQ_EMPTY(&vsc->docs)); |
702 |
16252 |
FREE_OBJ(vsc); |
703 |
16252 |
} |