[4.1] 365e605 Make param::nuke_limit a total count of nukes allowed for each object creation.

Martin Blix Grydeland martin at varnish-software.com
Thu Jun 15 14:45:06 CEST 2017


commit 365e605627d2b383bcd440dcc0379ae503536a05
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
    
    Conflicts:
    	bin/varnishd/cache/cache_fetch.c
    	bin/varnishd/storage/stevedore.c
    	bin/varnishd/storage/storage.h
    	bin/varnishd/storage/storage_lru.c
    	bin/varnishd/storage/storage_persistent.c
    	bin/varnishd/storage/storage_simple.c

diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index e63fdf0..7dfeff4 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -343,6 +343,7 @@ struct worker {
 	struct pool_task	task;
 
 	double			lastused;
+	int			strangelove;
 
 	struct v1l		*v1l;
 
diff --git a/bin/varnishd/cache/cache_expire.c b/bin/varnishd/cache/cache_expire.c
index 5c27d07..8a7c46b 100644
--- a/bin/varnishd/cache/cache_expire.c
+++ b/bin/varnishd/cache/cache_expire.c
@@ -329,6 +329,10 @@ EXP_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/cache/cache_obj.c b/bin/varnishd/cache/cache_obj.c
index edfd797..3c2eb01 100644
--- a/bin/varnishd/cache/cache_obj.c
+++ b/bin/varnishd/cache/cache_obj.c
@@ -239,7 +239,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);
@@ -252,18 +251,11 @@ objallocwithnuke(struct worker *wrk, const struct stevedore *stv,
 
 	assert(size <= UINT_MAX);	/* field limit in struct storage */
 
-	for (fail = 0; fail <= cache_param->nuke_limit; fail++) {
-		/* try to allocate from it */
-		AN(stv->alloc);
+	AN(stv->alloc);
+	do {
 		st = STV_alloc(stv, size, flags);
-		if (st != NULL)
-			break;
+	} while (st == NULL && EXP_NukeOne(wrk, stv->lru) == 1);
 
-		/* no luck; try to free some space and keep trying */
-		if (fail < cache_param->nuke_limit &&
-		    EXP_NukeOne(wrk, stv->lru) == -1)
-			break;
-	}
 	CHECK_OBJ_ORNULL(st, STORAGE_MAGIC);
 	return (st);
 }
diff --git a/bin/varnishd/storage/stevedore.c b/bin/varnishd/storage/stevedore.c
index 4845dba..d53b845 100644
--- a/bin/varnishd/storage/stevedore.c
+++ b/bin/varnishd/storage/stevedore.c
@@ -259,13 +259,15 @@ STV_NewObject(struct objcore *oc, struct worker *wrk,
     const char *hint, unsigned wsl)
 {
 	struct stevedore *stv, *stv0;
-	int i, j;
+	int j;
 
 	CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
 	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
 	assert(wsl > 0);
 
+	wrk->strangelove = cache_param->nuke_limit;
 	stv = stv0 = stv_pick_stevedore(wrk->vsl, &hint);
+	AN(stv);
 	AN(stv->allocobj);
 	j = stv->allocobj(stv, oc, wsl);
 	if (j == 0 && hint == NULL) {
@@ -275,15 +277,12 @@ STV_NewObject(struct objcore *oc, struct worker *wrk,
 			j = stv->allocobj(stv, oc, wsl);
 		} while (j == 0 && stv != stv0);
 	}
-	if (j == 0) {
+	while (j == 0) {
 		/* no luck; try to free some space and keep trying */
-		for (i = 0; j == 0 && i < cache_param->nuke_limit; i++) {
-			if (EXP_NukeOne(wrk, stv->lru) == -1)
-				break;
-			j = stv->allocobj(stv, oc, wsl);
-		}
+		if (EXP_NukeOne(wrk, stv->lru) != 1)
+			break;
+		j = stv->allocobj(stv, oc, wsl);
 	}
-
 	if (j == 0)
 		return (0);
 
diff --git a/bin/varnishtest/tests/r01764.vtc b/bin/varnishtest/tests/r01764.vtc
new file mode 100644
index 0000000..ba428ef
--- /dev/null
+++ b/bin/varnishtest/tests/r01764.vtc
@@ -0,0 +1,53 @@
+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
+
+	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