[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