[master] 12e571b Add a hash director to vmod.directors.

Poul-Henning Kamp phk at varnish-cache.org
Thu Mar 14 11:06:42 CET 2013


commit 12e571b3eba5d1b2d55a00fa237a3c946c0526fa
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Thu Mar 14 10:06:29 2013 +0000

    Add a hash director to vmod.directors.

diff --git a/bin/varnishtest/tests/v00026.vtc b/bin/varnishtest/tests/v00026.vtc
index e7f4fa4..d859658 100644
--- a/bin/varnishtest/tests/v00026.vtc
+++ b/bin/varnishtest/tests/v00026.vtc
@@ -16,13 +16,16 @@ server s2 {
 
 
 varnish v1 -vcl+backend {
-	director h1 hash {
-		{ .backend = s1; .weight = 1; }
-		{ .backend = s2; .weight = 1; }
+	import directors from "${topbuild}/lib/libvmod_directors/.libs/libvmod_directors.so" ;
+
+	sub vcl_init {
+		new h1 = directors.hash();
+		h1.add_backend(s1, 1);
+		h1.add_backend(s2, 1);
 	}
 
 	sub vcl_recv {
-		set req.backend = h1;
+		set req.backend = h1.backend(req.url);
 		return(pass);
 	}
 
@@ -30,11 +33,11 @@ varnish v1 -vcl+backend {
 
 
 client c1 {
-	txreq -url /12
+	txreq -url /1
 	rxresp
 	expect resp.http.foo == "1"
 
-	txreq -url /1
+	txreq -url /3
 	rxresp
 	expect resp.http.foo == "2"
 
@@ -42,7 +45,7 @@ client c1 {
 	rxresp
 	expect resp.http.foo == "3"
 
-	txreq -url /15
+	txreq -url /8
 	rxresp
 	expect resp.http.foo == "4"
 
diff --git a/lib/libvmod_directors/Makefile.am b/lib/libvmod_directors/Makefile.am
index b222026..e49a285 100644
--- a/lib/libvmod_directors/Makefile.am
+++ b/lib/libvmod_directors/Makefile.am
@@ -17,6 +17,7 @@ libvmod_directors_la_SOURCES = \
 	vdir.c \
 	vdir.h \
 	fall_back.c \
+	hash.c \
 	random.c \
 	round_robin.c
 
diff --git a/lib/libvmod_directors/hash.c b/lib/libvmod_directors/hash.c
new file mode 100644
index 0000000..ea011a3
--- /dev/null
+++ b/lib/libvmod_directors/hash.c
@@ -0,0 +1,123 @@
+/*-
+ * Copyright (c) 2013 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at FreeBSD.org>
+ *
+ * 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.
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "cache/cache.h"
+#include "cache/cache_backend.h"
+
+#include "vrt.h"
+#include "vbm.h"
+#include "vend.h"
+#include "vsha256.h"
+
+#include "vdir.h"
+
+#include "vcc_if.h"
+
+struct vmod_directors_hash {
+	unsigned				magic;
+#define VMOD_DIRECTORS_HASH_MAGIC		0xc08dd611
+	struct vdir				*vd;
+	unsigned				nloops;
+	struct vbitmap				*vbm;
+};
+
+VCL_VOID __match_proto__()
+vmod_hash__init(struct req *req, struct vmod_directors_hash **rrp,
+    const char *vcl_name)
+{
+	struct vmod_directors_hash *rr;
+
+	AZ(req);
+	AN(rrp);
+	AZ(*rrp);
+	ALLOC_OBJ(rr, VMOD_DIRECTORS_HASH_MAGIC);
+	AN(rr);
+	rr->vbm = vbit_init(8);
+	AN(rr->vbm);
+	rr->nloops = 3; //
+	*rrp = rr;
+	vdir_new(&rr->vd, vcl_name, NULL, NULL, rr);
+}
+
+VCL_VOID __match_proto__()
+vmod_hash__fini(struct req *req, struct vmod_directors_hash **rrp)
+{
+	struct vmod_directors_hash *rr;
+
+	AZ(req);
+	rr = *rrp;
+	*rrp = NULL;
+	CHECK_OBJ_NOTNULL(rr, VMOD_DIRECTORS_HASH_MAGIC);
+	vdir_delete(&rr->vd);
+	vbit_destroy(rr->vbm);
+	FREE_OBJ(rr);
+}
+
+VCL_VOID __match_proto__()
+vmod_hash_add_backend(struct req *req,
+    struct vmod_directors_hash *rr, VCL_BACKEND be, double w)
+{
+
+	(void)req;
+	CHECK_OBJ_NOTNULL(rr, VMOD_DIRECTORS_HASH_MAGIC);
+	(void)vdir_add_backend(rr->vd, be, w);
+}
+
+VCL_BACKEND __match_proto__()
+vmod_hash_backend(struct req *req, struct vmod_directors_hash *rr, const char *arg, ...)
+{
+	struct SHA256Context ctx;
+	va_list ap;
+	const char *p;
+	unsigned char sha256[SHA256_LEN];
+	VCL_BACKEND be;
+	double r;
+
+	(void)req;
+
+	CHECK_OBJ_NOTNULL(rr, VMOD_DIRECTORS_HASH_MAGIC);
+	SHA256_Init(&ctx);
+	va_start(ap, arg);
+	p = arg;
+	while (p != vrt_magic_string_end) {
+		SHA256_Update(&ctx, arg, strlen(arg));
+		p = va_arg(ap, const char *);
+	}
+	va_end(ap);
+	SHA256_Final(sha256, &ctx);
+
+	r = vbe32dec(sha256);
+	r = scalbn(r, -32);
+	be = vdir_pick_be(rr->vd, req, r, rr->nloops);
+	return (be);
+}
diff --git a/lib/libvmod_directors/random.c b/lib/libvmod_directors/random.c
index 32f829a..61eb677 100644
--- a/lib/libvmod_directors/random.c
+++ b/lib/libvmod_directors/random.c
@@ -62,36 +62,12 @@ static struct vbc * __match_proto__(vdi_getfd_f)
 vmod_rr_getfd(const struct director *dir, struct req *req)
 {
 	struct vmod_directors_random *rr;
-	struct vbitmap *vbm = NULL;
-	unsigned u, v, l;
-	VCL_BACKEND be = NULL;
-	double tw;
-	int nbe;
+	VCL_BACKEND be;
 	double r;
 
 	CAST_OBJ_NOTNULL(rr, dir->priv, VMOD_DIRECTORS_RANDOM_MAGIC);
-	tw = rr->vd->total_weight;
-	nbe = rr->vd->n_backend;
 	r = scalbn(random(), -31);
-	assert(r >= 0.0 && r <= 1.0);
-	vdir_lock(rr->vd);
-	for (l = 0; nbe > 0 && tw > 0.0 && l < rr->nloops; l++) {
-		u = vdir_pick_by_weight(rr->vd, r * tw, vbm);
-		be = rr->vd->backend[u];
-		CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
-		if (be->healthy(be, req))
-			break;
-		if (l == 0) {
-			vbm = rr->vbm;
-			for (v = 0; v < nbe; v++)
-				vbit_clr(vbm, v);
-		}
-		vbit_set(vbm, u);
-		nbe--;
-		tw -= rr->vd->weight[u];
-		be = NULL;
-	}
-	vdir_unlock(rr->vd);
+	be = vdir_pick_be(rr->vd, req, r, rr->nloops);
 	if (be == NULL)
 		return (NULL);
 	return (be->getfd(be, req));
diff --git a/lib/libvmod_directors/vdir.c b/lib/libvmod_directors/vdir.c
index c8d6fe5..0a8e954 100644
--- a/lib/libvmod_directors/vdir.c
+++ b/lib/libvmod_directors/vdir.c
@@ -70,6 +70,8 @@ vdir_new(struct vdir **vdp, const char *vcl_name, vdi_healthy *healthy,
 	vd->dir->priv = priv;
 	vd->dir->healthy = healthy;
 	vd->dir->getfd = getfd;
+	vd->vbm = vbit_init(8);
+	AN(vd->vbm);
 }
 
 void
@@ -87,6 +89,7 @@ vdir_delete(struct vdir **vdp)
 	free(vd->weight);
 	AZ(pthread_mutex_destroy(&vd->mtx));
 	FREE_OBJ(vd->dir);
+	vbit_destroy(vd->vbm);
 	FREE_OBJ(vd);
 }
 
@@ -145,7 +148,7 @@ vdir_any_healthy(struct vdir *vd, const struct req *req)
 	return (retval);
 }
 
-unsigned
+static unsigned
 vdir_pick_by_weight(const struct vdir *vd, double w,
     const struct vbitmap *blacklist)
 {
@@ -165,3 +168,36 @@ vdir_pick_by_weight(const struct vdir *vd, double w,
 	WRONG("");
 }
 
+VCL_BACKEND
+vdir_pick_be(struct vdir *vd, const struct req *req, double w, unsigned nloops)
+{
+	struct vbitmap *vbm = NULL;
+	unsigned u, v, l;
+	VCL_BACKEND be = NULL;
+	double tw;
+	int nbe;
+
+	tw = vd->total_weight;
+	nbe = vd->n_backend;
+	assert(w >= 0.0 && w <= 1.0);
+	vdir_lock(vd);
+	for (l = 0; nbe > 0 && tw > 0.0 && l <nloops; l++) {
+		u = vdir_pick_by_weight(vd, w * tw, vbm);
+		be = vd->backend[u];
+		CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
+		if (be->healthy(be, req))
+			break;
+		if (l == 0) {
+			vbm = vd->vbm;
+			for (v = 0; v < nbe; v++)
+				vbit_clr(vbm, v);
+		}
+		vbit_set(vbm, u);
+		nbe--;
+		tw -= vd->weight[u];
+		be = NULL;
+	}
+	vdir_unlock(vd);
+	return (be);
+}
+
diff --git a/lib/libvmod_directors/vdir.h b/lib/libvmod_directors/vdir.h
index 7f42e70..76795d7 100644
--- a/lib/libvmod_directors/vdir.h
+++ b/lib/libvmod_directors/vdir.h
@@ -38,6 +38,7 @@ struct vdir {
 	double					*weight;
 	double					total_weight;
 	struct director				*dir;
+	struct vbitmap				*vbm;
 };
 
 void vdir_new(struct vdir **vdp, const char *vcl_name, vdi_healthy *healthy,
@@ -47,5 +48,5 @@ void vdir_lock(struct vdir *vd);
 void vdir_unlock(struct vdir *vd);
 unsigned vdir_add_backend(struct vdir *vd, VCL_BACKEND be, double weight);
 unsigned vdir_any_healthy(struct vdir *vd, const struct req *);
-unsigned vdir_pick_by_weight(const struct vdir *vd, double w,
-    const struct vbitmap *blacklist);
+VCL_BACKEND vdir_pick_be(struct vdir *vd, const struct req *req, double w,
+    unsigned nloops);
diff --git a/lib/libvmod_directors/vmod.vcc b/lib/libvmod_directors/vmod.vcc
index b74057d..8b61944 100644
--- a/lib/libvmod_directors/vmod.vcc
+++ b/lib/libvmod_directors/vmod.vcc
@@ -41,3 +41,8 @@ Object random() {
 	Method VOID .add_backend(BACKEND, REAL)
 	Method BACKEND .backend()
 }
+
+Object hash() {
+	Method VOID .add_backend(BACKEND, REAL)
+	Method BACKEND .backend(STRING_LIST)
+}



More information about the varnish-commit mailing list