r3084 - trunk/varnish-cache/bin/varnishd

phk at projects.linpro.no phk at projects.linpro.no
Tue Aug 12 14:57:00 CEST 2008


Author: phk
Date: 2008-08-12 14:57:00 +0200 (Tue, 12 Aug 2008)
New Revision: 3084

Modified:
   trunk/varnish-cache/bin/varnishd/cache.h
   trunk/varnish-cache/bin/varnishd/cache_backend_poll.c
   trunk/varnish-cache/bin/varnishd/cache_main.c
Log:
Snapshot the backend polling code without the advanced math.

Presently we only record th state of the last 64 tries to poll the
backend in a shift register, which can be show with the interrim
CLI command "debug.health":

Health stats for backend b0
Oldest __________________________________________________ Newest
4444444444444444444444444444444444444444444444444444444444444444 Good IPv4
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Good Xmit
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS Good Shut
RR-RR-R-RRRR---RR-RR-R-R-R-R-R-RRRR-RR-----RR--RRRR--RRR-R-----R Good Recv

More to follow.


Modified: trunk/varnish-cache/bin/varnishd/cache.h
===================================================================
--- trunk/varnish-cache/bin/varnishd/cache.h	2008-08-12 12:28:38 UTC (rev 3083)
+++ trunk/varnish-cache/bin/varnishd/cache.h	2008-08-12 12:57:00 UTC (rev 3084)
@@ -427,6 +427,9 @@
 void VBE_SelectBackend(struct sess *sp);
 struct backend *VBE_AddBackend(struct cli *cli, const struct vrt_backend *vb);
 
+/* cache_backend_poll.c */
+void VBP_Init(void);
+
 /* cache_ban.c */
 int BAN_Add(struct cli *cli, const char *regexp, int hash);
 void BAN_Init(void);

Modified: trunk/varnish-cache/bin/varnishd/cache_backend_poll.c
===================================================================
--- trunk/varnish-cache/bin/varnishd/cache_backend_poll.c	2008-08-12 12:28:38 UTC (rev 3083)
+++ trunk/varnish-cache/bin/varnishd/cache_backend_poll.c	2008-08-12 12:57:00 UTC (rev 3084)
@@ -40,6 +40,7 @@
 #include "config.h"
 
 #include <stdio.h>
+#include <math.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -48,37 +49,276 @@
 #include <sys/socket.h>
 
 #include "shmlog.h"
+#include "cli_priv.h"
 #include "cache.h"
 #include "vrt.h"
 #include "cache_backend.h"
 
+static MTX	vbp_mtx;
+
 struct vbp_target {
 	unsigned			magic;
 #define VBP_TARGET_MAGIC		0x6b7cb656
 
 	struct backend			*backend;
+	struct vrt_backend_probe 	probe;
 	struct workreq			wrq;
 	int				stop;
+	int				req_len;
+	
+	/* Collected statistics */
+#define BITMAP(n, c, t, b)	uint64_t	n;
+#include "cache_backend_poll.h"
+#undef BITMAP
+
+	VTAILQ_ENTRY(vbp_target)	list;
 };
 
+static VTAILQ_HEAD(, vbp_target)	vbp_list =
+    VTAILQ_HEAD_INITIALIZER(vbp_list);
+
+static char default_request[] = 
+    "GET / HTTP/1.1\r\n"
+    "Connection: close\r\n"
+    "\r\n";
+
 static void
+dsleep(double t)
+{
+	if (t > 10.0)
+		(void)sleep((int)round(t));
+	else
+		(void)usleep((int)round(t * 1e6));
+}
+
+/*--------------------------------------------------------------------
+ * 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 int
+vbp_connect(int pf, const struct sockaddr *sa, socklen_t salen, int tmo)
+{
+	int s, i;
+
+	s = socket(pf, SOCK_STREAM, 0);
+	if (s < 0)
+		return (s);
+
+	i = TCP_connect(s, sa, salen, tmo);
+	if (i == 0)
+		return (s);
+	TCP_close(&s);
+	return (-1);
+}
+
+static int
+vbp_poke(struct vbp_target *vt)
+{
+	int s, tmo, i;
+	double t_start, t_now, t_end, rlen;
+	struct backend *bp;
+	char buf[8192];
+	struct pollfd pfda[1], *pfd = pfda;
+
+	bp = vt->backend;
+	CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC);
+
+	t_start = t_now = TIM_real();
+	t_end = t_start + vt->probe.timeout;
+	tmo = (int)round((t_end - t_now) * 1e3);
+
+	s = -1;
+	if (params->prefer_ipv6 && bp->ipv6 != NULL) {
+		s = vbp_connect(PF_INET6, bp->ipv6, bp->ipv6len, tmo);
+		t_now = TIM_real();
+		tmo = (int)round((t_end - t_now) * 1e3);
+		if (s >= 0)
+			vt->good_ipv6 |= 1;
+	}
+	if (tmo > 0 && s < 0 && bp->ipv4 != NULL) {
+		s = vbp_connect(PF_INET, bp->ipv4, bp->ipv4len, tmo);
+		t_now = TIM_real();
+		tmo = (int)round((t_end - t_now) * 1e3);
+		if (s >= 0)
+			vt->good_ipv4 |= 1;
+	}
+	if (tmo > 0 && s < 0 && bp->ipv6 != NULL) {
+		s = vbp_connect(PF_INET6, bp->ipv6, bp->ipv6len, tmo);
+		t_now = TIM_real();
+		tmo = (int)round((t_end - t_now) * 1e3);
+		if (s >= 0)
+			vt->good_ipv6 |= 1;
+	}
+	if (s < 0) {
+		/* Got no connection: failed */
+		return (0);
+	}
+
+	i = write(s, vt->probe.request, vt->req_len);
+	if (i != vt->req_len) {
+		if (i < 0)
+			vt->err_xmit |= 1;
+		TCP_close(&s);
+		return (0);
+	}
+	vt->good_xmit |= 1;
+	i = shutdown(s, SHUT_WR);
+	if (i != 0) {
+		vt->err_shut |= 1;
+		TCP_close(&s);
+		return (0);
+	}
+	vt->good_shut |= 1;
+
+	t_now = TIM_real();
+	tmo = (int)round((t_end - t_now) * 1e3);
+	if (tmo < 0) {
+		TCP_close(&s);
+		return (0);
+	}
+
+	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) {
+			TCP_close(&s);
+			return (0);
+		}
+		i = read(s, buf, sizeof buf);
+		rlen += i;
+	} while (i > 0);
+
+	if (i < 0) {
+		vt->err_recv |= 1;
+		TCP_close(&s);
+		return (0);
+	}
+
+	TCP_close(&s);
+	t_now = TIM_real();
+	vt->good_recv |= 1;
+	return (1);
+}
+
+/*--------------------------------------------------------------------
+ * One thread per backend to be poked.
+ */
+
+static void
 vbp_wrk_poll_backend(struct worker *w, void *priv)
 {
 	struct vbp_target *vt;
 
 	(void)w;
-	CAST_OBJ_NOTNULL(vt, priv, VBP_TARGET_MAGIC);
 	THR_SetName("backend poll");
 
+	CAST_OBJ_NOTNULL(vt, priv, VBP_TARGET_MAGIC);
+
+	LOCK(&vbp_mtx);
+	VTAILQ_INSERT_TAIL(&vbp_list, vt, list);
+	UNLOCK(&vbp_mtx);
+
+	/* Establish defaults (XXX: Should they go in VCC instead ?) */
+	if (vt->probe.request == NULL)
+		vt->probe.request = default_request;
+	if (vt->probe.timeout == 0.0)
+		vt->probe.timeout = 2.0;
+	if (vt->probe.interval == 0.0)
+		vt->probe.timeout = 5.0;
+
+	printf("Probe(\"%s\", %g, %g)\n",
+	    vt->probe.request,
+	    vt->probe.timeout,
+	    vt->probe.interval);
+
+	vt->req_len = strlen(vt->probe.request);
+
+	/*lint -e{525} indent */
 	while (!vt->stop) {
-		printf("Poke backend %s\n", vt->backend->vcl_name);
-		sleep(1);
+#define BITMAP(n, c, t, b)	vt->n <<= 1;
+#include "cache_backend_poll.h"
+#undef BITMAP
+		vbp_poke(vt);
+		dsleep(vt->probe.interval);
 	}
+	LOCK(&vbp_mtx);
+	VTAILQ_REMOVE(&vbp_list, vt, list);
+	UNLOCK(&vbp_mtx);
 	vt->backend->probe = NULL;
 	FREE_OBJ(vt);
 	THR_SetName("cache-worker");
 }
 
+/*--------------------------------------------------------------------
+ * Cli functions
+ */
+
+static void
+vbp_bitmap(struct cli *cli, const char *s, uint64_t map, const char *lbl)
+{
+	int i;
+	uint64_t u = (1ULL << 63);
+
+	for (i = 0; i < 64; i++) {
+		if (map & u)
+			cli_out(cli, s);
+		else
+			cli_out(cli, "-");
+		map <<= 1;
+	}
+	cli_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, struct vbp_target *vt)
+{
+
+	cli_out(cli, "Health stats for backend %s\n",
+	    vt->backend->vcl_name);
+	cli_out(cli, 
+	    "Oldest ______________________"
+	    "____________________________ Newest\n");
+
+#define BITMAP(n, c, t, b)					\
+		if ((vt->n != 0) || (b)) 				\
+			vbp_bitmap(cli, (c), vt->n, (t));
+#include "cache_backend_poll.h"
+#undef BITMAP
+}
+
+static void
+vbp_health(struct cli *cli, const char * const *av, void *priv)
+{
+	struct vbp_target *vt;
+
+	(void)av;
+	(void)priv;
+
+	VTAILQ_FOREACH(vt, &vbp_list, list)
+		vbp_health_one(cli, vt);
+}
+
+static struct cli_proto debug_cmds[] = {
+        { "debug.health", "debug.health",
+                "\tDump backend health stuff\n",
+                0, 0, vbp_health },
+        { NULL }
+};
+
+/*--------------------------------------------------------------------
+ * Start/Stop called from cache_backend_cfg.c
+ */
+
 void
 VBP_Start(struct backend *b, struct vrt_backend_probe const *p)
 {
@@ -86,13 +326,14 @@
 
 	ASSERT_CLI();
 
-	/* Is probing even configured ? */
-	if (p->request == NULL)
-		return;
-
 	ALLOC_OBJ(vt, VBP_TARGET_MAGIC);
 	AN(vt);
+	if (!memcmp(&vt->probe, p, sizeof *p)) {
+		FREE_OBJ(vt);
+		return;
+	}
 	vt->backend = b;
+	vt->probe = *p;
 	b->probe = vt;
 
 	vt->wrq.func = vbp_wrk_poll_backend;
@@ -111,3 +352,16 @@
 		return;
 	b->probe->stop = 1;
 }
+
+/*--------------------------------------------------------------------
+ * Initialize the backend probe subsystem
+ */
+
+void
+VBP_Init(void)
+{
+
+	MTX_INIT(&vbp_mtx);
+
+	CLI_AddFuncs(DEBUG_CLI, debug_cmds);
+}

Modified: trunk/varnish-cache/bin/varnishd/cache_main.c
===================================================================
--- trunk/varnish-cache/bin/varnishd/cache_main.c	2008-08-12 12:28:38 UTC (rev 3083)
+++ trunk/varnish-cache/bin/varnishd/cache_main.c	2008-08-12 12:57:00 UTC (rev 3084)
@@ -112,6 +112,7 @@
 	SES_Init();
 
 	VBE_Init();
+	VBP_Init();
 	VSL_Init();
 	WRK_Init();
 




More information about the varnish-commit mailing list