changeset:   1332:14dcf86fc4f3
user:        Nils Goroll <nils.goroll@uplex.de>
date:        Tue Aug 06 16:33:30 2013 +0200
description:
	Expire superseded objects early
	When lookup up a cache object, a grace object which we don't use because we
	have found an object with a valid ttl can be removed from the cache.

	There is no additional lookup cost to do this and the additional time spent
	with the objhead lock held has been minimized.

	Statistic: n_superseded / N superseded objects

diff -r 9772da39f505 -r 14dcf86fc4f3 src/varnish-2.0.3_VSLP/bin/varnishd/cache_hash.c
--- a/src/varnish-2.0.3_VSLP/bin/varnishd/cache_hash.c	Tue Aug 06 09:48:21 2013 +0200
+++ b/src/varnish-2.0.3_VSLP/bin/varnishd/cache_hash.c	Tue Aug 06 16:33:30 2013 +0200
@@ -225,7 +225,7 @@
 {
 	struct worker *w;
 	struct objhead *oh;
-	struct object *o, *busy_o, *grace_o;
+	struct object *o, *busy_o, *grace_o, *sup_o;
 
 	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
 	CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
@@ -279,6 +279,24 @@
 	}
 
 	/*
+	 * If we have found an object we like _and_ a grace object along the
+	 * way, we know that we wont't need the grace object any more
+	 */
+	sup_o = NULL;
+	if (o != NULL && grace_o != NULL && o != grace_o) {
+		sup_o = grace_o;
+		grace_o == NULL;
+
+		/* 
+		 * as we have the oh locked already, avoid taking it another
+		 * time in exp_timer->HSH_Deref
+		 */
+		VTAILQ_REMOVE(&oh->objects, sup_o, list);
+		sup_o->objhead = NULL;
+		/* do the rest on way out outside the oh lock */
+	}
+
+	/*
 	 * If we have a object in grace
 	 * - and req.grace is also satisfied
 	 * - and we're currently fetching the object
@@ -302,7 +320,7 @@
 
 		Lck_Unlock(&oh->mtx);
 		(void)hash->deref(oh);
-		return (o);
+		goto out;
 	}
 
 	if (busy_o != NULL) {
@@ -323,7 +341,8 @@
 		sp->objhead = oh;
 		Lck_Unlock(&oh->mtx);
 
-		return (NULL);
+		o = NULL;
+		goto out;
 	}
 
 	/* Insert (precreated) object in objecthead */
@@ -349,6 +364,23 @@
 	 * XXX: possibly move to when we commit to have it in the cache.
 	 */
 	BAN_NewObj(o);
+	/* return with looking after the sup_o we removed outside oh->mtx */
+
+  out:
+	if (sup_o) {
+		/* this finalizes sup_o->objhead = NULL, but outside the oh lock */
+		(void) hash->deref(oh);
+
+		/*
+		 * exp_timer will pick it up and call HSH_Deref, but because we have
+		 * unset sup_o->objhead above, we won't need the oh lock again
+		 */
+		VSL_stats->n_superseded++;		
+		VSL_stats->n_expired--;
+		sup_o->grace = 0;
+		EXP_Rearm(sup_o);
+	}
+
 	return (o);
 }
 
