[master] e676f7793 purge: Use EXP_Reduce() instead of EXP_Rearm()

Nils Goroll nils.goroll at uplex.de
Mon Mar 25 14:56:07 UTC 2024


commit e676f77939e7dbde851ee3aa58dfd36505f2b7e8
Author: AlveElde <alve_elde at hotmail.com>
Date:   Tue Mar 19 13:44:24 2024 +0100

    purge: Use EXP_Reduce() instead of EXP_Rearm()
    
    When a stale object is soft-purged, the time until the object expires
    should not be reset, as repeated soft-purges could keep the object
    around indefinitely.

diff --git a/bin/varnishd/cache/cache_hash.c b/bin/varnishd/cache/cache_hash.c
index 8627c7a95..32f9340c7 100644
--- a/bin/varnishd/cache/cache_hash.c
+++ b/bin/varnishd/cache/cache_hash.c
@@ -747,7 +747,7 @@ HSH_Purge(struct worker *wrk, struct objhead *oh, vtim_real ttl_now,
 			if (is_purge)
 				EXP_Remove(ocp[i], NULL);
 			else
-				EXP_Rearm(ocp[i], ttl_now, ttl, grace, keep);
+				EXP_Reduce(ocp[i], ttl_now, ttl, grace, keep);
 			(void)HSH_DerefObjCore(wrk, &ocp[i], 0);
 			AZ(ocp[i]);
 			total++;
diff --git a/bin/varnishtest/tests/m00057.vtc b/bin/varnishtest/tests/m00057.vtc
new file mode 100644
index 000000000..8f9c67d1f
--- /dev/null
+++ b/bin/varnishtest/tests/m00057.vtc
@@ -0,0 +1,60 @@
+varnishtest "Softpurging a stale object"
+
+server s1 {
+	rxreq
+	txresp -hdr "version: 1"
+
+	rxreq
+	txresp -hdr "version: 2"
+} -start
+
+varnish v1 -vcl+backend {
+	import purge;
+
+	sub vcl_hit {
+		if (req.http.purge) {
+			set req.http.npurged = purge.soft();
+			return (synth(200));
+		}
+	}
+
+	sub vcl_backend_response {
+		set beresp.grace = 3s;
+		set beresp.keep = 10s;
+	}
+
+	sub vcl_synth {
+		set resp.http.npurged = req.http.npurged;
+	}
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+	expect resp.http.version == "1"
+
+	# Softpurge the object
+	txreq -hdr "purge: yes"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.npurged == 1
+
+	# Wait for half the grace period
+	delay 1.5
+
+	# Softpurge the object again, this should not reset the expiry timer
+	txreq -hdr "purge: yes"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.npurged == 1
+
+	# Wait for the object to enter keep
+	delay 1.5
+
+	# A grace hit should not be possible now
+	txreq
+	rxresp
+	expect resp.http.version == "2"
+	expect resp.status == 200
+} -run
diff --git a/bin/varnishtest/tests/m00058.vtc b/bin/varnishtest/tests/m00058.vtc
new file mode 100644
index 000000000..e339764ae
--- /dev/null
+++ b/bin/varnishtest/tests/m00058.vtc
@@ -0,0 +1,86 @@
+varnishtest "Softpurging an object cannot increase grace or keep"
+
+server s1 {
+	rxreq
+	txresp -hdr "Last-Modified: Wed, 11 Sep 2013 13:36:55 GMT" -body "foo"
+
+	rxreq
+	expect req.http.if-modified-since == "Wed, 11 Sep 2013 13:36:55 GMT"
+	txresp -body "bar"
+} -start
+
+varnish v1 -arg "-p vsl_mask=+ExpKill" -vcl+backend {
+	import purge;
+	import std;
+
+	sub vcl_hit {
+		if (req.http.purge) {
+			set req.http.npurged = purge.soft(
+			    grace = std.duration(req.http.grace, -1s),
+			    keep = std.duration(req.http.keep, -1s));
+			return (synth(200));
+		}
+	}
+
+	sub vcl_backend_response {
+		set beresp.ttl = 1y;
+		set beresp.grace = 1y;
+		set beresp.keep = 1y;
+	}
+
+	sub vcl_synth {
+		set resp.http.npurged = req.http.npurged;
+	}
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+	expect resp.body == "foo"
+
+	# Reduce the objects grace
+	txreq -hdr "purge: yes" -hdr "grace: 10s"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.npurged == 1
+
+	# Reduce the objects keep
+	txreq -hdr "purge: yes" -hdr "keep: 10s"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.npurged == 1
+
+	# Reduce the objects grace and keep
+	txreq -hdr "purge: yes" -hdr "grace: 1s" -hdr "keep: 5s"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.npurged == 1
+
+	# Increasing the objects grace is not possible
+	txreq -hdr "purge: yes" -hdr "grace: 15s"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.npurged == 1
+
+	# Increasing the objects keep is not possible
+	txreq -hdr "purge: yes" -hdr "keep: 105"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.npurged == 1
+
+	# Increasing the objects grace and keep is not possible
+	txreq -hdr "purge: yes" -hdr "grace: 15s" -hdr "keep: 15s"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.npurged == 1
+
+	# Wait for the obejct to enter keep
+	delay 1
+
+	# We don't get a grace hit, but the backend gets an IMS header
+	txreq
+	rxresp
+	expect resp.status == 200
+	expect resp.body == "bar"
+} -run
diff --git a/vmod/vmod_purge.vcc b/vmod/vmod_purge.vcc
index dc55a7f30..7fa7639da 100644
--- a/vmod/vmod_purge.vcc
+++ b/vmod/vmod_purge.vcc
@@ -98,12 +98,46 @@ $Restrict vcl_hit vcl_miss
 
 $Function INT soft(DURATION ttl = 0, DURATION grace = -1, DURATION keep = -1)
 
-Sets the *ttl*, *grace* and *keep*.
-
-By default, *ttl* is set to 0 with *grace* and *keep* periods left
-untouched. Setting a negative value for *grace* or *keep* periods
-leaves them untouched. Setting all three parameters to ``0`` is
-equivalent to a hard purge. It returns the number of soft-purged objects.
+Sets the *ttl*, *grace* and *keep*. By default, *ttl* is set to ``0`` with
+*grace* and *keep* periods left untouched. Setting *grace* or *keep* to a
+negative value or to something higher than the objects current value leaves them
+untouched. Setting all three parameters to ``0`` is equivalent to a hard purge.
+Returns the number of soft-purged objects.
+
+A soft-purge can only decrease the lifetime of an object. Let's consider an
+object in cache created with *ttl*, *grace*, and *keep* of 60 seconds each:
+
+``purge.soft(ttl = 0s, grace = -1s, keep = -1s);``
+
+* If the object is **fresh**, the *ttl* is reduced to 0 seconds and the object
+  expires after 120 seconds.
+* If the object is **stale**, the expiry time is not changed.
+
+``purge.soft(ttl = 0s, grace = 10s, keep = 10s);``
+
+* If the object is **fresh**, the *ttl* is reduced to 0 seconds, *grace* and
+  *keep* are reduced to 10 seconds. The object expires after 20 seconds.
+* If the object has been **stale** for 5 seconds, *grace* is reduced to 5
+  seconds and *keep* is reduced to 10 seconds. The object expires after 15
+  seconds.
+* If the object has been **stale** for 15 seconds, *grace* is reduced to 0
+  seconds and *keep* is reduced to 5 seconds. The object expires after 5
+  seconds.
+* If the object has been **stale** for 20 seconds or more, the object
+  immediately expires.
+
+``purge.soft(ttl = 10s, grace = -1s, keep = -1s);``
+
+* If the object has been **fresh** for 5 seconds, the *ttl* is reduced to 10
+  seconds. The object expires after 130 seconds.
+* If the object has been **fresh** for 55 seconds, the *ttl* is not changed. The
+  object expires after 125 seconds.
+* If the object is **stale**, the expiry time is not changed.
+
+When the expiry time of an object is reduced due to a softpurge, an
+``EXP_Reduce`` entry is logged under the ``ExpKill`` VSL tag. If a softpurge
+does not reduce the expiry time of an object, an ``EXP_Unchanged`` entry is
+logged instead.
 
 $Restrict vcl_hit vcl_miss
 SEE ALSO


More information about the varnish-commit mailing list