[master] e44815a Turn delivery-side gunzip into a VDP

Poul-Henning Kamp phk at varnish-cache.org
Fri Sep 6 09:00:39 CEST 2013


commit e44815ad1a8bab42d014ebd2ca2cf5708792ec8c
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Thu Sep 5 16:25:08 2013 +0000

    Turn delivery-side gunzip into a VDP

diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index 7115141..d6ae10d 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -696,7 +696,8 @@ struct req {
 #define RES_GUNZIP		(1<<6)
 
 	/* Deliver pipeline */
-	vdp_bytes		*vdps[5];
+#define	N_VDPS			5
+	vdp_bytes		*vdps[N_VDPS];
 	int			vdp_nxt;
 
 	/* Range */
@@ -704,6 +705,9 @@ struct req {
 	ssize_t			range_high;
 	ssize_t			range_off;
 
+	/* Gunzip */
+	struct vgz		*vgz;
+
 	/* Transaction VSL buffer */
 	struct vsl_log		vsl[1];
 
@@ -833,17 +837,44 @@ int HTTP1_IterateReqBody(struct req *req, req_body_iter_f *func, void *priv);
 void V1D_Deliver(struct req *);
 
 static inline int
-VDP(struct req *req, int flush, void *ptr, ssize_t len)
+VDP_bytes(struct req *req, int flush, void *ptr, ssize_t len)
 {
 	int i, retval;
 
+	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+
 	/* Call the present layer, while pointing to the next layer down */
 	i = req->vdp_nxt--;
+	assert(i >= 0 && i < N_VDPS);
 	retval = req->vdps[i](req, flush, ptr, len);
 	req->vdp_nxt++;
 	return (retval);
 }
 
+static inline void
+VDP_push(struct req *req, vdp_bytes *func)
+{
+	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+	AN(func);
+
+	/* Push another layer */
+	assert(req->vdp_nxt >= 0);
+	assert(req->vdp_nxt + 1 < N_VDPS);
+	req->vdps[++req->vdp_nxt] = func;
+}
+
+static inline void
+VDP_pop(struct req *req, vdp_bytes *func)
+{
+	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+
+	/* Pop top layer */
+	assert(req->vdp_nxt >= 1);
+	assert(req->vdp_nxt < N_VDPS);
+	assert(req->vdps[req->vdp_nxt] == func);
+	req->vdp_nxt--;
+}
+
 /* cache_req_fsm.c [CNT] */
 enum req_fsm_nxt CNT_Request(struct worker *, struct req *);
 
@@ -911,6 +942,7 @@ enum vgzret_e VGZ_Gzip(struct vgz *, const void **, size_t *len, enum vgz_flag);
 enum vgzret_e VGZ_Gunzip(struct vgz *, const void **, size_t *len);
 enum vgzret_e VGZ_Destroy(struct vgz **);
 void VGZ_UpdateObj(const struct vgz*, struct object *);
+vdp_bytes VDP_gunzip;
 
 int VGZ_WrwInit(struct vgz *vg);
 enum vgzret_e VGZ_WrwGunzip(struct req *, struct vgz *, const void *ibuf,
diff --git a/bin/varnishd/cache/cache_gzip.c b/bin/varnishd/cache/cache_gzip.c
index a5b2cbd..6bbf07a 100644
--- a/bin/varnishd/cache/cache_gzip.c
+++ b/bin/varnishd/cache/cache_gzip.c
@@ -311,6 +311,53 @@ VGZ_WrwInit(struct vgz *vg)
 }
 
 /*--------------------------------------------------------------------
+ * VDP for gunzip'ing
+ */
+
+int __match_proto__(vdp_bytes)
+VDP_gunzip(struct req *req, int flush, void *ptr, ssize_t len)
+{
+	enum vgzret_e vr;
+	size_t dl;
+	const void *dp;
+	struct worker *wrk;
+	struct vgz *vg;
+
+	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+	wrk = req->wrk;
+	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
+	vg = req->vgz;
+	CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
+	AN(vg->m_buf);
+
+	if (len == 0) {
+		AN(flush);
+		return (VDP_bytes(req, 1, vg->m_buf, vg->m_len));
+	}
+
+	VGZ_Ibuf(vg, ptr, len);
+	do {
+		if (vg->m_len == vg->m_sz)
+			vr = VGZ_STUCK;
+		else {
+			vr = VGZ_Gunzip(vg, &dp, &dl);
+			vg->m_len += dl;
+		}
+		if (vr < VGZ_OK)
+			return (-1);
+		if (vg->m_len == vg->m_sz || vr == VGZ_STUCK) {
+			if (VDP_bytes(req, 1, vg->m_buf, vg->m_len))
+				return (-1);
+			vg->m_len = 0;
+			VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
+		}
+	} while (!VGZ_IbufEmpty(vg));
+	assert(vr == VGZ_STUCK || vr == VGZ_OK || vr == VGZ_END);
+	return (0);
+}
+
+
+/*--------------------------------------------------------------------
  * Gunzip ibuf into outb, if it runs full, emit it with WRW.
  * Leave flushing to caller, more data may be coming.
  */
@@ -342,7 +389,7 @@ VGZ_WrwGunzip(struct req *req, struct vgz *vg, const void *ibuf,
 		if (vr < VGZ_OK)
 			return (vr);
 		if (vg->m_len == vg->m_sz || vr == VGZ_STUCK) {
-			(void)VDP(req, 1, vg->m_buf, vg->m_len);
+			(void)VDP_bytes(req, 1, vg->m_buf, vg->m_len);
 			vg->m_len = 0;
 			VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
 		}
@@ -367,7 +414,7 @@ VGZ_WrwFlush(struct req *req, struct vgz *vg)
 	if (vg->m_len ==  0)
 		return;
 
-	(void)VDP(req, 1, vg->m_buf, vg->m_len);
+	(void)VDP_bytes(req, 1, vg->m_buf, vg->m_len);
 	vg->m_len = 0;
 	VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
 }
diff --git a/bin/varnishd/cache/cache_http1_deliver.c b/bin/varnishd/cache/cache_http1_deliver.c
index 6abae76..1d111e9 100644
--- a/bin/varnishd/cache/cache_http1_deliver.c
+++ b/bin/varnishd/cache/cache_http1_deliver.c
@@ -77,7 +77,7 @@ v1d_range_bytes(struct req *req, int flush, void *ptr, ssize_t len)
 	if (l > len)
 		l = len;
 	if (flush || l > 0)
-		retval = VDP(req, flush, p, l);
+		retval = VDP_bytes(req, flush, p, l);
 	req->range_off += len;
 	return (retval);
 }
@@ -147,45 +147,7 @@ v1d_dorange(struct req *req, const char *r)
 	req->range_off = 0;
 	req->range_low = low;
 	req->range_high = high + 1;
-	req->vdps[++req->vdp_nxt] = v1d_range_bytes;
-}
-
-/*--------------------------------------------------------------------
- * We have a gzip'ed object and need to ungzip it for a client which
- * does not understand gzip.
- * XXX: handle invalid gzip data better (how ?)
- */
-
-static void
-v1d_WriteGunzipObj(struct req *req)
-{
-	unsigned u = 0;
-	struct vgz *vg;
-	struct objiter *oi;
-	void *ptr;
-	ssize_t len;
-	int i;
-
-	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
-
-	vg = VGZ_NewUngzip(req->vsl, "U D -");
-	AZ(VGZ_WrwInit(vg));
-
-	oi = ObjIterBegin(req->obj);
-	XXXAN(oi);
-
-	while (ObjIter(oi, &ptr, &len)) {
-		CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
-		u += len;
-
-		i = VGZ_WrwGunzip(req, vg, ptr, len);
-		/* XXX: error check */
-		(void)i;
-	}
-	VGZ_WrwFlush(req, vg);
-	(void)VGZ_Destroy(&vg);
-	assert(u == req->obj->len);
-	ObjIterEnd(&oi);
+	VDP_push(req, v1d_range_bytes);
 }
 
 /*--------------------------------------------------------------------*/
@@ -203,9 +165,10 @@ v1d_WriteDirObj(struct req *req)
 	XXXAN(oi);
 
 	while (ObjIter(oi, &ptr, &len)) {
-		if (VDP(req, 0,  ptr, len))
+		if (VDP_bytes(req, 0,  ptr, len))
 			break;
 	}
+	(void)VDP_bytes(req, 1,  NULL, 0);
 	ObjIterEnd(&oi);
 }
 
@@ -329,9 +292,19 @@ V1D_Deliver(struct req *req)
 		ESI_DeliverChild(req);
 	} else if (req->res_mode & RES_ESI_CHILD &&
 	    !req->gzip_resp && req->obj->gziped) {
-		v1d_WriteGunzipObj(req);
+		VDP_push(req, VDP_gunzip);
+		req->vgz = VGZ_NewUngzip(req->vsl, "U D -");
+		AZ(VGZ_WrwInit(req->vgz));
+		v1d_WriteDirObj(req);
+		(void)VGZ_Destroy(&req->vgz);
+		VDP_pop(req, VDP_gunzip);
 	} else if (req->res_mode & RES_GUNZIP) {
-		v1d_WriteGunzipObj(req);
+		VDP_push(req, VDP_gunzip);
+		req->vgz = VGZ_NewUngzip(req->vsl, "U D -");
+		AZ(VGZ_WrwInit(req->vgz));
+		v1d_WriteDirObj(req);
+		(void)VGZ_Destroy(&req->vgz);
+		VDP_pop(req, VDP_gunzip);
 	} else {
 		v1d_WriteDirObj(req);
 	}



More information about the varnish-commit mailing list