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