varnish-cache/bin/varnishd/cache/cache_backend_probe.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
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
 * Poll backends for collection of health statistics
31
 *
32
 * We co-opt threads from the worker pool for probing the backends,
33 18461
 * but we want to avoid a potentially messy cleanup operation when we
34 18461
 * retire the backend, so the thread owns the health information, which
35 18461
 * the backend references, rather than the other way around.
36 18461
 *
37 18461
 */
38 18461
39 18461
#include "config.h"
40 18461
41
#include <poll.h>
42
#include <stdio.h>
43
#include <stdlib.h>
44
45
#include "cache_varnishd.h"
46
47
#include "vbh.h"
48
#include "vcli_serve.h"
49
#include "vsa.h"
50
#include "vtcp.h"
51
#include "vtim.h"
52
53
#include "cache_backend.h"
54
#include "cache_conn_pool.h"
55
56
#include "VSC_vbe.h"
57
58
/* Default averaging rate, we want something pretty responsive */
59
#define AVG_RATE                        4
60
61
struct vbp_target {
62
        unsigned                        magic;
63
#define VBP_TARGET_MAGIC                0x6b7cb656
64
65
        VRT_BACKEND_PROBE_FIELDS()
66
67
        struct backend                  *backend;
68
        struct conn_pool                *conn_pool;
69
70
        char                            *req;
71
        int                             req_len;
72
73
        char                            resp_buf[128];
74
        unsigned                        good;
75
76
        /* Collected statistics */
77
#define BITMAP(n, c, t, b)      uintmax_t       n;
78
#include "tbl/backend_poll.h"
79
80
        vtim_dur                        last;
81
        vtim_dur                        avg;
82
        double                          rate;
83
84
        vtim_real                       due;
85
        int                             running;
86
        int                             heap_idx;
87
        struct pool_task                task[1];
88
};
89
90
static struct lock                      vbp_mtx;
91
static pthread_cond_t                   vbp_cond;
92
static struct vbh                       *vbp_heap;
93
94
static const unsigned char vbp_proxy_local[] = {
95
        0x0d, 0x0a, 0x0d, 0x0a, 0x00, 0x0d, 0x0a, 0x51,
96
        0x55, 0x49, 0x54, 0x0a, 0x20, 0x00, 0x00, 0x00,
97
};
98
99
/*--------------------------------------------------------------------*/
100
101
static void
102 150
vbp_delete(struct vbp_target *vt)
103
{
104 150
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
105
106
#define DN(x)   /**/
107 150
        VRT_BACKEND_PROBE_HANDLE();
108
#undef DN
109 150
        VCP_Rel(&vt->conn_pool);
110 150
        free(vt->req);
111 150
        FREE_OBJ(vt);
112 150
}
113
114
115
/*--------------------------------------------------------------------
116
 * Record pokings...
117
 */
118
119
static void
120 9671
vbp_start_poke(struct vbp_target *vt)
121
{
122 9671
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
123
124
#define BITMAP(n, c, t, b) \
125
        vt->n <<= 1;
126
#include "tbl/backend_poll.h"
127
128 9671
        vt->last = 0;
129 9671
        vt->resp_buf[0] = '\0';
130 9671
}
131
132
static void
133 9590
vbp_has_poked(struct vbp_target *vt)
134
{
135
        unsigned i, j;
136
        uint64_t u;
137
138 9590
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
139
140
        /* Calculate exponential average */
141 9590
        if (vt->happy & 1) {
142 8407
                if (vt->rate < AVG_RATE)
143 4408
                        vt->rate += 1.0;
144 8407
                vt->avg += (vt->last - vt->avg) / vt->rate;
145 8407
        }
146
147 9590
        u = vt->happy;
148 80147
        for (i = j = 0; i < vt->window; i++) {
149 70557
                if (u & 1)
150 38950
                        j++;
151 70557
                u >>= 1;
152 70557
        }
153 9590
        vt->good = j;
154 9590
}
155
156
void
157 6590
VBP_Update_Backend(struct vbp_target *vt)
158
{
159 6590
        unsigned i = 0, chg;
160
        char bits[10];
161
162 6590
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
163
164
#define BITMAP(n, c, t, b)                      \
165
        bits[i++] = (vt->n & 1) ? c : '-';
166
#include "tbl/backend_poll.h"
167 6590
        bits[i] = '\0';
168 6590
        assert(i < sizeof bits);
169
170 6590
        Lck_Lock(&vbp_mtx);
171 6590
        if (vt->backend == NULL) {
172 0
                Lck_Unlock(&vbp_mtx);
173 0
                return;
174
        }
175
176 6590
        i = (vt->good < vt->threshold);
177 6590
        chg = (i != vt->backend->sick);
178 6590
        vt->backend->sick = i;
179
180 6590
        AN(vt->backend->vcl_name);
181 13180
        VSL(SLT_Backend_health, NO_VXID,
182
            "%s %s %s %s %u %u %u %.6f %.6f \"%s\"",
183 6590
            vt->backend->vcl_name, chg ? "Went" : "Still",
184 6590
            i ? "sick" : "healthy", bits,
185 6590
            vt->good, vt->threshold, vt->window,
186 6590
            vt->last, vt->avg, vt->resp_buf);
187 6590
        vt->backend->vsc->happy = vt->happy;
188 6590
        if (chg)
189 1685
                vt->backend->changed = VTIM_real();
190 6590
        Lck_Unlock(&vbp_mtx);
191 6590
}
192
193
static void
194 1875
vbp_reset(struct vbp_target *vt)
195
{
196
        unsigned u;
197
198 1875
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
199 1875
        vt->avg = 0.0;
200 1875
        vt->rate = 0.0;
201
#define BITMAP(n, c, t, b) \
202
        vt->n = 0;
203
#include "tbl/backend_poll.h"
204
205 6750
        for (u = 0; u < vt->initial; u++) {
206 4875
                vbp_start_poke(vt);
207 4875
                vt->happy |= 1;
208 4875
                vbp_has_poked(vt);
209 4875
        }
210 1875
}
211
212
/*--------------------------------------------------------------------
213
 * Poke one backend, once, but possibly at both IPv4 and IPv6 addresses.
214
 *
215
 * We do deliberately not use the stuff in cache_backend.c, because we
216
 * want to measure the backends response without local distractions.
217
 */
218
219
static int
220 4814
vbp_write(struct vbp_target *vt, int *sock, const void *buf, size_t len)
221
{
222
        int i;
223
224 4814
        i = write(*sock, buf, len);
225 4814
        VTCP_Assert(i);
226 4814
        if (i != len) {
227 0
                if (i < 0) {
228 0
                        vt->err_xmit |= 1;
229 0
                        bprintf(vt->resp_buf, "Write error %d (%s)",
230
                                errno, VAS_errtxt(errno));
231 0
                } else {
232 0
                        bprintf(vt->resp_buf,
233
                                "Short write (%d/%zu) error %d (%s)",
234
                                i, len, errno, VAS_errtxt(errno));
235
                }
236 0
                VTCP_close(sock);
237 0
                return (-1);
238
        }
239 4814
        return (0);
240 4814
}
241
242
static int
243 154
vbp_write_proxy_v1(struct vbp_target *vt, int *sock)
244
{
245
        char buf[105]; /* maximum size for a TCP6 PROXY line with null char */
246
        char addr[VTCP_ADDRBUFSIZE];
247
        char port[VTCP_PORTBUFSIZE];
248 154
        char vsabuf[vsa_suckaddr_len];
249
        const struct suckaddr *sua;
250
        int proto;
251
        struct vsb vsb;
252
253 154
        sua = VSA_getsockname(*sock, vsabuf, sizeof vsabuf);
254 154
        AN(sua);
255 154
        AN(VSB_init(&vsb, buf, sizeof buf));
256
257 154
        proto = VSA_Get_Proto(sua);
258 154
        if (proto == AF_INET || proto == AF_INET6) {
259 79
                VTCP_name(sua, addr, sizeof addr, port, sizeof port);
260 79
                VSB_printf(&vsb, "PROXY %s %s %s %s %s\r\n",
261 79
                    proto == AF_INET ? "TCP4" : "TCP6",
262 79
                    addr, addr, port, port);
263 79
        } else {
264 75
                VSB_cat(&vsb, "PROXY UNKNOWN\r\n");
265
        }
266 154
        AZ(VSB_finish(&vsb));
267
268 154
        VSB_fini(&vsb);
269 154
        return (vbp_write(vt, sock, buf, strlen(buf)));
270 154
}
271
272
static void
273 4771
vbp_poke(struct vbp_target *vt)
274
{
275
        int s, tmo, i, proxy_header, err;
276
        vtim_real t_start, t_now, t_end;
277
        unsigned rlen, resp;
278
        char buf[8192], *p;
279 4771
        struct pollfd pfda[1], *pfd = pfda;
280
        const struct suckaddr *sa;
281
282 4771
        t_start = t_now = VTIM_real();
283 4771
        t_end = t_start + vt->timeout;
284
285 4771
        s = VCP_Open(vt->conn_pool, t_end - t_now, &sa, &err);
286 4771
        if (s < 0) {
287 303
                bprintf(vt->resp_buf, "Open error %d (%s)", err, VAS_errtxt(err));
288 303
                Lck_Lock(&vbp_mtx);
289 303
                if (vt->backend)
290 303
                        VBE_Connect_Error(vt->backend->vsc, err);
291 303
                Lck_Unlock(&vbp_mtx);
292 303
                return;
293
        }
294
295 4468
        i = VSA_Get_Proto(sa);
296 4468
        if (VSA_Compare(sa, bogo_ip) == 0)
297 1584
                vt->good_unix |= 1;
298 2884
        else if (i == AF_INET)
299 2884
                vt->good_ipv4 |= 1;
300 0
        else if (i == AF_INET6)
301 0
                vt->good_ipv6 |= 1;
302
        else
303 0
                WRONG("Wrong probe protocol family");
304
305 4468
        t_now = VTIM_real();
306 4468
        tmo = (int)round((t_end - t_now) * 1e3);
307 4468
        if (tmo <= 0) {
308 56
                bprintf(vt->resp_buf,
309
                        "Open timeout %.3fs exceeded by %.3fs",
310
                        vt->timeout, t_now - t_end);
311 56
                VTCP_close(&s);
312 56
                return;
313
        }
314
315 4412
        Lck_Lock(&vbp_mtx);
316 4412
        if (vt->backend != NULL)
317 4412
                proxy_header = vt->backend->proxy_header;
318
        else
319 0
                proxy_header = -1;
320 4412
        Lck_Unlock(&vbp_mtx);
321
322 4412
        if (proxy_header < 0) {
323 0
                bprintf(vt->resp_buf, "%s", "No backend");
324 0
                VTCP_close(&s);
325 0
                return;
326
        }
327
328
        /* Send the PROXY header */
329 4412
        assert(proxy_header <= 2);
330 4412
        if (proxy_header == 1) {
331 154
                if (vbp_write_proxy_v1(vt, &s) != 0)
332 0
                        return;
333 4412
        } else if (proxy_header == 2 &&
334 192
            vbp_write(vt, &s, vbp_proxy_local, sizeof vbp_proxy_local) != 0)
335 0
                return;
336
337
        /* Send the request */
338 4412
        if (vbp_write(vt, &s, vt->req, vt->req_len) != 0)
339 0
                return;
340
341 4412
        vt->good_xmit |= 1;
342
343 4412
        pfd->fd = s;
344 4412
        rlen = 0;
345 8807
        while (1) {
346 8807
                pfd->events = POLLIN;
347 8807
                pfd->revents = 0;
348 8807
                t_now = VTIM_real();
349 8807
                tmo = (int)round((t_end - t_now) * 1e3);
350 8807
                if (tmo <= 0) {
351 0
                        bprintf(vt->resp_buf,
352
                            "Poll timeout %.3fs exceeded by %.3fs",
353
                            vt->timeout, t_now - t_end);
354 0
                        i = -1;
355 0
                        break;
356
                }
357 8807
                i = poll(pfd, 1, tmo);
358 8807
                if (i <= 0) {
359 505
                        if (!i) {
360 505
                                if (!vt->exp_close)
361 107
                                        break;
362 398
                                errno = ETIMEDOUT;
363 398
                        }
364 398
                        bprintf(vt->resp_buf, "Poll error %d (%s)",
365
                            errno, VAS_errtxt(errno));
366 398
                        i = -1;
367 398
                        break;
368
                }
369 8302
                if (rlen < sizeof vt->resp_buf)
370 15444
                        i = read(s, vt->resp_buf + rlen,
371 7722
                            sizeof vt->resp_buf - rlen);
372
                else
373 580
                        i = read(s, buf, sizeof buf);
374 8302
                VTCP_Assert(i);
375 8302
                if (i <= 0) {
376 3907
                        if (i < 0)
377 32
                                bprintf(vt->resp_buf, "Read error %d (%s)",
378
                                        errno, VAS_errtxt(errno));
379 3907
                        break;
380
                }
381 4395
                rlen += i;
382
        }
383
384 4412
        VTCP_close(&s);
385
386 4412
        if (i < 0) {
387
                /* errno reported above */
388 430
                vt->err_recv |= 1;
389 430
                return;
390
        }
391
392 3982
        if (rlen == 0) {
393 150
                bprintf(vt->resp_buf, "%s", "Empty response");
394 150
                return;
395
        }
396
397
        /* So we have a good receive ... */
398 3832
        t_now = VTIM_real();
399 3832
        vt->last = t_now - t_start;
400 3832
        vt->good_recv |= 1;
401
402
        /* Now find out if we like the response */
403 3832
        vt->resp_buf[sizeof vt->resp_buf - 1] = '\0';
404 3832
        p = strchr(vt->resp_buf, '\r');
405 3832
        if (p != NULL)
406 3832
                *p = '\0';
407 3832
        p = strchr(vt->resp_buf, '\n');
408 3832
        if (p != NULL)
409 0
                *p = '\0';
410
411 3832
        i = sscanf(vt->resp_buf, "HTTP/%*f %u ", &resp);
412
413 3832
        if (i == 1 && resp == vt->exp_status)
414 3507
                vt->happy |= 1;
415 4771
}
416
417
/*--------------------------------------------------------------------
418
 */
419
static void
420 5540
vbp_heap_insert(struct vbp_target *vt)
421
{
422
        // Lck_AssertHeld(&vbp_mtx);
423 5540
        VBH_insert(vbp_heap, vt);
424 5540
        if (VBH_root(vbp_heap) == vt)
425 5133
                PTOK(pthread_cond_signal(&vbp_cond));
426 5540
}
427
428
/*--------------------------------------------------------------------
429
 */
430
431
static void v_matchproto_(task_func_t)
432 4715
vbp_task(struct worker *wrk, void *priv)
433
{
434
        struct vbp_target *vt;
435
436 4715
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
437 4715
        CAST_OBJ_NOTNULL(vt, priv, VBP_TARGET_MAGIC);
438
439 4715
        AN(vt->running);
440 4715
        AN(vt->req);
441 4715
        assert(vt->req_len > 0);
442
443 4715
        vbp_start_poke(vt);
444 4715
        vbp_poke(vt);
445 4715
        vbp_has_poked(vt);
446 4715
        VBP_Update_Backend(vt);
447
448 4715
        Lck_Lock(&vbp_mtx);
449 4715
        if (vt->running < 0) {
450 0
                assert(vt->heap_idx == VBH_NOIDX);
451 0
                vbp_delete(vt);
452 0
        } else {
453 4715
                vt->running = 0;
454 4715
                if (vt->heap_idx != VBH_NOIDX) {
455 4690
                        vt->due = VTIM_real() + vt->interval;
456 4690
                        VBH_delete(vbp_heap, vt->heap_idx);
457 4690
                        vbp_heap_insert(vt);
458 4690
                }
459
        }
460 4715
        Lck_Unlock(&vbp_mtx);
461 4715
}
462
463
/*--------------------------------------------------------------------
464
 */
465
466
static void * v_matchproto_(bgthread_t)
467 0
vbp_thread(struct worker *wrk, void *priv)
468
{
469
        vtim_real now, nxt;
470
        struct vbp_target *vt;
471
        int r;
472
473 0
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
474 0
        AZ(priv);
475 0
        Lck_Lock(&vbp_mtx);
476 42384
        while (1) {
477 42384
                now = VTIM_real();
478 42384
                vt = VBH_root(vbp_heap);
479 42384
                if (vt == NULL) {
480 22750
                        nxt = 8.192 + now;
481 22750
                        (void)Lck_CondWaitUntil(&vbp_cond, &vbp_mtx, nxt);
482 42384
                } else if (vt->due > now) {
483 11956
                        nxt = vt->due;
484 11956
                        vt = NULL;
485 11956
                        (void)Lck_CondWaitUntil(&vbp_cond, &vbp_mtx, nxt);
486 11956
                } else {
487 7678
                        VBH_delete(vbp_heap, vt->heap_idx);
488 7678
                        vt->due = now + vt->interval;
489 7678
                        VBH_insert(vbp_heap, vt);
490 7678
                        if (!vt->running) {
491 4796
                                vt->running = 1;
492 4796
                                vt->task->func = vbp_task;
493 4796
                                vt->task->priv = vt;
494 4796
                                Lck_Unlock(&vbp_mtx);
495 4796
                                r = Pool_Task_Any(vt->task, TASK_QUEUE_REQ);
496 4796
                                Lck_Lock(&vbp_mtx);
497 4796
                                if (r)
498 0
                                        vt->running = 0;
499 4796
                        }
500
                }
501
        }
502
        NEEDLESS(Lck_Unlock(&vbp_mtx));
503
        NEEDLESS(return (NULL));
504
}
505
506
507
/*--------------------------------------------------------------------
508
 * Cli functions
509
 */
510
511
static void
512 975
vbp_bitmap(struct vsb *vsb, char c, uint64_t map, const char *lbl)
513
{
514
        int i;
515 975
        uint64_t u = (1ULL << 63);
516
517 975
        VSB_cat(vsb, "  ");
518 63375
        for (i = 0; i < 64; i++) {
519 62400
                if (map & u)
520 6227
                        VSB_putc(vsb, c);
521
                else
522 56173
                        VSB_putc(vsb, '-');
523 62400
                map <<= 1;
524 62400
        }
525 975
        VSB_printf(vsb, " %s\n", lbl);
526 975
}
527
528
/*lint -e{506} constant value boolean */
529
/*lint -e{774} constant value boolean */
530
void
531 1950
VBP_Status(struct vsb *vsb, const struct backend *be, int details, int json)
532
{
533
        struct vbp_target *vt;
534
535 1950
        CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
536 1950
        vt = be->probe;
537 1950
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
538
539 1950
        if (!details) {
540 1625
                if (json)
541 150
                        VSB_printf(vsb, "[%u, %u, \"%s\"]",
542 75
                            vt->good, vt->window,
543 75
                            vt->backend->sick ? "sick" : "healthy");
544
                else
545 3100
                        VSB_printf(vsb, "%u/%u\t%s", vt->good, vt->window,
546 1550
                            vt->backend->sick ? "sick" : "healthy");
547 1625
                return;
548
        }
549
550 325
        if (json) {
551 50
                VSB_cat(vsb, "{\n");
552 50
                VSB_indent(vsb, 2);
553
#define BITMAP(nn, cc, tt, bb)                                  \
554
                VSB_printf(vsb, "\"bits_%c\": %ju,\n", cc, vt->nn);
555
#include "tbl/backend_poll.h"
556 50
                VSB_printf(vsb, "\"good\": %u,\n", vt->good);
557 50
                VSB_printf(vsb, "\"threshold\": %u,\n", vt->threshold);
558 50
                VSB_printf(vsb, "\"window\": %u", vt->window);
559 50
                VSB_indent(vsb, -2);
560 50
                VSB_cat(vsb, "\n");
561 50
                VSB_cat(vsb, "},\n");
562 50
                return;
563
        }
564
565 550
        VSB_printf(vsb,
566
            "\n Current states  good: %2u threshold: %2u window: %2u\n",
567 275
            vt->good, vt->threshold, vt->window);
568 550
        VSB_printf(vsb,
569 275
            "  Average response time of good probes: %.6f\n", vt->avg);
570 275
        VSB_cat(vsb,
571
            "  Oldest ======================"
572
            "============================ Newest\n");
573
574
#define BITMAP(n, c, t, b)                                      \
575
                if ((vt->n != 0) || (b))                        \
576
                        vbp_bitmap(vsb, (c), vt->n, (t));
577
#include "tbl/backend_poll.h"
578 1950
}
579
580
/*--------------------------------------------------------------------
581
 * Build request from probe spec
582
 */
583
584
static void
585 850
vbp_build_req(struct vbp_target *vt, const struct vrt_backend_probe *vbp,
586
    const struct backend *be)
587
{
588
        struct vsb *vsb;
589
590 850
        vsb = VSB_new_auto();
591 850
        AN(vsb);
592 850
        VSB_clear(vsb);
593 850
        if (vbp->request != NULL) {
594 50
                VSB_cat(vsb, vbp->request);
595 50
        } else {
596 800
                AN(be->hosthdr);
597 1600
                VSB_printf(vsb,
598
                    "GET %s HTTP/1.1\r\n"
599
                    "Host: %s\r\n"
600
                    "Connection: close\r\n"
601
                    "\r\n",
602 800
                    vbp->url != NULL ?  vbp->url : "/",
603 800
                    be->hosthdr);
604
        }
605 850
        AZ(VSB_finish(vsb));
606 850
        vt->req = strdup(VSB_data(vsb));
607 850
        AN(vt->req);
608 850
        vt->req_len = VSB_len(vsb);
609 850
        VSB_destroy(&vsb);
610 850
}
611
612
/*--------------------------------------------------------------------
613
 * Sanitize and set defaults
614
 * XXX: we could make these defaults parameters
615
 */
616
617
static void
618 850
vbp_set_defaults(struct vbp_target *vt, const struct vrt_backend_probe *vp)
619
{
620
621
#define DN(x)   do { vt->x = vp->x; } while (0)
622 850
        VRT_BACKEND_PROBE_HANDLE();
623
#undef DN
624
625 850
        if (vt->timeout == 0.0)
626 650
                vt->timeout = 2.0;
627 850
        if (vt->interval == 0.0)
628 200
                vt->interval = 5.0;
629 850
        if (vt->window == 0)
630 400
                vt->window = 8;
631 850
        if (vt->threshold == 0)
632 400
                vt->threshold = 3;
633 850
        if (vt->exp_status == 0)
634 850
                vt->exp_status = 200;
635
636 850
        if (vt->initial == ~0U)
637 525
                vt->initial = vt->threshold - 1;
638
639 850
        vt->initial = vmin(vt->initial, vt->threshold);
640 850
}
641
642
/*--------------------------------------------------------------------
643
 */
644
645
void
646 1025
VBP_Control(const struct backend *be, int enable)
647
{
648
        struct vbp_target *vt;
649
650 1025
        CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
651 1025
        vt = be->probe;
652 1025
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
653
654 1025
        vbp_reset(vt);
655 1025
        VBP_Update_Backend(vt);
656
657 1025
        Lck_Lock(&vbp_mtx);
658 1025
        if (enable) {
659 850
                assert(vt->heap_idx == VBH_NOIDX);
660 850
                vt->due = VTIM_real();
661 850
                vbp_heap_insert(vt);
662 850
        } else {
663 175
                assert(vt->heap_idx != VBH_NOIDX);
664 175
                VBH_delete(vbp_heap, vt->heap_idx);
665
        }
666 1025
        Lck_Unlock(&vbp_mtx);
667 1025
}
668
669
/*--------------------------------------------------------------------
670
 * Insert/Remove/Use called from cache_backend.c
671
 */
672
673
void
674 850
VBP_Insert(struct backend *b, const struct vrt_backend_probe *vp,
675
    struct conn_pool *tp)
676
{
677
        struct vbp_target *vt;
678
679 850
        CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
680 850
        CHECK_OBJ_NOTNULL(vp, VRT_BACKEND_PROBE_MAGIC);
681
682 850
        AZ(b->probe);
683
684 850
        ALLOC_OBJ(vt, VBP_TARGET_MAGIC);
685 850
        XXXAN(vt);
686
687 850
        vt->conn_pool = tp;
688 850
        VCP_AddRef(vt->conn_pool);
689 850
        vt->backend = b;
690 850
        b->probe = vt;
691
692 850
        vbp_set_defaults(vt, vp);
693 850
        vbp_build_req(vt, vp, b);
694
695 850
        vbp_reset(vt);
696 850
}
697
698
void
699 150
VBP_Remove(struct backend *be)
700
{
701
        struct vbp_target *vt;
702
703 150
        CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
704 150
        vt = be->probe;
705 150
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
706
707 150
        Lck_Lock(&vbp_mtx);
708 150
        be->sick = 1;
709 150
        be->probe = NULL;
710 150
        vt->backend = NULL;
711 150
        if (vt->running) {
712
                // task scheduled, it calls vbp_delete()
713 0
                vt->running = -1;
714 0
                vt = NULL;
715 150
        } else if (vt->heap_idx != VBH_NOIDX) {
716
                // task done, not yet rescheduled
717 0
                VBH_delete(vbp_heap, vt->heap_idx);
718 0
        }
719 150
        Lck_Unlock(&vbp_mtx);
720 150
        if (vt != NULL) {
721 150
                assert(vt->heap_idx == VBH_NOIDX);
722 150
                vbp_delete(vt);
723 150
        }
724 150
}
725
726
/*-------------------------------------------------------------------*/
727
728
static int v_matchproto_(vbh_cmp_t)
729 1747
vbp_cmp(void *priv, const void *a, const void *b)
730
{
731
        const struct vbp_target *aa, *bb;
732
        int ar, br;
733
734 1747
        AZ(priv);
735 1747
        CAST_OBJ_NOTNULL(aa, a, VBP_TARGET_MAGIC);
736 1747
        CAST_OBJ_NOTNULL(bb, b, VBP_TARGET_MAGIC);
737
738 1747
        ar = aa->running == 0;
739 1747
        br = bb->running == 0;
740
741 1747
        if (ar != br)
742 581
                return (ar);
743
744 1166
        return (aa->due < bb->due);
745 1747
}
746
747
static void v_matchproto_(vbh_update_t)
748 28593
vbp_update(void *priv, void *p, unsigned u)
749
{
750
        struct vbp_target *vt;
751
752 28593
        AZ(priv);
753 28593
        CAST_OBJ_NOTNULL(vt, p, VBP_TARGET_MAGIC);
754 28593
        vt->heap_idx = u;
755 28593
}
756
757
/*-------------------------------------------------------------------*/
758
759
void
760 22197
VBP_Init(void)
761
{
762
        pthread_t thr;
763
764 22197
        Lck_New(&vbp_mtx, lck_probe);
765 22197
        vbp_heap = VBH_new(NULL, vbp_cmp, vbp_update);
766 22197
        AN(vbp_heap);
767 22197
        PTOK(pthread_cond_init(&vbp_cond, NULL));
768 22197
        WRK_BgThread(&thr, "backend-poller", vbp_thread, NULL);
769 22197
}