[master] 9d73cd1 Make param::nuke_limit a total count of nukes allowed for each object creation.

Poul-Henning Kamp phk at FreeBSD.org
Mon Feb 27 10:44:06 CET 2017


commit 9d73cd1a369f35be867138a81fae2f4d737c9b6c
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Mon Feb 27 09:41:37 2017 +0000

    Make param::nuke_limit a total count of nukes allowed for each
    object creation.
    
    Fixes #1764

diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index c1c2f97..c9fda21 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -321,6 +321,7 @@ struct worker {
 	struct pool_task	task;
 
 	double			lastused;
+	int			strangelove;
 
 	struct v1l		*v1l;
 
diff --git a/bin/varnishd/cache/cache_fetch.c b/bin/varnishd/cache/cache_fetch.c
index 2b701d4..1287f08 100644
--- a/bin/varnishd/cache/cache_fetch.c
+++ b/bin/varnishd/cache/cache_fetch.c
@@ -82,8 +82,7 @@ vbf_allocobj(struct busyobj *bo, unsigned l)
 		oc->ttl = cache_param->shortlived;
 	oc->grace = 0.0;
 	oc->keep = 0.0;
-	return (STV_NewObject(bo->wrk, bo->fetch_objcore,
-	    stv_transient, l));
+	return (STV_NewObject(bo->wrk, bo->fetch_objcore, stv_transient, l));
 }
 
 /*--------------------------------------------------------------------
diff --git a/bin/varnishd/storage/stevedore.c b/bin/varnishd/storage/stevedore.c
index ba9001e..48a3c7b 100644
--- a/bin/varnishd/storage/stevedore.c
+++ b/bin/varnishd/storage/stevedore.c
@@ -84,8 +84,9 @@ STV_NewObject(struct worker *wrk, struct objcore *oc,
 	CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
 	assert(wsl > 0);
 
+	wrk->strangelove = cache_param->nuke_limit;
 	AN(stv->allocobj);
-	if (stv->allocobj(wrk, stv, oc, wsl, cache_param->nuke_limit) == 0)
+	if (stv->allocobj(wrk, stv, oc, wsl) == 0)
 		return (0);
 
 	wrk->stats->n_object++;
diff --git a/bin/varnishd/storage/storage.h b/bin/varnishd/storage/storage.h
index 2b7ae53..8b78326 100644
--- a/bin/varnishd/storage/storage.h
+++ b/bin/varnishd/storage/storage.h
@@ -65,7 +65,7 @@ struct storage {
 typedef void storage_init_f(struct stevedore *, int ac, char * const *av);
 typedef void storage_open_f(struct stevedore *);
 typedef int storage_allocobj_f(struct worker *, const struct stevedore *,
-    struct objcore *, unsigned, int);
+    struct objcore *, unsigned);
 typedef void storage_close_f(const struct stevedore *, int pass);
 typedef int storage_baninfo_f(const struct stevedore *, enum baninfo event,
     const uint8_t *ban, unsigned len);
diff --git a/bin/varnishd/storage/storage_lru.c b/bin/varnishd/storage/storage_lru.c
index 2d650c7..f3588b1 100644
--- a/bin/varnishd/storage/storage_lru.c
+++ b/bin/varnishd/storage/storage_lru.c
@@ -171,6 +171,11 @@ LRU_NukeOne(struct worker *wrk, struct lru *lru)
 	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
 	CHECK_OBJ_NOTNULL(lru, LRU_MAGIC);
 
+	if (wrk->strangelove-- <= 0) {
+		VSLb(wrk->vsl, SLT_ExpKill, "LRU_Exhausted");
+		return (0);
+	}
+
 	/* Find the first currently unused object on the LRU.  */
 	Lck_Lock(&lru->mtx);
 	VTAILQ_FOREACH_SAFE(oc, &lru->lru_head, lru_list, oc2) {
diff --git a/bin/varnishd/storage/storage_persistent.c b/bin/varnishd/storage/storage_persistent.c
index ad2d2a1..9bdf536 100644
--- a/bin/varnishd/storage/storage_persistent.c
+++ b/bin/varnishd/storage/storage_persistent.c
@@ -505,7 +505,7 @@ smp_allocx(const struct stevedore *st, size_t min_size, size_t max_size,
 
 static int __match_proto__(storage_allocobj_f)
 smp_allocobj(struct worker *wrk, const struct stevedore *stv,
-    struct objcore *oc, unsigned wsl, int nuke_limit)
+    struct objcore *oc, unsigned wsl)
 {
 	struct object *o;
 	struct storage *st;
@@ -518,7 +518,6 @@ smp_allocobj(struct worker *wrk, const struct stevedore *stv,
 	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
 	CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
 	CAST_OBJ_NOTNULL(sc, stv->priv, SMP_SC_MAGIC);
-	assert(nuke_limit >= 0);
 
 	/* Don't entertain already dead objects */
 	if (oc->flags & OC_F_DYING)
@@ -535,17 +534,16 @@ smp_allocobj(struct worker *wrk, const struct stevedore *stv,
 	sg = NULL;
 	so = NULL;
 	objidx = 0;
-	for (; nuke_limit >= 0; nuke_limit--) {
+
+	do {
 		st = smp_allocx(stv, ltot, ltot, &so, &objidx, &sg);
 		if (st != NULL && st->space < ltot) {
 			stv->sml_free(st);		// NOP
 			st = NULL;
 		}
-		if (st != NULL)
-			break;
-		if (!nuke_limit || !LRU_NukeOne(wrk, stv->lru))
-			return (0);
-	}
+	} while (st == NULL && LRU_NukeOne(wrk, stv->lru));
+	if (st == NULL)
+		return (0);
 
 	AN(st);
 	AN(sg);
diff --git a/bin/varnishd/storage/storage_simple.c b/bin/varnishd/storage/storage_simple.c
index 0ad45f7..c3bffe9 100644
--- a/bin/varnishd/storage/storage_simple.c
+++ b/bin/varnishd/storage/storage_simple.c
@@ -130,7 +130,7 @@ SML_MkObject(const struct stevedore *stv, struct objcore *oc, void *ptr)
 
 int __match_proto__(storage_allocobj_f)
 SML_allocobj(struct worker *wrk, const struct stevedore *stv,
-    struct objcore *oc, unsigned wsl, int nuke_limit)
+    struct objcore *oc, unsigned wsl)
 {
 	struct object *o;
 	struct storage *st = NULL;
@@ -141,20 +141,19 @@ SML_allocobj(struct worker *wrk, const struct stevedore *stv,
 	CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
 
 	AN(stv->sml_alloc);
-	assert(nuke_limit >= 0);
 
 	ltot = sizeof(struct object) + PRNDUP(wsl);
-	for (; nuke_limit >= 0; nuke_limit--) {
+
+	do {
 		st = stv->sml_alloc(stv, ltot);
 		if (st != NULL && st->space < ltot) {
 			stv->sml_free(st);
 			st = NULL;
 		}
-		if (st != NULL)
-			break;
-		if (!nuke_limit || !LRU_NukeOne(wrk, stv->lru))
-			return (0);
-	}
+	} while (st == NULL && LRU_NukeOne(wrk, stv->lru));
+	if (st == NULL)
+		return (0);
+
 	CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
 	o = SML_MkObject(stv, oc, st->ptr);
 	CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
@@ -342,7 +341,6 @@ objallocwithnuke(struct worker *wrk, const struct stevedore *stv, size_t size,
     int flags)
 {
 	struct storage *st = NULL;
-	unsigned fail;
 
 	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
 	CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
@@ -355,7 +353,7 @@ objallocwithnuke(struct worker *wrk, const struct stevedore *stv, size_t size,
 
 	assert(size <= UINT_MAX);	/* field limit in struct storage */
 
-	for (fail = 0; fail <= cache_param->nuke_limit; fail++) {
+	do {
 		/* try to allocate from it */
 		st = sml_stv_alloc(stv, size, flags);
 		if (st != NULL)
@@ -364,10 +362,8 @@ objallocwithnuke(struct worker *wrk, const struct stevedore *stv, size_t size,
 		/* no luck; try to free some space and keep trying */
 		if (stv->lru == NULL)
 			break;
-		if (fail < cache_param->nuke_limit &&
-		    !LRU_NukeOne(wrk, stv->lru))
-			break;
-	}
+	} while (LRU_NukeOne(wrk, stv->lru));
+
 	CHECK_OBJ_ORNULL(st, STORAGE_MAGIC);
 	return (st);
 }
diff --git a/bin/varnishtest/tests/r01764.vtc b/bin/varnishtest/tests/r01764.vtc
new file mode 100644
index 0000000..e5b8211
--- /dev/null
+++ b/bin/varnishtest/tests/r01764.vtc
@@ -0,0 +1,54 @@
+varnishtest "Test nuke_limit"
+
+server s1 {
+	# First consume (almost) all of the storage
+	rxreq
+	expect req.url == /url1
+	txresp -bodylen 200000
+
+	rxreq
+	expect req.url == /url2
+	txresp -bodylen 200000
+
+	rxreq
+	expect req.url == /url3
+	txresp -bodylen 200000
+
+	rxreq
+	expect req.url == /url4
+	txresp -bodylen 200000
+
+	non_fatal
+	rxreq
+	expect req.url == /url5
+	txresp -bodylen 1000000
+} -start
+
+varnish v1  -arg "-smalloc,1M" -arg "-p nuke_limit=1" -vcl+backend {
+	sub vcl_backend_response {
+		set beresp.do_stream = false;
+	}
+} -start
+
+
+client c1 {
+	txreq -url /url1
+	rxresp
+	expect resp.status == 200
+
+	txreq -url /url2
+	rxresp
+	expect resp.status == 200
+
+	txreq -url /url3
+	rxresp
+	expect resp.status == 200
+
+	txreq -url /url4
+	rxresp
+	expect resp.status == 200
+
+	txreq -url /url5
+	rxresp
+	expect resp.status == 503
+} -run



More information about the varnish-commit mailing list