You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2015/10/29 13:20:53 UTC

svn commit: r1711235 - in /httpd/httpd/trunk/modules/http2: h2_conn_io.c h2_h2.c h2_h2.h h2_mplx.c h2_session.c h2_task_queue.c h2_task_queue.h

Author: icing
Date: Thu Oct 29 12:20:53 2015
New Revision: 1711235

URL: http://svn.apache.org/viewvc?rev=1711235&view=rev
Log:
inserting needed flush buckets on master connections again, rewrite task queue for better mem usage and less copying

Modified:
    httpd/httpd/trunk/modules/http2/h2_conn_io.c
    httpd/httpd/trunk/modules/http2/h2_h2.c
    httpd/httpd/trunk/modules/http2/h2_h2.h
    httpd/httpd/trunk/modules/http2/h2_mplx.c
    httpd/httpd/trunk/modules/http2/h2_session.c
    httpd/httpd/trunk/modules/http2/h2_task_queue.c
    httpd/httpd/trunk/modules/http2/h2_task_queue.h

Modified: httpd/httpd/trunk/modules/http2/h2_conn_io.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_conn_io.c?rev=1711235&r1=1711234&r2=1711235&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_conn_io.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_conn_io.c Thu Oct 29 12:20:53 2015
@@ -190,7 +190,7 @@ apr_status_t h2_conn_io_read(h2_conn_io
     return status;
 }
 
-static apr_status_t flush_out(apr_bucket_brigade *bb, void *ctx) 
+static apr_status_t pass_out(apr_bucket_brigade *bb, void *ctx) 
 {
     h2_conn_io *io = (h2_conn_io*)ctx;
     apr_status_t status;
@@ -274,7 +274,7 @@ apr_status_t h2_conn_io_write(h2_conn_io
             apr_size_t avail = io->bufsize - io->buflen;
             if (avail <= 0) {
                 bucketeer_buffer(io);
-                status = flush_out(io->output, io);
+                status = pass_out(io->output, io);
                 io->buflen = 0;
             }
             else if (length > avail) {
@@ -293,7 +293,7 @@ apr_status_t h2_conn_io_write(h2_conn_io
         
     }
     else {
-        status = apr_brigade_write(io->output, flush_out, io, buf, length);
+        status = apr_brigade_write(io->output, pass_out, io, buf, length);
         if (status != APR_SUCCESS) {
             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, io->connection,
                           "h2_conn_io: write error");
@@ -315,8 +315,11 @@ apr_status_t h2_conn_io_flush(h2_conn_io
             bucketeer_buffer(io);
             io->buflen = 0;
         }
+        
+        APR_BRIGADE_INSERT_TAIL(io->output,
+                                apr_bucket_flush_create(io->output->bucket_alloc));
         /* Send it out */
-        status = flush_out(io->output, io);
+        status = pass_out(io->output, io);
         
         if (status != APR_SUCCESS) {
             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, io->connection,

Modified: httpd/httpd/trunk/modules/http2/h2_h2.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_h2.c?rev=1711235&r1=1711234&r2=1711235&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_h2.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_h2.c Thu Oct 29 12:20:53 2015
@@ -64,6 +64,36 @@ static char *(*opt_ssl_var_lookup)(apr_p
                                    conn_rec *, request_rec *,
                                    char *);
 
+
+/*******************************************************************************
+ * HTTP/2 error stuff
+ */
+static const char *h2_err_descr[] = {
+    "no error",                    /* 0x0 */
+    "protocol error",
+    "internal error",
+    "flow control error",
+    "settings timeout",
+    "stream closed",               /* 0x5 */
+    "frame size error",
+    "refused stream",
+    "cancel",
+    "compression error",
+    "connect error",               /* 0xa */
+    "enhance your calm",
+    "inadequate security",
+    "http/1.1 required",
+};
+
+const char *h2_h2_err_description(int h2_error)
+{
+    if (h2_error >= 0 
+        && h2_error < (sizeof(h2_err_descr)/sizeof(h2_err_descr[0]))) {
+        return h2_err_descr[h2_error];
+    }
+    return "unknown http/2 errotr code";
+}
+
 /*******************************************************************************
  * Check connection security requirements of RFC 7540
  */

Modified: httpd/httpd/trunk/modules/http2/h2_h2.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_h2.h?rev=1711235&r1=1711234&r2=1711235&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_h2.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_h2.h Thu Oct 29 12:20:53 2015
@@ -49,6 +49,13 @@ extern const char *H2_MAGIC_TOKEN;
 #define H2_ERR_INADEQUATE_SECURITY  (0x0c)
 #define H2_ERR_HTTP_1_1_REQUIRED    (0x0d)
 
+/**
+ * Provide a user readable description of the HTTP/2 error code-
+ * @param h2_error http/2 error code, as in rfc 7540, ch. 7
+ * @return textual description of code or that it is unknown.
+ */
+const char *h2_h2_err_description(int h2_error);
+
 /*
  * One time, post config intialization.
  */

Modified: httpd/httpd/trunk/modules/http2/h2_mplx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_mplx.c?rev=1711235&r1=1711234&r2=1711235&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_mplx.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_mplx.c Thu Oct 29 12:20:53 2015
@@ -60,10 +60,6 @@ static void h2_mplx_destroy(h2_mplx *m)
 {
     AP_DEBUG_ASSERT(m);
     m->aborted = 1;
-    if (m->q) {
-        h2_tq_destroy(m->q);
-        m->q = NULL;
-    }
     if (m->ready_ios) {
         h2_io_set_destroy(m->ready_ios);
         m->ready_ios = NULL;
@@ -128,7 +124,7 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr
         
         m->bucket_alloc = apr_bucket_alloc_create(m->pool);
         
-        m->q = h2_tq_create(m->pool, 23);
+        m->q = h2_tq_create(m->pool, h2_config_geti(conf, H2_CONF_MAX_STREAMS));
         m->stream_ios = h2_io_set_create(m->pool);
         m->ready_ios = h2_io_set_create(m->pool);
         m->closed = h2_stream_set_create(m->pool);

Modified: httpd/httpd/trunk/modules/http2/h2_session.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_session.c?rev=1711235&r1=1711234&r2=1711235&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_session.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_session.c Thu Oct 29 12:20:53 2015
@@ -313,7 +313,7 @@ static apr_status_t stream_destroy(h2_se
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
                       "h2_stream(%ld-%d): closing with err=%d %s", 
                       session->id, (int)stream->id, (int)error_code,
-                      nghttp2_strerror(error_code));
+                      h2_h2_err_description(error_code));
         h2_stream_rst(stream, error_code);
     }
     
@@ -988,6 +988,7 @@ apr_status_t h2_session_write(h2_session
     
     if (session->reprioritize) {
         h2_mplx_reprioritize(session->mplx, stream_pri_cmp, session);
+        session->reprioritize = 0;
     }
     
     /* Check that any pending window updates are sent. */

Modified: httpd/httpd/trunk/modules/http2/h2_task_queue.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_task_queue.c?rev=1711235&r1=1711234&r2=1711235&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_task_queue.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_task_queue.c Thu Oct 29 12:20:53 2015
@@ -23,26 +23,24 @@
 #include "h2_task_queue.h"
 
 
-static void grow(h2_task_queue *q, int nlen);
-static h2_task *qrm(h2_task_queue *q, int index);
-static void tqsort(h2_task_queue *q, int left, int right,  
-                   h2_tq_cmp *cmp, void *ctx);
+static void tq_grow(h2_task_queue *q, int nlen);
+static void tq_swap(h2_task_queue *q, int i, int j);
+static int tq_bubble_up(h2_task_queue *q, int i, int top, 
+                        h2_tq_cmp *cmp, void *ctx);
+static int tq_bubble_down(h2_task_queue *q, int i, int bottom, 
+                          h2_tq_cmp *cmp, void *ctx);
 
 h2_task_queue *h2_tq_create(apr_pool_t *pool, int capacity)
 {
     h2_task_queue *q = apr_pcalloc(pool, sizeof(h2_task_queue));
     if (q) {
         q->pool = pool;
-        grow(q, capacity);
+        tq_grow(q, capacity);
         q->nelts = 0;
     }
     return q;
 }
 
-void h2_tq_destroy(h2_task_queue *q)
-{
-}
-
 int h2_tq_empty(h2_task_queue *q)
 {
     return q->nelts == 0;
@@ -54,108 +52,111 @@ void h2_tq_add(h2_task_queue *q, struct
     int i;
     
     if (q->nelts >= q->nalloc) {
-        grow(q, q->nalloc * 2);
+        tq_grow(q, q->nalloc * 2);
     }
     
-    /* Assume tasks most commonly arrive in ascending order */
-    for (i = q->nelts; i > 0; --i) {
-        if (cmp(q->elts[i-1], task, ctx) <= 0) {
-            if (i < q->nelts) {
-                memmove(q->elts+i+1, q->elts+i, q->nelts - i);
-            }
-            q->elts[i] = task;
-            q->nelts++;
-            return;
-        }
-    }
-    /* insert at front */
-    if (q->nelts) {
-        memmove(q->elts+1, q->elts, q->nelts);
-    }
-    q->elts[q->nelts++] = task;
+    i = (q->head + q->nelts) % q->nalloc;
+    q->elts[i] = task;
+    ++q->nelts;
+    
+    /* bubble it to the front of the queue */
+    tq_bubble_up(q, i, q->head, cmp, ctx);
 }
 
 void h2_tq_sort(h2_task_queue *q, h2_tq_cmp *cmp, void *ctx)
 {
-    tqsort(q, 0, q->nelts - 1, cmp, ctx);
+    /* Assume that changes in ordering are minimal. This needs,
+     * best case, q->nelts - 1 comparisions to check that nothing
+     * changed.
+     */
+    if (q->nelts > 0) {
+        int i, ni, prev, last;
+        
+        /* Start at the end of the queue and create a tail of sorted
+         * entries. Make that tail one element longer in each iteration.
+         */
+        last = i = (q->head + q->nelts - 1) % q->nalloc;
+        while (i != q->head) {
+            prev = (q->nalloc + i - 1) % q->nalloc;
+            
+            ni = tq_bubble_up(q, i, prev, cmp, ctx);
+            if (ni == prev) {
+                /* i bubbled one up, bubble the new i down, which
+                 * keeps all tasks below i sorted. */
+                tq_bubble_down(q, i, last, cmp, ctx);
+            }
+            i = prev;
+        };
+    }
 }
 
 
-apr_status_t h2_tq_remove(h2_task_queue *q, struct h2_task *task)
+h2_task *h2_tq_shift(h2_task_queue *q)
 {
-    int i;
+    h2_task *t;
     
-    for (i = 0; i < q->nelts; ++i) {
-        if (task == q->elts[i]) {
-            qrm(q, i);
-            return APR_SUCCESS;
-        }
+    if (q->nelts <= 0) {
+        return NULL;
     }
-    return APR_NOTFOUND;
-}
-
-h2_task *h2_tq_shift(h2_task_queue *q)
-{
-    return qrm(q, 0);
+    
+    t = q->elts[q->head];
+    q->head = (q->head + 1) % q->nalloc;
+    q->nelts--;
+    
+    return t;
 }
 
-static void grow(h2_task_queue *q, int nlen)
+static void tq_grow(h2_task_queue *q, int nlen)
 {
     AP_DEBUG_ASSERT(q->nalloc <= nlen);
     if (nlen > q->nalloc) {
         h2_task **nq = apr_pcalloc(q->pool, sizeof(h2_task *) * nlen);
         if (q->nelts > 0) {
-            memmove(nq, q->elts, sizeof(h2_task *) * q->nelts);
+            int l = ((q->head + q->nelts) % q->nalloc) - q->head;
+            
+            memmove(nq, q->elts + q->head, sizeof(h2_task *) * l);
+            if (l < q->nelts) {
+                /* elts wrapped, append elts in [0, remain] to nq */
+                int remain = q->nelts - l;
+                memmove(nq + l, q->elts, sizeof(h2_task *) * remain);
+            }
         }
         q->elts = nq;
         q->nalloc = nlen;
+        q->head = 0;
     }
 }
 
-static h2_task *qrm(h2_task_queue *q, int index)
-{
-    if (index >= q->nelts) {
-        return NULL;
-    }
-    else if (index == q->nelts - 1) {
-        q->nelts--;
-        return q->elts[index];
-    }
-    else {
-        h2_task *t = q->elts[index];
-        q->nelts--;
-        memmove(q->elts+index, q->elts+index+1, 
-                sizeof(q->elts[0]) * (q->nelts - index));
-        return t;
-    }
-}
-
-static void tqswap(h2_task_queue *q, int i, int j)
+static void tq_swap(h2_task_queue *q, int i, int j)
 {
     h2_task *t = q->elts[i];
     q->elts[i] = q->elts[j];
     q->elts[j] = t;
 }
 
-static void tqsort(h2_task_queue *q, int left, int right,  
-                   h2_tq_cmp *cmp, void *ctx) 
+static int tq_bubble_up(h2_task_queue *q, int i, int top, 
+                        h2_tq_cmp *cmp, void *ctx) 
 {
-    int i, last;
-
-    if (left >= right)
-        return;
-    tqswap(q, left, (left + right)/2);
-    last = left;
-    for (i = left+1; i <= right; i++) {
-        if ((*cmp)(q->elts[i], q->elts[left], ctx) < 0) {
-            tqswap(q, ++last, i);
-        }
+    int prev;
+    while (((prev = (q->nalloc + i - 1) % q->nalloc), i != top) 
+           && (*cmp)(q->elts[i], q->elts[prev], ctx) < 0) {
+        tq_swap(q, prev, i);
+        i = prev;
     }
-    tqswap(q, left, last);
-    tqsort(q, left, last-1, cmp, ctx);
-    tqsort(q, last+1, right, cmp, ctx);
+    return i;
 }
 
+static int tq_bubble_down(h2_task_queue *q, int i, int bottom, 
+                          h2_tq_cmp *cmp, void *ctx)
+{
+    int next;
+    while (((next = (q->nalloc + i + 1) % q->nalloc), i != bottom) 
+           && (*cmp)(q->elts[i], q->elts[next], ctx) > 0) {
+        tq_swap(q, next, i);
+        i = next;
+    }
+    return i;
+}
 
 
 

Modified: httpd/httpd/trunk/modules/http2/h2_task_queue.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_task_queue.h?rev=1711235&r1=1711234&r2=1711235&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_task_queue.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_task_queue.h Thu Oct 29 12:20:53 2015
@@ -19,19 +19,33 @@
 struct h2_task;
 
 /**
- * A simple ring of rings that keeps a list of h2_tasks and can
- * be ringed itself, using the APR RING macros.
+ * h2_task_queue keeps a list of sorted h2_task* in ascending order.
  */
 typedef struct h2_task_queue h2_task_queue;
 
 struct h2_task_queue {
-    apr_pool_t *pool;
     struct h2_task **elts;
+    int head;
     int nelts;
     int nalloc;
+    apr_pool_t *pool;
 };
 
 /**
+ * Comparator for two task to determine their order.
+ *
+ * @param t1 task to compare
+ * @param t2 task to compare
+ * @param ctx provided user data
+ * @return value is the same as for strcmp() and has the effect:
+ *    == 0: t1 and t2 are treated equal in ordering
+ *     < 0: t1 should be sorted before t2
+ *     > 0: t2 should be sorted before t1
+ */
+typedef int h2_tq_cmp(struct h2_task *t1, struct h2_task *t2, void *ctx);
+
+
+/**
  * Allocate a new queue from the pool and initialize.
  * @param id the identifier of the queue
  * @param pool the memory pool
@@ -39,53 +53,38 @@ struct h2_task_queue {
 h2_task_queue *h2_tq_create(apr_pool_t *pool, int capacity);
 
 /**
- * Release all queue tasks.
- * @param q the queue to destroy
- */
-void h2_tq_destroy(h2_task_queue *q);
-
-/**
  * Return != 0 iff there are no tasks in the queue.
  * @param q the queue to check
  */
 int h2_tq_empty(h2_task_queue *q);
 
-typedef int h2_tq_cmp(struct h2_task *t1, struct h2_task *t2, void *ctx);
-
 /**
- * Add the task to the sorted queue. For optimiztation, it is assumed
- * that the order of the existing tasks has not changed.
+ * Add the task to the queue. 
  *
  * @param q the queue to append the task to
  * @param task the task to add
- * @param cmp the compare function for sorting
- * @param ctx user data for the compare function 
+ * @param cmp the comparator for sorting
+ * @param ctx user data for comparator 
  */
 void h2_tq_add(h2_task_queue *q, struct h2_task *task,
                h2_tq_cmp *cmp, void *ctx);
 
 /**
- * Sort the tasks queue again. Useful to call if the task order
+ * Sort the tasks queue again. Call if the task ordering
  * has changed.
  *
  * @param q the queue to sort
- * @param cmp the compare function for sorting
- * @param ctx user data for the compare function 
+ * @param cmp the comparator for sorting
+ * @param ctx user data for the comparator 
  */
 void h2_tq_sort(h2_task_queue *q, h2_tq_cmp *cmp, void *ctx);
 
 /**
- * Remove a task from the queue. Return APR_SUCCESS if the task
- * was indeed queued, APR_NOTFOUND otherwise.
- * @param q the queue to remove from
- * @param task the task to remove
- */
-apr_status_t h2_tq_remove(h2_task_queue *q, struct h2_task *task);
-
-/**
  * Get the first task from the queue or NULL if the queue is empty. 
  * The task will be removed.
+ *
  * @param q the queue to get the first task from
+ * @return the first task of the queue, NULL if empty
  */
 h2_task *h2_tq_shift(h2_task_queue *q);