[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