]> err.no Git - varnish/commitdiff
Snapshot the backend polling code without the advanced math.
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Tue, 12 Aug 2008 12:57:00 +0000 (12:57 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Tue, 12 Aug 2008 12:57:00 +0000 (12:57 +0000)
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.

git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@3084 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/bin/varnishd/cache.h
varnish-cache/bin/varnishd/cache_backend_poll.c
varnish-cache/bin/varnishd/cache_main.c

index b4af870b687ad01759146d8cb5b847a806536d04..279d5a3ff1aa00ee9ea39b99c00ed4234a15bfe7 100644 (file)
@@ -427,6 +427,9 @@ void VBE_DropRef(struct backend *);
 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);
index e5d72ae41779ee251e35a833b8497cf47920f784..9125c12d28418dbfcdfd99d65b9a5fc5a0945342 100644 (file)
@@ -40,6 +40,7 @@
 #include "config.h"
 
 #include <stdio.h>
+#include <math.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #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 @@ VBP_Start(struct backend *b, struct vrt_backend_probe const *p)
 
        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 @@ VBP_Stop(struct backend *b)
                return;
        b->probe->stop = 1;
 }
+
+/*--------------------------------------------------------------------
+ * Initialize the backend probe subsystem
+ */
+
+void
+VBP_Init(void)
+{
+
+       MTX_INIT(&vbp_mtx);
+
+       CLI_AddFuncs(DEBUG_CLI, debug_cmds);
+}
index 6e9ea68df406a5e6b9b662cb988ebc6345cf84b5..53fef7c9d8042ede16ee4809dfd98fdfb65f656f 100644 (file)
@@ -112,6 +112,7 @@ child_main(void)
        SES_Init();
 
        VBE_Init();
+       VBP_Init();
        VSL_Init();
        WRK_Init();