[master] 141ea56a4 Add the VCF - aka "The CatFlap"
Poul-Henning Kamp
phk at FreeBSD.org
Mon Mar 4 09:40:08 UTC 2019
commit 141ea56a43459d2c1b29d2a299ff9b67356228c6
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Mon Mar 4 09:37:24 2019 +0000
Add the VCF - aka "The CatFlap"
I have reimplemented this based on Nils's #2858, because I found
it too complex and intrusive. (In particular we try to avoid
unions in Varnish).
Testcase m00051 by: Nils Goroll
Closes: #2858
diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index 2018c9bce..163c52948 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -101,6 +101,7 @@ struct sess;
struct transport;
struct worker;
struct listen_sock;
+struct vcf;
#define DIGEST_LEN 32
@@ -530,6 +531,8 @@ struct req {
struct acct_req acct;
struct vrt_privs privs[1];
+
+ struct vcf *vcf;
};
#define IS_TOPREQ(req) ((req)->topreq == (req))
diff --git a/bin/varnishd/cache/cache_hash.c b/bin/varnishd/cache/cache_hash.c
index e9b8466d9..a778bf535 100644
--- a/bin/varnishd/cache/cache_hash.c
+++ b/bin/varnishd/cache/cache_hash.c
@@ -81,6 +81,15 @@ static int hsh_deref_objhead_unlock(struct worker *wrk, struct objhead **poh);
/*---------------------------------------------------------------------*/
+#define VCF_RETURN(x) const struct vcf_return VCF_##x[1] = { \
+ { .name = #x, } \
+};
+
+VCF_RETURNS()
+#undef VCF_RETURN
+
+/*---------------------------------------------------------------------*/
+
static struct objhead *
hsh_newobjhead(void)
{
@@ -344,6 +353,7 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp)
struct objhead *oh;
struct objcore *oc;
struct objcore *exp_oc;
+ const struct vcf_return *vr;
vtim_real exp_t_origin;
int busy_found;
const uint8_t *vary;
@@ -359,6 +369,7 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp)
wrk = req->wrk;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(req->http, HTTP_MAGIC);
+ CHECK_OBJ_ORNULL(req->vcf, VCF_MAGIC);
AN(hash);
hsh_prealloc(wrk);
@@ -436,6 +447,19 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp)
continue;
}
+ if (req->vcf != NULL) {
+ vr = req->vcf->func(req, &oc, &exp_oc, 0);
+ if (vr == VCF_CONTINUE)
+ continue;
+ if (vr == VCF_MISS) {
+ oc = NULL;
+ break;
+ }
+ if (vr == VCF_HIT)
+ break;
+ assert(vr == VCF_DEFAULT);
+ }
+
if (EXP_Ttl(req, oc) > req->t_req) {
assert(oh->refcnt > 1);
assert(oc->objhead == oh);
@@ -452,6 +476,9 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp)
}
}
+ if (req->vcf != NULL)
+ (void)req->vcf->func(req, &oc, &exp_oc, 1);
+
if (oc != NULL && oc->flags & OC_F_HFP) {
xid = ObjGetXID(wrk, oc);
dttl = EXP_Dttl(req, oc);
diff --git a/bin/varnishd/cache/cache_req_fsm.c b/bin/varnishd/cache/cache_req_fsm.c
index 1768efee1..1bd7911ee 100644
--- a/bin/varnishd/cache/cache_req_fsm.c
+++ b/bin/varnishd/cache/cache_req_fsm.c
@@ -490,6 +490,11 @@ cnt_lookup(struct worker *wrk, struct req *req)
if (had_objhead)
VSLb_ts_req(req, "Waitinglist", W_TIM_real(wrk));
+ if (req->vcf != NULL) {
+ (void)req->vcf->func(req, NULL, NULL, 2);
+ req->vcf = NULL;
+ }
+
if (busy == NULL) {
VRY_Finish(req, DISCARD);
} else {
diff --git a/bin/varnishd/cache/cache_varnishd.h b/bin/varnishd/cache/cache_varnishd.h
index 2aab94ab7..a117d8b8d 100644
--- a/bin/varnishd/cache/cache_varnishd.h
+++ b/bin/varnishd/cache/cache_varnishd.h
@@ -85,6 +85,37 @@ typedef enum htc_status_e htc_complete_f(struct http_conn *);
extern volatile struct params * cache_param;
+/* -------------------------------------------------------------------
+ * The VCF facility is deliberately undocumented, use at your peril.
+ */
+
+struct vcf_return {
+ const char *name;
+};
+
+#define VCF_RETURNS() \
+ VCF_RETURN(CONTINUE) \
+ VCF_RETURN(DEFAULT) \
+ VCF_RETURN(MISS) \
+ VCF_RETURN(HIT)
+
+#define VCF_RETURN(x) extern const struct vcf_return VCF_##x[1];
+VCF_RETURNS()
+#undef VCF_RETURN
+
+typedef const struct vcf_return *vcf_func_f(
+ struct req *req,
+ struct objcore **oc,
+ struct objcore **oc_exp,
+ int state);
+
+struct vcf {
+ unsigned magic;
+#define VCF_MAGIC 0x183285d1
+ vcf_func_f *func;
+ void *priv;
+};
+
/* Prototypes etc ----------------------------------------------------*/
/* cache_acceptor.c */
diff --git a/bin/varnishd/flint.lnt b/bin/varnishd/flint.lnt
index 42a40290f..5a1942528 100644
--- a/bin/varnishd/flint.lnt
+++ b/bin/varnishd/flint.lnt
@@ -39,6 +39,7 @@
-esym(765, vrt_magic_string_end)
-esym(759, vrt_magic_string_end)
-esym(768, vrt_ref::*)
+-esym(768, vcf_return::name)
-esym(768, VCL_conf::*)
// FLINT Bug20090910_838
diff --git a/bin/varnishtest/tests/m00051.vtc b/bin/varnishtest/tests/m00051.vtc
new file mode 100644
index 000000000..a5231894a
--- /dev/null
+++ b/bin/varnishtest/tests/m00051.vtc
@@ -0,0 +1,54 @@
+varnishtest "catflap"
+
+varnish v1 -vcl {
+ import debug;
+
+ backend dummy { .host = "${bad_backend}"; }
+
+ sub vcl_recv {
+ if (req.http.id) {
+ debug.catflap(miss);
+ } else if (req.http.get == "first") {
+ debug.catflap(first);
+ } else if (req.http.get == "last") {
+ debug.catflap(last);
+ } else {
+ return (fail);
+ }
+ return (hash);
+ }
+
+ sub vcl_backend_error {
+ if (! bereq.http.id) {
+ return (deliver);
+ }
+ set beresp.status = 200;
+ set beresp.ttl = 1s;
+ set beresp.grace = 1m;
+ set beresp.http.id = bereq.http.id;
+ }
+} -start
+
+client c1 {
+ txreq -hdr "id: 1"
+ rxresp
+ expect resp.status == 200
+ txreq -hdr "id: 2"
+ rxresp
+ expect resp.status == 200
+ txreq -hdr "id: 3"
+ rxresp
+ expect resp.status == 200
+
+ # the first object is the one which went into cache last
+
+ txreq -hdr "get: first"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.id == "3"
+
+ txreq -hdr "get: last"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.id == "1"
+} -run
diff --git a/doc/sphinx/reference/vtla.rst b/doc/sphinx/reference/vtla.rst
index 1fdfb4abf..76dccd068 100644
--- a/doc/sphinx/reference/vtla.rst
+++ b/doc/sphinx/reference/vtla.rst
@@ -31,6 +31,9 @@ VCA
VCC
VCL to C Compiler -- The code that compiles VCL to C code. (lib/libvcl)
+VCF
+ Varnish CatFlap
+
VCL
Varnish Configuration Language -- The domain-specific programming
language used for configuring a varnishd.
diff --git a/lib/libvmod_debug/vmod.vcc b/lib/libvmod_debug/vmod.vcc
index 2ff1d0220..4c5f652eb 100644
--- a/lib/libvmod_debug/vmod.vcc
+++ b/lib/libvmod_debug/vmod.vcc
@@ -230,3 +230,7 @@ $Method STRING .meth_opt(PRIV_CALL, PRIV_VCL, PRIV_TASK,
Test object method with all the fancy stuff.
$Function STRANDS return_strands(STRANDS strand)
+
+$Function VOID catflap(ENUM {miss, first, last} type)
+
+Test the HSH_Lookup catflap
diff --git a/lib/libvmod_debug/vmod_debug.c b/lib/libvmod_debug/vmod_debug.c
index fa05142b6..7161596ae 100644
--- a/lib/libvmod_debug/vmod_debug.c
+++ b/lib/libvmod_debug/vmod_debug.c
@@ -630,3 +630,72 @@ xyzzy_return_strands(VRT_CTX, VCL_STRANDS strand)
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
return (strand);
}
+
+/*---------------------------------------------------------------------*/
+
+static const struct vcf_return * v_matchproto_(vcf_func_f)
+xyzzy_catflap_simple(struct req *req, struct objcore **oc,
+ struct objcore **oc_exp, int state)
+{
+
+ CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+ CHECK_OBJ_NOTNULL(req->vcf, VCF_MAGIC);
+ assert(req->vcf->func == xyzzy_catflap_simple);
+
+ (void)oc;
+ (void)oc_exp;
+ if (state == 0) {
+ if (req->vcf->priv == VENUM(first))
+ return (VCF_HIT);
+ if (req->vcf->priv == VENUM(miss))
+ return (VCF_MISS);
+ WRONG("Shouldn't get here");
+ }
+ return (VCF_DEFAULT);
+}
+
+static const struct vcf_return * v_matchproto_(vcf_func_f)
+xyzzy_catflap_last(struct req *req, struct objcore **oc,
+ struct objcore **oc_exp, int state)
+{
+
+ CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+ CHECK_OBJ_NOTNULL(req->vcf, VCF_MAGIC);
+ assert(req->vcf->func == xyzzy_catflap_last);
+
+ (void)oc_exp;
+ if (state == 0) {
+ AN(oc);
+ CHECK_OBJ_NOTNULL(*oc, OBJCORE_MAGIC);
+ req->vcf->priv = *oc;
+ return (VCF_CONTINUE);
+ }
+ if (state == 1) {
+ AN(oc);
+ if (req->vcf->priv != NULL)
+ CAST_OBJ_NOTNULL(*oc, req->vcf->priv, OBJCORE_MAGIC);
+ return (VCF_CONTINUE);
+ }
+ return (VCF_DEFAULT);
+}
+
+VCL_VOID
+xyzzy_catflap(VRT_CTX, VCL_ENUM type)
+{
+ struct req *req;
+
+ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+ req = ctx->req;
+ CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+ XXXAZ(req->vcf);
+ req->vcf = WS_Alloc(req->ws, sizeof *req->vcf);
+ INIT_OBJ(req->vcf, VCF_MAGIC);
+ if (type == VENUM(first) || type == VENUM(miss)) {
+ req->vcf->func = xyzzy_catflap_simple;
+ req->vcf->priv = TRUST_ME(type);
+ } else if (type == VENUM(last)) {
+ req->vcf->func = xyzzy_catflap_last;
+ } else {
+ WRONG("Wrong VENUM");
+ }
+}
More information about the varnish-commit
mailing list