[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