From: phk Date: Mon, 14 Jan 2008 10:42:56 +0000 (+0000) Subject: Pave more road for prefetch: X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b7277ec81a819813f4cfe240a484fc5e64ba54dc;p=varnish Pave more road for prefetch: Sanity-check values assigned to obj.prefetch from VCL: if before present time or after ttl, SHM a VCL_info message and set obj.prefetch to zero disabling prefetch. Change objects/timer interaction: We only keep track of the first timer for each object (->timer_when) and add a field to remember what we intend to do at that time (->timer_what). Rename heap_idx to timer_idx to group the relevant fields (XXX: it should be accessed through function outside cache_expire.c which should be called cache_timer.c now). Abolish the 30 second advance move to death-row. When the prefetch timer expires, SHM a debug message and don't do anything. Minor polishing and cleanup. Add vcl_prefetch{} to default VCL and set prefetch 30 seconds before ttl. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@2344 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- diff --git a/varnish-cache/bin/varnishd/cache.h b/varnish-cache/bin/varnishd/cache.h index a38821bb..8d7af81b 100644 --- a/varnish-cache/bin/varnishd/cache.h +++ b/varnish-cache/bin/varnishd/cache.h @@ -232,7 +232,13 @@ struct object { struct ws ws_o[1]; unsigned char *vary; - unsigned heap_idx; + double timer_when; + enum { + TIMER_TTL, + TIMER_PREFETCH + } timer_what; + unsigned timer_idx; + unsigned ban_seq; unsigned pass; diff --git a/varnish-cache/bin/varnishd/cache_expire.c b/varnish-cache/bin/varnishd/cache_expire.c index 3f8318a5..2bc616d5 100644 --- a/varnish-cache/bin/varnishd/cache_expire.c +++ b/varnish-cache/bin/varnishd/cache_expire.c @@ -50,7 +50,6 @@ static pthread_t exp_thread; static struct binheap *exp_heap; static MTX exp_mtx; -static unsigned expearly = 30; static VTAILQ_HEAD(,object) exp_deathrow = VTAILQ_HEAD_INITIALIZER(exp_deathrow); static VTAILQ_HEAD(,object) exp_lru = VTAILQ_HEAD_INITIALIZER(exp_lru); @@ -61,6 +60,30 @@ static VTAILQ_HEAD(,object) exp_lru = VTAILQ_HEAD_INITIALIZER(exp_lru); */ static const unsigned lru_target = (unsigned)(-3); +/*-------------------------------------------------------------------- + * Figure out which object timer fires next + */ + +/* When does the timer fire for this object ? */ +static void +update_object_when(struct object *o) +{ + double w; + + w = o->ttl; + if (o->prefetch < 0.0) { + o->timer_when = o->ttl + o->prefetch; + o->timer_what = TIMER_PREFETCH; + } else if (o->prefetch > 0.0) { + assert(o->prefetch <= o->ttl); + o->timer_when = o->prefetch; + o->timer_what = TIMER_PREFETCH; + } else { + o->timer_when = o->ttl; + o->timer_what = TIMER_TTL; + } +} + /*--------------------------------------------------------------------*/ void @@ -68,7 +91,8 @@ EXP_Insert(struct object *o) { CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC); - assert(o->heap_idx == 0); + assert(o->timer_idx == 0); + update_object_when(o); LOCK(&exp_mtx); binheap_insert(exp_heap, o); VTAILQ_INSERT_TAIL(&exp_lru, o, deathrow); @@ -82,7 +106,7 @@ EXP_Touch(struct object *o, double now) CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC); if (o->lru_stamp + params->lru_timeout < now) { LOCK(&exp_mtx); /* XXX: should be ..._TRY */ - if (o->heap_idx != lru_target && o->heap_idx != 0) { + if (o->timer_idx != lru_target && o->timer_idx != 0) { VTAILQ_REMOVE(&exp_lru, o, deathrow); VTAILQ_INSERT_TAIL(&exp_lru, o, deathrow); o->lru_stamp = now; @@ -96,9 +120,10 @@ EXP_TTLchange(struct object *o) { LOCK(&exp_mtx); - if (o->heap_idx != lru_target) { - assert(o->heap_idx != 0); - binheap_delete(exp_heap, o->heap_idx); + if (o->timer_idx != lru_target) { + assert(o->timer_idx != 0); /* XXX: symbolic zero ? */ + update_object_when(o); + binheap_delete(exp_heap, o->timer_idx); binheap_insert(exp_heap, o); } UNLOCK(&exp_mtx); @@ -185,40 +210,58 @@ exp_prefetch(void *arg) LOCK(&exp_mtx); o = binheap_root(exp_heap); CHECK_OBJ_ORNULL(o, OBJECT_MAGIC); - if (o == NULL || o->ttl > t + expearly) { + if (o == NULL || o->timer_when > t) { /* XXX: >= ? */ UNLOCK(&exp_mtx); + WSL_Flush(&ww); AZ(sleep(1)); VCL_Refresh(&sp->vcl); t = TIM_real(); continue; } - binheap_delete(exp_heap, o->heap_idx); - assert(o->heap_idx == 0); + binheap_delete(exp_heap, o->timer_idx); + assert(o->timer_idx == 0); /* Sanity check */ o2 = binheap_root(exp_heap); if (o2 != NULL) - assert(o2->ttl >= o->ttl); + assert(o2->timer_when >= o->timer_when); UNLOCK(&exp_mtx); - WSL(&ww, SLT_ExpPick, 0, "%u", o->xid); - sp->obj = o; - VCL_timeout_method(sp); + WSL(&ww, SLT_ExpPick, 0, "%u %s", o->xid, + o->timer_what == TIMER_PREFETCH ? "prefetch" : "ttl"); - if (sp->handling == VCL_RET_DISCARD) { + if (o->timer_what == TIMER_PREFETCH) { + o->prefetch = 0.0; + update_object_when(o); LOCK(&exp_mtx); - VTAILQ_REMOVE(&exp_lru, o, deathrow); - VTAILQ_INSERT_TAIL(&exp_deathrow, o, deathrow); - VSL_stats->n_deathrow++; + binheap_insert(exp_heap, o); UNLOCK(&exp_mtx); - continue; + sp->obj = o; + VCL_prefetch_method(sp); + if (sp->handling == VCL_RET_FETCH) { + WSL(&ww, SLT_Debug, 0, "Attempt Prefetch %u", + o->xid); + } + } else { /* TIMER_TTL */ + sp->obj = o; + VCL_timeout_method(sp); + + if (sp->handling == VCL_RET_DISCARD) { + LOCK(&exp_mtx); + VTAILQ_REMOVE(&exp_lru, o, deathrow); + VTAILQ_INSERT_TAIL(&exp_deathrow, o, deathrow); + VSL_stats->n_deathrow++; + UNLOCK(&exp_mtx); + } + assert(sp->handling == VCL_RET_DISCARD); } - assert(sp->handling == VCL_RET_DISCARD); } } -/*--------------------------------------------------------------------*/ +/*-------------------------------------------------------------------- + * BinHeap helper functions for objects. + */ static int object_cmp(void *priv, void *a, void *b) @@ -226,19 +269,19 @@ object_cmp(void *priv, void *a, void *b) struct object *aa, *bb; (void)priv; - - aa = a; - bb = b; - return (aa->ttl < bb->ttl); + CAST_OBJ_NOTNULL(aa, a, OBJECT_MAGIC); + CAST_OBJ_NOTNULL(bb, b, OBJECT_MAGIC); + return (aa->timer_when < bb->timer_when); } static void object_update(void *priv, void *p, unsigned u) { - struct object *o = p; + struct object *o; (void)priv; - o->heap_idx = u; + CAST_OBJ_NOTNULL(o, p, OBJECT_MAGIC); + o->timer_idx = u; } /*-------------------------------------------------------------------- @@ -263,9 +306,9 @@ EXP_NukeOne(struct sess *sp) * means that we own the EXP refcnt on this object. */ VTAILQ_REMOVE(&exp_lru, o, deathrow); - binheap_delete(exp_heap, o->heap_idx); - assert(o->heap_idx == 0); - o->heap_idx = lru_target; + binheap_delete(exp_heap, o->timer_idx); + assert(o->timer_idx == 0); + o->timer_idx = lru_target; VSL_stats->n_lru_nuked++; /* May be premature */ } UNLOCK(&exp_mtx); @@ -296,7 +339,7 @@ EXP_NukeOne(struct sess *sp) LOCK(&exp_mtx); VSL_stats->n_lru_nuked--; /* It was premature */ VSL_stats->n_lru_saved++; - o->heap_idx = 0; + o->timer_idx = 0; o->lru_stamp = sp->wrk->used; binheap_insert(exp_heap, o); VTAILQ_INSERT_TAIL(&exp_lru, o, deathrow); diff --git a/varnish-cache/bin/varnishd/cache_hash.c b/varnish-cache/bin/varnishd/cache_hash.c index 26e44b3f..644f4414 100644 --- a/varnish-cache/bin/varnishd/cache_hash.c +++ b/varnish-cache/bin/varnishd/cache_hash.c @@ -216,7 +216,7 @@ HSH_Lookup(struct sess *sp) h->hd[HTTP_HDR_URL].b, oh->hash)) { o->ttl = 0; WSP(sp, SLT_ExpBan, "%u was banned", o->xid); - if (o->heap_idx != 0) + if (o->timer_idx != 0) EXP_TTLchange(o); } else if (o->vary == NULL || VRY_Match(sp, o->vary)) break; diff --git a/varnish-cache/bin/varnishd/cache_vrt.c b/varnish-cache/bin/varnishd/cache_vrt.c index 12cc68fb..9e042fcd 100644 --- a/varnish-cache/bin/varnishd/cache_vrt.c +++ b/varnish-cache/bin/varnishd/cache_vrt.c @@ -292,7 +292,7 @@ VRT_l_obj_ttl(const struct sess *sp, double a) if (a < 0) a = 0; sp->obj->ttl = sp->t_req + a; - if (sp->obj->heap_idx != 0) + if (sp->obj->timer_idx != 0) EXP_TTLchange(sp->obj); } @@ -306,15 +306,31 @@ VRT_r_obj_ttl(const struct sess *sp) /*--------------------------------------------------------------------*/ +/* XXX: the VCL_info messages has unexpected fractions on the ttl */ + void VRT_l_obj_prefetch(const struct sess *sp, double a) { CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC); /* XXX */ - sp->obj->prefetch = a; - if (a > 0.0) - sp->obj->prefetch += sp->t_req; + sp->obj->prefetch = 0.0; + if (a == 0.0) + sp->obj->prefetch = a; + else if (a > 0.0 && a + sp->t_req <= sp->obj->ttl) + sp->obj->prefetch = a + sp->t_req; + else if (a < 0.0 && a + sp->obj->ttl > sp->t_req) + sp->obj->prefetch = a; + else if (a > 0.0) + WSL(sp->wrk, SLT_VCL_info, sp->id, + "XID %u: obj.prefetch (%g) after TTL (%g), ignored.", + sp->obj->xid, a, sp->obj->ttl - sp->t_req); + else /* if (a < 0.0) */ + WSL(sp->wrk, SLT_VCL_info, sp->id, + "XID %u: obj.prefetch (%g) less than ttl (%g), ignored.", + sp->obj->xid, a, sp->obj->ttl - sp->t_req); + if (sp->obj->timer_idx != 0) + EXP_TTLchange(sp->obj); } double diff --git a/varnish-cache/bin/varnishd/mgt_vcc.c b/varnish-cache/bin/varnishd/mgt_vcc.c index 87205772..c6fd3185 100644 --- a/varnish-cache/bin/varnishd/mgt_vcc.c +++ b/varnish-cache/bin/varnishd/mgt_vcc.c @@ -128,6 +128,7 @@ static const char *default_vcl = " if (obj.http.Set-Cookie) {\n" " pass;\n" " }\n" + " set obj.prefetch = -30s;" " insert;\n" "}\n" "sub vcl_deliver {\n" @@ -136,6 +137,9 @@ static const char *default_vcl = "sub vcl_discard {\n" " discard;\n" "}\n" + "sub vcl_prefetch {\n" + " fetch;\n" + "}\n" "sub vcl_timeout {\n" " discard;\n" "}\n"; @@ -278,7 +282,7 @@ mgt_run_cc(const char *source, struct vsb *sb) /* Next, try to load the object into the management process */ if ((dlh = dlopen(of, RTLD_NOW | RTLD_LOCAL)) == NULL) { vsb_printf(sb, - "%s(): failed to load compiled VCL program: %s", + "%s(): failed to load compiled VCL program:\n %s", __func__, dlerror()); unlink(of); free(of); @@ -419,7 +423,7 @@ mgt_vcc_default(const char *b_arg, const char *f_arg, int f_fd, int C_flag) if (C_flag) return (0); if (vf == NULL) { - fprintf(stderr, "VCL compilation failed"); + fprintf(stderr, "\nVCL compilation failed\n"); return (1); } vp = mgt_vcc_add("boot", vf);