varnish-cache/vmod/vmod_directors.c
0
/*-
1
 * Copyright (c) 2013-2015 Varnish Software AS
2
 * Copyright 2019 UPLEX - Nils Goroll Systemoptimierung
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@FreeBSD.org>
6
 * Author: Nils Goroll <nils.goroll@uplex.de>
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 <stdlib.h>
35
#include <stdio.h>
36
37
#include "cache/cache.h"
38
39
#include "vbm.h"
40
#include "vcl.h"
41
#include "vsb.h"
42
43
#include "vcc_directors_if.h"
44
45
#include "vmod_directors.h"
46
47
VCL_BACKEND
48 34
VPFX(lookup)(VRT_CTX, VCL_STRING name)
49
{
50 34
        AN(ctx->method & VCL_MET_TASK_H);
51 34
        return (VRT_LookupDirector(ctx, name));
52
}
53
54
static void
55 1122
vdir_expand(struct vdir *vd, unsigned n)
56
{
57 1122
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
58
59 1122
        vd->backend = realloc(vd->backend, n * sizeof *vd->backend);
60 1122
        AN(vd->backend);
61 1122
        vd->weight = realloc(vd->weight, n * sizeof *vd->weight);
62 1122
        AN(vd->weight);
63 1122
        if (n > vd->healthy->nbits)
64 0
                vbit_expand(vd->healthy, n);
65 1122
        AN(vd->healthy);
66 1122
        vd->l_backend = n;
67 1122
}
68
69
void
70 1224
vdir_new(VRT_CTX, struct vdir **vdp, const char *vcl_name,
71
    const struct vdi_methods *m, void *priv)
72
{
73
        struct vdir *vd;
74
75 1224
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
76 1224
        CHECK_OBJ_NOTNULL(m, VDI_METHODS_MAGIC);
77 1224
        AN(vcl_name);
78 1224
        AN(vdp);
79 1224
        AZ(*vdp);
80 1224
        ALLOC_OBJ(vd, VDIR_MAGIC);
81 1224
        AN(vd);
82 1224
        *vdp = vd;
83 1224
        PTOK(pthread_rwlock_init(&vd->mtx, NULL));
84 1224
        vd->dir = VRT_AddDirector(ctx, m, priv, "%s", vcl_name);
85 1224
        vd->healthy = vbit_new(8);
86 1224
        AN(vd->healthy);
87 1224
}
88
89
void
90 272
vdir_release(struct vdir *vd)
91
{
92
        unsigned u;
93
94 272
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
95
96 272
        vdir_wrlock(vd);
97 680
        for (u = 0; u < vd->n_backend; u++)
98 408
                VRT_Assign_Backend(&vd->backend[u], NULL);
99 272
        vd->n_backend = 0;
100 272
        vdir_unlock(vd);
101 272
}
102
103
void
104 272
vdir_delete(struct vdir **vdp)
105
{
106
        struct vdir *vd;
107
108 272
        TAKE_OBJ_NOTNULL(vd, vdp, VDIR_MAGIC);
109
110 272
        AZ(vd->dir);
111 272
        AZ(vd->n_backend);
112 272
        free(vd->backend);
113 272
        free(vd->weight);
114 272
        PTOK(pthread_rwlock_destroy(&vd->mtx));
115 272
        vbit_destroy(vd->healthy);
116 272
        FREE_OBJ(vd);
117 272
}
118
119
void
120 5338
vdir_rdlock(struct vdir *vd)
121
{
122 5338
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
123 5338
        PTOK(pthread_rwlock_rdlock(&vd->mtx));
124 5338
}
125
126
void
127 6154
vdir_wrlock(struct vdir *vd)
128
{
129 6154
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
130 6154
        PTOK(pthread_rwlock_wrlock(&vd->mtx));
131 6154
}
132
133
void
134 11492
vdir_unlock(struct vdir *vd)
135
{
136 11492
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
137 11492
        PTOK(pthread_rwlock_unlock(&vd->mtx));
138 11492
}
139
140
141
void
142 3060
vdir_add_backend(VRT_CTX, struct vdir *vd, VCL_BACKEND be, double weight)
143
{
144
        unsigned u;
145
146 3060
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
147 3060
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
148 3060
        if (be == NULL) {
149 204
                VRT_fail(ctx, "%s: None backend cannot be added",
150 102
                    VRT_BACKEND_string(vd->dir));
151 102
                return;
152
        }
153 2958
        AN(be);
154 2958
        vdir_wrlock(vd);
155 2958
        if (vd->n_backend >= vd->l_backend)
156 1122
                vdir_expand(vd, vd->l_backend + 16);
157 2958
        assert(vd->n_backend < vd->l_backend);
158 2958
        u = vd->n_backend++;
159 2958
        vd->backend[u] = NULL;
160 2958
        VRT_Assign_Backend(&vd->backend[u], be);
161 2958
        vd->weight[u] = weight;
162 2958
        vdir_unlock(vd);
163 3060
}
164
165
void
166 408
vdir_remove_backend(VRT_CTX, struct vdir *vd, VCL_BACKEND be, unsigned *cur)
167
{
168
        unsigned u, n;
169
170 408
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
171 408
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
172 408
        if (be == NULL) {
173 0
                VRT_fail(ctx, "%s: None backend cannot be removed",
174 0
                    VRT_BACKEND_string(vd->dir));
175 0
                return;
176
        }
177 408
        CHECK_OBJ(be, DIRECTOR_MAGIC);
178 408
        vdir_wrlock(vd);
179 578
        for (u = 0; u < vd->n_backend; u++)
180 578
                if (vd->backend[u] == be)
181 408
                        break;
182 408
        if (u == vd->n_backend) {
183 0
                vdir_unlock(vd);
184 0
                return;
185
        }
186 408
        VRT_Assign_Backend(&vd->backend[u], NULL);
187 408
        n = (vd->n_backend - u) - 1;
188 408
        memmove(&vd->backend[u], &vd->backend[u+1], n * sizeof(vd->backend[0]));
189 408
        memmove(&vd->weight[u], &vd->weight[u+1], n * sizeof(vd->weight[0]));
190 408
        vd->n_backend--;
191
192 408
        if (cur) {
193 136
                assert(*cur <= vd->n_backend);
194 136
                if (u < *cur)
195 34
                        (*cur)--;
196 102
                else if (*cur == vd->n_backend)
197 34
                        *cur = 0;
198 136
        }
199 408
        vdir_unlock(vd);
200 408
}
201
202
VCL_BOOL
203 1666
vdir_any_healthy(VRT_CTX, struct vdir *vd, VCL_TIME *changed)
204
{
205 1666
        unsigned retval = 0;
206
        VCL_BACKEND be;
207
        unsigned u;
208
        vtim_real c;
209
210 1666
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
211 1666
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
212 1666
        vdir_rdlock(vd);
213 1666
        if (changed != NULL)
214 340
                *changed = 0;
215 2380
        for (u = 0; u < vd->n_backend; u++) {
216 2142
                be = vd->backend[u];
217 2142
                CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
218 2142
                retval = VRT_Healthy(ctx, be, &c);
219 2142
                if (changed != NULL && c > *changed)
220 442
                        *changed = c;
221 2142
                if (retval)
222 1428
                        break;
223 714
        }
224 1666
        vdir_unlock(vd);
225 1666
        return (retval);
226
}
227
228
void
229 1768
vdir_list(VRT_CTX, struct vdir *vd, struct vsb *vsb, int pflag, int jflag,
230
    int weight)
231
{
232
        VCL_BACKEND be;
233
        VCL_BOOL h;
234
        unsigned u, nh;
235
        double w;
236
237 1768
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
238 1768
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
239
240 1768
        if (pflag) {
241 272
                if (jflag) {
242 136
                        VSB_cat(vsb, "{\n");
243 136
                        VSB_indent(vsb, 2);
244 136
                        if (weight)
245 68
                                VSB_printf(vsb, "\"total_weight\": %f,\n",
246 34
                                    vd->total_weight);
247 136
                        VSB_cat(vsb, "\"backends\": {\n");
248 136
                        VSB_indent(vsb, 2);
249 136
                } else {
250 136
                        VSB_cat(vsb, "\n\n\tBackend\tWeight\tHealth\n");
251
                }
252 272
        }
253
254 1768
        vdir_rdlock(vd);
255 1768
        vdir_update_health(ctx, vd);
256 2516
        for (u = 0; pflag && u < vd->n_backend; u++) {
257 748
                be = vd->backend[u];
258 748
                CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
259
260 748
                h = vbit_test(vd->healthy, u);
261
262 748
                w = h ? vd->weight[u] : 0.0;
263
264 748
                if (jflag) {
265 374
                        if (u)
266 238
                                VSB_cat(vsb, ",\n");
267 374
                        VSB_printf(vsb, "\"%s\": {\n", be->vcl_name);
268 374
                        VSB_indent(vsb, 2);
269
270 374
                        if (weight)
271 136
                                VSB_printf(vsb, "\"weight\": %f,\n", w);
272
273 374
                        if (h)
274 272
                                VSB_cat(vsb, "\"health\": \"healthy\"\n");
275
                        else
276 102
                                VSB_cat(vsb, "\"health\": \"sick\"\n");
277
278 374
                        VSB_indent(vsb, -2);
279 374
                        VSB_cat(vsb, "}");
280 374
                } else {
281 374
                        VSB_cat(vsb, "\t");
282 374
                        VSB_cat(vsb, be->vcl_name);
283 374
                        if (weight)
284 272
                                VSB_printf(vsb, "\t%6.2f%%\t",
285 136
                                    100 * w / vd->total_weight);
286
                        else
287 238
                                VSB_cat(vsb, "\t-\t");
288 374
                        VSB_cat(vsb, h ? "healthy" : "sick");
289 374
                        VSB_cat(vsb, "\n");
290
                }
291 748
        }
292 1768
        nh = vd->n_healthy;
293 1768
        u = vd->n_backend;
294 1768
        vdir_unlock(vd);
295
296 1768
        if (jflag && (pflag)) {
297 136
                VSB_cat(vsb, "\n");
298 136
                VSB_indent(vsb, -2);
299 136
                VSB_cat(vsb, "}\n");
300 136
                VSB_indent(vsb, -2);
301 136
                VSB_cat(vsb, "},\n");
302 136
        }
303
304 1768
        if (pflag)
305 272
                return;
306
307 1496
        if (jflag)
308 680
                VSB_printf(vsb, "[%u, %u, \"%s\"]", nh, u,
309 340
                    nh ? "healthy" : "sick");
310
        else
311 1156
                VSB_printf(vsb, "%u/%u\t%s", nh, u, nh ? "healthy" : "sick");
312 1768
}
313
314
/*
315
 * iterate backends and update
316
 * - healthy bitmap
317
 * - number of healthy backends
318
 * - total_weight
319
 * - last change time of the VCL_BACKEND
320
 *
321
 * must be called under the vdir lock (read or write).
322
 *
323
 * A write lock is required if consistency between the individual attributes is
324
 * a must, e.g. when total_weight is required to be the exact sum of the weights
325
 *
326
 * The read lock is safe because add_backend expands the healthy bitmap and all
327
 * other members are atomic and may be used if consistency is not required.
328
 */
329
void
330 3808
vdir_update_health(VRT_CTX, struct vdir *vd)
331
{
332 3808
        VCL_TIME c, changed = 0;
333
        VCL_BOOL h;
334
        VCL_BACKEND be;
335 3808
        unsigned u, nh = 0;
336 3808
        double tw = 0.0;
337
        struct vbitmap *healthy;
338
339 3808
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
340 3808
        healthy = vd->healthy;
341 12716
        for (u = 0; u < vd->n_backend; u++) {
342 8908
                be = vd->backend[u];
343 8908
                CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
344 8908
                c = 0;
345 8908
                h = VRT_Healthy(ctx, vd->backend[u], &c);
346 8908
                if (h) {
347 6902
                        nh++;
348 6902
                        tw += vd->weight[u];
349 6902
                }
350 8908
                if (c > changed)
351 8568
                        changed = c;
352 8908
                if (h != vbit_test(healthy, u)) {
353 4556
                        if (h)
354 4488
                                vbit_set(healthy, u);
355
                        else
356 68
                                vbit_clr(healthy, u);
357 4556
                }
358 8908
        }
359 3808
        VRT_SetChanged(vd->dir, changed);
360 3808
        vd->total_weight = tw;
361 3808
        vd->n_healthy = nh;
362 3808
}
363
364
static unsigned
365 1564
vdir_pick_by_weight(const struct vdir *vd, double w)
366
{
367 1564
        const struct vbitmap *healthy = vd->healthy;
368 1564
        double a = 0.0;
369
        unsigned u;
370
371 1564
        AN(healthy);
372 2382
        for (u = 0; u < vd->n_backend; u++) {
373 2382
                if (! vbit_test(healthy, u))
374 136
                        continue;
375 2246
                a += vd->weight[u];
376 2246
                if (w < a)
377 1564
                        return (u);
378 682
        }
379 0
        WRONG("");
380
}
381
382
VCL_BACKEND
383 1598
vdir_pick_be(VRT_CTX, struct vdir *vd, double w)
384
{
385
        unsigned u;
386 1598
        VCL_BACKEND be = NULL;
387
388 1598
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
389 1598
        CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
390 1598
        vdir_wrlock(vd);
391 1598
        vdir_update_health(ctx, vd);
392 1598
        if (vd->total_weight > 0.0) {
393 1564
                u = vdir_pick_by_weight(vd, w * vd->total_weight);
394 1564
                assert(u < vd->n_backend);
395 1564
                be = vd->backend[u];
396 1564
                CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
397 1564
        }
398 1598
        vdir_unlock(vd);
399 1598
        return (be);
400
}