[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