[master] 867743f Split rushing of waiting list into two stages: 1 get the req's to be rushed under the oh->mtx. 2 rush them out of the mtx.
Poul-Henning Kamp
phk at FreeBSD.org
Mon May 9 14:28:05 CEST 2016
commit 867743f0257413304c5922b77513201da0b9242b
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Mon May 9 12:26:51 2016 +0000
Split rushing of waiting list into two stages: 1 get the req's to be rushed
under the oh->mtx. 2 rush them out of the mtx.
diff --git a/bin/varnishd/cache/cache_hash.c b/bin/varnishd/cache/cache_hash.c
index cc4e96f..c808494 100644
--- a/bin/varnishd/cache/cache_hash.c
+++ b/bin/varnishd/cache/cache_hash.c
@@ -57,15 +57,21 @@
#include "cache.h"
-
#include "hash/hash_slinger.h"
#include "vsha256.h"
#include "vtim.h"
+struct rush {
+ unsigned magic;
+#define RUSH_MAGIC 0xa1af5f01
+ VTAILQ_HEAD(,req) reqs;
+};
+
static const struct hash_slinger *hash;
static struct objhead *private_oh;
-static void hsh_rush(struct worker *wrk, struct objhead *oh);
+static void hsh_rush1(struct worker *, struct objhead *, struct rush *, int);
+static void hsh_rush2(struct worker *, struct rush *);
/*---------------------------------------------------------------------*/
@@ -258,6 +264,7 @@ HSH_Insert(struct worker *wrk, const void *digest, struct objcore *oc,
struct ban *ban)
{
struct objhead *oh;
+ struct rush rush;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
AN(digest);
@@ -266,6 +273,7 @@ HSH_Insert(struct worker *wrk, const void *digest, struct objcore *oc,
AN(oc->flags & OC_F_BUSY);
AZ(oc->flags & OC_F_PRIVATE);
assert(oc->refcnt == 1);
+ INIT_OBJ(&rush, RUSH_MAGIC);
hsh_prealloc(wrk);
@@ -293,8 +301,9 @@ HSH_Insert(struct worker *wrk, const void *digest, struct objcore *oc,
VTAILQ_INSERT_HEAD(&oh->objcs, oc, hsh_list);
oc->flags &= ~OC_F_BUSY;
if (!VTAILQ_EMPTY(&oh->waitinglist))
- hsh_rush(wrk, oh);
+ hsh_rush1(wrk, oh, &rush, 0);
Lck_Unlock(&oh->mtx);
+ hsh_rush2(wrk, &rush);
}
/*---------------------------------------------------------------------
@@ -495,19 +504,21 @@ HSH_Lookup(struct req *req, struct objcore **ocp, struct objcore **bocp,
}
/*---------------------------------------------------------------------
+ * Pick the req's we are going to rush from the waiting list
*/
static void
-hsh_rush(struct worker *wrk, struct objhead *oh)
+hsh_rush1(struct worker *wrk, struct objhead *oh, struct rush *r, int all)
{
unsigned u;
struct req *req;
- struct sess *sp;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
+ CHECK_OBJ_NOTNULL(r, RUSH_MAGIC);
+ VTAILQ_INIT(&r->reqs);
Lck_AssertHeld(&oh->mtx);
- for (u = 0; u < cache_param->rush_exponent; u++) {
+ for (u = 0; u < cache_param->rush_exponent || all; u++) {
req = VTAILQ_FIRST(&oh->waitinglist);
if (req == NULL)
break;
@@ -515,32 +526,42 @@ hsh_rush(struct worker *wrk, struct objhead *oh)
wrk->stats->busy_wakeup++;
AZ(req->wrk);
VTAILQ_REMOVE(&oh->waitinglist, req, w_list);
+ VTAILQ_INSERT_TAIL(&r->reqs, req, w_list);
+ }
+}
+
+/*---------------------------------------------------------------------
+ * Rush req's that came from waiting list.
+ */
+
+static void
+hsh_rush2(struct worker *wrk, struct rush *r)
+{
+ struct req *req;
+ struct sess *sp;
+
+ CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
+ CHECK_OBJ_NOTNULL(r, RUSH_MAGIC);
+
+ while(!VTAILQ_EMPTY(&r->reqs)) {
+ req = VTAILQ_FIRST(&r->reqs);
+ CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+ VTAILQ_REMOVE(&r->reqs, req, w_list);
DSL(DBG_WAITINGLIST, req->vsl->wid, "off waiting list");
- if (SES_Reschedule_Req(req)) {
- /*
- * In case of overloads, we ditch the entire
- * waiting list.
- */
- wrk->stats->busy_wakeup--;
- while (1) {
- wrk->stats->busy_killed++;
- AN (req->vcl);
- VCL_Rel(&req->vcl);
- sp = req->sp;
- CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
- CNT_AcctLogCharge(wrk->stats, req);
- Req_Release(req);
- SES_Delete(sp, SC_OVERLOAD, NAN);
- req = VTAILQ_FIRST(&oh->waitinglist);
- if (req == NULL)
- break;
- CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
- VTAILQ_REMOVE(&oh->waitinglist, req, w_list);
- DSL(DBG_WAITINGLIST, req->vsl->wid,
- "kill from waiting list");
- }
- break;
- }
+ if (!SES_Reschedule_Req(req))
+ continue;
+ /* Couldn't schedule, ditch */
+ wrk->stats->busy_wakeup--;
+ wrk->stats->busy_killed++;
+ AN (req->vcl);
+ VCL_Rel(&req->vcl);
+ sp = req->sp;
+ CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+ CNT_AcctLogCharge(wrk->stats, req);
+ Req_Release(req);
+ SES_Delete(sp, SC_OVERLOAD, NAN);
+ DSL(DBG_WAITINGLIST, req->vsl->wid, "kill from waiting list");
+ (void)usleep(100000);
}
}
@@ -657,11 +678,13 @@ void
HSH_Unbusy(struct worker *wrk, struct objcore *oc)
{
struct objhead *oh;
+ struct rush rush;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
oh = oc->objhead;
CHECK_OBJ(oh, OBJHEAD_MAGIC);
+ INIT_OBJ(&rush, RUSH_MAGIC);
AN(oc->stobj->stevedore);
AN(oc->flags & OC_F_BUSY);
@@ -684,10 +707,11 @@ HSH_Unbusy(struct worker *wrk, struct objcore *oc)
VTAILQ_INSERT_HEAD(&oh->objcs, oc, hsh_list);
oc->flags &= ~OC_F_BUSY;
if (!VTAILQ_EMPTY(&oh->waitinglist))
- hsh_rush(wrk, oh);
+ hsh_rush1(wrk, oh, &rush, 0);
Lck_Unlock(&oh->mtx);
if (!(oc->flags & OC_F_PRIVATE))
EXP_Insert(wrk, oc);
+ hsh_rush2(wrk, &rush);
}
/*====================================================================
@@ -818,6 +842,7 @@ HSH_DerefObjCore(struct worker *wrk, struct objcore **ocp)
{
struct objcore *oc;
struct objhead *oh;
+ struct rush rush;
unsigned r;
AN(ocp);
@@ -827,6 +852,7 @@ HSH_DerefObjCore(struct worker *wrk, struct objcore **ocp)
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
assert(oc->refcnt > 0);
+ INIT_OBJ(&rush, RUSH_MAGIC);
oh = oc->objhead;
CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
@@ -837,8 +863,9 @@ HSH_DerefObjCore(struct worker *wrk, struct objcore **ocp)
if (!r)
VTAILQ_REMOVE(&oh->objcs, oc, hsh_list);
if (!VTAILQ_EMPTY(&oh->waitinglist))
- hsh_rush(wrk, oh);
+ hsh_rush1(wrk, oh, &rush, 0);
Lck_Unlock(&oh->mtx);
+ hsh_rush2(wrk, &rush);
if (r != 0)
return (r);
@@ -861,10 +888,12 @@ int
HSH_DerefObjHead(struct worker *wrk, struct objhead **poh)
{
struct objhead *oh;
+ struct rush rush;
int r;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
TAKE_OBJ_NOTNULL(oh, poh, OBJHEAD_MAGIC);
+ INIT_OBJ(&rush, RUSH_MAGIC);
if (oh == private_oh) {
assert(VTAILQ_EMPTY(&oh->waitinglist));
@@ -883,16 +912,14 @@ HSH_DerefObjHead(struct worker *wrk, struct objhead **poh)
* just make the hold the same ref's as objcore, that would
* confuse hashers.
*/
- while (!VTAILQ_EMPTY(&oh->waitinglist)) {
- Lck_Lock(&oh->mtx);
- assert(oh->refcnt > 0);
- r = oh->refcnt;
- hsh_rush(wrk, oh);
+ Lck_Lock(&oh->mtx);
+ while (oh->refcnt == 1 && !VTAILQ_EMPTY(&oh->waitinglist)) {
+ hsh_rush1(wrk, oh, &rush, 1);
Lck_Unlock(&oh->mtx);
- if (r > 1)
- break;
- usleep(100000);
+ hsh_rush2(wrk, &rush);
+ Lck_Lock(&oh->mtx);
}
+ Lck_Unlock(&oh->mtx);
assert(oh->refcnt > 0);
r = hash->deref(oh);
More information about the varnish-commit
mailing list