[master] dd90a88 Minimal locking to prevent two backend fetches from trying to get at uncached req.body at the same time.
Poul-Henning Kamp
phk at varnish-cache.org
Mon Jul 8 14:33:57 CEST 2013
commit dd90a88b1c64b5880f2c4fcd83d3a8d3973d182c
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Mon Jul 8 12:33:26 2013 +0000
Minimal locking to prevent two backend fetches from trying to
get at uncached req.body at the same time.
diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index b673eb1..eaaffb7 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -620,7 +620,7 @@ struct req {
enum req_step req_step;
VTAILQ_ENTRY(req) w_list;
- enum req_body_state_e req_body_status;
+ volatile enum req_body_state_e req_body_status;
struct storagehead body;
struct {
diff --git a/bin/varnishd/cache/cache_http1_fsm.c b/bin/varnishd/cache/cache_http1_fsm.c
index d4a296a..9f150ea 100644
--- a/bin/varnishd/cache/cache_http1_fsm.c
+++ b/bin/varnishd/cache/cache_http1_fsm.c
@@ -490,9 +490,27 @@ HTTP1_IterateReqBody(struct req *req, req_body_iter_f *func, void *priv)
return (0);
case REQ_BODY_PRESENT:
break;
+ case REQ_BODY_DONE:
+ case REQ_BODY_TAKEN:
+ VSLb(req->vsl, SLT_VCL_Error,
+ "Uncached req.body can only be consumed once.");
+ return (-1);
default:
WRONG("Wrong req_body_status in HTTP1_IterateReqBody()");
}
+ Lck_Lock(&req->sp->mtx);
+ if (req->req_body_status == REQ_BODY_PRESENT) {
+ req->req_body_status = REQ_BODY_TAKEN;
+ i = 0;
+ } else
+ i = -1;
+ Lck_Unlock(&req->sp->mtx);
+ if (i) {
+ VSLb(req->vsl, SLT_VCL_Error,
+ "Multiple attempts to access non-cached req.body");
+ return (i);
+ }
+
do {
l = http1_iter_req_body(req, buf, sizeof buf);
if (l < 0) {
@@ -531,11 +549,16 @@ HTTP1_DiscardReqBody(struct req *req)
if (req->req_body_status == REQ_BODY_DONE)
return(0);
+ if (req->req_body_status == REQ_BODY_TAKEN)
+ return(0);
return(HTTP1_IterateReqBody(req, httpq_req_body_discard, NULL));
}
/*----------------------------------------------------------------------
* Cache the req.body if it is smaller than the given size
+ *
+ * This function must be called before any backend fetches are kicked
+ * off to prevent parallelism.
*/
int
diff --git a/bin/varnishd/cache/cache_vrt.c b/bin/varnishd/cache/cache_vrt.c
index 3009e90..c63be80 100644
--- a/bin/varnishd/cache/cache_vrt.c
+++ b/bin/varnishd/cache/cache_vrt.c
@@ -494,6 +494,11 @@ VRT_CacheReqBody(const struct vrt_ctx *ctx, long long maxsize)
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
+ if (ctx->method != VCL_MET_RECV) {
+ VSLb(ctx->vsl, SLT_VCL_Error,
+ "req.body can only be cached in vcl_recv{}");
+ return (0);
+ }
return (HTTP1_CacheReqBody(ctx->req, maxsize));
}
More information about the varnish-commit
mailing list