[master] 0d33c1d Rename this file to the name I keep typing

Poul-Henning Kamp phk at FreeBSD.org
Mon Jun 29 14:04:40 CEST 2015


commit 0d33c1da14232df83057d667c9a684bd88c56328
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Mon Jun 29 12:04:25 2015 +0000

    Rename this file to the name I keep typing

diff --git a/bin/varnishd/Makefile.am b/bin/varnishd/Makefile.am
index dc20242..dd2bae2 100644
--- a/bin/varnishd/Makefile.am
+++ b/bin/varnishd/Makefile.am
@@ -12,7 +12,7 @@ varnishd_SOURCES = \
 	cache/cache_acceptor.c \
 	cache/cache_backend.c \
 	cache/cache_backend_cfg.c \
-	cache/cache_backend_poll.c \
+	cache/cache_backend_probe.c \
 	cache/cache_backend_tcp.c \
 	cache/cache_ban.c \
 	cache/cache_busyobj.c \
diff --git a/bin/varnishd/cache/cache_backend_poll.c b/bin/varnishd/cache/cache_backend_poll.c
deleted file mode 100644
index 8060bb7..0000000
--- a/bin/varnishd/cache/cache_backend_poll.c
+++ /dev/null
@@ -1,632 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Poll backends for collection of health statistics
- *
- * We co-opt threads from the worker pool for probing the backends,
- * but we want to avoid a potentially messy cleanup operation when we
- * retire the backend, so the thread owns the health information, which
- * the backend references, rather than the other way around.
- *
- */
-
-#include "config.h"
-
-#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "cache.h"
-
-#include "binary_heap.h"
-#include "vcli_priv.h"
-#include "vrt.h"
-#include "vsa.h"
-#include "vtcp.h"
-#include "vtim.h"
-
-#include "cache_director.h"
-#include "cache_backend.h"
-
-/* Default averaging rate, we want something pretty responsive */
-#define AVG_RATE			4
-
-struct vbp_target {
-	unsigned			magic;
-#define VBP_TARGET_MAGIC		0x6b7cb656
-
-	VRT_BACKEND_PROBE_FIELDS()
-
-	struct backend			*backend;
-	struct tcp_pool			*tcp_pool;
-
-	char				*req;
-	int				req_len;
-
-	char				resp_buf[128];
-	unsigned			good;
-
-	/* Collected statistics */
-#define BITMAP(n, c, t, b)	uint64_t	n;
-#include "tbl/backend_poll.h"
-#undef BITMAP
-
-	double				last;
-	double				avg;
-	double				rate;
-
-	double				due;
-	int				running;
-	int				heap_idx;
-	struct pool_task		task;
-};
-
-static struct lock			vbp_mtx;
-static pthread_cond_t			vbp_cond;
-static struct binheap			*vbp_heap;
-
-/*--------------------------------------------------------------------*/
-
-static void
-vbp_delete(struct vbp_target *vt)
-{
-#define DN(x)	/**/
-	VRT_BACKEND_PROBE_HANDLE();
-#undef DN
-	VBT_Rel(&vt->tcp_pool);
-	free(vt->req);
-	FREE_OBJ(vt);
-}
-
-
-/*--------------------------------------------------------------------
- * Record pokings...
- */
-
-static void
-vbp_start_poke(struct vbp_target *vt)
-{
-	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
-
-#define BITMAP(n, c, t, b) \
-	vt->n <<= 1;
-#include "tbl/backend_poll.h"
-#undef BITMAP
-
-	vt->last = 0;
-	vt->resp_buf[0] = '\0';
-}
-
-static void
-vbp_has_poked(struct vbp_target *vt)
-{
-	unsigned i, j;
-	uint64_t u;
-
-	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
-
-	/* Calculate exponential average */
-	if (vt->happy & 1) {
-		if (vt->rate < AVG_RATE)
-			vt->rate += 1.0;
-		vt->avg += (vt->last - vt->avg) / vt->rate;
-	}
-
-	u = vt->happy;
-	for (i = j = 0; i < vt->window; i++) {
-		if (u & 1)
-			j++;
-		u >>= 1;
-	}
-	vt->good = j;
-}
-
-static void
-vbp_update_backend(struct vbp_target *vt)
-{
-	unsigned i;
-	char bits[10];
-	const char *logmsg;
-
-	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
-
-	Lck_Lock(&vbp_mtx);
-	if (vt->backend != NULL) {
-		i = 0;
-#define BITMAP(n, c, t, b) \
-		bits[i++] = (vt->n & 1) ? c : '-';
-#include "tbl/backend_poll.h"
-#undef BITMAP
-		bits[i] = '\0';
-
-		if (vt->good >= vt->threshold) {
-			if (vt->backend->healthy)
-				logmsg = "Still healthy";
-			else {
-				logmsg = "Back healthy";
-				vt->backend->health_changed = VTIM_real();
-			}
-			vt->backend->healthy = 1;
-		} else {
-			if (vt->backend->healthy) {
-				logmsg = "Went sick";
-				vt->backend->health_changed = VTIM_real();
-			} else
-				logmsg = "Still sick";
-			vt->backend->healthy = 0;
-		}
-		VSL(SLT_Backend_health, 0, "%s %s %s %u %u %u %.6f %.6f %s",
-		    vt->backend->display_name, logmsg, bits,
-		    vt->good, vt->threshold, vt->window,
-		    vt->last, vt->avg, vt->resp_buf);
-		if (vt->backend != NULL && vt->backend->vsc != NULL)
-			vt->backend->vsc->happy = vt->happy;
-	}
-	Lck_Unlock(&vbp_mtx);
-}
-
-static void
-vbp_reset(struct vbp_target *vt)
-{
-	unsigned u;
-
-	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
-	vt->avg = 0.0;
-	vt->rate = 0.0;
-#define BITMAP(n, c, t, b) \
-	vt->n = 0;
-#include "tbl/backend_poll.h"
-#undef BITMAP
-
-	for (u = 0; u < vt->initial; u++) {
-		vbp_start_poke(vt);
-		vt->happy |= 1;
-		vbp_has_poked(vt);
-	}
-}
-
-/*--------------------------------------------------------------------
- * Poke one backend, once, but possibly at both IPv4 and IPv6 addresses.
- *
- * We do deliberately not use the stuff in cache_backend.c, because we
- * want to measure the backends response without local distractions.
- */
-
-static void
-vbp_poke(struct vbp_target *vt)
-{
-	int s, tmo, i;
-	double t_start, t_now, t_end;
-	unsigned rlen, resp;
-	char buf[8192], *p;
-	struct pollfd pfda[1], *pfd = pfda;
-	const struct suckaddr *sa;
-
-	t_start = t_now = VTIM_real();
-	t_end = t_start + vt->timeout;
-
-	s = VBT_Open(vt->tcp_pool, t_end - t_now, &sa);
-	if (s < 0) {
-		/* Got no connection: failed */
-		return;
-	}
-
-	i = VSA_Get_Proto(sa);
-	if (i == AF_INET)
-		vt->good_ipv4 |= 1;
-	else if(i == AF_INET6)
-		vt->good_ipv6 |= 1;
-	else
-		WRONG("Wrong probe protocol family");
-
-	t_now = VTIM_real();
-	tmo = (int)round((t_end - t_now) * 1e3);
-	if (tmo <= 0) {
-		/* Spent too long time getting it */
-		VTCP_close(&s);
-		return;
-	}
-
-	/* Send the request */
-	i = write(s, vt->req, vt->req_len);
-	if (i != vt->req_len) {
-		if (i < 0)
-			vt->err_xmit |= 1;
-		VTCP_close(&s);
-		return;
-	}
-	vt->good_xmit |= 1;
-
-	pfd->fd = s;
-	rlen = 0;
-	do {
-		pfd->events = POLLIN;
-		pfd->revents = 0;
-		tmo = (int)round((t_end - t_now) * 1e3);
-		if (tmo > 0)
-			i = poll(pfd, 1, tmo);
-		if (i == 0 || tmo <= 0) {
-			VTCP_close(&s);
-			return;
-		}
-		if (rlen < sizeof vt->resp_buf)
-			i = read(s, vt->resp_buf + rlen,
-			    sizeof vt->resp_buf - rlen);
-		else
-			i = read(s, buf, sizeof buf);
-		rlen += i;
-	} while (i > 0);
-
-	VTCP_close(&s);
-
-	if (i < 0) {
-		vt->err_recv |= 1;
-		return;
-	}
-
-	if (rlen == 0)
-		return;
-
-	/* So we have a good receive ... */
-	t_now = VTIM_real();
-	vt->last = t_now - t_start;
-	vt->good_recv |= 1;
-
-	/* Now find out if we like the response */
-	vt->resp_buf[sizeof vt->resp_buf - 1] = '\0';
-	p = strchr(vt->resp_buf, '\r');
-	if (p != NULL)
-		*p = '\0';
-	p = strchr(vt->resp_buf, '\n');
-	if (p != NULL)
-		*p = '\0';
-
-	i = sscanf(vt->resp_buf, "HTTP/%*f %u %s", &resp, buf);
-
-	if ((i == 1 || i == 2) && resp == vt->exp_status)
-		vt->happy |= 1;
-}
-
-/*--------------------------------------------------------------------
- */
-
-static void __match_proto__(task_func_t)
-vbp_task(struct worker *wrk, void *priv)
-{
-	struct vbp_target *vt;
-
-	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
-	CAST_OBJ_NOTNULL(vt, priv, VBP_TARGET_MAGIC);
-
-	AN(vt->running);
-	AN(vt->req);
-	assert(vt->req_len > 0);
-
-	vbp_start_poke(vt);
-	vbp_poke(vt);
-	vbp_has_poked(vt);
-	vbp_update_backend(vt);
-
-	Lck_Lock(&vbp_mtx);
-	if (vt->running < 0) {
-		assert(vt->heap_idx == BINHEAP_NOIDX);
-		vbp_delete(vt);
-	} else {
-		vt->running = 0;
-		if (vt->heap_idx != BINHEAP_NOIDX) {
-			vt->due = VTIM_real() + vt->interval;
-			binheap_delete(vbp_heap, vt->heap_idx);
-			binheap_insert(vbp_heap, vt);
-		}
-	}
-	Lck_Unlock(&vbp_mtx);
-}
-
-/*--------------------------------------------------------------------
- */
-
-static void * __match_proto__()
-vbp_thread(struct worker *wrk, void *priv)
-{
-	double now, nxt;
-	struct vbp_target *vt;
-
-	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
-	AZ(priv);
-	Lck_Lock(&vbp_mtx);
-	while (1) {
-		now = VTIM_real();
-		vt = binheap_root(vbp_heap);
-		if (vt == NULL) {
-			nxt = 8.192 + now;
-			(void)Lck_CondWait(&vbp_cond, &vbp_mtx, nxt);
-		} else if (vt->due > now) {
-			nxt = vt->due;
-			vt = NULL;
-			(void)Lck_CondWait(&vbp_cond, &vbp_mtx, nxt);
-		} else {
-			binheap_delete(vbp_heap, vt->heap_idx);
-			vt->due = now + vt->interval;
-			if (!vt->running) {
-				vt->running = 1;
-				vt->task.func = vbp_task;
-				vt->task.priv = vt;
-				if (Pool_Task_Any(&vt->task, TASK_QUEUE_REQ))
-					vt->running = 0;
-			}
-			binheap_insert(vbp_heap, vt);
-		}
-	}
-	Lck_Unlock(&vbp_mtx);
-	NEEDLESS_RETURN(NULL);
-}
-
-
-/*--------------------------------------------------------------------
- * Cli functions
- */
-
-static void
-vbp_bitmap(struct cli *cli, char c, uint64_t map, const char *lbl)
-{
-	int i;
-	uint64_t u = (1ULL << 63);
-
-	VCLI_Out(cli, "  ");
-	for (i = 0; i < 64; i++) {
-		if (map & u)
-			VCLI_Out(cli, "%c", c);
-		else
-			VCLI_Out(cli, "-");
-		map <<= 1;
-	}
-	VCLI_Out(cli, " %s\n", lbl);
-}
-
-/*lint -e{506} constant value boolean */
-/*lint -e{774} constant value boolean */
-static void
-vbp_health_one(struct cli *cli, const struct vbp_target *vt)
-{
-
-	VCLI_Out(cli,
-	    "  Current states  good: %2u threshold: %2u window: %2u\n",
-	    vt->good, vt->threshold, vt->window);
-	VCLI_Out(cli,
-	    "  Average response time of good probes: %.6f\n", vt->avg);
-	VCLI_Out(cli,
-	    "  Oldest ======================"
-	    "============================ Newest\n");
-
-#define BITMAP(n, c, t, b)					\
-		if ((vt->n != 0) || (b))			\
-			vbp_bitmap(cli, (c), vt->n, (t));
-#include "tbl/backend_poll.h"
-#undef BITMAP
-}
-
-void
-VBP_Status(struct cli *cli, const struct backend *be, int details)
-{
-	struct vbp_target *vt;
-
-	CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
-	vt = be->probe;
-	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
-	VCLI_Out(cli, "%d/%d", vt->good, vt->window);
-	if (details) {
-		VCLI_Out(cli, "\n");
-		vbp_health_one(cli, vt);
-	}
-}
-
-/*--------------------------------------------------------------------
- * Build request from probe spec
- */
-
-static void
-vbp_build_req(struct vbp_target *vt, const struct vrt_backend_probe *vbp,
-    const struct backend *be)
-{
-	struct vsb *vsb;
-
-	vsb = VSB_new_auto();
-	AN(vsb);
-	VSB_clear(vsb);
-	if(vbp->request != NULL) {
-		VSB_cat(vsb, vbp->request);
-	} else {
-		VSB_printf(vsb, "GET %s HTTP/1.1\r\n",
-		    vbp->url != NULL ?  vbp->url : "/");
-		if (be->hosthdr != NULL)
-			VSB_printf(vsb, "Host: %s\r\n", be->hosthdr);
-		VSB_printf(vsb, "Connection: close\r\n");
-		VSB_printf(vsb, "\r\n");
-	}
-	AZ(VSB_finish(vsb));
-	vt->req = strdup(VSB_data(vsb));
-	AN(vt->req);
-	vt->req_len = VSB_len(vsb);
-	VSB_delete(vsb);
-}
-
-/*--------------------------------------------------------------------
- * Sanitize and set defaults
- * XXX: we could make these defaults parameters
- */
-
-static void
-vbp_set_defaults(struct vbp_target *vt, const struct vrt_backend_probe *vp)
-{
-
-#define DN(x)	do { vt->x = vp->x; } while (0)
-	VRT_BACKEND_PROBE_HANDLE();
-#undef DN
-
-	if (vt->timeout == 0.0)
-		vt->timeout = 2.0;
-	if (vt->interval == 0.0)
-		vt->interval = 5.0;
-	if (vt->window == 0)
-		vt->window = 8;
-	if (vt->threshold == 0)
-		vt->threshold = 3;
-	if (vt->exp_status == 0)
-		vt->exp_status = 200;
-
-	if (vt->initial == ~0U)
-		vt->initial = vt->threshold - 1;
-
-	if (vt->initial > vt->threshold)
-		vt->initial = vt->threshold;
-}
-
-/*--------------------------------------------------------------------
- */
-
-void
-VBP_Control(const struct backend *be, int enable)
-{
-	struct vbp_target *vt;
-
-	ASSERT_CLI();
-	CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
-	vt = be->probe;
-	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
-
-	vbp_reset(vt);
-	vbp_update_backend(vt);
-
-	Lck_Lock(&vbp_mtx);
-	if (enable) {
-		assert(vt->heap_idx == BINHEAP_NOIDX);
-		vt->due = VTIM_real();
-		binheap_insert(vbp_heap, vt);
-		AZ(pthread_cond_signal(&vbp_cond));
-	} else {
-		assert(vt->heap_idx != BINHEAP_NOIDX);
-		binheap_delete(vbp_heap, vt->heap_idx);
-	}
-	Lck_Unlock(&vbp_mtx);
-}
-
-/*--------------------------------------------------------------------
- * Insert/Remove/Use called from cache_backend.c
- */
-
-void
-VBP_Insert(struct backend *b, const struct vrt_backend_probe *vp,
-    struct tcp_pool *tp)
-{
-	struct vbp_target *vt;
-
-	ASSERT_CLI();
-	CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
-	CHECK_OBJ_NOTNULL(vp, VRT_BACKEND_PROBE_MAGIC);
-
-	AZ(b->probe);
-
-	ALLOC_OBJ(vt, VBP_TARGET_MAGIC);
-	XXXAN(vt);
-
-	vt->tcp_pool = tp;
-	vt->backend = b;
-	b->probe = vt;
-
-	vbp_set_defaults(vt, vp);
-	vbp_build_req(vt, vp, b);
-
-	vbp_reset(vt);
-	vbp_update_backend(vt);
-}
-
-void
-VBP_Remove(struct backend *be)
-{
-	struct vbp_target *vt;
-
-	ASSERT_CLI();
-	CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
-	vt = be->probe;
-	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
-
-	Lck_Lock(&vbp_mtx);
-	be->healthy = 1;
-	be->probe = NULL;
-	vt->backend = NULL;
-	if (vt->running) {
-		vt->running = -1;
-		vt = NULL;
-	}
-	Lck_Unlock(&vbp_mtx);
-	if (vt != NULL) {
-		assert(vt->heap_idx == BINHEAP_NOIDX);
-		vbp_delete(vt);
-	}
-}
-
-/*-------------------------------------------------------------------*/
-
-static int __match_proto__(binheap_cmp_t)
-vbp_cmp(void *priv, const void *a, const void *b)
-{
-	const struct vbp_target *aa, *bb;
-
-	AZ(priv);
-	CAST_OBJ_NOTNULL(aa, a, VBP_TARGET_MAGIC);
-	CAST_OBJ_NOTNULL(bb, b, VBP_TARGET_MAGIC);
-
-	if (aa->running && !bb->running)
-		return (0);
-
-	return (aa->due < bb->due);
-}
-
-static void __match_proto__(binheap_update_t)
-vbp_update(void *priv, void *p, unsigned u)
-{
-	struct vbp_target *vt;
-
-	AZ(priv);
-	CAST_OBJ_NOTNULL(vt, p, VBP_TARGET_MAGIC);
-	vt->heap_idx = u;
-}
-
-/*-------------------------------------------------------------------*/
-
-void
-VBP_Init(void)
-{
-	pthread_t thr;
-
-	Lck_New(&vbp_mtx, lck_backend);
-	vbp_heap = binheap_new(NULL, vbp_cmp, vbp_update);
-	AN(vbp_heap);
-	AZ(pthread_cond_init(&vbp_cond, NULL));
-	WRK_BgThread(&thr, "Backend poller", vbp_thread, NULL);
-}
diff --git a/bin/varnishd/cache/cache_backend_probe.c b/bin/varnishd/cache/cache_backend_probe.c
new file mode 100644
index 0000000..8060bb7
--- /dev/null
+++ b/bin/varnishd/cache/cache_backend_probe.c
@@ -0,0 +1,632 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Poll backends for collection of health statistics
+ *
+ * We co-opt threads from the worker pool for probing the backends,
+ * but we want to avoid a potentially messy cleanup operation when we
+ * retire the backend, so the thread owns the health information, which
+ * the backend references, rather than the other way around.
+ *
+ */
+
+#include "config.h"
+
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cache.h"
+
+#include "binary_heap.h"
+#include "vcli_priv.h"
+#include "vrt.h"
+#include "vsa.h"
+#include "vtcp.h"
+#include "vtim.h"
+
+#include "cache_director.h"
+#include "cache_backend.h"
+
+/* Default averaging rate, we want something pretty responsive */
+#define AVG_RATE			4
+
+struct vbp_target {
+	unsigned			magic;
+#define VBP_TARGET_MAGIC		0x6b7cb656
+
+	VRT_BACKEND_PROBE_FIELDS()
+
+	struct backend			*backend;
+	struct tcp_pool			*tcp_pool;
+
+	char				*req;
+	int				req_len;
+
+	char				resp_buf[128];
+	unsigned			good;
+
+	/* Collected statistics */
+#define BITMAP(n, c, t, b)	uint64_t	n;
+#include "tbl/backend_poll.h"
+#undef BITMAP
+
+	double				last;
+	double				avg;
+	double				rate;
+
+	double				due;
+	int				running;
+	int				heap_idx;
+	struct pool_task		task;
+};
+
+static struct lock			vbp_mtx;
+static pthread_cond_t			vbp_cond;
+static struct binheap			*vbp_heap;
+
+/*--------------------------------------------------------------------*/
+
+static void
+vbp_delete(struct vbp_target *vt)
+{
+#define DN(x)	/**/
+	VRT_BACKEND_PROBE_HANDLE();
+#undef DN
+	VBT_Rel(&vt->tcp_pool);
+	free(vt->req);
+	FREE_OBJ(vt);
+}
+
+
+/*--------------------------------------------------------------------
+ * Record pokings...
+ */
+
+static void
+vbp_start_poke(struct vbp_target *vt)
+{
+	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
+
+#define BITMAP(n, c, t, b) \
+	vt->n <<= 1;
+#include "tbl/backend_poll.h"
+#undef BITMAP
+
+	vt->last = 0;
+	vt->resp_buf[0] = '\0';
+}
+
+static void
+vbp_has_poked(struct vbp_target *vt)
+{
+	unsigned i, j;
+	uint64_t u;
+
+	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
+
+	/* Calculate exponential average */
+	if (vt->happy & 1) {
+		if (vt->rate < AVG_RATE)
+			vt->rate += 1.0;
+		vt->avg += (vt->last - vt->avg) / vt->rate;
+	}
+
+	u = vt->happy;
+	for (i = j = 0; i < vt->window; i++) {
+		if (u & 1)
+			j++;
+		u >>= 1;
+	}
+	vt->good = j;
+}
+
+static void
+vbp_update_backend(struct vbp_target *vt)
+{
+	unsigned i;
+	char bits[10];
+	const char *logmsg;
+
+	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
+
+	Lck_Lock(&vbp_mtx);
+	if (vt->backend != NULL) {
+		i = 0;
+#define BITMAP(n, c, t, b) \
+		bits[i++] = (vt->n & 1) ? c : '-';
+#include "tbl/backend_poll.h"
+#undef BITMAP
+		bits[i] = '\0';
+
+		if (vt->good >= vt->threshold) {
+			if (vt->backend->healthy)
+				logmsg = "Still healthy";
+			else {
+				logmsg = "Back healthy";
+				vt->backend->health_changed = VTIM_real();
+			}
+			vt->backend->healthy = 1;
+		} else {
+			if (vt->backend->healthy) {
+				logmsg = "Went sick";
+				vt->backend->health_changed = VTIM_real();
+			} else
+				logmsg = "Still sick";
+			vt->backend->healthy = 0;
+		}
+		VSL(SLT_Backend_health, 0, "%s %s %s %u %u %u %.6f %.6f %s",
+		    vt->backend->display_name, logmsg, bits,
+		    vt->good, vt->threshold, vt->window,
+		    vt->last, vt->avg, vt->resp_buf);
+		if (vt->backend != NULL && vt->backend->vsc != NULL)
+			vt->backend->vsc->happy = vt->happy;
+	}
+	Lck_Unlock(&vbp_mtx);
+}
+
+static void
+vbp_reset(struct vbp_target *vt)
+{
+	unsigned u;
+
+	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
+	vt->avg = 0.0;
+	vt->rate = 0.0;
+#define BITMAP(n, c, t, b) \
+	vt->n = 0;
+#include "tbl/backend_poll.h"
+#undef BITMAP
+
+	for (u = 0; u < vt->initial; u++) {
+		vbp_start_poke(vt);
+		vt->happy |= 1;
+		vbp_has_poked(vt);
+	}
+}
+
+/*--------------------------------------------------------------------
+ * Poke one backend, once, but possibly at both IPv4 and IPv6 addresses.
+ *
+ * We do deliberately not use the stuff in cache_backend.c, because we
+ * want to measure the backends response without local distractions.
+ */
+
+static void
+vbp_poke(struct vbp_target *vt)
+{
+	int s, tmo, i;
+	double t_start, t_now, t_end;
+	unsigned rlen, resp;
+	char buf[8192], *p;
+	struct pollfd pfda[1], *pfd = pfda;
+	const struct suckaddr *sa;
+
+	t_start = t_now = VTIM_real();
+	t_end = t_start + vt->timeout;
+
+	s = VBT_Open(vt->tcp_pool, t_end - t_now, &sa);
+	if (s < 0) {
+		/* Got no connection: failed */
+		return;
+	}
+
+	i = VSA_Get_Proto(sa);
+	if (i == AF_INET)
+		vt->good_ipv4 |= 1;
+	else if(i == AF_INET6)
+		vt->good_ipv6 |= 1;
+	else
+		WRONG("Wrong probe protocol family");
+
+	t_now = VTIM_real();
+	tmo = (int)round((t_end - t_now) * 1e3);
+	if (tmo <= 0) {
+		/* Spent too long time getting it */
+		VTCP_close(&s);
+		return;
+	}
+
+	/* Send the request */
+	i = write(s, vt->req, vt->req_len);
+	if (i != vt->req_len) {
+		if (i < 0)
+			vt->err_xmit |= 1;
+		VTCP_close(&s);
+		return;
+	}
+	vt->good_xmit |= 1;
+
+	pfd->fd = s;
+	rlen = 0;
+	do {
+		pfd->events = POLLIN;
+		pfd->revents = 0;
+		tmo = (int)round((t_end - t_now) * 1e3);
+		if (tmo > 0)
+			i = poll(pfd, 1, tmo);
+		if (i == 0 || tmo <= 0) {
+			VTCP_close(&s);
+			return;
+		}
+		if (rlen < sizeof vt->resp_buf)
+			i = read(s, vt->resp_buf + rlen,
+			    sizeof vt->resp_buf - rlen);
+		else
+			i = read(s, buf, sizeof buf);
+		rlen += i;
+	} while (i > 0);
+
+	VTCP_close(&s);
+
+	if (i < 0) {
+		vt->err_recv |= 1;
+		return;
+	}
+
+	if (rlen == 0)
+		return;
+
+	/* So we have a good receive ... */
+	t_now = VTIM_real();
+	vt->last = t_now - t_start;
+	vt->good_recv |= 1;
+
+	/* Now find out if we like the response */
+	vt->resp_buf[sizeof vt->resp_buf - 1] = '\0';
+	p = strchr(vt->resp_buf, '\r');
+	if (p != NULL)
+		*p = '\0';
+	p = strchr(vt->resp_buf, '\n');
+	if (p != NULL)
+		*p = '\0';
+
+	i = sscanf(vt->resp_buf, "HTTP/%*f %u %s", &resp, buf);
+
+	if ((i == 1 || i == 2) && resp == vt->exp_status)
+		vt->happy |= 1;
+}
+
+/*--------------------------------------------------------------------
+ */
+
+static void __match_proto__(task_func_t)
+vbp_task(struct worker *wrk, void *priv)
+{
+	struct vbp_target *vt;
+
+	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
+	CAST_OBJ_NOTNULL(vt, priv, VBP_TARGET_MAGIC);
+
+	AN(vt->running);
+	AN(vt->req);
+	assert(vt->req_len > 0);
+
+	vbp_start_poke(vt);
+	vbp_poke(vt);
+	vbp_has_poked(vt);
+	vbp_update_backend(vt);
+
+	Lck_Lock(&vbp_mtx);
+	if (vt->running < 0) {
+		assert(vt->heap_idx == BINHEAP_NOIDX);
+		vbp_delete(vt);
+	} else {
+		vt->running = 0;
+		if (vt->heap_idx != BINHEAP_NOIDX) {
+			vt->due = VTIM_real() + vt->interval;
+			binheap_delete(vbp_heap, vt->heap_idx);
+			binheap_insert(vbp_heap, vt);
+		}
+	}
+	Lck_Unlock(&vbp_mtx);
+}
+
+/*--------------------------------------------------------------------
+ */
+
+static void * __match_proto__()
+vbp_thread(struct worker *wrk, void *priv)
+{
+	double now, nxt;
+	struct vbp_target *vt;
+
+	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
+	AZ(priv);
+	Lck_Lock(&vbp_mtx);
+	while (1) {
+		now = VTIM_real();
+		vt = binheap_root(vbp_heap);
+		if (vt == NULL) {
+			nxt = 8.192 + now;
+			(void)Lck_CondWait(&vbp_cond, &vbp_mtx, nxt);
+		} else if (vt->due > now) {
+			nxt = vt->due;
+			vt = NULL;
+			(void)Lck_CondWait(&vbp_cond, &vbp_mtx, nxt);
+		} else {
+			binheap_delete(vbp_heap, vt->heap_idx);
+			vt->due = now + vt->interval;
+			if (!vt->running) {
+				vt->running = 1;
+				vt->task.func = vbp_task;
+				vt->task.priv = vt;
+				if (Pool_Task_Any(&vt->task, TASK_QUEUE_REQ))
+					vt->running = 0;
+			}
+			binheap_insert(vbp_heap, vt);
+		}
+	}
+	Lck_Unlock(&vbp_mtx);
+	NEEDLESS_RETURN(NULL);
+}
+
+
+/*--------------------------------------------------------------------
+ * Cli functions
+ */
+
+static void
+vbp_bitmap(struct cli *cli, char c, uint64_t map, const char *lbl)
+{
+	int i;
+	uint64_t u = (1ULL << 63);
+
+	VCLI_Out(cli, "  ");
+	for (i = 0; i < 64; i++) {
+		if (map & u)
+			VCLI_Out(cli, "%c", c);
+		else
+			VCLI_Out(cli, "-");
+		map <<= 1;
+	}
+	VCLI_Out(cli, " %s\n", lbl);
+}
+
+/*lint -e{506} constant value boolean */
+/*lint -e{774} constant value boolean */
+static void
+vbp_health_one(struct cli *cli, const struct vbp_target *vt)
+{
+
+	VCLI_Out(cli,
+	    "  Current states  good: %2u threshold: %2u window: %2u\n",
+	    vt->good, vt->threshold, vt->window);
+	VCLI_Out(cli,
+	    "  Average response time of good probes: %.6f\n", vt->avg);
+	VCLI_Out(cli,
+	    "  Oldest ======================"
+	    "============================ Newest\n");
+
+#define BITMAP(n, c, t, b)					\
+		if ((vt->n != 0) || (b))			\
+			vbp_bitmap(cli, (c), vt->n, (t));
+#include "tbl/backend_poll.h"
+#undef BITMAP
+}
+
+void
+VBP_Status(struct cli *cli, const struct backend *be, int details)
+{
+	struct vbp_target *vt;
+
+	CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
+	vt = be->probe;
+	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
+	VCLI_Out(cli, "%d/%d", vt->good, vt->window);
+	if (details) {
+		VCLI_Out(cli, "\n");
+		vbp_health_one(cli, vt);
+	}
+}
+
+/*--------------------------------------------------------------------
+ * Build request from probe spec
+ */
+
+static void
+vbp_build_req(struct vbp_target *vt, const struct vrt_backend_probe *vbp,
+    const struct backend *be)
+{
+	struct vsb *vsb;
+
+	vsb = VSB_new_auto();
+	AN(vsb);
+	VSB_clear(vsb);
+	if(vbp->request != NULL) {
+		VSB_cat(vsb, vbp->request);
+	} else {
+		VSB_printf(vsb, "GET %s HTTP/1.1\r\n",
+		    vbp->url != NULL ?  vbp->url : "/");
+		if (be->hosthdr != NULL)
+			VSB_printf(vsb, "Host: %s\r\n", be->hosthdr);
+		VSB_printf(vsb, "Connection: close\r\n");
+		VSB_printf(vsb, "\r\n");
+	}
+	AZ(VSB_finish(vsb));
+	vt->req = strdup(VSB_data(vsb));
+	AN(vt->req);
+	vt->req_len = VSB_len(vsb);
+	VSB_delete(vsb);
+}
+
+/*--------------------------------------------------------------------
+ * Sanitize and set defaults
+ * XXX: we could make these defaults parameters
+ */
+
+static void
+vbp_set_defaults(struct vbp_target *vt, const struct vrt_backend_probe *vp)
+{
+
+#define DN(x)	do { vt->x = vp->x; } while (0)
+	VRT_BACKEND_PROBE_HANDLE();
+#undef DN
+
+	if (vt->timeout == 0.0)
+		vt->timeout = 2.0;
+	if (vt->interval == 0.0)
+		vt->interval = 5.0;
+	if (vt->window == 0)
+		vt->window = 8;
+	if (vt->threshold == 0)
+		vt->threshold = 3;
+	if (vt->exp_status == 0)
+		vt->exp_status = 200;
+
+	if (vt->initial == ~0U)
+		vt->initial = vt->threshold - 1;
+
+	if (vt->initial > vt->threshold)
+		vt->initial = vt->threshold;
+}
+
+/*--------------------------------------------------------------------
+ */
+
+void
+VBP_Control(const struct backend *be, int enable)
+{
+	struct vbp_target *vt;
+
+	ASSERT_CLI();
+	CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
+	vt = be->probe;
+	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
+
+	vbp_reset(vt);
+	vbp_update_backend(vt);
+
+	Lck_Lock(&vbp_mtx);
+	if (enable) {
+		assert(vt->heap_idx == BINHEAP_NOIDX);
+		vt->due = VTIM_real();
+		binheap_insert(vbp_heap, vt);
+		AZ(pthread_cond_signal(&vbp_cond));
+	} else {
+		assert(vt->heap_idx != BINHEAP_NOIDX);
+		binheap_delete(vbp_heap, vt->heap_idx);
+	}
+	Lck_Unlock(&vbp_mtx);
+}
+
+/*--------------------------------------------------------------------
+ * Insert/Remove/Use called from cache_backend.c
+ */
+
+void
+VBP_Insert(struct backend *b, const struct vrt_backend_probe *vp,
+    struct tcp_pool *tp)
+{
+	struct vbp_target *vt;
+
+	ASSERT_CLI();
+	CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
+	CHECK_OBJ_NOTNULL(vp, VRT_BACKEND_PROBE_MAGIC);
+
+	AZ(b->probe);
+
+	ALLOC_OBJ(vt, VBP_TARGET_MAGIC);
+	XXXAN(vt);
+
+	vt->tcp_pool = tp;
+	vt->backend = b;
+	b->probe = vt;
+
+	vbp_set_defaults(vt, vp);
+	vbp_build_req(vt, vp, b);
+
+	vbp_reset(vt);
+	vbp_update_backend(vt);
+}
+
+void
+VBP_Remove(struct backend *be)
+{
+	struct vbp_target *vt;
+
+	ASSERT_CLI();
+	CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
+	vt = be->probe;
+	CHECK_OBJ_NOTNULL(vt, VBP_TARGET_MAGIC);
+
+	Lck_Lock(&vbp_mtx);
+	be->healthy = 1;
+	be->probe = NULL;
+	vt->backend = NULL;
+	if (vt->running) {
+		vt->running = -1;
+		vt = NULL;
+	}
+	Lck_Unlock(&vbp_mtx);
+	if (vt != NULL) {
+		assert(vt->heap_idx == BINHEAP_NOIDX);
+		vbp_delete(vt);
+	}
+}
+
+/*-------------------------------------------------------------------*/
+
+static int __match_proto__(binheap_cmp_t)
+vbp_cmp(void *priv, const void *a, const void *b)
+{
+	const struct vbp_target *aa, *bb;
+
+	AZ(priv);
+	CAST_OBJ_NOTNULL(aa, a, VBP_TARGET_MAGIC);
+	CAST_OBJ_NOTNULL(bb, b, VBP_TARGET_MAGIC);
+
+	if (aa->running && !bb->running)
+		return (0);
+
+	return (aa->due < bb->due);
+}
+
+static void __match_proto__(binheap_update_t)
+vbp_update(void *priv, void *p, unsigned u)
+{
+	struct vbp_target *vt;
+
+	AZ(priv);
+	CAST_OBJ_NOTNULL(vt, p, VBP_TARGET_MAGIC);
+	vt->heap_idx = u;
+}
+
+/*-------------------------------------------------------------------*/
+
+void
+VBP_Init(void)
+{
+	pthread_t thr;
+
+	Lck_New(&vbp_mtx, lck_backend);
+	vbp_heap = binheap_new(NULL, vbp_cmp, vbp_update);
+	AN(vbp_heap);
+	AZ(pthread_cond_init(&vbp_cond, NULL));
+	WRK_BgThread(&thr, "Backend poller", vbp_thread, NULL);
+}



More information about the varnish-commit mailing list