Author: rhuijben
Date: Wed Nov 25 12:27:42 2015
New Revision: 1716371

URL: http://svn.apache.org/viewvc?rev=1716371&view=rev
Log:
Remove a lot of bucket reading from the http2 processing by trying to read
a headers bucket before reading the separate lines to fill it.

Before this patch we usually created a header bucket and then read it into
another header bucket.

* buckets/barrier_buckets.c
  (serf_barrier_read_bucket): New function.
  (serf_bucket_type_barrier): Resolve TODO.

* buckets/hpack_buckets.c
  (serf_hpack_decode_read,
   serf_hpack_decode_peek): Remove unneeded check.
  (serf_hpack_decode_read_bucket): New function.

* buckets/response_buckets.c
  (response_context_t): Introduce new substates, to allow skipping
    some parts of processing.
  (serf_bucket_response_create,
   serf_bucket_response_get_headers): Initialize headers on demand.
  (run_machine): Handle the first and last headers read operations
      as specific states to allow reading the headers as a bucket.

Modified:
    serf/trunk/buckets/barrier_buckets.c
    serf/trunk/buckets/hpack_buckets.c
    serf/trunk/buckets/response_buckets.c

Modified: serf/trunk/buckets/barrier_buckets.c
URL: 
http://svn.apache.org/viewvc/serf/trunk/buckets/barrier_buckets.c?rev=1716371&r1=1716370&r2=1716371&view=diff
==============================================================================
--- serf/trunk/buckets/barrier_buckets.c (original)
+++ serf/trunk/buckets/barrier_buckets.c Wed Nov 25 12:27:42 2015
@@ -72,6 +72,20 @@ static apr_status_t serf_barrier_readlin
     return serf_bucket_readline(stream, acceptable, found, data, len);
 }
 
+static serf_bucket_t *serf_barrier_read_bucket(serf_bucket_t *bucket,
+                                               const serf_bucket_type_t *type)
+{
+    serf_bucket_t *stream = bucket->data;
+
+    /* If a not-NULL bucket is returned then the ownership of that bucket may
+       now have been transferred. (See aggregate bucket read support).
+
+       This may affect something in our bucket, like any read does, but
+       we still perform our 'barrier job' of keeping the stream alive. */
+
+    return serf_bucket_read_bucket(stream, type);
+}
+
 static apr_status_t serf_barrier_peek(serf_bucket_t *bucket,
                                      const char **data,
                                      apr_size_t *len)
@@ -118,7 +132,7 @@ const serf_bucket_type_t serf_bucket_typ
     serf_buckets_are_v2,
     serf_barrier_peek,
     serf_barrier_destroy,
-    serf_default_read_bucket, /* ### TODO? */
+    serf_barrier_read_bucket,
     serf_barrier_get_remaining,
     serf_barrier_set_config,
 };

Modified: serf/trunk/buckets/hpack_buckets.c
URL: 
http://svn.apache.org/viewvc/serf/trunk/buckets/hpack_buckets.c?rev=1716371&r1=1716370&r2=1716371&view=diff
==============================================================================
--- serf/trunk/buckets/hpack_buckets.c (original)
+++ serf/trunk/buckets/hpack_buckets.c Wed Nov 25 12:27:42 2015
@@ -1877,7 +1877,7 @@ serf_hpack_decode_read(serf_bucket_t *bu
     apr_status_t status;
 
     status = hpack_process(bucket);
-    if (status || !ctx->agg)
+    if (status)
     {
         *len = 0;
         return (status == SERF_ERROR_EMPTY_READ) ? APR_SUCCESS : status;
@@ -1895,7 +1895,7 @@ serf_hpack_decode_peek(serf_bucket_t *bu
     apr_status_t status;
 
     status = hpack_process(bucket);
-    if (status || !ctx->agg)
+    if (status)
     {
         *len = 0;
         return (status == SERF_ERROR_EMPTY_READ) ? APR_SUCCESS : status;
@@ -1904,6 +1904,18 @@ serf_hpack_decode_peek(serf_bucket_t *bu
     return serf_bucket_peek(ctx->agg, data, len);
 }
 
+static serf_bucket_t *
+serf_hpack_decode_read_bucket(serf_bucket_t *bucket,
+                              const serf_bucket_type_t *type)
+{
+    serf_hpack_decode_ctx_t *ctx = bucket->data;
+
+    if (!ctx->hit_eof)
+        return serf_default_read_bucket(bucket, type);
+    else
+        return serf_bucket_read_bucket(ctx->agg, type);
+}
+
 static apr_status_t
 serf_hpack_decode_set_config(serf_bucket_t *bucket,
                              serf_config_t *config)
@@ -1930,10 +1942,9 @@ static void
 serf_hpack_decode_destroy(serf_bucket_t *bucket)
 {
     serf_hpack_decode_ctx_t *ctx = bucket->data;
-    serf_bucket_destroy(ctx->stream);
 
-    if (ctx->agg)
-        serf_bucket_destroy(ctx->agg);
+    serf_bucket_destroy(ctx->stream);
+    serf_bucket_destroy(ctx->agg);
 
     if (ctx->method)
         serf_bucket_mem_free(bucket->allocator, (void*)ctx->method);
@@ -1960,7 +1971,7 @@ const serf_bucket_type_t serf_bucket_typ
   serf_buckets_are_v2,
   serf_hpack_decode_peek,
   serf_hpack_decode_destroy,
-  serf_default_read_bucket,
+  serf_hpack_decode_read_bucket,
   serf_default_get_remaining,
   serf_hpack_decode_set_config
 };

Modified: serf/trunk/buckets/response_buckets.c
URL: 
http://svn.apache.org/viewvc/serf/trunk/buckets/response_buckets.c?rev=1716371&r1=1716370&r2=1716371&view=diff
==============================================================================
--- serf/trunk/buckets/response_buckets.c (original)
+++ serf/trunk/buckets/response_buckets.c Wed Nov 25 12:27:42 2015
@@ -35,7 +35,9 @@ typedef struct response_context_t {
     enum {
         STATE_STATUS_LINE,      /* reading status line */
         STATE_NEXT_STATUS_LINE,
+        STATE_PRE_HEADERS,
         STATE_HEADERS,          /* reading headers */
+        STATE_PRE_BODY,
         STATE_BODY,             /* reading body */
         STATE_TRAILERS,         /* reading trailers */
         STATE_DONE              /* we've sent EOF */
@@ -87,8 +89,8 @@ serf_bucket_t *serf_bucket_response_crea
     ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
     ctx->stream = stream;
     ctx->body = NULL;
-    ctx->incoming_headers = serf_bucket_headers_create(allocator);
-    ctx->fetch_headers = ctx->incoming_headers;
+    ctx->incoming_headers = NULL;
+    ctx->fetch_headers = NULL;
     ctx->state = STATE_STATUS_LINE;
     ctx->chunked = 0;
     ctx->head_req = 0;
@@ -118,10 +120,21 @@ void serf_bucket_response_decode_content
     ctx->decode_content = decode;
 }
 
-serf_bucket_t *serf_bucket_response_get_headers(
-    serf_bucket_t *bucket)
+serf_bucket_t *serf_bucket_response_get_headers(serf_bucket_t *bucket)
 {
-    return ((response_context_t *)bucket->data)->fetch_headers;
+    response_context_t *ctx = bucket->data;
+
+    if (!ctx->fetch_headers) {
+
+        if (!ctx->incoming_headers) {
+            ctx->incoming_headers = serf_bucket_headers_create(
+                                                        bucket->allocator);
+        }
+
+        ctx->fetch_headers = ctx->incoming_headers;
+    }
+
+    return ctx->fetch_headers;
 }
 
 
@@ -281,7 +294,7 @@ static apr_status_t run_machine(serf_buc
             }
 
             /* Okay... move on to reading the headers. */
-            ctx->state = STATE_HEADERS;
+            ctx->state = STATE_PRE_HEADERS;
         }
         else {
             /* The connection closed before we could get the next
@@ -293,6 +306,34 @@ static apr_status_t run_machine(serf_buc
             }
         }
         break;
+    case STATE_PRE_HEADERS:
+        {
+            serf_bucket_t *read_hdrs;
+
+            ctx->state = STATE_HEADERS;
+
+            /* Perhaps we can just read a headers bucket? */
+            read_hdrs = serf_bucket_read_bucket(ctx->stream,
+                                                &serf_bucket_type_headers);
+
+            if (read_hdrs) {
+                if (ctx->incoming_headers)
+                    serf_bucket_destroy(ctx->incoming_headers);
+
+                ctx->incoming_headers = read_hdrs;
+
+                ctx->state = STATE_PRE_BODY;
+            }
+            else if (!ctx->incoming_headers) {
+                ctx->incoming_headers =
+                    serf_bucket_headers_create(bkt->allocator);
+            }
+
+            if (!ctx->fetch_headers)
+                ctx->fetch_headers = ctx->incoming_headers;
+        }
+        break;
+
     case STATE_HEADERS:
         status = fetch_headers(bkt, ctx);
         if (SERF_BUCKET_READ_ERROR(status))
@@ -301,7 +342,15 @@ static apr_status_t run_machine(serf_buc
         /* If an empty line was read, then we hit the end of the headers.
          * Move on to the body.
          */
-        if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
+        if (ctx->linebuf.state != SERF_LINEBUF_READY || ctx->linebuf.used)
+            break;
+
+        /* Advance the state. */
+        ctx->state = STATE_PRE_BODY;
+        /* fall through */
+
+    case STATE_PRE_BODY:
+        {
             const char *v;
             int chunked = 0;
             int gzip = 0;
@@ -523,7 +572,7 @@ apr_status_t serf_bucket_response_status
      * it is quite possible to advance *and* to return APR_EAGAIN.
      */
     status = run_machine(bkt, ctx);
-    if (ctx->state == STATE_HEADERS) {
+    if (ctx->state != STATE_STATUS_LINE) {
         *sline = ctx->sl;
     }
     else {


Reply via email to