| | 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 |
|
|
51 |
|
#include "vapi/vsc.h" |
52 |
|
#include "vapi/vsm.h" |
53 |
|
|
54 |
|
struct vsc_sf_mode { |
55 |
|
const char *name; |
56 |
|
unsigned include; |
57 |
|
unsigned fail; |
58 |
|
unsigned append; |
59 |
|
}; |
60 |
|
|
61 |
|
static const struct vsc_sf_mode VSC_SF_INCLUDE[1] = {{"include", 1, 1, 1}}; |
62 |
|
static const struct vsc_sf_mode VSC_SF_EXCLUDE[1] = {{"exclude", 0, 0, 1}}; |
63 |
|
static const struct vsc_sf_mode VSC_SF_REQUIRE[1] = {{"require", 1, 0, 0}}; |
64 |
|
|
65 |
|
struct vsc_sf { |
66 |
|
unsigned magic; |
67 |
|
#define VSC_SF_MAGIC 0x558478dd |
68 |
|
VTAILQ_ENTRY(vsc_sf) list; |
69 |
|
char *pattern; |
70 |
|
const struct vsc_sf_mode *mode; |
71 |
|
}; |
72 |
|
|
73 |
|
VTAILQ_HEAD(vsc_sf_head, vsc_sf); |
74 |
|
|
75 |
|
struct vsc_pt { |
76 |
|
struct VSC_point point; |
77 |
|
char *name; |
78 |
|
}; |
79 |
|
|
80 |
|
enum vsc_seg_type { |
81 |
|
VSC_SEG_COUNTERS = 1, |
82 |
|
VSC_SEG_DOCS, |
83 |
|
}; |
84 |
|
|
85 |
|
struct vsc_seg { |
86 |
|
unsigned magic; |
87 |
|
#define VSC_SEG_MAGIC 0x801177d4 |
88 |
|
enum vsc_seg_type type; |
89 |
|
VTAILQ_ENTRY(vsc_seg) list; |
90 |
|
VTAILQ_ENTRY(vsc_seg) doc_list; |
91 |
|
struct vsm_fantom fantom[1]; |
92 |
|
const struct vsc_head *head; |
93 |
|
const char *body; |
94 |
|
|
95 |
|
struct vjsn *vj; |
96 |
|
|
97 |
|
unsigned npoints; |
98 |
|
struct vsc_pt *points; |
99 |
|
|
100 |
|
int mapped; |
101 |
|
int exposed; |
102 |
|
}; |
103 |
|
VTAILQ_HEAD(vsc_seg_head, vsc_seg); |
104 |
|
|
105 |
|
struct vsc { |
106 |
|
unsigned magic; |
107 |
|
#define VSC_MAGIC 0x3373554a |
108 |
|
|
109 |
|
unsigned raw; |
110 |
|
struct vsc_sf_head sf_list; |
111 |
|
struct vsc_seg_head segs; |
112 |
|
struct vsc_seg_head docs; |
113 |
|
|
114 |
|
VSC_new_f *fnew; |
115 |
|
VSC_destroy_f *fdestroy; |
116 |
|
void *priv; |
117 |
|
}; |
118 |
|
|
119 |
|
/*-------------------------------------------------------------------- |
120 |
|
* Build the static level, type and point descriptions |
121 |
|
*/ |
122 |
|
|
123 |
|
enum vsc_levels { |
124 |
|
#define VSC_LEVEL_F(v,l,e,d) v, |
125 |
|
#include "tbl/vsc_levels.h" |
126 |
|
}; |
127 |
|
|
128 |
|
static const struct VSC_level_desc levels[] = { |
129 |
|
#define VSC_LEVEL_F(v,l,e,d) [v] = {#v, l, e, d}, |
130 |
|
#include "tbl/vsc_levels.h" |
131 |
|
}; |
132 |
|
|
133 |
|
static const ssize_t nlevels = sizeof(levels)/sizeof(*levels); |
134 |
|
|
135 |
|
/*--------------------------------------------------------------------*/ |
136 |
|
|
137 |
|
struct vsc * |
138 |
38800 |
VSC_New(void) |
139 |
|
{ |
140 |
|
struct vsc *vsc; |
141 |
|
|
142 |
38800 |
ALLOC_OBJ(vsc, VSC_MAGIC); |
143 |
38800 |
if (vsc == NULL) |
144 |
0 |
return (vsc); |
145 |
38800 |
VTAILQ_INIT(&vsc->sf_list); |
146 |
38800 |
VTAILQ_INIT(&vsc->segs); |
147 |
38800 |
VTAILQ_INIT(&vsc->docs); |
148 |
38800 |
return (vsc); |
149 |
38800 |
} |
150 |
|
|
151 |
|
/*--------------------------------------------------------------------*/ |
152 |
|
|
153 |
|
static int |
154 |
1480 |
vsc_sf_arg(struct vsc *vsc, const char *glob, const struct vsc_sf_mode *mode) |
155 |
|
{ |
156 |
|
struct vsc_sf *sf; |
157 |
|
|
158 |
1480 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
159 |
1480 |
AN(glob); |
160 |
1480 |
AN(mode); |
161 |
|
|
162 |
1480 |
ALLOC_OBJ(sf, VSC_SF_MAGIC); |
163 |
1480 |
AN(sf); |
164 |
1480 |
REPLACE(sf->pattern, glob); |
165 |
1480 |
sf->mode = mode; |
166 |
1480 |
AN(mode->name); |
167 |
1480 |
if (mode->append) |
168 |
1160 |
VTAILQ_INSERT_TAIL(&vsc->sf_list, sf, list); |
169 |
|
else |
170 |
320 |
VTAILQ_INSERT_HEAD(&vsc->sf_list, sf, list); |
171 |
1480 |
return (1); |
172 |
|
} |
173 |
|
|
174 |
|
static int |
175 |
840 |
vsc_f_arg(struct vsc *vsc, const char *opt) |
176 |
|
{ |
177 |
|
|
178 |
840 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
179 |
840 |
AN(opt); |
180 |
|
|
181 |
840 |
if (opt[0] == '^') |
182 |
200 |
return (vsc_sf_arg(vsc, opt + 1, VSC_SF_EXCLUDE)); |
183 |
640 |
return (vsc_sf_arg(vsc, opt, VSC_SF_INCLUDE)); |
184 |
840 |
} |
185 |
|
|
186 |
|
/*--------------------------------------------------------------------*/ |
187 |
|
|
188 |
|
int |
189 |
1480 |
VSC_Arg(struct vsc *vsc, char arg, const char *opt) |
190 |
|
{ |
191 |
|
|
192 |
1480 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
193 |
|
|
194 |
1480 |
switch (arg) { |
195 |
280 |
case 'I': return (vsc_sf_arg(vsc, opt, VSC_SF_INCLUDE)); |
196 |
40 |
case 'X': return (vsc_sf_arg(vsc, opt, VSC_SF_EXCLUDE)); |
197 |
320 |
case 'R': return (vsc_sf_arg(vsc, opt, VSC_SF_REQUIRE)); |
198 |
840 |
case 'f': return (vsc_f_arg(vsc, opt)); |
199 |
0 |
case 'r': vsc->raw = !vsc->raw; return (1); |
200 |
0 |
default: return (0); |
201 |
|
} |
202 |
1480 |
} |
203 |
|
|
204 |
|
unsigned |
205 |
240 |
VSC_IsRaw(const struct vsc *vsc) |
206 |
|
{ |
207 |
|
|
208 |
240 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
209 |
240 |
return (vsc->raw); |
210 |
|
} |
211 |
|
|
212 |
|
/*-------------------------------------------------------------------- |
213 |
|
*/ |
214 |
|
|
215 |
|
static int |
216 |
2149984 |
vsc_filter(const struct vsc *vsc, const char *nm) |
217 |
|
{ |
218 |
|
struct vsc_sf *sf; |
219 |
2149984 |
unsigned res = 0; |
220 |
|
|
221 |
2149984 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
222 |
2594664 |
VTAILQ_FOREACH(sf, &vsc->sf_list, list) { |
223 |
452800 |
if (!fnmatch(sf->pattern, nm, 0)) |
224 |
8120 |
return (!sf->mode->include); |
225 |
444680 |
res |= sf->mode->fail; |
226 |
444680 |
} |
227 |
2141864 |
return (res); |
228 |
2149984 |
} |
229 |
|
|
230 |
|
/*-------------------------------------------------------------------- |
231 |
|
*/ |
232 |
|
|
233 |
|
static void |
234 |
1836544 |
vsc_clean_point(struct vsc_pt *point) |
235 |
|
{ |
236 |
1836544 |
REPLACE(point->name, NULL); |
237 |
1836544 |
} |
238 |
|
|
239 |
|
static void |
240 |
2149984 |
vsc_fill_point(const struct vsc *vsc, const struct vsc_seg *seg, |
241 |
|
const struct vjsn_val *vv, struct vsb *vsb, struct vsc_pt *point) |
242 |
|
{ |
243 |
|
struct vjsn_val *vt; |
244 |
|
|
245 |
2149984 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
246 |
2149984 |
memset(point, 0, sizeof *point); |
247 |
|
|
248 |
2149984 |
vt = vjsn_child(vv, "name"); |
249 |
2149984 |
AN(vt); |
250 |
2149984 |
assert(vjsn_is_string(vt)); |
251 |
|
|
252 |
2149984 |
VSB_clear(vsb); |
253 |
2149984 |
VSB_printf(vsb, "%s.%s", seg->fantom->ident, vt->value); |
254 |
2149984 |
AZ(VSB_finish(vsb)); |
255 |
|
|
256 |
2149984 |
if (vsc_filter(vsc, VSB_data(vsb))) |
257 |
154960 |
return; |
258 |
|
|
259 |
1995024 |
point->name = strdup(VSB_data(vsb)); |
260 |
1995024 |
AN(point->name); |
261 |
1995024 |
point->point.name = point->name; |
262 |
|
|
263 |
|
#define DOF(n, k) \ |
264 |
|
vt = vjsn_child(vv, k); \ |
265 |
|
AN(vt); \ |
266 |
|
assert(vjsn_is_string(vt)); \ |
267 |
|
point->point.n = vt->value; |
268 |
|
|
269 |
1995024 |
DOF(ctype, "ctype"); |
270 |
1995024 |
DOF(sdesc, "oneliner"); |
271 |
1995024 |
DOF(ldesc, "docs"); |
272 |
|
#undef DOF |
273 |
1995024 |
vt = vjsn_child(vv, "type"); |
274 |
1995024 |
AN(vt); |
275 |
1995024 |
assert(vjsn_is_string(vt)); |
276 |
|
|
277 |
1995024 |
if (!strcmp(vt->value, "counter")) { |
278 |
1753865 |
point->point.semantics = 'c'; |
279 |
1995024 |
} else if (!strcmp(vt->value, "gauge")) { |
280 |
235610 |
point->point.semantics = 'g'; |
281 |
241159 |
} else if (!strcmp(vt->value, "bitmap")) { |
282 |
5549 |
point->point.semantics = 'b'; |
283 |
5549 |
} else { |
284 |
0 |
point->point.semantics = '?'; |
285 |
|
} |
286 |
|
|
287 |
1995024 |
vt = vjsn_child(vv, "format"); |
288 |
1995024 |
AN(vt); |
289 |
1995024 |
assert(vjsn_is_string(vt)); |
290 |
|
|
291 |
1995024 |
if (!strcmp(vt->value, "integer")) { |
292 |
1803286 |
point->point.format = 'i'; |
293 |
1995024 |
} else if (!strcmp(vt->value, "bytes")) { |
294 |
167829 |
point->point.format = 'B'; |
295 |
191738 |
} else if (!strcmp(vt->value, "bitmap")) { |
296 |
5549 |
point->point.format = 'b'; |
297 |
23909 |
} else if (!strcmp(vt->value, "duration")) { |
298 |
18360 |
point->point.format = 'd'; |
299 |
18360 |
} else { |
300 |
0 |
point->point.format = '?'; |
301 |
|
} |
302 |
|
|
303 |
1995024 |
vt = vjsn_child(vv, "level"); |
304 |
1995024 |
AN(vt); |
305 |
1995024 |
assert(vjsn_is_string(vt)); |
306 |
|
|
307 |
1995024 |
if (!strcmp(vt->value, "info")) { |
308 |
946603 |
point->point.level = &levels[info]; |
309 |
1995024 |
} else if (!strcmp(vt->value, "diag")) { |
310 |
613323 |
point->point.level = &levels[diag]; |
311 |
1048421 |
} else if (!strcmp(vt->value, "debug")) { |
312 |
435098 |
point->point.level = &levels[debug]; |
313 |
435098 |
} else { |
314 |
0 |
WRONG("Illegal level"); |
315 |
|
} |
316 |
|
|
317 |
1995024 |
vt = vjsn_child(vv, "index"); |
318 |
1995024 |
AN(vt); |
319 |
|
|
320 |
1995024 |
point->point.ptr = (volatile const void*)(seg->body + atoi(vt->value)); |
321 |
1995024 |
point->point.raw = vsc->raw; |
322 |
2149984 |
} |
323 |
|
|
324 |
|
static struct vsc_seg * |
325 |
417321 |
vsc_new_seg(const struct vsm_fantom *fp, enum vsc_seg_type type) |
326 |
|
{ |
327 |
|
struct vsc_seg *sp; |
328 |
|
|
329 |
417321 |
ALLOC_OBJ(sp, VSC_SEG_MAGIC); |
330 |
417321 |
AN(sp); |
331 |
417321 |
*sp->fantom = *fp; |
332 |
417321 |
sp->type = type; |
333 |
|
|
334 |
417321 |
return (sp); |
335 |
|
} |
336 |
|
|
337 |
|
static void |
338 |
387121 |
vsc_unmap_seg(const struct vsc *vsc, struct vsm *vsm, struct vsc_seg *sp) |
339 |
|
{ |
340 |
|
unsigned u; |
341 |
|
struct vsc_pt *pp; |
342 |
|
|
343 |
387121 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
344 |
387121 |
AN(vsm); |
345 |
387121 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
346 |
|
|
347 |
387121 |
AZ(sp->exposed); |
348 |
387121 |
if (!sp->mapped) |
349 |
280371 |
return; |
350 |
|
|
351 |
106750 |
if (sp->type == VSC_SEG_COUNTERS) { |
352 |
79602 |
pp = sp->points; |
353 |
1916146 |
for (u = 0; u < sp->npoints; u++, pp++) |
354 |
1836544 |
vsc_clean_point(pp); |
355 |
79602 |
free(sp->points); |
356 |
79602 |
sp->points = NULL; |
357 |
79602 |
sp->npoints = 0; |
358 |
79602 |
AZ(sp->vj); |
359 |
106750 |
} else if (sp->type == VSC_SEG_DOCS) { |
360 |
27148 |
if (sp->vj != NULL) |
361 |
27148 |
vjsn_delete(&sp->vj); |
362 |
27148 |
AZ(sp->vj); |
363 |
27148 |
AZ(sp->points); |
364 |
27148 |
} else { |
365 |
0 |
WRONG("Invalid segment type"); |
366 |
|
} |
367 |
|
|
368 |
106750 |
AZ(VSM_Unmap(vsm, sp->fantom)); |
369 |
106750 |
sp->head = NULL; |
370 |
106750 |
sp->body = NULL; |
371 |
106750 |
sp->mapped = 0; |
372 |
387121 |
} |
373 |
|
|
374 |
|
static int |
375 |
918480 |
vsc_map_seg(const struct vsc *vsc, struct vsm *vsm, struct vsc_seg *sp) |
376 |
|
{ |
377 |
|
const struct vsc_head *head; |
378 |
|
struct vsc_seg *spd; |
379 |
|
const char *e; |
380 |
|
struct vjsn_val *vv, *vve; |
381 |
|
struct vsb *vsb; |
382 |
|
struct vsc_pt *pp; |
383 |
|
int retry; |
384 |
|
|
385 |
918480 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
386 |
918480 |
AN(vsm); |
387 |
918480 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
388 |
|
|
389 |
918480 |
if (sp->mapped) |
390 |
781530 |
return (0); |
391 |
|
|
392 |
136950 |
AZ(sp->exposed); |
393 |
|
|
394 |
136950 |
if (VSM_Map(vsm, sp->fantom)) |
395 |
0 |
return (-1); |
396 |
136950 |
head = sp->fantom->b; |
397 |
|
|
398 |
|
/* It isn't ready yet. Sleep and try again. If it still |
399 |
|
* isn't ready, fail the mapping. The transitions inside |
400 |
|
* varnishd that we are waiting for are just some memcpy() |
401 |
|
* operations, so there is no reason to allow a long retry |
402 |
|
* time. */ |
403 |
136950 |
for (retry = 10; retry > 0 && head->ready == 0; retry--) |
404 |
0 |
usleep(10000); |
405 |
|
|
406 |
136950 |
if (head->ready == 0) { |
407 |
0 |
AZ(VSM_Unmap(vsm, sp->fantom)); |
408 |
0 |
return (-1); |
409 |
|
} |
410 |
|
|
411 |
136950 |
sp->head = head; |
412 |
136950 |
sp->body = (char*)sp->fantom->b + sp->head->body_offset; |
413 |
136950 |
sp->mapped = 1; |
414 |
|
|
415 |
136950 |
if (sp->type == VSC_SEG_DOCS) { |
416 |
|
/* Parse the DOCS json */ |
417 |
31628 |
sp->vj = vjsn_parse(sp->body, &e); |
418 |
31628 |
XXXAZ(e); |
419 |
31628 |
AN(sp->vj); |
420 |
31628 |
return (0); |
421 |
|
} |
422 |
|
|
423 |
105322 |
assert(sp->type == VSC_SEG_COUNTERS); |
424 |
|
|
425 |
|
/* Find the corresponding DOCS seg. We are not able to |
426 |
|
* read and match on the doc_id until the DOCS section is |
427 |
|
* mapped. Iterate over all the DOCS sections, attempt to |
428 |
|
* map if needed, and then check the doc_id. */ |
429 |
344051 |
VTAILQ_FOREACH(spd, &vsc->docs, doc_list) { |
430 |
344051 |
CHECK_OBJ_NOTNULL(spd, VSC_SEG_MAGIC); |
431 |
344051 |
assert(spd->type == VSC_SEG_DOCS); |
432 |
344051 |
if (!spd->mapped && vsc_map_seg(vsc, vsm, spd)) |
433 |
0 |
continue; /* Failed to map it */ |
434 |
344051 |
AN(spd->mapped); |
435 |
344051 |
if (spd->head->doc_id == sp->head->doc_id) |
436 |
105322 |
break; /* We have a match */ |
437 |
238729 |
} |
438 |
105322 |
if (spd == NULL) { |
439 |
|
/* Could not find the right DOCS seg. Leave this |
440 |
|
* seg as unmapped. */ |
441 |
0 |
vsc_unmap_seg(vsc, vsm, sp); |
442 |
0 |
return (-1); |
443 |
|
} |
444 |
|
|
445 |
|
/* Create the VSC points list */ |
446 |
105322 |
vve = vjsn_child(spd->vj->value, "elements"); |
447 |
105322 |
AN(vve); |
448 |
105322 |
sp->npoints = strtoul(vve->value, NULL, 0); |
449 |
105322 |
sp->points = calloc(sp->npoints, sizeof *sp->points); |
450 |
105322 |
AN(sp->points); |
451 |
105322 |
vsb = VSB_new_auto(); |
452 |
105322 |
AN(vsb); |
453 |
105322 |
vve = vjsn_child(spd->vj->value, "elem"); |
454 |
105322 |
AN(vve); |
455 |
105322 |
pp = sp->points; |
456 |
2255306 |
VTAILQ_FOREACH(vv, &vve->children, list) { |
457 |
2149984 |
vsc_fill_point(vsc, sp, vv, vsb, pp); |
458 |
2149984 |
pp++; |
459 |
2149984 |
} |
460 |
105322 |
VSB_destroy(&vsb); |
461 |
105322 |
return (0); |
462 |
918480 |
} |
463 |
|
|
464 |
|
/*-------------------------------------------------------------------- |
465 |
|
*/ |
466 |
|
|
467 |
|
static void |
468 |
1273973 |
vsc_expose(const struct vsc *vsc, struct vsc_seg *sp, int del) |
469 |
|
{ |
470 |
|
struct vsc_pt *pp; |
471 |
|
unsigned u; |
472 |
|
int expose; |
473 |
|
|
474 |
1273973 |
if (!sp->mapped) { |
475 |
280371 |
AZ(sp->exposed); |
476 |
280371 |
return; |
477 |
|
} |
478 |
|
|
479 |
1001682 |
if (vsc->fnew != NULL && !sp->exposed && |
480 |
9680 |
!del && sp->head->ready == 1) |
481 |
8080 |
expose = 1; |
482 |
1041932 |
else if (vsc->fdestroy != NULL && sp->exposed && |
483 |
64490 |
(del || sp->head->ready == 2)) |
484 |
8080 |
expose = 0; |
485 |
|
else |
486 |
977442 |
return; |
487 |
|
|
488 |
16160 |
pp = sp->points; |
489 |
188640 |
for (u = 0; u < sp->npoints; u++, pp++) { |
490 |
172480 |
if (pp->name == NULL) |
491 |
27280 |
continue; |
492 |
145200 |
if (expose) |
493 |
72600 |
pp->point.priv = vsc->fnew(vsc->priv, &pp->point); |
494 |
|
else |
495 |
72600 |
vsc->fdestroy(vsc->priv, &pp->point); |
496 |
145200 |
} |
497 |
16160 |
sp->exposed = expose; |
498 |
1273973 |
} |
499 |
|
|
500 |
|
/*-------------------------------------------------------------------- |
501 |
|
*/ |
502 |
|
|
503 |
|
static void |
504 |
88608 |
vsc_del_segs(struct vsc *vsc, struct vsm *vsm, struct vsc_seg_head *head) |
505 |
|
{ |
506 |
|
struct vsc_seg *sp, *sp2; |
507 |
|
|
508 |
475729 |
VTAILQ_FOREACH_SAFE(sp, head, list, sp2) { |
509 |
387121 |
CHECK_OBJ(sp, VSC_SEG_MAGIC); |
510 |
387121 |
VTAILQ_REMOVE(head, sp, list); |
511 |
387121 |
if (sp->type == VSC_SEG_DOCS) |
512 |
64560 |
VTAILQ_REMOVE(&vsc->docs, sp, doc_list); |
513 |
387121 |
vsc_expose(vsc, sp, 1); |
514 |
387121 |
vsc_unmap_seg(vsc, vsm, sp); |
515 |
387121 |
FREE_OBJ(sp); |
516 |
387121 |
} |
517 |
88608 |
} |
518 |
|
|
519 |
|
/*-------------------------------------------------------------------- |
520 |
|
*/ |
521 |
|
|
522 |
|
static int |
523 |
810322 |
vsc_iter_seg(const struct vsc *vsc, const struct vsc_seg *sp, |
524 |
|
VSC_iter_f *fiter, void *priv) |
525 |
|
{ |
526 |
|
unsigned u; |
527 |
810322 |
int i = 0; |
528 |
|
struct vsc_pt *pp; |
529 |
|
|
530 |
810322 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
531 |
810322 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
532 |
810322 |
AN(fiter); |
533 |
810322 |
pp = sp->points; |
534 |
11306618 |
for (u = 0; u < sp->npoints && i == 0; u++, pp++) { |
535 |
10496296 |
if (pp->name != NULL) |
536 |
10414976 |
i = fiter(priv, &pp->point); |
537 |
10496296 |
} |
538 |
810322 |
return (i); |
539 |
|
} |
540 |
|
|
541 |
|
int |
542 |
50768 |
VSC_Iter(struct vsc *vsc, struct vsm *vsm, VSC_iter_f *fiter, void *priv) |
543 |
|
{ |
544 |
|
enum vsc_seg_type type; |
545 |
|
struct vsm_fantom ifantom; |
546 |
|
struct vsc_seg *sp, *sp2; |
547 |
|
struct vsc_seg_head removed; |
548 |
50768 |
int i = 0; |
549 |
|
|
550 |
50768 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
551 |
50768 |
AN(vsm); |
552 |
|
|
553 |
|
/* First walk the VSM segment list and consolidate with the shadow |
554 |
|
* VSC seg list. We avoid calling any of the callback functions |
555 |
|
* while iterating the VSMs. This removes any headaches wrt to |
556 |
|
* callbacks calling VSM_Status(). */ |
557 |
50768 |
VTAILQ_INIT(&removed); |
558 |
50768 |
sp = VTAILQ_FIRST(&vsc->segs); |
559 |
2454112 |
VSM_FOREACH(&ifantom, vsm) { |
560 |
2403344 |
AN(ifantom.category); |
561 |
2403344 |
if (!strcmp(ifantom.category, VSC_CLASS)) |
562 |
1746194 |
type = VSC_SEG_COUNTERS; |
563 |
657150 |
else if (!strcmp(ifantom.category, VSC_DOC_CLASS)) |
564 |
353839 |
type = VSC_SEG_DOCS; |
565 |
|
else { |
566 |
|
/* Not one of the categories we care about */ |
567 |
303311 |
continue; |
568 |
|
} |
569 |
|
|
570 |
2125741 |
while (sp != NULL) { |
571 |
1708420 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
572 |
1708420 |
if (VSM_StillValid(vsm, sp->fantom) == VSM_valid && |
573 |
1682712 |
!strcmp(ifantom.ident, sp->fantom->ident)) { |
574 |
|
/* sp matches the expected value */ |
575 |
1682712 |
break; |
576 |
|
} |
577 |
|
|
578 |
|
/* sp is no longer in the VSM list. Remove it from |
579 |
|
* our list. */ |
580 |
25708 |
sp2 = sp; |
581 |
25708 |
sp = VTAILQ_NEXT(sp, list); |
582 |
25708 |
VTAILQ_REMOVE(&vsc->segs, sp2, list); |
583 |
25708 |
VTAILQ_INSERT_TAIL(&removed, sp2, list); |
584 |
|
} |
585 |
|
|
586 |
2100033 |
if (sp == NULL) { |
587 |
|
/* New entries are always appended last in the VSM |
588 |
|
* list. Since we have iterated past all the |
589 |
|
* entries in our shadow list, the VSM entry is a |
590 |
|
* new entry we have not seen before. */ |
591 |
417321 |
sp = vsc_new_seg(&ifantom, type); |
592 |
417321 |
AN(sp); |
593 |
417321 |
VTAILQ_INSERT_TAIL(&vsc->segs, sp, list); |
594 |
417321 |
if (type == VSC_SEG_DOCS) |
595 |
69040 |
VTAILQ_INSERT_TAIL(&vsc->docs, sp, doc_list); |
596 |
417321 |
} |
597 |
|
|
598 |
2100033 |
assert(sp->type == type); |
599 |
2100033 |
sp = VTAILQ_NEXT(sp, list); |
600 |
|
} |
601 |
50768 |
while (sp != NULL) { |
602 |
|
/* Clean up the tail end of the shadow list. */ |
603 |
0 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
604 |
0 |
sp2 = sp; |
605 |
0 |
sp = VTAILQ_NEXT(sp, list); |
606 |
|
|
607 |
0 |
VTAILQ_REMOVE(&vsc->segs, sp2, list); |
608 |
0 |
VTAILQ_INSERT_TAIL(&removed, sp2, list); |
609 |
|
} |
610 |
|
|
611 |
50768 |
vsc_del_segs(vsc, vsm, &removed); |
612 |
|
|
613 |
|
/* Iterate our shadow list, reporting on each pointer value */ |
614 |
1113154 |
VTAILQ_FOREACH(sp, &vsc->segs, list) { |
615 |
1100209 |
CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC); |
616 |
|
|
617 |
1100209 |
if (sp->type != VSC_SEG_COUNTERS) |
618 |
213357 |
continue; |
619 |
|
|
620 |
|
/* Attempt to map the VSM. This is a noop if it was |
621 |
|
* already mapped. If we fail we skip this seg on this |
622 |
|
* call to VSC_Iter(), but will attempt again the next |
623 |
|
* time VSC_Iter() is called. */ |
624 |
886852 |
if (vsc_map_seg(vsc, vsm, sp)) |
625 |
0 |
continue; |
626 |
|
|
627 |
|
/* Expose the counters if necessary */ |
628 |
886852 |
vsc_expose(vsc, sp, 0); |
629 |
|
|
630 |
886852 |
if (fiter != NULL && sp->head->ready == 1) |
631 |
810322 |
i = vsc_iter_seg(vsc, sp, fiter, priv); |
632 |
886852 |
if (i) |
633 |
37823 |
break; |
634 |
849029 |
} |
635 |
|
|
636 |
50768 |
return (i); |
637 |
|
} |
638 |
|
|
639 |
|
/*-------------------------------------------------------------------- |
640 |
|
*/ |
641 |
|
|
642 |
|
void |
643 |
240 |
VSC_State(struct vsc *vsc, VSC_new_f *fn, VSC_destroy_f *fd, void *priv) |
644 |
|
{ |
645 |
|
struct vsc_seg *sp; |
646 |
|
|
647 |
240 |
CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC); |
648 |
240 |
assert((fn == NULL && fd == NULL) || (fn != NULL && fd != NULL)); |
649 |
240 |
if (fd == NULL) { |
650 |
0 |
VTAILQ_FOREACH(sp, &vsc->segs, list) |
651 |
0 |
vsc_expose(vsc, sp, 1); |
652 |
0 |
} |
653 |
240 |
vsc->fnew = fn; |
654 |
240 |
vsc->fdestroy = fd; |
655 |
240 |
vsc->priv = priv; |
656 |
240 |
} |
657 |
|
|
658 |
|
/*-------------------------------------------------------------------- |
659 |
|
*/ |
660 |
|
|
661 |
|
const struct VSC_level_desc * |
662 |
400 |
VSC_ChangeLevel(const struct VSC_level_desc *old, int chg) |
663 |
|
{ |
664 |
|
int i; |
665 |
|
|
666 |
400 |
if (old == NULL) |
667 |
240 |
old = &levels[0]; |
668 |
440 |
for (i = 0; i < nlevels; i++) |
669 |
440 |
if (old == &levels[i]) |
670 |
400 |
break; |
671 |
400 |
if (i == nlevels) |
672 |
0 |
i = 0; |
673 |
|
|
674 |
400 |
i += chg; |
675 |
400 |
if (i >= nlevels) |
676 |
0 |
i = nlevels - 1; |
677 |
400 |
if (i < 0) |
678 |
0 |
i = 0; |
679 |
400 |
return (&levels[i]); |
680 |
|
} |
681 |
|
|
682 |
|
/*--------------------------------------------------------------------*/ |
683 |
|
|
684 |
|
void |
685 |
37840 |
VSC_Destroy(struct vsc **vscp, struct vsm *vsm) |
686 |
|
{ |
687 |
|
struct vsc *vsc; |
688 |
|
struct vsc_sf *sf, *sf2; |
689 |
|
|
690 |
37840 |
TAKE_OBJ_NOTNULL(vsc, vscp, VSC_MAGIC); |
691 |
|
|
692 |
38640 |
VTAILQ_FOREACH_SAFE(sf, &vsc->sf_list, list, sf2) { |
693 |
800 |
CHECK_OBJ_NOTNULL(sf, VSC_SF_MAGIC); |
694 |
800 |
VTAILQ_REMOVE(&vsc->sf_list, sf, list); |
695 |
800 |
free(sf->pattern); |
696 |
800 |
FREE_OBJ(sf); |
697 |
800 |
} |
698 |
|
|
699 |
37840 |
vsc_del_segs(vsc, vsm, &vsc->segs); |
700 |
37840 |
assert(VTAILQ_EMPTY(&vsc->docs)); |
701 |
37840 |
FREE_OBJ(vsc); |
702 |
37840 |
} |