From 41072afb195b843807543d6df2a5f90699f2675c Mon Sep 17 00:00:00 2001 From: phk Date: Mon, 28 Jan 2008 10:28:24 +0000 Subject: [PATCH] Finish (the "easy") part of degraded mode: Add req.grace timer: We only serve degraded mode objects if both the request and the object's grace timers are satisfied. Sort expiry list on obj.ttl + obj.grace and fiddle list if either changes. In the hash lookup: record if any objects still in grace by obj.grace which match our Vary: criteria (if any). If no in-ttl object was found AND we have a graced object AND it is also graced by req.grace AND it is being fetched: serve the graced object. Otherwise, mark us as successor to the graced object while we fetch to give others the chance. When we unbusy the object, clean the magic pointers between the two objects again. To play with this you need at least: sub vcl_recv { set req.grace = 2m; } sub vcl_fetch { set obj.grace = 2m; } git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@2392 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- varnish-cache/bin/varnishd/cache.h | 8 ++++- varnish-cache/bin/varnishd/cache_expire.c | 2 +- varnish-cache/bin/varnishd/cache_hash.c | 38 +++++++++++++++++++--- varnish-cache/bin/varnishd/cache_vrt.c | 23 +++++++++++++ varnish-cache/bin/varnishd/cache_ws.c | 2 +- varnish-cache/include/vrt_obj.h | 2 ++ varnish-cache/lib/libvcl/vcc_fixed_token.c | 2 ++ varnish-cache/lib/libvcl/vcc_gen_obj.tcl | 5 +++ varnish-cache/lib/libvcl/vcc_obj.c | 7 ++++ 9 files changed, 82 insertions(+), 7 deletions(-) diff --git a/varnish-cache/bin/varnishd/cache.h b/varnish-cache/bin/varnishd/cache.h index 9e0c854e..d00f4be7 100644 --- a/varnish-cache/bin/varnishd/cache.h +++ b/varnish-cache/bin/varnishd/cache.h @@ -220,7 +220,6 @@ struct storage { }; /* -------------------------------------------------------------------*/ - enum e_objtimer { TIMER_TTL, TIMER_PREFETCH @@ -271,6 +270,10 @@ struct object { VTAILQ_HEAD(, esi_bit) esibits; double lru_stamp; + + /* Prefetch */ + struct object *parent; + struct object *child; }; struct objhead { @@ -326,6 +329,9 @@ struct sess { double t_resp; double t_end; + /* Acceptable grace period */ + double grace; + enum step step; unsigned cur_method; unsigned handling; diff --git a/varnish-cache/bin/varnishd/cache_expire.c b/varnish-cache/bin/varnishd/cache_expire.c index 2bc616d5..2b93ae71 100644 --- a/varnish-cache/bin/varnishd/cache_expire.c +++ b/varnish-cache/bin/varnishd/cache_expire.c @@ -79,7 +79,7 @@ update_object_when(struct object *o) o->timer_when = o->prefetch; o->timer_what = TIMER_PREFETCH; } else { - o->timer_when = o->ttl; + o->timer_when = o->ttl + o->grace; o->timer_what = TIMER_TTL; } } diff --git a/varnish-cache/bin/varnishd/cache_hash.c b/varnish-cache/bin/varnishd/cache_hash.c index eafa0852..1703daec 100644 --- a/varnish-cache/bin/varnishd/cache_hash.c +++ b/varnish-cache/bin/varnishd/cache_hash.c @@ -173,7 +173,7 @@ HSH_Lookup(struct sess *sp) struct worker *w; struct http *h; struct objhead *oh; - struct object *o, *busy_o; + struct object *o, *busy_o, *grace_o; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); @@ -198,6 +198,7 @@ HSH_Lookup(struct sess *sp) } busy_o = NULL; + grace_o = NULL; VTAILQ_FOREACH(o, &oh->objects, list) { if (o->busy) { busy_o = o; @@ -207,8 +208,6 @@ HSH_Lookup(struct sess *sp) continue; if (o->ttl == 0) continue; - if (o->ttl <= sp->t_req) - continue; if (BAN_CheckObject(o, h->hd[HTTP_HDR_URL].b, oh->hash)) { o->ttl = 0; WSP(sp, SLT_ExpBan, "%u was banned", o->xid); @@ -216,9 +215,27 @@ HSH_Lookup(struct sess *sp) EXP_TTLchange(o); continue; } - if (o->vary == NULL || VRY_Match(sp, o->vary)) + if (o->vary != NULL && !VRY_Match(sp, o->vary)) + continue; + + /* If still valid, use it */ + if (o->ttl >= sp->t_req) break; + + /* Remember any matching objects inside their grace period */ + if (o->ttl + o->grace >= sp->t_req) + grace_o = o; } + + /* + * If we have a object in grace and being fetched, + * use it, if req.grace is also satisified. + */ + if (o == NULL && grace_o != NULL && + grace_o->child != NULL && + grace_o->ttl + sp->grace >= sp->t_req) + o = grace_o; + if (o != NULL) { /* We found an object we like */ o->refcnt++; @@ -239,8 +256,14 @@ HSH_Lookup(struct sess *sp) o = w->nobj; w->nobj = NULL; o->objhead = oh; + /* XXX: Should this not be ..._HEAD now ? */ VTAILQ_INSERT_TAIL(&oh->objects, o, list); /* NB: do not deref objhead the new object inherits our reference */ + if (grace_o != NULL) { + grace_o->child = o; + o->parent = grace_o; + grace_o->refcnt++; + } UNLOCK(&oh->mtx); BAN_NewObj(o); /* @@ -271,6 +294,7 @@ void HSH_Unbusy(struct object *o) { struct objhead *oh; + struct object *parent; CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC); assert(o->busy); @@ -284,8 +308,14 @@ HSH_Unbusy(struct object *o) } o->busy = 0; hsh_rush(oh); + parent = o->parent; + o->parent = NULL; + if (parent != NULL) + parent->child = NULL; if (oh != NULL) UNLOCK(&oh->mtx); + if (parent != NULL) + HSH_Deref(parent); } void diff --git a/varnish-cache/bin/varnishd/cache_vrt.c b/varnish-cache/bin/varnishd/cache_vrt.c index d2e873f7..c43258ec 100644 --- a/varnish-cache/bin/varnishd/cache_vrt.c +++ b/varnish-cache/bin/varnishd/cache_vrt.c @@ -317,6 +317,8 @@ VRT_l_obj_grace(const struct sess *sp, double a) if (a < 0) a = 0; sp->obj->grace = a; + if (sp->obj->timer_idx != 0) + EXP_TTLchange(sp->obj); } double @@ -427,6 +429,27 @@ VRT_r_req_restarts(const struct sess *sp) return (sp->restarts); } +/*-------------------------------------------------------------------- + * req.grace + */ + +void +VRT_l_req_grace(struct sess *sp, double a) +{ + + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + if (a < 0) + a = 0; + sp->grace = a; +} + +double +VRT_r_req_grace(struct sess *sp) +{ + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + return (sp->grace); +} + /*--------------------------------------------------------------------*/ const char * diff --git a/varnish-cache/bin/varnishd/cache_ws.c b/varnish-cache/bin/varnishd/cache_ws.c index 8c7a9ccd..068cb091 100644 --- a/varnish-cache/bin/varnishd/cache_ws.c +++ b/varnish-cache/bin/varnishd/cache_ws.c @@ -46,7 +46,7 @@ #include "cache.h" /* Enable this to get detailed logging of WS usage */ -#ifdef DIAGNOSTICS +#ifdef DIAGNOSTICS0 # define WS_DEBUG(fmt, ...) VSL(SLT_Debug, 0, fmt, __VA_ARGS__) #else # define WS_DEBUG(fmt, ...) /* nothing */ diff --git a/varnish-cache/include/vrt_obj.h b/varnish-cache/include/vrt_obj.h index 8594d775..6c7cef88 100644 --- a/varnish-cache/include/vrt_obj.h +++ b/varnish-cache/include/vrt_obj.h @@ -22,6 +22,8 @@ void VRT_l_req_hash(struct sess *, const char *); struct backend * VRT_r_req_backend(struct sess *); void VRT_l_req_backend(struct sess *, struct backend *); int VRT_r_req_restarts(const struct sess *); +double VRT_r_req_grace(struct sess *); +void VRT_l_req_grace(struct sess *, double); const char * VRT_r_bereq_request(const struct sess *); void VRT_l_bereq_request(const struct sess *, const char *, ...); const char * VRT_r_bereq_url(const struct sess *); diff --git a/varnish-cache/lib/libvcl/vcc_fixed_token.c b/varnish-cache/lib/libvcl/vcc_fixed_token.c index 62ae6638..9d4f2b3f 100644 --- a/varnish-cache/lib/libvcl/vcc_fixed_token.c +++ b/varnish-cache/lib/libvcl/vcc_fixed_token.c @@ -521,6 +521,8 @@ vcl_output_lang_h(struct vsb *sb) vsb_cat(sb, "struct backend * VRT_r_req_backend(struct sess *);\n"); vsb_cat(sb, "void VRT_l_req_backend(struct sess *, struct backend *);\n"); vsb_cat(sb, "int VRT_r_req_restarts(const struct sess *);\n"); + vsb_cat(sb, "double VRT_r_req_grace(const struct sess *);\n"); + vsb_cat(sb, "void VRT_l_req_grace(const struct sess *, double);\n"); vsb_cat(sb, "const char * VRT_r_bereq_request(const struct sess *);\n"); vsb_cat(sb, "void VRT_l_bereq_request(const struct sess *, const char *, ...);\n"); vsb_cat(sb, "const char * VRT_r_bereq_url(const struct sess *);\n"); diff --git a/varnish-cache/lib/libvcl/vcc_gen_obj.tcl b/varnish-cache/lib/libvcl/vcc_gen_obj.tcl index ebc8b1d2..7fcdafbb 100755 --- a/varnish-cache/lib/libvcl/vcc_gen_obj.tcl +++ b/varnish-cache/lib/libvcl/vcc_gen_obj.tcl @@ -97,6 +97,11 @@ set spobj { {recv pipe pass hash miss hit fetch deliver } "const struct sess *" } + { req.grace + RW TIME + {recv pipe pass hash miss hit fetch deliver } + "struct sess *" + } # Request sent to backend { bereq.request diff --git a/varnish-cache/lib/libvcl/vcc_obj.c b/varnish-cache/lib/libvcl/vcc_obj.c index 4f006797..9bdca4db 100644 --- a/varnish-cache/lib/libvcl/vcc_obj.c +++ b/varnish-cache/lib/libvcl/vcc_obj.c @@ -105,6 +105,13 @@ struct var vcc_vars[] = { 0, VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER }, + { "req.grace", TIME, 9, + "VRT_r_req_grace(sp)", + "VRT_l_req_grace(sp, ", + V_RW, + 0, + VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER + }, { "bereq.request", STRING, 13, "VRT_r_bereq_request(sp)", "VRT_l_bereq_request(sp, ", -- 2.39.5