varnish-cache/bin/varnishd/cache/cache_backend_probe.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2011 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * Poll backends for collection of health statistics
30
 *
31
 * We co-opt threads from the worker pool for probing the backends,
32
 * but we want to avoid a potentially messy cleanup operation when we
33
 * retire the backend, so the thread owns the health information, which
34
 * the backend references, rather than the other way around.
35
 *
36
 */
37
38
#include "config.h"
39
40
#include <poll.h>
41
#include <stdio.h>
42
#include <errno.h>
43
#include <string.h>
44
#include <stdlib.h>
45
46
#include "cache_varnishd.h"
47
48
#include "binary_heap.h"
49
#include "vcli_serve.h"
50
#include "vsa.h"
51
#include "vtcp.h"
52
#include "vtim.h"
53
54
#include "cache_backend.h"
55
#include "cache_tcp_pool.h"
56
57
/* Default averaging rate, we want something pretty responsive */
58
#define AVG_RATE                        4
59
60
struct vbp_target {
61
        unsigned                        magic;
62
#define VBP_TARGET_MAGIC                0x6b7cb656
63
64
        VRT_BACKEND_PROBE_FIELDS()
65
66
        struct backend                  *backend;
67
        struct tcp_pool                 *tcp_pool;
68
69
        char                            *req;
70
        int                             req_len;
71
72
        char                            resp_buf[128];
73
        unsigned                        good;
74
75
        /* Collected statistics */
76
#define BITMAP(n, c, t, b)      uintmax_t       n;
77
#include "tbl/backend_poll.h"
78
79
        double                          last;
80
        double                          avg;
81
        double                          rate;
82
83
        double                          due;
84
        int                             running;
85
        int                             heap_idx;
86
        struct pool_task                task;
87
};
88
89
static struct lock                      vbp_mtx;
90
static pthread_cond_t                   vbp_cond;
91
static struct binheap                   *vbp_heap;
92
93
static const unsigned char vbp_proxy_local[] = {
94
        0x0d, 0x0a, 0x0d, 0x0a, 0x00, 0x0d, 0x0a, 0x51,
95
        0x55, 0x49, 0x54, 0x0a, 0x20, 0x00, 0x00, 0x00,
96
};
97
98
/*--------------------------------------------------------------------*/
99
100
static void
101 4
vbp_delete(struct vbp_target *vt)
102
{
103
#define DN(x)   /**/
104
        VRT_BACKEND_PROBE_HANDLE();
105
#undef DN
106 4
        VTP_Rel(&vt->tcp_pool);
107 4
        free(vt->req);
108 4
        FREE_OBJ(vt);
109 4
}
110
111
112
/*--------------------------------------------------------------------
113
 * Record pokings...
114
 */
115
116
static void
117 342
vbp_start_poke(struct vbp_target *vt)
118
{
119 342
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
120
121
#define BITMAP(n, c, t, b) \
122
        vt->n <<= 1;
123
#include "tbl/backend_poll.h"
124
125 342
        vt->last = 0;
126 342
        vt->resp_buf[0] = '\0';
127 342
}
128
129
static void
130 342
vbp_has_poked(struct vbp_target *vt)
131
{
132
        unsigned i, j;
133
        uint64_t u;
134
135 342
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
136
137
        /* Calculate exponential average */
138 342
        if (vt->happy & 1) {
139 240
                if (vt->rate < AVG_RATE)
140 96
                        vt->rate += 1.0;
141 240
                vt->avg += (vt->last - vt->avg) / vt->rate;
142
        }
143
144 342
        u = vt->happy;
145 2770
        for (i = j = 0; i < vt->window; i++) {
146 2428
                if (u & 1)
147 1308
                        j++;
148 2428
                u >>= 1;
149
        }
150 342
        vt->good = j;
151 342
}
152
153
void
154 314
VBP_Update_Backend(struct vbp_target *vt)
155
{
156 314
        unsigned i = 0;
157
        char bits[10];
158
        const char *logmsg;
159
160 314
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
161
162 314
        Lck_Lock(&vbp_mtx);
163 314
        if (vt->backend == NULL) {
164 2
                Lck_Unlock(&vbp_mtx);
165 2
                return;
166
        }
167
168
#define BITMAP(n, c, t, b) \
169
        bits[i++] = (vt->n & 1) ? c : '-';
170
#include "tbl/backend_poll.h"
171 312
        bits[i] = '\0';
172 312
        assert(i < sizeof bits);
173
174 312
        if (vt->backend->director == NULL) {
175 21
                Lck_Unlock(&vbp_mtx);
176 21
                return;
177
        }
178
179 291
        if (vt->good >= vt->threshold) {
180 147
                if (vt->backend->director->sick) {
181 15
                        logmsg = "Back healthy";
182 15
                        VRT_SetHealth(vt->backend->director, 1);
183
                } else {
184 132
                        logmsg = "Still healthy";
185
                }
186
        } else {
187 144
                if (vt->backend->director->sick) {
188 115
                        logmsg = "Still sick";
189
                } else {
190 29
                        logmsg = "Went sick";
191 29
                        VRT_SetHealth(vt->backend->director, 0);
192
                }
193
        }
194 582
        VSL(SLT_Backend_health, 0, "%s %s %s %u %u %u %.6f %.6f %s",
195 291
            vt->backend->director->vcl_name, logmsg, bits,
196
            vt->good, vt->threshold, vt->window,
197 291
            vt->last, vt->avg, vt->resp_buf);
198 291
        VBE_SetHappy(vt->backend, vt->happy);
199
200 291
        Lck_Unlock(&vbp_mtx);
201
}
202
203
static void
204 49
vbp_reset(struct vbp_target *vt)
205
{
206
        unsigned u;
207
208 49
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
209 49
        vt->avg = 0.0;
210 49
        vt->rate = 0.0;
211
#define BITMAP(n, c, t, b) \
212
        vt->n = 0;
213
#include "tbl/backend_poll.h"
214
215 147
        for (u = 0; u < vt->initial; u++) {
216 98
                vbp_start_poke(vt);
217 98
                vt->happy |= 1;
218 98
                vbp_has_poked(vt);
219
        }
220 49
}
221
222
/*--------------------------------------------------------------------
223
 * Poke one backend, once, but possibly at both IPv4 and IPv6 addresses.
224
 *
225
 * We do deliberately not use the stuff in cache_backend.c, because we
226
 * want to measure the backends response without local distractions.
227
 */
228
229
static int
230 191
vbp_write(struct vbp_target *vt, int *sock, const void *buf, size_t len)
231
{
232
        int i;
233
234 191
        i = write(*sock, buf, len);
235 191
        if (i != len) {
236 1
                if (i < 0) {
237 1
                        vt->err_xmit |= 1;
238 1
                        bprintf(vt->resp_buf, "Write error %d (%s)",
239
                                errno, strerror(errno));
240
                } else {
241 0
                        bprintf(vt->resp_buf,
242
                                "Short write (%d/%zu) error %d (%s)",
243
                                i, len, errno, strerror(errno));
244
                }
245 1
                VTCP_close(sock);
246 1
                return (-1);
247
        }
248 190
        return (0);
249
}
250
251
static int
252 10
vbp_write_proxy_v1(struct vbp_target *vt, int *sock)
253
{
254
        char buf[105]; /* maximum size for a TCP6 PROXY line with null char */
255
        char addr[VTCP_ADDRBUFSIZE];
256
        char port[VTCP_PORTBUFSIZE];
257
        struct sockaddr_storage ss;
258
        struct vsb vsb;
259
        socklen_t l;
260
261 10
        VTCP_myname(*sock, addr, sizeof addr, port, sizeof port);
262 10
        AN(VSB_new(&vsb, buf, sizeof buf, VSB_FIXEDLEN));
263
264 10
        l = sizeof ss;
265 10
        AZ(getsockname(*sock, (void *)&ss, &l));
266 10
        if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
267 4
                VSB_printf(&vsb, "PROXY %s %s %s %s %s\r\n",
268 4
                    ss.ss_family == AF_INET ? "TCP4" : "TCP6",
269
                    addr, addr, port, port);
270
        } else
271 6
                VSB_cat(&vsb, "PROXY UNKNOWN\r\n");
272 10
        AZ(VSB_finish(&vsb));
273
274 10
        return (vbp_write(vt, sock, VSB_data(&vsb), VSB_len(&vsb)));
275
}
276
277
static void
278 244
vbp_poke(struct vbp_target *vt)
279
{
280
        int s, tmo, i, proxy_header, err;
281
        double t_start, t_now, t_end;
282
        unsigned rlen, resp;
283
        char buf[8192], *p;
284 244
        struct pollfd pfda[1], *pfd = pfda;
285
        const struct suckaddr *sa;
286
287 244
        t_start = t_now = VTIM_real();
288 244
        t_end = t_start + vt->timeout;
289
290 244
        s = VTP_Open(vt->tcp_pool, t_end - t_now, (const void **)&sa, &err);
291 244
        if (s < 0) {
292 76
                bprintf(vt->resp_buf, "Open error %d (%s)", err, strerror(err));
293 76
                Lck_Lock(&vbp_mtx);
294 76
                if (vt->backend)
295 76
                        VBE_Connect_Error(vt->backend->vsc, err);
296 76
                Lck_Unlock(&vbp_mtx);
297 76
                return;
298
        }
299
300 168
        i = VSA_Get_Proto(sa);
301 168
        if (VSA_Compare(sa, bogo_ip) == 0)
302 77
                vt->good_unix |= 1;
303 91
        else if (i == AF_INET)
304 91
                vt->good_ipv4 |= 1;
305 0
        else if (i == AF_INET6)
306 0
                vt->good_ipv6 |= 1;
307
        else
308 0
                WRONG("Wrong probe protocol family");
309
310 168
        t_now = VTIM_real();
311 168
        tmo = (int)round((t_end - t_now) * 1e3);
312 168
        if (tmo <= 0) {
313 0
                bprintf(vt->resp_buf,
314
                        "Open timeout %.3fs exceeded by %.3fs",
315
                        vt->timeout, t_now - t_end);
316 0
                VTCP_close(&s);
317 0
                return;
318
        }
319
320 168
        Lck_Lock(&vbp_mtx);
321 168
        if (vt->backend != NULL)
322 168
                proxy_header = vt->backend->proxy_header;
323
        else
324 0
                proxy_header = -1;
325 168
        Lck_Unlock(&vbp_mtx);
326
327 168
        if (proxy_header < 0) {
328 0
                bprintf(vt->resp_buf, "%s", "No backend");
329 0
                VTCP_close(&s);
330 0
                return;
331
        }
332
333
        /* Send the PROXY header */
334 168
        assert(proxy_header <= 2);
335 168
        if (proxy_header == 1) {
336 10
                if (vbp_write_proxy_v1(vt, &s) != 0)
337 0
                        return;
338 171
        } else if (proxy_header == 2 &&
339 13
            vbp_write(vt, &s, vbp_proxy_local, sizeof vbp_proxy_local) != 0)
340 0
                return;
341
342
        /* Send the request */
343 168
        if (vbp_write(vt, &s, vt->req, vt->req_len) != 0)
344 1
                return;
345 167
        vt->good_xmit |= 1;
346
347 167
        pfd->fd = s;
348 167
        rlen = 0;
349
        while (1) {
350 503
                pfd->events = POLLIN;
351 335
                pfd->revents = 0;
352 335
                tmo = (int)round((t_end - t_now) * 1e3);
353 335
                if (tmo > 0)
354 335
                        i = poll(pfd, 1, tmo);
355 335
                if (i == 0) {
356 4
                        vt->err_recv |= 1;
357 4
                        bprintf(vt->resp_buf, "Poll error %d (%s)",
358
                                errno, strerror(errno));
359 4
                        VTCP_close(&s);
360 4
                        return;
361
                }
362 331
                if (tmo <= 0) {
363 0
                        bprintf(vt->resp_buf,
364
                                "Poll (read) timeout %.3fs exceeded by %.3fs",
365
                                vt->timeout, t_now - t_end);
366 0
                        VTCP_close(&s);
367 0
                        return;
368
                }
369 331
                if (rlen < sizeof vt->resp_buf)
370 299
                        i = read(s, vt->resp_buf + rlen,
371
                            sizeof vt->resp_buf - rlen);
372
                else
373 32
                        i = read(s, buf, sizeof buf);
374 331
                if (i <= 0) {
375 163
                        if (i < 0)
376 6
                                bprintf(vt->resp_buf, "Read error %d (%s)",
377
                                        errno, strerror(errno));
378 163
                        break;
379
                }
380 168
                rlen += i;
381
        }
382
383 163
        VTCP_close(&s);
384
385 163
        if (i < 0) {
386
                /* errno reported above */
387 6
                vt->err_recv |= 1;
388 6
                return;
389
        }
390
391 157
        if (rlen == 0) {
392 5
                bprintf(vt->resp_buf, "%s", "Empty response");
393 5
                return;
394
        }
395
396
        /* So we have a good receive ... */
397 152
        t_now = VTIM_real();
398 152
        vt->last = t_now - t_start;
399 152
        vt->good_recv |= 1;
400
401
        /* Now find out if we like the response */
402 152
        vt->resp_buf[sizeof vt->resp_buf - 1] = '\0';
403 152
        p = strchr(vt->resp_buf, '\r');
404 152
        if (p != NULL)
405 152
                *p = '\0';
406 152
        p = strchr(vt->resp_buf, '\n');
407 152
        if (p != NULL)
408 0
                *p = '\0';
409
410 152
        i = sscanf(vt->resp_buf, "HTTP/%*f %u ", &resp);
411
412 152
        if (i == 1 && resp == vt->exp_status)
413 140
                vt->happy |= 1;
414
}
415
416
/*--------------------------------------------------------------------
417
 */
418
419
static void v_matchproto_(task_func_t)
420 244
vbp_task(struct worker *wrk, void *priv)
421
{
422
        struct vbp_target *vt;
423
424 244
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
425 244
        CAST_OBJ_NOTNULL(vt, priv, VBP_TARGET_MAGIC);
426
427 244
        AN(vt->running);
428 244
        AN(vt->req);
429 244
        assert(vt->req_len > 0);
430
431 244
        vbp_start_poke(vt);
432 244
        vbp_poke(vt);
433 244
        vbp_has_poked(vt);
434 244
        VBP_Update_Backend(vt);
435
436 244
        Lck_Lock(&vbp_mtx);
437 244
        if (vt->running < 0) {
438 2
                assert(vt->heap_idx == BINHEAP_NOIDX);
439 2
                vbp_delete(vt);
440
        } else {
441 242
                vt->running = 0;
442 242
                if (vt->heap_idx != BINHEAP_NOIDX) {
443 242
                        vt->due = VTIM_real() + vt->interval;
444 242
                        binheap_delete(vbp_heap, vt->heap_idx);
445 242
                        binheap_insert(vbp_heap, vt);
446
                }
447
        }
448 244
        Lck_Unlock(&vbp_mtx);
449 244
}
450
451
/*--------------------------------------------------------------------
452
 */
453
454
static void * v_matchproto_(bgthread_t)
455 685
vbp_thread(struct worker *wrk, void *priv)
456
{
457
        double now, nxt;
458
        struct vbp_target *vt;
459
460 685
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
461 685
        AZ(priv);
462 685
        Lck_Lock(&vbp_mtx);
463
        while (1) {
464 1841
                now = VTIM_real();
465 1263
                vt = binheap_root(vbp_heap);
466 1263
                if (vt == NULL) {
467 734
                        nxt = 8.192 + now;
468 734
                        (void)Lck_CondWait(&vbp_cond, &vbp_mtx, nxt);
469 529
                } else if (vt->due > now) {
470 268
                        nxt = vt->due;
471 268
                        vt = NULL;
472 268
                        (void)Lck_CondWait(&vbp_cond, &vbp_mtx, nxt);
473
                } else {
474 261
                        binheap_delete(vbp_heap, vt->heap_idx);
475 261
                        vt->due = now + vt->interval;
476 261
                        if (!vt->running) {
477 244
                                vt->running = 1;
478 244
                                vt->task.func = vbp_task;
479 244
                                vt->task.priv = vt;
480 244
                                if (Pool_Task_Any(&vt->task, TASK_QUEUE_REQ))
481 0
                                        vt->running = 0;
482
                        }
483 261
                        binheap_insert(vbp_heap, vt);
484
                }
485
        }
486
        NEEDLESS(Lck_Unlock(&vbp_mtx));
487
        NEEDLESS(return NULL);
488
}
489
490
491
/*--------------------------------------------------------------------
492
 * Cli functions
493
 */
494
495
static void
496 35
vbp_bitmap(struct vsb *vsb, char c, uint64_t map, const char *lbl)
497
{
498
        int i;
499 35
        uint64_t u = (1ULL << 63);
500
501 35
        VSB_printf(vsb, "  ");
502 2275
        for (i = 0; i < 64; i++) {
503 2240
                if (map & u)
504 232
                        VSB_putc(vsb, c);
505
                else
506 2008
                        VSB_putc(vsb, '-');
507 2240
                map <<= 1;
508
        }
509 35
        VSB_printf(vsb, " %s\n", lbl);
510 35
}
511
512
/*lint -e{506} constant value boolean */
513
/*lint -e{774} constant value boolean */
514
void
515 53
VBP_Status(struct vsb *vsb, const struct backend *be, int details, int json)
516
{
517
        struct vbp_target *vt;
518
        char buf[12];
519
520 53
        CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
521 53
        vt = be->probe;
522 53
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
523
524 53
        if (!details) {
525 42
                bprintf(buf, "%u/%u %s", vt->good, vt->window,
526
                    vt->backend->director->sick ? "bad" : "good");
527 42
                if (json)
528 1
                        VSB_printf(vsb, "\"%s\"", buf);
529
                else
530 41
                        VSB_printf(vsb, "%-10s", buf);
531 85
                return;
532
        }
533
534 11
        if (json) {
535 1
                VSB_printf(vsb, "{\n");
536 1
                VSB_indent(vsb, 2);
537
#define BITMAP(nn, cc, tt, bb)                                  \
538
                VSB_printf(vsb, "\"bits_%c\": %ju,\n", cc, vt->nn);
539
#include "tbl/backend_poll.h"
540 1
                VSB_printf(vsb, "\"good\": %u,\n", vt->good);
541 1
                VSB_printf(vsb, "\"threshold\": %u,\n", vt->threshold);
542 1
                VSB_printf(vsb, "\"window\": %u", vt->window);
543 1
                VSB_indent(vsb, -2);
544 1
                VSB_printf(vsb, "\n");
545 1
                VSB_printf(vsb, "},\n");
546 1
                return;
547
        }
548
549 10
        VSB_printf(vsb,
550
            "\nCurrent states  good: %2u threshold: %2u window: %2u\n",
551
            vt->good, vt->threshold, vt->window);
552 10
        VSB_printf(vsb,
553
            "  Average response time of good probes: %.6f\n", vt->avg);
554 10
        VSB_printf(vsb,
555
            "  Oldest ======================"
556
            "============================ Newest\n");
557
558
#define BITMAP(n, c, t, b)                                      \
559
                if ((vt->n != 0) || (b))                        \
560
                        vbp_bitmap(vsb, (c), vt->n, (t));
561
#include "tbl/backend_poll.h"
562
}
563
564
/*--------------------------------------------------------------------
565
 * Build request from probe spec
566
 */
567
568
static void
569 21
vbp_build_req(struct vbp_target *vt, const struct vrt_backend_probe *vbp,
570
    const struct backend *be)
571
{
572
        struct vsb *vsb;
573
574 21
        vsb = VSB_new_auto();
575 21
        AN(vsb);
576 21
        VSB_clear(vsb);
577 21
        if (vbp->request != NULL) {
578 0
                VSB_cat(vsb, vbp->request);
579
        } else {
580 21
                VSB_printf(vsb, "GET %s HTTP/1.1\r\n",
581 21
                    vbp->url != NULL ?  vbp->url : "/");
582 21
                if (be->hosthdr != NULL)
583 21
                        VSB_printf(vsb, "Host: %s\r\n", be->hosthdr);
584 21
                VSB_printf(vsb, "Connection: close\r\n");
585 21
                VSB_printf(vsb, "\r\n");
586
        }
587 21
        AZ(VSB_finish(vsb));
588 21
        vt->req = strdup(VSB_data(vsb));
589 21
        AN(vt->req);
590 21
        vt->req_len = VSB_len(vsb);
591 21
        VSB_destroy(&vsb);
592 21
}
593
594
/*--------------------------------------------------------------------
595
 * Sanitize and set defaults
596
 * XXX: we could make these defaults parameters
597
 */
598
599
static void
600 21
vbp_set_defaults(struct vbp_target *vt, const struct vrt_backend_probe *vp)
601
{
602
603
#define DN(x)   do { vt->x = vp->x; } while (0)
604 21
        VRT_BACKEND_PROBE_HANDLE();
605
#undef DN
606
607 21
        if (vt->timeout == 0.0)
608 16
                vt->timeout = 2.0;
609 21
        if (vt->interval == 0.0)
610 4
                vt->interval = 5.0;
611 21
        if (vt->window == 0)
612 9
                vt->window = 8;
613 21
        if (vt->threshold == 0)
614 9
                vt->threshold = 3;
615 21
        if (vt->exp_status == 0)
616 21
                vt->exp_status = 200;
617
618 21
        if (vt->initial == ~0U)
619 8
                vt->initial = vt->threshold - 1;
620
621 21
        if (vt->initial > vt->threshold)
622 0
                vt->initial = vt->threshold;
623 21
}
624
625
/*--------------------------------------------------------------------
626
 */
627
628
void
629 28
VBP_Control(const struct backend *be, int enable)
630
{
631
        struct vbp_target *vt;
632
633 28
        CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
634 28
        vt = be->probe;
635 28
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
636
637 28
        vbp_reset(vt);
638 28
        VBP_Update_Backend(vt);
639
640 28
        Lck_Lock(&vbp_mtx);
641 28
        if (enable) {
642 22
                assert(vt->heap_idx == BINHEAP_NOIDX);
643 22
                vt->due = VTIM_real();
644 22
                binheap_insert(vbp_heap, vt);
645 22
                AZ(pthread_cond_signal(&vbp_cond));
646
        } else {
647 6
                assert(vt->heap_idx != BINHEAP_NOIDX);
648 6
                binheap_delete(vbp_heap, vt->heap_idx);
649
        }
650 28
        Lck_Unlock(&vbp_mtx);
651 28
}
652
653
/*--------------------------------------------------------------------
654
 * Insert/Remove/Use called from cache_backend.c
655
 */
656
657
void
658 21
VBP_Insert(struct backend *b, const struct vrt_backend_probe *vp,
659
    struct tcp_pool *tp)
660
{
661
        struct vbp_target *vt;
662
663 21
        CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
664 21
        CHECK_OBJ_NOTNULL(vp, VRT_BACKEND_PROBE_MAGIC);
665
666 21
        AZ(b->probe);
667
668 21
        ALLOC_OBJ(vt, VBP_TARGET_MAGIC);
669 21
        XXXAN(vt);
670
671 21
        vt->tcp_pool = tp;
672 21
        VTP_AddRef(vt->tcp_pool);
673 21
        vt->backend = b;
674 21
        b->probe = vt;
675
676 21
        vbp_set_defaults(vt, vp);
677 21
        vbp_build_req(vt, vp, b);
678
679 21
        vbp_reset(vt);
680 21
        VBP_Update_Backend(vt);
681 21
}
682
683
void
684 4
VBP_Remove(struct backend *be)
685
{
686
        struct vbp_target *vt;
687
688 4
        CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
689 4
        vt = be->probe;
690 4
        CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
691
692 4
        Lck_Lock(&vbp_mtx);
693 4
        VRT_SetHealth(be->director, 1);
694 4
        be->probe = NULL;
695 4
        vt->backend = NULL;
696 4
        if (vt->running) {
697 2
                vt->running = -1;
698 2
                vt = NULL;
699
        }
700 4
        Lck_Unlock(&vbp_mtx);
701 4
        if (vt != NULL) {
702 2
                assert(vt->heap_idx == BINHEAP_NOIDX);
703 2
                vbp_delete(vt);
704
        }
705 4
}
706
707
/*-------------------------------------------------------------------*/
708
709
static int v_matchproto_(binheap_cmp_t)
710 55
vbp_cmp(void *priv, const void *a, const void *b)
711
{
712
        const struct vbp_target *aa, *bb;
713
714 55
        AZ(priv);
715 55
        CAST_OBJ_NOTNULL(aa, a, VBP_TARGET_MAGIC);
716 55
        CAST_OBJ_NOTNULL(bb, b, VBP_TARGET_MAGIC);
717
718 55
        if (aa->running && !bb->running)
719 21
                return (0);
720
721 34
        return (aa->due < bb->due);
722
}
723
724
static void v_matchproto_(binheap_update_t)
725 1076
vbp_update(void *priv, void *p, unsigned u)
726
{
727
        struct vbp_target *vt;
728
729 1076
        AZ(priv);
730 1076
        CAST_OBJ_NOTNULL(vt, p, VBP_TARGET_MAGIC);
731 1076
        vt->heap_idx = u;
732 1076
}
733
734
/*-------------------------------------------------------------------*/
735
736
void
737 685
VBP_Init(void)
738
{
739
        pthread_t thr;
740
741 685
        Lck_New(&vbp_mtx, lck_backend);
742 685
        vbp_heap = binheap_new(NULL, vbp_cmp, vbp_update);
743 685
        AN(vbp_heap);
744 685
        AZ(pthread_cond_init(&vbp_cond, NULL));
745 685
        WRK_BgThread(&thr, "backend-poller", vbp_thread, NULL);
746 685
}