[4.1] 5811a87 Add Dridi's test-suite for dynamic backends, with some semi-heavy modifications relating to the object refcount issue.

Poul-Henning Kamp phk at FreeBSD.org
Fri Sep 4 15:54:50 CEST 2015


commit 5811a87e33056e8aeb8bce3fcfdc0c5023b67a43
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Sun Jul 12 09:10:03 2015 +0000

    Add Dridi's test-suite for dynamic backends, with some semi-heavy
    modifications relating to the object refcount issue.

diff --git a/bin/varnishtest/tests/d00007.vtc b/bin/varnishtest/tests/d00007.vtc
new file mode 100644
index 0000000..298fbf7
--- /dev/null
+++ b/bin/varnishtest/tests/d00007.vtc
@@ -0,0 +1,28 @@
+varnishtest "Test dynamic backends"
+
+server s1 {
+	rxreq
+	txresp
+} -start
+
+varnish v1 -vcl {
+	import ${vmod_debug};
+
+	backend dummy { .host = "${bad_ip}"; }
+
+	sub vcl_init {
+		new s1 = debug.dyn("${s1_addr}", "${s1_port}");
+	}
+
+	sub vcl_recv {
+		set req.backend_hint = s1.backend();
+	}
+} -start
+
+varnish v1 -expect MAIN.n_backend == 2
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+} -run
diff --git a/bin/varnishtest/tests/d00008.vtc b/bin/varnishtest/tests/d00008.vtc
new file mode 100644
index 0000000..a30edd8
--- /dev/null
+++ b/bin/varnishtest/tests/d00008.vtc
@@ -0,0 +1,52 @@
+varnishtest "Test dynamic backends hot swap"
+
+server s1 {
+	rxreq
+	expect req.url == "/foo"
+	txresp
+} -start
+
+server s2 {
+	rxreq
+	expect req.url == "/bar"
+	txresp
+} -start
+
+varnish v1 -vcl {
+	import ${vmod_debug};
+
+	backend dummy { .host = "${bad_ip}"; }
+
+	sub vcl_init {
+		new s1 = debug.dyn("${s1_addr}", "${s1_port}");
+	}
+
+	sub vcl_recv {
+		if (req.method == "SWAP") {
+			s1.refresh(req.http.X-Addr, req.http.X-Port);
+			return (synth(200));
+		}
+		set req.backend_hint = s1.backend();
+	}
+} -start
+
+varnish v1 -expect MAIN.n_backend == 2
+
+client c1 {
+	txreq -url "/foo"
+	rxresp
+	expect resp.status == 200
+
+	txreq -req "SWAP" -hdr "X-Addr: ${s2_addr}" -hdr "X-Port: ${s2_port}"
+	rxresp
+	expect resp.status == 200
+
+	txreq -url "/bar"
+	rxresp
+	expect resp.status == 200
+} -run
+
+delay 1
+
+varnish v1 -cli backend.list
+# varnish v1 -expect MAIN.n_backend == 2
diff --git a/bin/varnishtest/tests/d00009.vtc b/bin/varnishtest/tests/d00009.vtc
new file mode 100644
index 0000000..c888d20
--- /dev/null
+++ b/bin/varnishtest/tests/d00009.vtc
@@ -0,0 +1,58 @@
+varnishtest "Test dynamic backends hot swap while being used"
+
+server s1 {
+	rxreq
+	expect req.url == "/foo"
+	sema r1 sync 2
+	sema r2 sync 2
+	txresp
+} -start
+
+server s2 {
+	rxreq
+	expect req.url == "/bar"
+	sema r2 sync 2
+	txresp
+} -start
+
+varnish v1 -vcl {
+	import ${vmod_debug};
+
+	backend dummy { .host = "${bad_ip}"; }
+
+	sub vcl_init {
+		new s1 = debug.dyn("${s1_addr}", "${s1_port}");
+	}
+
+	sub vcl_recv {
+		if (req.method == "SWAP") {
+			s1.refresh(req.http.X-Addr, req.http.X-Port);
+			return (synth(200));
+		}
+		set req.backend_hint = s1.backend();
+	}
+} -start
+
+varnish v1 -expect MAIN.n_backend == 2
+
+client c1 {
+	txreq -url "/foo"
+	rxresp
+	expect resp.status == 200
+} -start
+
+client c2 {
+	sema r1 sync 2
+	txreq -req "SWAP" -hdr "X-Addr: ${s2_addr}" -hdr "X-Port: ${s2_port}"
+	rxresp
+	expect resp.status == 200
+
+	txreq -url "/bar"
+	rxresp
+	expect resp.status == 200
+} -run
+
+client c1 -wait
+
+varnish v1 -cli backend.list
+# varnish v1 -expect MAIN.n_backend == 2
diff --git a/bin/varnishtest/tests/d00010.vtc b/bin/varnishtest/tests/d00010.vtc
new file mode 100644
index 0000000..1db0ea7
--- /dev/null
+++ b/bin/varnishtest/tests/d00010.vtc
@@ -0,0 +1,59 @@
+varnishtest "Test dynamic backends hot swap during a pipe"
+
+server s1 {
+	rxreq
+	expect req.url == "/foo"
+	sema r1 sync 2
+	sema r2 sync 2
+	txresp
+} -start
+
+server s2 {
+	rxreq
+	expect req.url == "/bar"
+	sema r2 sync 2
+	txresp
+} -start
+
+varnish v1 -vcl {
+	import ${vmod_debug};
+
+	backend dummy { .host = "${bad_ip}"; }
+
+	sub vcl_init {
+		new s1 = debug.dyn("${s1_addr}", "${s1_port}");
+	}
+
+	sub vcl_recv {
+		if (req.method == "SWAP") {
+			s1.refresh(req.http.X-Addr, req.http.X-Port);
+			return (synth(200));
+		}
+		set req.backend_hint = s1.backend();
+		return (pipe);
+	}
+} -start
+
+varnish v1 -expect MAIN.n_backend == 2
+
+client c1 {
+	txreq -url "/foo"
+	rxresp
+	expect resp.status == 200
+} -start
+
+client c2 {
+	sema r1 sync 2
+	txreq -req "SWAP" -hdr "X-Addr: ${s2_addr}" -hdr "X-Port: ${s2_port}"
+	rxresp
+	expect resp.status == 200
+
+	txreq -url "/bar"
+	rxresp
+	expect resp.status == 200
+} -run
+
+client c1 -wait
+
+varnish v1 -cli backend.list
+#varnish v1 -expect MAIN.n_backend == 2
diff --git a/bin/varnishtest/tests/d00011.vtc b/bin/varnishtest/tests/d00011.vtc
new file mode 100644
index 0000000..01d45a1
--- /dev/null
+++ b/bin/varnishtest/tests/d00011.vtc
@@ -0,0 +1,62 @@
+varnishtest "Test a dynamic backend hot swap after it was picked by a bereq"
+
+server s1 {
+} -start
+
+server s2 {
+	rxreq
+	txresp
+} -start
+
+varnish v1 -vcl {
+	import ${vmod_std};
+	import ${vmod_debug};
+
+	backend dummy { .host = "${bad_ip}"; }
+
+	sub vcl_init {
+		new s1 = debug.dyn("${s1_addr}", "${s1_port}");
+	}
+
+	sub vcl_recv {
+		if (req.method == "SWAP") {
+			s1.refresh(req.http.X-Addr, req.http.X-Port);
+			return (synth(200));
+		}
+	}
+
+	sub vcl_backend_fetch {
+		set bereq.backend = s1.backend();
+		# hot swap should happen while we sleep
+		debug.sleep(2s);
+		if (std.healthy(bereq.backend)) {
+			return(abandon);
+		} else {
+			set bereq.backend = s1.backend();
+		}
+	}
+} -start
+
+varnish v1 -expect MAIN.n_backend == 2
+
+client c1 {
+	txreq
+	sema r2 sync 2
+	rxresp
+	expect resp.status == 200
+}
+
+client c2 {
+	sema r2 sync 2
+	delay 0.1
+	txreq -req "SWAP" -hdr "X-Addr: ${s2_addr}" -hdr "X-Port: ${s2_port}"
+	rxresp
+	expect resp.status == 200
+}
+
+client c1 -start
+client c2 -run
+client c1 -wait
+
+varnish v1 -cli backend.list
+#varnish v1 -expect MAIN.n_backend == 2
diff --git a/bin/varnishtest/tests/d00012.vtc b/bin/varnishtest/tests/d00012.vtc
new file mode 100644
index 0000000..74aaa8d
--- /dev/null
+++ b/bin/varnishtest/tests/d00012.vtc
@@ -0,0 +1,77 @@
+varnishtest "Test a dynamic backend discard during a request"
+
+# vcl.discard testing inspired by v00006.vtc from commit e1f7207
+
+server s1 {
+	rxreq
+	expect req.url == "/foo"
+	sema r1 sync 2
+	txresp
+} -start
+
+varnish v1 -arg "-p thread_pools=1" -vcl {
+	import ${vmod_debug};
+
+	backend dummy { .host = "${bad_ip}"; }
+
+	sub vcl_init {
+		new s1 = debug.dyn("${s1_addr}", "${s1_port}");
+	}
+
+	sub vcl_recv {
+		set req.backend_hint = s1.backend();
+	}
+} -start
+
+client c1 {
+	txreq -url "/foo"
+	rxresp
+	expect resp.status == 200
+} -start
+
+varnish v1 -expect MAIN.n_backend == 2
+# expected: vcl1.dummy, vcl1.s1
+
+server s2 {
+	rxreq
+	expect req.url == "/bar"
+	txresp
+} -start
+
+varnish v1 -vcl {
+	import ${vmod_debug};
+
+	backend dummy { .host = "${bad_ip}"; }
+
+	sub vcl_init {
+		new s2 = debug.dyn("${s2_addr}", "${s2_port}");
+	}
+
+	sub vcl_recv {
+		set req.backend_hint = s2.backend();
+	}
+}
+
+varnish v1 -cli "vcl.discard vcl1"
+sema r1 sync 2
+
+client c1 -wait
+delay 2
+
+varnish v1 -expect MAIN.n_backend == 4
+# expected: vcl1.dummy, vcl1.s1, vcl2.dummy, vcl2.s2
+
+varnish v1 -expect n_vcl_avail == 1
+varnish v1 -expect n_vcl_discard == 1
+
+client c1 {
+	txreq -url "/bar"
+	rxresp
+	expect resp.status == 200
+} -run
+
+varnish v1 -cli "vcl.list"
+#varnish v1 -expect MAIN.n_backend == 2
+# expected: vcl2.dummy, vcl2.s2
+varnish v1 -expect n_vcl_avail == 1
+varnish v1 -expect n_vcl_discard == 0
diff --git a/bin/varnishtest/tests/d00013.vtc b/bin/varnishtest/tests/d00013.vtc
new file mode 100644
index 0000000..25ab33f
--- /dev/null
+++ b/bin/varnishtest/tests/d00013.vtc
@@ -0,0 +1,59 @@
+varnishtest "Test a dynamic backend hot swap after it was hinted to a req"
+
+server s1 {
+} -start
+
+server s2 {
+	rxreq
+	txresp
+} -start
+
+varnish v1 -vcl {
+	import ${vmod_std};
+	import ${vmod_debug};
+
+	backend dummy { .host = "${bad_ip}"; }
+
+	sub vcl_init {
+		new s1 = debug.dyn("${s1_addr}", "${s1_port}");
+	}
+
+	sub vcl_recv {
+		if (req.method == "SWAP") {
+			s1.refresh(req.http.X-Addr, req.http.X-Port);
+			return (synth(200));
+		}
+		set req.backend_hint = s1.backend();
+		# hot swap should happen while we sleep
+		debug.sleep(2s);
+		if (std.healthy(req.backend_hint)) {
+			return(synth(800));
+		} else {
+			set req.backend_hint = s1.backend();
+		}
+	}
+} -start
+
+varnish v1 -expect MAIN.n_backend == 2
+
+client c1 {
+	txreq
+	sema r2 sync 2
+	rxresp
+	expect resp.status == 200
+}
+
+client c2 {
+	sema r2 sync 2
+	delay 0.1
+	txreq -req "SWAP" -hdr "X-Addr: ${s2_addr}" -hdr "X-Port: ${s2_port}"
+	rxresp
+	expect resp.status == 200
+}
+
+client c1 -start
+client c2 -run
+client c1 -wait
+
+varnish v1 -cli backend.list
+#varnish v1 -expect MAIN.n_backend == 2
diff --git a/lib/libvmod_debug/Makefile.am b/lib/libvmod_debug/Makefile.am
index d189102..9115713 100644
--- a/lib/libvmod_debug/Makefile.am
+++ b/lib/libvmod_debug/Makefile.am
@@ -17,14 +17,15 @@ libvmod_debug_la_LDFLAGS = $(AM_LDFLAGS) -module -export-dynamic -avoid-version
 
 libvmod_debug_la_SOURCES = \
 	vmod_debug.c \
-	vmod_debug_obj.c
+	vmod_debug_obj.c \
+	vmod_debug_dyn.c
 
 nodist_libvmod_debug_la_SOURCES = \
 	vcc_if.c \
 	vcc_if.h
 
 # BUILT_SOURCES is only a hack and dependency tracking does not help for the first build
-vmod_debug.lo vmod_debug_obj.lo: vcc_if.h
+vmod_debug.lo vmod_debug_obj.lo vmod_debug_dyn.lo: vcc_if.h
 
 vcc_if.c vcc_if.h vmod_debug.rst vmod_debug.man.rst: $(vmodtool) $(vmod_srcdir)/vmod.vcc
 	@PYTHON@ $(vmodtool) $(vmodtoolargs) $(vmod_srcdir)/vmod.vcc
diff --git a/lib/libvmod_debug/vmod.vcc b/lib/libvmod_debug/vmod.vcc
index 305deaa..3a60814 100644
--- a/lib/libvmod_debug/vmod.vcc
+++ b/lib/libvmod_debug/vmod.vcc
@@ -108,4 +108,16 @@ Function to fail vcl_init{}
 
 $Function VOID sleep(DURATION)
 
-Block the current worker thread.
+Sleep the current worker thread.
+
+$Object dyn(STRING addr, STRING port)
+
+Dynamically create a single-backend director
+
+$Method BACKEND .backend()
+
+Return the dynamic backend.
+
+$Method VOID .refresh(STRING addr, STRING port)
+
+Dynamically refresh & (always!) replace the backend by a new one.
diff --git a/lib/libvmod_debug/vmod_debug_dyn.c b/lib/libvmod_debug/vmod_debug_dyn.c
new file mode 100644
index 0000000..7e4afea
--- /dev/null
+++ b/lib/libvmod_debug/vmod_debug_dyn.c
@@ -0,0 +1,165 @@
+/*-
+ * Copyright (c) 2015 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Dridi Boukelmoune <dridi at varnish-software.com>
+ *
+ * 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 <netdb.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "vcl.h"
+#include "vrt.h"
+
+#include "cache/cache.h"
+#include "cache/cache_director.h"
+#include "cache/cache_backend.h"
+
+#include "vsa.h"
+#include "vcc_if.h"
+
+struct vmod_debug_dyn {
+	unsigned		magic;
+#define VMOD_DEBUG_DYN_MAGIC	0x9b77ccbd
+	pthread_mutex_t		mtx;
+	char			*vcl_name;
+	struct director		*dir;
+};
+
+static void
+dyn_dir_init(VRT_CTX, struct vmod_debug_dyn *dyn,
+    VCL_STRING addr, VCL_STRING port)
+{
+	struct addrinfo hints, *res = NULL;
+	struct suckaddr *sa;
+	struct director *dir, *dir2;
+	struct vrt_backend vrt;
+
+	CHECK_OBJ_NOTNULL(dyn, VMOD_DEBUG_DYN_MAGIC);
+	XXXAN(addr);
+	XXXAN(port);
+
+	INIT_OBJ(&vrt, VRT_BACKEND_MAGIC);
+	vrt.port = port;
+	vrt.vcl_name = dyn->vcl_name;
+	vrt.hosthdr = vrt.ipv4_addr;
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_INET;
+	hints.ai_socktype = SOCK_STREAM;
+	AZ(getaddrinfo(vrt.ipv4_addr, vrt.port, &hints, &res));
+	XXXAZ(res->ai_next);
+
+	sa = VSA_Malloc(res->ai_addr, res->ai_addrlen);
+	AN(sa);
+	if (VSA_Get_Proto(sa) == AF_INET) {
+		vrt.ipv4_addr = addr;
+		vrt.ipv4_suckaddr = sa;
+	} else if (VSA_Get_Proto(sa) == AF_INET6) {
+		vrt.ipv6_addr = addr;
+		vrt.ipv6_suckaddr = sa;
+	} else
+		WRONG("Wrong proto family");
+
+	freeaddrinfo(res);
+
+	dir = VRT_new_backend(ctx, &vrt);
+	AN(dir);
+
+	/*
+	 * NB: A real dynamic backend should not replace the previous
+	 * instance if the new one is identical.  We do it here because
+	 * the d* tests requires a replacement.
+	 */
+	AZ(pthread_mutex_lock(&dyn->mtx));
+	dir2 = dyn->dir;
+	dyn->dir = dir;
+	AZ(pthread_mutex_unlock(&dyn->mtx));
+
+	if (dir2 != NULL)
+		VRT_delete_backend(ctx, &dir2);
+
+	free(sa);
+}
+
+VCL_VOID
+vmod_dyn__init(VRT_CTX, struct vmod_debug_dyn **dynp,
+    const char *vcl_name, VCL_STRING addr, VCL_STRING port)
+{
+	struct vmod_debug_dyn *dyn;
+
+	ASSERT_CLI();
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	AN(dynp);
+	AZ(*dynp);
+	AN(vcl_name);
+
+	ALLOC_OBJ(dyn, VMOD_DEBUG_DYN_MAGIC);
+	AN(dyn);
+	REPLACE(dyn->vcl_name, vcl_name);
+
+	AZ(pthread_mutex_init(&dyn->mtx, NULL));
+
+	dyn_dir_init(ctx, dyn, addr, port);
+	XXXAN(dyn->dir);
+	*dynp = dyn;
+}
+
+VCL_VOID
+vmod_dyn__fini(struct vmod_debug_dyn **dynp)
+{
+	struct vmod_debug_dyn *dyn;
+
+	AN(dynp);
+	CAST_OBJ_NOTNULL(dyn, *dynp, VMOD_DEBUG_DYN_MAGIC);
+	/* at this point all backends will be deleted by the vcl */
+	free(dyn->vcl_name);
+	AZ(pthread_mutex_destroy(&dyn->mtx));
+	FREE_OBJ(dyn);
+	*dynp = NULL;
+}
+
+VCL_BACKEND __match_proto__()
+vmod_dyn_backend(VRT_CTX, struct vmod_debug_dyn *dyn)
+{
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	CHECK_OBJ_NOTNULL(dyn, VMOD_DEBUG_DYN_MAGIC);
+	AN(dyn->dir);
+	return (dyn->dir);
+}
+
+VCL_VOID
+vmod_dyn_refresh(VRT_CTX, struct vmod_debug_dyn *dyn,
+    VCL_STRING addr, VCL_STRING port)
+{
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	CHECK_OBJ_NOTNULL(dyn, VMOD_DEBUG_DYN_MAGIC);
+	dyn_dir_init(ctx, dyn, addr, port);
+}



More information about the varnish-commit mailing list