[master] 841e8ff0c VCL: Introduce new obj_stale variable

Walid Boudebouda walid.boudebouda at gmail.com
Mon Sep 1 08:46:05 UTC 2025


commit 841e8ff0c3317f53e231ef24af6711dd20c3b4e8
Author: Walid Boudebouda <walid.boudebouda at gmail.com>
Date:   Sat Oct 14 20:07:44 2023 +0200

    VCL: Introduce new obj_stale variable
    
    obj_stale variable gives access to the stale object we had in cache
    when doing a 304 revalidation. It is only readable from vcl_backend_refresh
    subroutine.

diff --git a/bin/varnishd/cache/cache_vrt.c b/bin/varnishd/cache/cache_vrt.c
index edec7d64f..2847e8b87 100644
--- a/bin/varnishd/cache/cache_vrt.c
+++ b/bin/varnishd/cache/cache_vrt.c
@@ -259,6 +259,7 @@ VRT_selecthttp(VRT_CTX, enum gethdr_e where)
 	case HDR_RESP:
 		hp = ctx->http_resp;
 		break;
+	case HDR_OBJ_STALE:
 	case HDR_OBJ:
 		hp = NULL;
 		break;
@@ -283,6 +284,13 @@ VRT_GetHdr(VRT_CTX, VCL_HEADER hs)
 		return (HTTP_GetHdrPack(ctx->req->wrk, ctx->req->objcore,
 		    hs->what));
 	}
+
+	if (hs->where == HDR_OBJ_STALE) {
+		CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
+		CHECK_OBJ_NOTNULL(ctx->bo->stale_oc, OBJCORE_MAGIC);
+		return (HTTP_GetHdrPack(ctx->bo->wrk, ctx->bo->stale_oc,
+		    hs->what));
+	}
 	hp = VRT_selecthttp(ctx, hs->where);
 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
 	if (!http_GetHdr(hp, hs->what, &p))
diff --git a/bin/varnishd/cache/cache_vrt_var.c b/bin/varnishd/cache/cache_vrt_var.c
index 7b76b8f35..777f11ad2 100644
--- a/bin/varnishd/cache/cache_vrt_var.c
+++ b/bin/varnishd/cache/cache_vrt_var.c
@@ -561,6 +561,7 @@ VRT_r_##obj##_reason(VRT_CTX)					\
 }
 
 VRT_OC_VAR_R(obj, req, REQ_MAGIC, objcore);
+VRT_OC_VAR_R(obj_stale, bo, BUSYOBJ_MAGIC, stale_oc);
 
 /*--------------------------------------------------------------------*/
 
@@ -800,9 +801,13 @@ VRT_r_##which##_##fld(VRT_CTX)					\
 
 /*lint -save -e835 */	// Zero right hand arg to '-'
 
+VRT_DO_EXP_R(obj_stale, ctx->bo->stale_oc, ttl,
+    ttl_now(ctx) - ctx->bo->stale_oc->t_origin)
 VRT_DO_EXP_R(obj, ctx->req->objcore, ttl,
     ttl_now(ctx) - ctx->req->objcore->t_origin)
+VRT_DO_EXP_R(obj_stale, ctx->bo->stale_oc, grace, 0)
 VRT_DO_EXP_R(obj, ctx->req->objcore, grace, 0)
+VRT_DO_EXP_R(obj_stale, ctx->bo->stale_oc, keep, 0)
 VRT_DO_EXP_R(obj, ctx->req->objcore, keep, 0)
 VRT_DO_EXP_L(beresp, ctx->bo->fetch_objcore, ttl,
     ttl_now(ctx) - ctx->bo->fetch_objcore->t_origin)
@@ -834,6 +839,7 @@ VRT_DO_TIME_R(resp, req, t_resp)
 VRT_DO_TIME_R(bereq, bo, t_first)
 VRT_DO_TIME_R(beresp, bo, t_resp)
 VRT_DO_TIME_R(obj, req->objcore, t_origin)
+VRT_DO_TIME_R(obj_stale, bo->stale_oc, t_origin)
 
 /*--------------------------------------------------------------------
  */
@@ -848,6 +854,7 @@ VRT_r_##which##_##age(VRT_CTX)					\
 	return (ttl_now(ctx) - oc->t_origin);			\
 }
 
+VRT_DO_AGE_R(obj_stale, ctx->bo->stale_oc)
 VRT_DO_AGE_R(obj, ctx->req->objcore)
 VRT_DO_AGE_R(beresp, ctx->bo->fetch_objcore)
 
@@ -1011,6 +1018,28 @@ VRT_r_obj_hits(VRT_CTX)
 
 /*--------------------------------------------------------------------*/
 
+VCL_INT
+VRT_r_obj_stale_hits(VRT_CTX)
+{
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
+	CHECK_OBJ_NOTNULL(ctx->bo->stale_oc, OBJCORE_MAGIC);
+
+	return (ctx->bo->stale_oc->hits);
+}
+
+VCL_BOOL
+VRT_r_obj_stale_is_valid(VRT_CTX)
+{
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
+	CHECK_OBJ_NOTNULL(ctx->bo->stale_oc, OBJCORE_MAGIC);
+
+	return (!(ctx->bo->stale_oc->flags & OC_F_DYING));
+}
+
+/*--------------------------------------------------------------------*/
+
 VCL_BOOL
 VRT_r_resp_is_streaming(VRT_CTX)
 {
diff --git a/doc/sphinx/reference/vcl_var.rst b/doc/sphinx/reference/vcl_var.rst
index 633a2eeb6..627caa15f 100644
--- a/doc/sphinx/reference/vcl_var.rst
+++ b/doc/sphinx/reference/vcl_var.rst
@@ -1429,6 +1429,176 @@ beresp.was_304
 	to our conditional fetch from the backend and turned
 	that into ``beresp.status = 200``
 
+obj_stale
+---------
+
+This is the stale object we had in cache. It cannot be modified.
+
+.. _obj_stale.age:
+
+obj_stale.age
+
+	Type: DURATION
+
+	Readable from: vcl_backend_refresh
+
+	The age of the stale object.
+
+
+.. _obj_stale.can_esi:
+
+obj_stale.can_esi
+
+	Type: BOOL
+
+	Readable from: vcl_backend_refresh
+
+	If the stale object can be ESI processed, that is if setting
+	``resp.do_esi`` or adding ``esi`` to ``resp.filters`` in
+	``vcl_deliver {}`` would cause the response body to be ESI
+	processed.
+
+
+.. _obj_stale.grace:
+
+obj_stale.grace
+
+	Type: DURATION
+
+	Readable from: vcl_backend_refresh
+
+	The stale object's grace period in seconds.
+
+
+.. _obj_stale.hits:
+
+obj_stale.hits
+
+	Type: INT
+
+	Readable from: vcl_backend_refresh
+
+	The count of cache-hits on this stale object.
+
+	In `vcl_deliver` a value of 0 indicates a cache miss.
+
+
+.. _obj_stale.http:
+
+obj_stale.http.*
+
+	Type: HEADER
+
+	Readable from: vcl_backend_refresh
+
+	The HTTP headers stored in the stale object.
+
+	See req.http_ for general notes.
+
+
+.. _obj_stale.keep:
+
+obj_stale.keep
+
+	Type: DURATION
+
+	Readable from: vcl_backend_refresh
+
+	The stale object's keep period in seconds.
+
+
+.. _obj_stale.proto:
+
+obj_stale.proto
+
+	Type: STRING
+
+	Readable from: vcl_backend_refresh
+
+	The HTTP protocol version stored in the stale object.
+
+
+.. _obj_stale.reason:
+
+obj_stale.reason
+
+	Type: STRING
+
+	Readable from: vcl_backend_refresh
+
+
+	The HTTP reason phrase stored in the stale object.
+
+
+.. _obj_stale.status:
+
+obj_stale.status
+
+	Type: INT
+
+	Readable from: vcl_backend_refresh
+
+
+	The HTTP status code stored in the stale object.
+
+	More information in the `HTTP response status`_ section.
+
+
+.. _obj_stale.storage:
+
+obj_stale.storage
+
+	Type: STEVEDORE
+
+	Readable from: vcl_backend_refresh
+
+	The storage backend where this stale object is stored.
+
+
+.. _obj_stale.time:
+
+obj_stale.time
+
+	Type: TIME
+
+	Readable from: vcl_backend_refresh
+
+	The time the stale object was created from the perspective of the
+	server which generated it. This will roughly be equivalent to
+	``now`` - ``obj.age``.
+
+
+.. _obj_stale.ttl:
+
+obj_stale.ttl
+
+	Type: DURATION
+
+	Readable from: vcl_backend_refresh
+
+	The stale object's time to live, in seconds.
+
+
+.. _obj_stale.uncacheable:
+
+obj_stale.uncacheable
+
+	Type: BOOL
+
+	Readable from: vcl_backend_refresh
+
+	Whether the stale object is uncacheable (pass, hit-for-pass or
+	hit-for-miss).
+
+.. _obj_stale.is_valid:
+
+obj_stale.is_valid
+
+	Type: BOOL
+
+	Readable from: vcl_backend_refresh
+
+	Whether the stale object is still valid.
 
 obj
 ---
diff --git a/include/vrt.h b/include/vrt.h
index 730df304a..188ab693e 100644
--- a/include/vrt.h
+++ b/include/vrt.h
@@ -58,6 +58,19 @@
  * binary/load-time compatible, increment MAJOR version
  *
  * XX.X (unreleased)
+ *	VRT_r_obj_stale_age() added
+ *	VRT_r_obj_stale_can_esi() added
+ *	VRT_r_obj_stale_grace() added
+ *	VRT_r_obj_stale_hits() added
+ *	VRT_r_obj_stale_keep() added
+ *	VRT_r_obj_stale_proto() added
+ *	VRT_r_obj_stale_reason() added
+ *	VRT_r_obj_stale_status() added
+ *	VRT_r_obj_stale_storage() added
+ *	VRT_r_obj_stale_time() added
+ *	VRT_r_obj_stale_ttl() added
+ *	VRT_r_obj_stale_uncacheable() added
+ *	enum gethdr_e has new value HDR_OBJ_STALE
  *	typedef hdr_t added
  *	struct gethdr_s.what changed to hdr_t
  *	VRT_VSC_Alloc() renamed to VRT_VSC_Allocv()
@@ -727,7 +740,8 @@ enum gethdr_e {
 	HDR_RESP,
 	HDR_OBJ,
 	HDR_BEREQ,
-	HDR_BERESP
+	HDR_BERESP,
+	HDR_OBJ_STALE
 };
 
 typedef const struct {


More information about the varnish-commit mailing list