[master] 4687245 cache_vcl.c was getting too long, split along lines of "maintain list of VCLs" vs. "Do things with VCLs on list"

Poul-Henning Kamp phk at FreeBSD.org
Thu Apr 19 07:45:13 UTC 2018


commit 468724563de4de1cad2a876c24bc1f5944ed6160
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Thu Apr 19 07:43:55 2018 +0000

    cache_vcl.c was getting too long, split along lines of "maintain
    list of VCLs" vs. "Do things with VCLs on list"

diff --git a/bin/varnishd/Makefile.am b/bin/varnishd/Makefile.am
index 1e8640e..9329f36 100644
--- a/bin/varnishd/Makefile.am
+++ b/bin/varnishd/Makefile.am
@@ -44,6 +44,7 @@ varnishd_SOURCES = \
 	cache/cache_tcp_pool.c \
 	cache/cache_vary.c \
 	cache/cache_vcl.c \
+	cache/cache_vcl_vrt.c \
 	cache/cache_vrt.c \
 	cache/cache_vrt_priv.c \
 	cache/cache_vrt_re.c \
@@ -125,6 +126,7 @@ noinst_HEADERS = \
 	cache/cache_pool.h \
 	cache/cache_tcp_pool.h \
 	cache/cache_transport.h \
+	cache/cache_vcl.h \
 	cache/cache_vgz.h \
 	common/heritage.h \
 	common/vsmw.h \
diff --git a/bin/varnishd/cache/cache_vcl.c b/bin/varnishd/cache/cache_vcl.c
index 30adf54..abc519f 100644
--- a/bin/varnishd/cache/cache_vcl.c
+++ b/bin/varnishd/cache/cache_vcl.c
@@ -42,49 +42,15 @@
 #include "vcl.h"
 
 #include "cache_director.h"
-#include "cache_backend.h"
+#include "cache_vcl.h"
 #include "vcli_serve.h"
 
-static const char * const VCL_TEMP_INIT = "init";
-static const char * const VCL_TEMP_COLD = "cold";
-static const char * const VCL_TEMP_WARM = "warm";
-static const char * const VCL_TEMP_BUSY = "busy";
-static const char * const VCL_TEMP_COOLING = "cooling";
-static const char * const VCL_TEMP_LABEL = "label";
-
-/*
- * NB: The COOLING temperature is neither COLD nor WARM.
- * And LABEL is not a temperature, it's a different kind of VCL.
- */
-#define VCL_WARM(v) ((v)->temp == VCL_TEMP_WARM || (v)->temp == VCL_TEMP_BUSY)
-#define VCL_COLD(v) ((v)->temp == VCL_TEMP_INIT || (v)->temp == VCL_TEMP_COLD)
-
-struct vcl {
-	unsigned		magic;
-#define VCL_MAGIC		0x214188f2
-	VTAILQ_ENTRY(vcl)	list;
-	void			*dlh;
-	const struct VCL_conf	*conf;
-	char			state[8];
-	char			*loaded_name;
-	unsigned		busy;
-	unsigned		discard;
-	const char		*temp;
-	pthread_rwlock_t	temp_rwl;
-	VTAILQ_HEAD(,director)	director_list;
-	VTAILQ_HEAD(,vclref)	ref_list;
-	int			nrefs;
-	struct vcl		*label;
-	int			nlabels;
-};
-
-struct vclref {
-	unsigned		magic;
-#define VCLREF_MAGIC		0x47fb6848
-	const struct vcl	*vcl;
-	VTAILQ_ENTRY(vclref)	list;
-	char			desc[32];
-};
+const char * const VCL_TEMP_INIT = "init";
+const char * const VCL_TEMP_COLD = "cold";
+const char * const VCL_TEMP_WARM = "warm";
+const char * const VCL_TEMP_BUSY = "busy";
+const char * const VCL_TEMP_COOLING = "cooling";
+const char * const VCL_TEMP_LABEL = "label";
 
 /*
  * XXX: Presently all modifications to this list happen from the
@@ -93,8 +59,8 @@ struct vclref {
 static VTAILQ_HEAD(, vcl)	vcl_head =
     VTAILQ_HEAD_INITIALIZER(vcl_head);
 
-static struct lock		vcl_mtx;
-static struct vcl		*vcl_active; /* protected by vcl_mtx */
+struct lock		vcl_mtx;
+struct vcl		*vcl_active; /* protected by vcl_mtx */
 
 static struct vrt_ctx ctx_cli;
 static unsigned handling_cli;
@@ -171,7 +137,7 @@ vcl_send_event(VRT_CTX, enum vcl_event_e ev)
 
 /*--------------------------------------------------------------------*/
 
-static struct vcl *
+struct vcl *
 vcl_find(const char *name)
 {
 	struct vcl *vcl;
@@ -225,37 +191,7 @@ VCL_Panic(struct vsb *vsb, const struct vcl *vcl)
 
 /*--------------------------------------------------------------------*/
 
-const char *
-VCL_Return_Name(unsigned r)
-{
-
-	switch (r) {
-#define VCL_RET_MAC(l, U, B)	\
-	case VCL_RET_##U:	\
-		return(#l);
-#include "tbl/vcl_returns.h"
-	default:
-		return (NULL);
-	}
-}
-
-const char *
-VCL_Method_Name(unsigned m)
-{
-
-	switch (m) {
-#define VCL_MET_MAC(func, upper, typ, bitmap)	\
-	case VCL_MET_##upper:			\
-		return (#upper);
-#include "tbl/vcl_returns.h"
-	default:
-		return (NULL);
-	}
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
+void
 vcl_get(struct vcl **vcc, struct vcl *vcl)
 {
 	AN(vcc);
@@ -281,114 +217,8 @@ vcl_get(struct vcl **vcc, struct vcl *vcl)
 	AZ(errno=pthread_rwlock_unlock(&(*vcc)->temp_rwl));
 }
 
-void
-VCL_Refresh(struct vcl **vcc)
-{
-	if (*vcc == vcl_active)
-		return;
-	if (*vcc != NULL)
-		VCL_Rel(vcc);	/* XXX: optimize locking */
-
-	while (vcl_active == NULL)
-		(void)usleep(100000);
-
-	vcl_get(vcc, NULL);
-}
-
-void
-VCL_Ref(struct vcl *vcl)
-{
-
-	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
-	AZ(errno=pthread_rwlock_rdlock(&vcl->temp_rwl));
-	assert(!VCL_COLD(vcl));
-	AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
-	Lck_Lock(&vcl_mtx);
-	assert(vcl->busy > 0);
-	vcl->busy++;
-	Lck_Unlock(&vcl_mtx);
-}
-
-void
-VCL_Rel(struct vcl **vcc)
-{
-	struct vcl *vcl;
-
-	AN(*vcc);
-	vcl = *vcc;
-	*vcc = NULL;
-
-	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
-	Lck_Lock(&vcl_mtx);
-	assert(vcl->busy > 0);
-	vcl->busy--;
-	/*
-	 * We do not garbage collect discarded VCL's here, that happens
-	 * in VCL_Poll() which is called from the CLI thread.
-	 */
-	Lck_Unlock(&vcl_mtx);
-}
-
 /*--------------------------------------------------------------------*/
 
-int
-VCL_AddDirector(struct vcl *vcl, struct director *d, const char *vcl_name)
-{
-	struct vsb *vsb;
-
-	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
-	CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
-	AN(d->destroy);
-
-	vsb = VSB_new_auto();
-	AN(vsb);
-	VSB_printf(vsb, "%s.%s", VCL_Name(vcl), vcl_name);
-	AZ(VSB_finish(vsb));
-	REPLACE((d->display_name), VSB_data(vsb));
-	VSB_destroy(&vsb);
-
-	AZ(errno=pthread_rwlock_rdlock(&vcl->temp_rwl));
-	if (vcl->temp == VCL_TEMP_COOLING) {
-		AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
-		return (1);
-	}
-
-	Lck_Lock(&vcl_mtx);
-	VTAILQ_INSERT_TAIL(&vcl->director_list, d, vcl_list);
-	d->vcl = vcl;
-	Lck_Unlock(&vcl_mtx);
-
-	if (VCL_WARM(vcl))
-		/* Only when adding backend to already warm VCL */
-		VDI_Event(d, VCL_EVENT_WARM);
-	else if (vcl->temp != VCL_TEMP_INIT)
-		WRONG("Dynamic Backends can only be added to warm VCLs");
-	AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
-
-	return (0);
-}
-
-void
-VCL_DelDirector(struct director *d)
-{
-	struct vcl *vcl;
-
-	CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
-	vcl = d->vcl;
-	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
-	Lck_Lock(&vcl_mtx);
-	VTAILQ_REMOVE(&vcl->director_list, d, vcl_list);
-	Lck_Unlock(&vcl_mtx);
-
-	AZ(errno=pthread_rwlock_rdlock(&vcl->temp_rwl));
-	if (VCL_WARM(vcl))
-		VDI_Event(d, VCL_EVENT_COLD);
-	AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
-	AN(d->destroy);
-	REPLACE(d->display_name, NULL);
-	d->destroy(d);
-}
-
 static int
 vcl_iterdir(struct cli *cli, const char *pat, const struct vcl *vcl,
     vcl_be_func *func, void *priv)
@@ -572,153 +402,6 @@ VCL_TestLoad(const char *fn)
 
 /*--------------------------------------------------------------------*/
 
-struct director *
-VCL_DefaultDirector(const struct vcl *vcl)
-{
-
-	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
-	CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);
-	return (*vcl->conf->default_director);
-}
-
-const char *
-VCL_Name(const struct vcl *vcl)
-{
-
-	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
-	return (vcl->loaded_name);
-}
-
-const struct vrt_backend_probe *
-VCL_DefaultProbe(const struct vcl *vcl)
-{
-
-	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
-	CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);
-	return (vcl->conf->default_probe);
-}
-
-/*--------------------------------------------------------------------
- * VRT apis relating to VCL's as VCLS.
- */
-
-void
-VRT_count(VRT_CTX, unsigned u)
-{
-
-	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
-	CHECK_OBJ_NOTNULL(ctx->vcl, VCL_MAGIC);
-	CHECK_OBJ_NOTNULL(ctx->vcl->conf, VCL_CONF_MAGIC);
-	assert(u < ctx->vcl->conf->nref);
-	if (ctx->vsl != NULL)
-		VSLb(ctx->vsl, SLT_VCL_trace, "%s %u %u.%u.%u",
-		    ctx->vcl->loaded_name, u, ctx->vcl->conf->ref[u].source,
-		    ctx->vcl->conf->ref[u].line, ctx->vcl->conf->ref[u].pos);
-	else
-		VSL(SLT_VCL_trace, 0, "%s %u %u.%u.%u",
-		    ctx->vcl->loaded_name, u, ctx->vcl->conf->ref[u].source,
-		    ctx->vcl->conf->ref[u].line, ctx->vcl->conf->ref[u].pos);
-}
-
-VCL_VCL
-VRT_vcl_get(VRT_CTX, const char *name)
-{
-	VCL_VCL vcl;
-
-	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
-	vcl = vcl_find(name);
-	AN(vcl);
-	Lck_Lock(&vcl_mtx);
-	vcl->nrefs++;
-	Lck_Unlock(&vcl_mtx);
-	return (vcl);
-}
-
-void
-VRT_vcl_rel(VRT_CTX, VCL_VCL vcl)
-{
-	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
-	AN(vcl);
-	Lck_Lock(&vcl_mtx);
-	vcl->nrefs--;
-	Lck_Unlock(&vcl_mtx);
-}
-
-void
-VRT_vcl_select(VRT_CTX, VCL_VCL vcl)
-{
-	struct req *req = ctx->req;
-
-	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
-	VCL_Rel(&req->vcl);
-	vcl_get(&req->vcl, vcl);
-	/* XXX: better logging */
-	VSLb(ctx->req->vsl, SLT_Debug, "Now using %s VCL", vcl->loaded_name);
-}
-
-struct vclref *
-VRT_ref_vcl(VRT_CTX, const char *desc)
-{
-	struct vcl *vcl;
-	struct vclref* ref;
-
-	ASSERT_CLI();
-	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
-	AN(desc);
-	AN(*desc);
-
-	vcl = ctx->vcl;
-	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
-	assert(VCL_WARM(vcl));
-
-	ALLOC_OBJ(ref, VCLREF_MAGIC);
-	AN(ref);
-	ref->vcl = vcl;
-	bprintf(ref->desc, "%s", desc);
-
-	Lck_Lock(&vcl_mtx);
-	VTAILQ_INSERT_TAIL(&vcl->ref_list, ref, list);
-	vcl->nrefs++;
-	Lck_Unlock(&vcl_mtx);
-
-	return (ref);
-}
-
-void
-VRT_rel_vcl(VRT_CTX, struct vclref **refp)
-{
-	struct vcl *vcl;
-	struct vclref *ref;
-
-	AN(refp);
-	ref = *refp;
-	*refp = NULL;
-
-	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
-	CHECK_OBJ_NOTNULL(ref, VCLREF_MAGIC);
-
-	vcl = ctx->vcl;
-	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
-	assert(vcl == ref->vcl);
-
-	/* NB: A VCL may be released by a VMOD at any time, but it must happen
-	 * after a warmup and before the end of a cooldown. The release may or
-	 * may not happen while the same thread holds the temperature lock, so
-	 * instead we check that all references are gone in VCL_Nuke.
-	 */
-
-	Lck_Lock(&vcl_mtx);
-	assert(!VTAILQ_EMPTY(&vcl->ref_list));
-	VTAILQ_REMOVE(&vcl->ref_list, ref, list);
-	vcl->nrefs--;
-	/* No garbage collection here, for the same reasons as in VCL_Rel. */
-	Lck_Unlock(&vcl_mtx);
-
-	FREE_OBJ(ref);
-}
-
-/*--------------------------------------------------------------------*/
-
 static void
 vcl_print_refs(VRT_CTX)
 {
@@ -1100,92 +783,6 @@ vcl_cli_show(struct cli *cli, const char * const *av, void *priv)
 	}
 }
 
-/*--------------------------------------------------------------------
- * Method functions to call into VCL programs.
- *
- * Either the request or busyobject must be specified, but not both.
- * The workspace argument is where random VCL stuff gets space from.
- */
-
-static void
-vcl_call_method(struct worker *wrk, struct req *req, struct busyobj *bo,
-    void *specific, unsigned method, vcl_func_f *func)
-{
-	uintptr_t aws;
-	struct vsl_log *vsl = NULL;
-	struct vrt_ctx ctx;
-
-	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
-	INIT_OBJ(&ctx, VRT_CTX_MAGIC);
-	if (req != NULL) {
-		CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
-		CHECK_OBJ_NOTNULL(req->sp, SESS_MAGIC);
-		CHECK_OBJ_NOTNULL(req->vcl, VCL_MAGIC);
-		vsl = req->vsl;
-		ctx.vcl = req->vcl;
-		ctx.http_req = req->http;
-		ctx.http_req_top = req->top->http;
-		ctx.http_resp = req->resp;
-		ctx.req = req;
-		ctx.sp = req->sp;
-		ctx.now = req->t_prev;
-		ctx.ws = req->ws;
-	}
-	if (bo != NULL) {
-		if (req)
-			assert(method == VCL_MET_PIPE);
-		CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
-		CHECK_OBJ_NOTNULL(bo->vcl, VCL_MAGIC);
-		vsl = bo->vsl;
-		ctx.vcl = bo->vcl;
-		ctx.http_bereq = bo->bereq;
-		ctx.http_beresp = bo->beresp;
-		ctx.bo = bo;
-		ctx.sp = bo->sp;
-		ctx.now = bo->t_prev;
-		ctx.ws = bo->ws;
-	}
-	assert(ctx.now != 0);
-	ctx.syntax = ctx.vcl->conf->syntax;
-	ctx.vsl = vsl;
-	ctx.specific = specific;
-	ctx.method = method;
-	wrk->handling = 0;
-	ctx.handling = &wrk->handling;
-	aws = WS_Snapshot(wrk->aws);
-	wrk->cur_method = method;
-	wrk->seen_methods |= method;
-	AN(vsl);
-	VSLb(vsl, SLT_VCL_call, "%s", VCL_Method_Name(method));
-	func(&ctx);
-	VSLb(vsl, SLT_VCL_return, "%s", VCL_Return_Name(wrk->handling));
-	wrk->cur_method |= 1;		// Magic marker
-	if (wrk->handling == VCL_RET_FAIL)
-		wrk->stats->vcl_fail++;
-
-	/*
-	 * VCL/Vmods are not allowed to make permanent allocations from
-	 * wrk->aws, but they can reserve and return from it.
-	 */
-	assert(aws == WS_Snapshot(wrk->aws));
-}
-
-#define VCL_MET_MAC(func, upper, typ, bitmap)				\
-void									\
-VCL_##func##_method(struct vcl *vcl, struct worker *wrk,		\
-     struct req *req, struct busyobj *bo, void *specific)		\
-{									\
-									\
-	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);				\
-	CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);			\
-	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);				\
-	vcl_call_method(wrk, req, bo, specific,				\
-	    VCL_MET_ ## upper, vcl->conf->func##_func);			\
-	AN((1U << wrk->handling) & bitmap);				\
-}
-
-#include "tbl/vcl_returns.h"
-
 /*--------------------------------------------------------------------*/
 
 static struct cli_proto vcl_cmds[] = {
diff --git a/bin/varnishd/cache/cache_vcl.h b/bin/varnishd/cache/cache_vcl.h
new file mode 100644
index 0000000..87433af
--- /dev/null
+++ b/bin/varnishd/cache/cache_vcl.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2016 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * 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.
+ *
+ */
+
+struct vcl {
+	unsigned		magic;
+#define VCL_MAGIC		0x214188f2
+	VTAILQ_ENTRY(vcl)	list;
+	void			*dlh;
+	const struct VCL_conf	*conf;
+	char			state[8];
+	char			*loaded_name;
+	unsigned		busy;
+	unsigned		discard;
+	const char		*temp;
+	pthread_rwlock_t	temp_rwl;
+	VTAILQ_HEAD(,director)	director_list;
+	VTAILQ_HEAD(,vclref)	ref_list;
+	int			nrefs;
+	struct vcl		*label;
+	int			nlabels;
+};
+
+struct vclref {
+	unsigned		magic;
+#define VCLREF_MAGIC		0x47fb6848
+	const struct vcl	*vcl;
+	VTAILQ_ENTRY(vclref)	list;
+	char			desc[32];
+};
+
+extern struct lock		vcl_mtx;
+extern struct vcl		*vcl_active; /* protected by vcl_mtx */
+struct vcl *vcl_find(const char *);
+void vcl_get(struct vcl **, struct vcl *);
+
+extern const char * const VCL_TEMP_INIT;
+extern const char * const VCL_TEMP_COLD;
+extern const char * const VCL_TEMP_WARM;
+extern const char * const VCL_TEMP_BUSY;
+extern const char * const VCL_TEMP_COOLING;
+extern const char * const VCL_TEMP_LABEL;
+
+/*
+ * NB: The COOLING temperature is neither COLD nor WARM.
+ * And LABEL is not a temperature, it's a different kind of VCL.
+ */
+#define VCL_WARM(v) ((v)->temp == VCL_TEMP_WARM || (v)->temp == VCL_TEMP_BUSY)
+#define VCL_COLD(v) ((v)->temp == VCL_TEMP_INIT || (v)->temp == VCL_TEMP_COLD)
+
+
diff --git a/bin/varnishd/cache/cache_vcl_vrt.c b/bin/varnishd/cache/cache_vcl_vrt.c
new file mode 100644
index 0000000..484c14b
--- /dev/null
+++ b/bin/varnishd/cache/cache_vcl_vrt.c
@@ -0,0 +1,415 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2016 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cache_varnishd.h"
+
+#include "vcl.h"
+
+#include "cache_director.h"
+#include "cache_vcl.h"
+
+/*--------------------------------------------------------------------*/
+
+const char *
+VCL_Return_Name(unsigned r)
+{
+
+	switch (r) {
+#define VCL_RET_MAC(l, U, B)	\
+	case VCL_RET_##U:	\
+		return(#l);
+#include "tbl/vcl_returns.h"
+	default:
+		return (NULL);
+	}
+}
+
+const char *
+VCL_Method_Name(unsigned m)
+{
+
+	switch (m) {
+#define VCL_MET_MAC(func, upper, typ, bitmap)	\
+	case VCL_MET_##upper:			\
+		return (#upper);
+#include "tbl/vcl_returns.h"
+	default:
+		return (NULL);
+	}
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+VCL_Refresh(struct vcl **vcc)
+{
+	if (*vcc == vcl_active)
+		return;
+	if (*vcc != NULL)
+		VCL_Rel(vcc);	/* XXX: optimize locking */
+
+	while (vcl_active == NULL)
+		(void)usleep(100000);
+
+	vcl_get(vcc, NULL);
+}
+
+void
+VCL_Ref(struct vcl *vcl)
+{
+
+	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
+	AZ(errno=pthread_rwlock_rdlock(&vcl->temp_rwl));
+	assert(!VCL_COLD(vcl));
+	AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
+	Lck_Lock(&vcl_mtx);
+	assert(vcl->busy > 0);
+	vcl->busy++;
+	Lck_Unlock(&vcl_mtx);
+}
+
+void
+VCL_Rel(struct vcl **vcc)
+{
+	struct vcl *vcl;
+
+	AN(*vcc);
+	vcl = *vcc;
+	*vcc = NULL;
+
+	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
+	Lck_Lock(&vcl_mtx);
+	assert(vcl->busy > 0);
+	vcl->busy--;
+	/*
+	 * We do not garbage collect discarded VCL's here, that happens
+	 * in VCL_Poll() which is called from the CLI thread.
+	 */
+	Lck_Unlock(&vcl_mtx);
+}
+
+/*--------------------------------------------------------------------*/
+
+int
+VCL_AddDirector(struct vcl *vcl, struct director *d, const char *vcl_name)
+{
+	struct vsb *vsb;
+
+	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
+	CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
+	AN(d->destroy);
+
+	vsb = VSB_new_auto();
+	AN(vsb);
+	VSB_printf(vsb, "%s.%s", VCL_Name(vcl), vcl_name);
+	AZ(VSB_finish(vsb));
+	REPLACE((d->display_name), VSB_data(vsb));
+	VSB_destroy(&vsb);
+
+	AZ(errno=pthread_rwlock_rdlock(&vcl->temp_rwl));
+	if (vcl->temp == VCL_TEMP_COOLING) {
+		AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
+		return (1);
+	}
+
+	Lck_Lock(&vcl_mtx);
+	VTAILQ_INSERT_TAIL(&vcl->director_list, d, vcl_list);
+	d->vcl = vcl;
+	Lck_Unlock(&vcl_mtx);
+
+	if (VCL_WARM(vcl))
+		/* Only when adding backend to already warm VCL */
+		VDI_Event(d, VCL_EVENT_WARM);
+	else if (vcl->temp != VCL_TEMP_INIT)
+		WRONG("Dynamic Backends can only be added to warm VCLs");
+	AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
+
+	return (0);
+}
+
+void
+VCL_DelDirector(struct director *d)
+{
+	struct vcl *vcl;
+
+	CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
+	vcl = d->vcl;
+	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
+	Lck_Lock(&vcl_mtx);
+	VTAILQ_REMOVE(&vcl->director_list, d, vcl_list);
+	Lck_Unlock(&vcl_mtx);
+
+	AZ(errno=pthread_rwlock_rdlock(&vcl->temp_rwl));
+	if (VCL_WARM(vcl))
+		VDI_Event(d, VCL_EVENT_COLD);
+	AZ(errno=pthread_rwlock_unlock(&vcl->temp_rwl));
+	AN(d->destroy);
+	REPLACE(d->display_name, NULL);
+	d->destroy(d);
+}
+
+/*--------------------------------------------------------------------*/
+
+struct director *
+VCL_DefaultDirector(const struct vcl *vcl)
+{
+
+	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
+	CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);
+	return (*vcl->conf->default_director);
+}
+
+const char *
+VCL_Name(const struct vcl *vcl)
+{
+
+	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
+	return (vcl->loaded_name);
+}
+
+const struct vrt_backend_probe *
+VCL_DefaultProbe(const struct vcl *vcl)
+{
+
+	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
+	CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);
+	return (vcl->conf->default_probe);
+}
+
+/*--------------------------------------------------------------------
+ * VRT apis relating to VCL's as VCLS.
+ */
+
+void
+VRT_count(VRT_CTX, unsigned u)
+{
+
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	CHECK_OBJ_NOTNULL(ctx->vcl, VCL_MAGIC);
+	CHECK_OBJ_NOTNULL(ctx->vcl->conf, VCL_CONF_MAGIC);
+	assert(u < ctx->vcl->conf->nref);
+	if (ctx->vsl != NULL)
+		VSLb(ctx->vsl, SLT_VCL_trace, "%s %u %u.%u.%u",
+		    ctx->vcl->loaded_name, u, ctx->vcl->conf->ref[u].source,
+		    ctx->vcl->conf->ref[u].line, ctx->vcl->conf->ref[u].pos);
+	else
+		VSL(SLT_VCL_trace, 0, "%s %u %u.%u.%u",
+		    ctx->vcl->loaded_name, u, ctx->vcl->conf->ref[u].source,
+		    ctx->vcl->conf->ref[u].line, ctx->vcl->conf->ref[u].pos);
+}
+
+VCL_VCL
+VRT_vcl_get(VRT_CTX, const char *name)
+{
+	VCL_VCL vcl;
+
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	vcl = vcl_find(name);
+	AN(vcl);
+	Lck_Lock(&vcl_mtx);
+	vcl->nrefs++;
+	Lck_Unlock(&vcl_mtx);
+	return (vcl);
+}
+
+void
+VRT_vcl_rel(VRT_CTX, VCL_VCL vcl)
+{
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	AN(vcl);
+	Lck_Lock(&vcl_mtx);
+	vcl->nrefs--;
+	Lck_Unlock(&vcl_mtx);
+}
+
+void
+VRT_vcl_select(VRT_CTX, VCL_VCL vcl)
+{
+	struct req *req = ctx->req;
+
+	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
+	VCL_Rel(&req->vcl);
+	vcl_get(&req->vcl, vcl);
+	/* XXX: better logging */
+	VSLb(ctx->req->vsl, SLT_Debug, "Now using %s VCL", vcl->loaded_name);
+}
+
+struct vclref *
+VRT_ref_vcl(VRT_CTX, const char *desc)
+{
+	struct vcl *vcl;
+	struct vclref* ref;
+
+	ASSERT_CLI();
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	AN(desc);
+	AN(*desc);
+
+	vcl = ctx->vcl;
+	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
+	assert(VCL_WARM(vcl));
+
+	ALLOC_OBJ(ref, VCLREF_MAGIC);
+	AN(ref);
+	ref->vcl = vcl;
+	bprintf(ref->desc, "%s", desc);
+
+	Lck_Lock(&vcl_mtx);
+	VTAILQ_INSERT_TAIL(&vcl->ref_list, ref, list);
+	vcl->nrefs++;
+	Lck_Unlock(&vcl_mtx);
+
+	return (ref);
+}
+
+void
+VRT_rel_vcl(VRT_CTX, struct vclref **refp)
+{
+	struct vcl *vcl;
+	struct vclref *ref;
+
+	AN(refp);
+	ref = *refp;
+	*refp = NULL;
+
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	CHECK_OBJ_NOTNULL(ref, VCLREF_MAGIC);
+
+	vcl = ctx->vcl;
+	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
+	assert(vcl == ref->vcl);
+
+	/* NB: A VCL may be released by a VMOD at any time, but it must happen
+	 * after a warmup and before the end of a cooldown. The release may or
+	 * may not happen while the same thread holds the temperature lock, so
+	 * instead we check that all references are gone in VCL_Nuke.
+	 */
+
+	Lck_Lock(&vcl_mtx);
+	assert(!VTAILQ_EMPTY(&vcl->ref_list));
+	VTAILQ_REMOVE(&vcl->ref_list, ref, list);
+	vcl->nrefs--;
+	/* No garbage collection here, for the same reasons as in VCL_Rel. */
+	Lck_Unlock(&vcl_mtx);
+
+	FREE_OBJ(ref);
+}
+
+/*--------------------------------------------------------------------
+ * Method functions to call into VCL programs.
+ *
+ * Either the request or busyobject must be specified, but not both.
+ * The workspace argument is where random VCL stuff gets space from.
+ */
+
+static void
+vcl_call_method(struct worker *wrk, struct req *req, struct busyobj *bo,
+    void *specific, unsigned method, vcl_func_f *func)
+{
+	uintptr_t aws;
+	struct vsl_log *vsl = NULL;
+	struct vrt_ctx ctx;
+
+	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
+	INIT_OBJ(&ctx, VRT_CTX_MAGIC);
+	if (req != NULL) {
+		CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+		CHECK_OBJ_NOTNULL(req->sp, SESS_MAGIC);
+		CHECK_OBJ_NOTNULL(req->vcl, VCL_MAGIC);
+		vsl = req->vsl;
+		ctx.vcl = req->vcl;
+		ctx.http_req = req->http;
+		ctx.http_req_top = req->top->http;
+		ctx.http_resp = req->resp;
+		ctx.req = req;
+		ctx.sp = req->sp;
+		ctx.now = req->t_prev;
+		ctx.ws = req->ws;
+	}
+	if (bo != NULL) {
+		if (req)
+			assert(method == VCL_MET_PIPE);
+		CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
+		CHECK_OBJ_NOTNULL(bo->vcl, VCL_MAGIC);
+		vsl = bo->vsl;
+		ctx.vcl = bo->vcl;
+		ctx.http_bereq = bo->bereq;
+		ctx.http_beresp = bo->beresp;
+		ctx.bo = bo;
+		ctx.sp = bo->sp;
+		ctx.now = bo->t_prev;
+		ctx.ws = bo->ws;
+	}
+	assert(ctx.now != 0);
+	ctx.syntax = ctx.vcl->conf->syntax;
+	ctx.vsl = vsl;
+	ctx.specific = specific;
+	ctx.method = method;
+	wrk->handling = 0;
+	ctx.handling = &wrk->handling;
+	aws = WS_Snapshot(wrk->aws);
+	wrk->cur_method = method;
+	wrk->seen_methods |= method;
+	AN(vsl);
+	VSLb(vsl, SLT_VCL_call, "%s", VCL_Method_Name(method));
+	func(&ctx);
+	VSLb(vsl, SLT_VCL_return, "%s", VCL_Return_Name(wrk->handling));
+	wrk->cur_method |= 1;		// Magic marker
+	if (wrk->handling == VCL_RET_FAIL)
+		wrk->stats->vcl_fail++;
+
+	/*
+	 * VCL/Vmods are not allowed to make permanent allocations from
+	 * wrk->aws, but they can reserve and return from it.
+	 */
+	assert(aws == WS_Snapshot(wrk->aws));
+}
+
+#define VCL_MET_MAC(func, upper, typ, bitmap)				\
+void									\
+VCL_##func##_method(struct vcl *vcl, struct worker *wrk,		\
+     struct req *req, struct busyobj *bo, void *specific)		\
+{									\
+									\
+	CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);				\
+	CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);			\
+	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);				\
+	vcl_call_method(wrk, req, bo, specific,				\
+	    VCL_MET_ ## upper, vcl->conf->func##_func);			\
+	AN((1U << wrk->handling) & bitmap);				\
+}
+
+#include "tbl/vcl_returns.h"


More information about the varnish-commit mailing list