[master] 9c10c5aca kill stale oc for backend synth and clarify when we cache errors

Nils Goroll nils.goroll at uplex.de
Mon Apr 15 13:39:07 UTC 2019


commit 9c10c5aca8b2595997f5ce490991d734d6af6928
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Sun Mar 17 11:45:18 2019 +0100

    kill stale oc for backend synth and clarify when we cache errors
    
    Fixes #2946 in the sense that we want to treat a cacheable backend synth
    like any other object and kill the stale object it replaces.
    
    We do not replace the stale oc when
    - abandoning the bereq
    - leaving vcl_backend_error with return (deliver) and beresp.ttl == 0s
    - there is a waitinglist on this object because in this case the default
      ttl would be 1s, so we might be looking at the same case as the
      previous
    
    Thank you @mbgrydeland for the review and spotting a mistake.

diff --git a/bin/varnishd/cache/cache_fetch.c b/bin/varnishd/cache/cache_fetch.c
index 33a751ea2..a7ecafa22 100644
--- a/bin/varnishd/cache/cache_fetch.c
+++ b/bin/varnishd/cache/cache_fetch.c
@@ -683,6 +683,7 @@ vbf_stp_error(struct worker *wrk, struct busyobj *bo)
 	vtim_real now;
 	uint8_t *ptr;
 	struct vsb *synth_body;
+	struct objcore *stale = NULL;
 
 	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
 	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
@@ -708,6 +709,7 @@ vbf_stp_error(struct worker *wrk, struct busyobj *bo)
 	http_TimeHeader(bo->beresp, "Date: ", now);
 	http_SetHeader(bo->beresp, "Server: Varnish");
 
+	stale = bo->stale_oc;
 	bo->fetch_objcore->t_origin = now;
 	if (!VTAILQ_EMPTY(&bo->fetch_objcore->objhead->waitinglist)) {
 		/*
@@ -720,6 +722,7 @@ vbf_stp_error(struct worker *wrk, struct busyobj *bo)
 		bo->fetch_objcore->ttl = 1;
 		bo->fetch_objcore->grace = 5;
 		bo->fetch_objcore->keep = 5;
+		stale = NULL;
 	} else {
 		bo->fetch_objcore->ttl = 0;
 		bo->fetch_objcore->grace = 0;
@@ -775,6 +778,8 @@ vbf_stp_error(struct worker *wrk, struct busyobj *bo)
 	AZ(ObjSetU64(wrk, bo->fetch_objcore, OA_LEN, o));
 	VSB_destroy(&synth_body);
 	HSH_Unbusy(wrk, bo->fetch_objcore);
+	if (stale != NULL && bo->fetch_objcore->ttl > 0)
+		HSH_Kill(stale);
 	ObjSetState(wrk, bo->fetch_objcore, BOS_FINISHED);
 	return (F_STP_DONE);
 }
diff --git a/bin/varnishtest/tests/r01395.vtc b/bin/varnishtest/tests/r01395.vtc
index b7e388101..ce56cf708 100644
--- a/bin/varnishtest/tests/r01395.vtc
+++ b/bin/varnishtest/tests/r01395.vtc
@@ -1,4 +1,4 @@
-varnishtest "Test vcl_synth is called even if vcl_backend_fetch failed"
+varnishtest "Test vcl_backend_error is called if vcl_backend_fetch fails"
 
 varnish v1 -vcl {
 	backend default { .host = "${bad_backend}"; }
diff --git a/bin/varnishtest/tests/r02946.vtc b/bin/varnishtest/tests/r02946.vtc
new file mode 100644
index 000000000..b0eb3e6bf
--- /dev/null
+++ b/bin/varnishtest/tests/r02946.vtc
@@ -0,0 +1,45 @@
+varnishtest "#2946 - objcore leak for backend_synth"
+
+varnish v1 -vcl {
+	backend bad { .host = "${bad_backend}"; }
+
+	sub vcl_backend_error {
+		if (bereq.http.abandon) {
+			return (abandon);
+		}
+		if (bereq.http.ttl0) {
+			set beresp.ttl = 0s;
+			return (deliver);
+		}
+		set beresp.status = 200;
+		set beresp.ttl = 0.0001s;
+		set beresp.grace = 1h;
+		return (deliver);
+	}
+} -start
+
+client c1 -repeat 20 -keepalive {
+	txreq
+	rxresp
+	expect resp.status == 200
+
+	delay 0.001
+} -run
+
+delay 2
+
+client c1 {
+	txreq -hdr "abandon: true"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.age > 1
+} -run
+
+client c1 {
+	txreq -hdr "ttl0: true"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.age > 1
+} -run
+
+varnish v1 -expect n_objectcore == 1
diff --git a/doc/sphinx/users-guide/vcl-built-in-subs.rst b/doc/sphinx/users-guide/vcl-built-in-subs.rst
index a911ed005..0315b4838 100644
--- a/doc/sphinx/users-guide/vcl-built-in-subs.rst
+++ b/doc/sphinx/users-guide/vcl-built-in-subs.rst
@@ -495,8 +495,12 @@ vcl_backend_error
 This subroutine is called if we fail the backend fetch or if
 *max_retries* has been exceeded.
 
-A synthetic object is generated in VCL, whose body may be constructed
-using the ``synthetic()`` function.
+Returning with `abandon`_ does not leave a cache object.
+
+If returning with ``deliver`` and a ``beresp.ttl > 0s``, a synthetic
+cache object is generated in VCL, whose body may be constructed using
+the ``synthetic()`` function. This may be useful to increase the
+efficiency of failing backend requests.
 
 The `vcl_backend_error` subroutine may terminate with calling ``return()``
 with one of the following keywords:


More information about the varnish-commit mailing list