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 2016/10/30 20:38:51 UTC
svn commit: r1767180 - in /httpd/httpd/trunk: CHANGES
modules/http2/NWGNUmod_http2 modules/http2/h2_mplx.c
modules/http2/h2_mplx.h modules/http2/h2_task.c modules/http2/h2_util.c
modules/http2/h2_util.h
Author: icing
Date: Sun Oct 30 20:38:50 2016
New Revision: 1767180
URL: http://svn.apache.org/viewvc?rev=1767180&view=rev
Log:
mod_http2: using int queue instead of ihash for stream output event handling
Modified:
httpd/httpd/trunk/CHANGES
httpd/httpd/trunk/modules/http2/NWGNUmod_http2
httpd/httpd/trunk/modules/http2/h2_mplx.c
httpd/httpd/trunk/modules/http2/h2_mplx.h
httpd/httpd/trunk/modules/http2/h2_task.c
httpd/httpd/trunk/modules/http2/h2_util.c
httpd/httpd/trunk/modules/http2/h2_util.h
Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1767180&r1=1767179&r2=1767180&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Sun Oct 30 20:38:50 2016
@@ -1,7 +1,7 @@
-*- coding: utf-8 -*-
Changes with Apache 2.5.0
- *) mod_http2: allocators from slave connections is released earlier, resulting
+ *) mod_http2: allocators from slave connections are released earlier, resulting
in less overall memory use on busy, long lived connections.
[Stefan Eissing]
Modified: httpd/httpd/trunk/modules/http2/NWGNUmod_http2
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/NWGNUmod_http2?rev=1767180&r1=1767179&r2=1767180&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/NWGNUmod_http2 (original)
+++ httpd/httpd/trunk/modules/http2/NWGNUmod_http2 Sun Oct 30 20:38:50 2016
@@ -355,18 +355,6 @@ $(OBJDIR)/mod_http2.imp : NWGNUmod_http2
@echo $(DL)GEN $@$(DL)
@echo $(DL) (HTTP2)$(DL) > $@
@echo $(DL) http2_module,$(DL) >> $@
- @echo $(DL) h2_ihash_add,$(DL) >> $@
- @echo $(DL) h2_ihash_clear,$(DL) >> $@
- @echo $(DL) h2_ihash_count,$(DL) >> $@
- @echo $(DL) h2_ihash_create,$(DL) >> $@
- @echo $(DL) h2_ihash_empty,$(DL) >> $@
- @echo $(DL) h2_ihash_iter,$(DL) >> $@
- @echo $(DL) h2_ihash_remove,$(DL) >> $@
- @echo $(DL) h2_iq_add,$(DL) >> $@
- @echo $(DL) h2_iq_create,$(DL) >> $@
- @echo $(DL) h2_iq_remove,$(DL) >> $@
- @echo $(DL) h2_log2,$(DL) >> $@
- @echo $(DL) h2_headers_add_h1,$(DL) >> $@
@echo $(DL) nghttp2_is_fatal,$(DL) >> $@
@echo $(DL) nghttp2_option_del,$(DL) >> $@
@echo $(DL) nghttp2_option_new,$(DL) >> $@
Modified: httpd/httpd/trunk/modules/http2/h2_mplx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_mplx.c?rev=1767180&r1=1767179&r2=1767180&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_mplx.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_mplx.c Sun Oct 30 20:38:50 2016
@@ -301,7 +301,7 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr
m->shold = h2_ihash_create(m->pool, offsetof(h2_stream,id));
m->spurge = h2_ihash_create(m->pool, offsetof(h2_stream,id));
m->q = h2_iq_create(m->pool, m->max_streams);
- m->sready = h2_ihash_create(m->pool, offsetof(h2_stream,id));
+ m->readyq = h2_iq_create(m->pool, m->max_streams);
m->tasks = h2_ihash_create(m->pool, offsetof(h2_task,stream_id));
m->redo_tasks = h2_ihash_create(m->pool, offsetof(h2_task, stream_id));
@@ -435,7 +435,6 @@ static void stream_done(h2_mplx *m, h2_s
* stream destruction until the task is done.
*/
h2_iq_remove(m->q, stream->id);
- h2_ihash_remove(m->sready, stream->id);
h2_ihash_remove(m->streams, stream->id);
h2_stream_cleanup(stream);
@@ -786,7 +785,7 @@ apr_status_t h2_mplx_out_trywait(h2_mplx
if (m->aborted) {
status = APR_ECONNABORTED;
}
- else if (!h2_ihash_empty(m->sready)) {
+ else if (!h2_iq_empty(m->readyq)) {
status = APR_SUCCESS;
}
else {
@@ -809,11 +808,9 @@ static void have_out_data_for(h2_mplx *m
{
ap_assert(m);
ap_assert(stream);
- if (!h2_ihash_get(m->sready, stream->id)) {
- h2_ihash_add(m->sready, stream);
- if (m->added_output) {
- apr_thread_cond_signal(m->added_output);
- }
+ h2_iq_append(m->readyq, stream->id);
+ if (m->added_output) {
+ apr_thread_cond_signal(m->added_output);
}
}
@@ -850,7 +847,7 @@ apr_status_t h2_mplx_process(h2_mplx *m,
else {
h2_ihash_add(m->streams, stream);
if (h2_stream_is_ready(stream)) {
- h2_ihash_add(m->sready, stream);
+ h2_iq_append(m->readyq, stream->id);
}
else {
if (!m->need_registration) {
@@ -1357,7 +1354,7 @@ apr_status_t h2_mplx_dispatch_master_eve
{
apr_status_t status;
int acquired;
- int streams[32];
+ int ids[100];
h2_stream *stream;
size_t i, n;
@@ -1367,17 +1364,16 @@ apr_status_t h2_mplx_dispatch_master_eve
/* update input windows for streams */
h2_ihash_iter(m->streams, update_window, m);
- if (on_resume && !h2_ihash_empty(m->sready)) {
- n = h2_ihash_ishift(m->sready, streams, H2_ALEN(streams));
+ if (on_resume && !h2_iq_empty(m->readyq)) {
+ n = h2_iq_mshift(m->readyq, ids, H2_ALEN(ids));
for (i = 0; i < n; ++i) {
- stream = h2_ihash_get(m->streams, streams[i]);
- if (!stream) {
- continue;
+ stream = h2_ihash_get(m->streams, ids[i]);
+ if (stream) {
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, m->c,
+ "h2_mplx(%ld-%d): on_resume",
+ m->id, stream->id);
+ on_resume(on_ctx, stream);
}
- ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, m->c,
- "h2_mplx(%ld-%d): on_resume",
- m->id, stream->id);
- on_resume(on_ctx, stream);
}
}
@@ -1394,7 +1390,7 @@ apr_status_t h2_mplx_keep_active(h2_mplx
if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) {
h2_stream *s = h2_ihash_get(m->streams, stream_id);
if (s) {
- h2_ihash_add(m->sready, s);
+ h2_iq_append(m->readyq, stream_id);
}
leave_mutex(m, acquired);
}
Modified: httpd/httpd/trunk/modules/http2/h2_mplx.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_mplx.h?rev=1767180&r1=1767179&r2=1767180&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_mplx.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_mplx.h Sun Oct 30 20:38:50 2016
@@ -75,7 +75,7 @@ struct h2_mplx {
struct h2_ihash_t *spurge; /* all streams done, ready for destroy */
struct h2_iqueue *q; /* all stream ids that need to be started */
- struct h2_ihash_t *sready; /* all streams ready for output */
+ struct h2_iqueue *readyq; /* all stream ids ready for output */
struct h2_ihash_t *tasks; /* all tasks started and not destroyed */
struct h2_ihash_t *redo_tasks; /* all tasks that need to be redone */
Modified: httpd/httpd/trunk/modules/http2/h2_task.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_task.c?rev=1767180&r1=1767179&r2=1767180&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_task.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_task.c Sun Oct 30 20:38:50 2016
@@ -90,7 +90,7 @@ static apr_status_t open_output(h2_task
return h2_mplx_out_open(task->mplx, task->stream_id, task->output.beam);
}
-static apr_status_t send_out(h2_task *task, apr_bucket_brigade* bb)
+static apr_status_t send_out(h2_task *task, apr_bucket_brigade* bb, int block)
{
apr_off_t written, left;
apr_status_t status;
@@ -99,8 +99,7 @@ static apr_status_t send_out(h2_task *ta
H2_TASK_OUT_LOG(APLOG_TRACE2, task, bb, "h2_task send_out");
/* engines send unblocking */
status = h2_beam_send(task->output.beam, bb,
- task->assigned? APR_NONBLOCK_READ
- : APR_BLOCK_READ);
+ block? APR_BLOCK_READ : APR_NONBLOCK_READ);
if (APR_STATUS_IS_EAGAIN(status)) {
apr_brigade_length(bb, 0, &left);
written -= left;
@@ -130,13 +129,7 @@ static apr_status_t slave_out(h2_task *t
{
apr_bucket *b;
apr_status_t status = APR_SUCCESS;
- int flush = 0;
-
- if (APR_BRIGADE_EMPTY(bb)) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c,
- "h2_slave_out(%s): empty write", task->id);
- return APR_SUCCESS;
- }
+ int flush = 0, blocking;
if (task->frozen) {
h2_util_bb_log(task->c, task->stream_id, APLOG_TRACE2,
@@ -153,57 +146,46 @@ static apr_status_t slave_out(h2_task *t
}
return APR_SUCCESS;
}
-
- /* Attempt to write saved brigade first */
- if (task->output.bb && !APR_BRIGADE_EMPTY(task->output.bb)) {
- status = send_out(task, task->output.bb);
- if (status != APR_SUCCESS) {
- return status;
- }
- }
-
- /* If there is nothing saved (anymore), try to write the brigade passed */
- if ((!task->output.bb || APR_BRIGADE_EMPTY(task->output.bb))
- && !APR_BRIGADE_EMPTY(bb)) {
- /* check if we have a flush before the end-of-request */
- if (!task->output.opened) {
- for (b = APR_BRIGADE_FIRST(bb);
- b != APR_BRIGADE_SENTINEL(bb);
- b = APR_BUCKET_NEXT(b)) {
- if (AP_BUCKET_IS_EOR(b)) {
- break;
- }
- else if (APR_BUCKET_IS_FLUSH(b)) {
- flush = 1;
- }
- }
- }
- status = send_out(task, bb);
- if (status != APR_SUCCESS) {
- return status;
+ /* we send block once we opened the output, so someone is there
+ * reading it *and* the task is not assigned to a h2_req_engine */
+ blocking = (!task->assigned && task->output.opened);
+ if (!task->output.opened) {
+ for (b = APR_BRIGADE_FIRST(bb);
+ b != APR_BRIGADE_SENTINEL(bb);
+ b = APR_BUCKET_NEXT(b)) {
+ if (APR_BUCKET_IS_FLUSH(b)) {
+ flush = 1;
+ break;
+ }
}
}
- /* If the passed brigade is not empty, save it before return */
- if (!APR_BRIGADE_EMPTY(bb)) {
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, task->c, APLOGNO(03405)
- "h2_slave_out(%s): could not write all, saving brigade",
- task->id);
- if (!task->output.bb) {
- task->output.bb = apr_brigade_create(task->pool,
- task->c->bucket_alloc);
- }
- status = ap_save_brigade(f, &task->output.bb, &bb, task->pool);
- if (status != APR_SUCCESS) {
- return status;
+ if (task->output.bb && !APR_BRIGADE_EMPTY(task->output.bb)) {
+ /* still have data buffered from previous attempt.
+ * setaside and append new data and try to pass the complete data */
+ if (!APR_BRIGADE_EMPTY(bb)) {
+ status = ap_save_brigade(f, &task->output.bb, &bb, task->pool);
+ }
+ if (status == APR_SUCCESS) {
+ status = send_out(task, task->output.bb, blocking);
+ }
+ }
+ else {
+ /* no data buffered here, try to pass the brigade directly */
+ status = send_out(task, bb, blocking);
+ if (status == APR_SUCCESS && !APR_BRIGADE_EMPTY(bb)) {
+ /* could not write all, buffer the rest */
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, task->c, APLOGNO(03405)
+ "h2_slave_out(%s): saving brigade",
+ task->id);
+ status = ap_save_brigade(f, &task->output.bb, &bb, task->pool);
+ flush = 1;
}
}
- if (!task->output.opened
- && (flush || h2_beam_get_mem_used(task->output.beam) > (32*1024))) {
- /* if we have enough buffered or we got a flush bucket, open
- * the response now. */
+ if (status == APR_SUCCESS && !task->output.opened && flush) {
+ /* got a flush or could not write all, time to tell someone to read */
status = open_output(task);
}
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, task->c,
Modified: httpd/httpd/trunk/modules/http2/h2_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_util.c?rev=1767180&r1=1767179&r2=1767180&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_util.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_util.c Sun Oct 30 20:38:50 2016
@@ -440,10 +440,12 @@ void h2_iq_add(h2_iqueue *q, int sid, h2
{
int i;
+ if (h2_iq_contains(q, sid)) {
+ return;
+ }
if (q->nelts >= q->nalloc) {
iq_grow(q, q->nalloc * 2);
}
-
i = (q->head + q->nelts) % q->nalloc;
q->elts[i] = sid;
++q->nelts;
@@ -454,6 +456,11 @@ void h2_iq_add(h2_iqueue *q, int sid, h2
}
}
+void h2_iq_append(h2_iqueue *q, int sid)
+{
+ h2_iq_add(q, sid, NULL, NULL);
+}
+
int h2_iq_remove(h2_iqueue *q, int sid)
{
int i;
@@ -522,6 +529,17 @@ int h2_iq_shift(h2_iqueue *q)
return sid;
}
+size_t h2_iq_mshift(h2_iqueue *q, int *pint, size_t max)
+{
+ for (int i = 0; i < max; ++i) {
+ pint[i] = h2_iq_shift(q);
+ if (pint[i] == 0) {
+ break;
+ }
+ }
+ return i;
+}
+
static void iq_grow(h2_iqueue *q, int nlen)
{
if (nlen > q->nalloc) {
@@ -573,6 +591,17 @@ static int iq_bubble_down(h2_iqueue *q,
return i;
}
+int h2_iq_contains(h2_iqueue *q, int sid)
+{
+ int i;
+ for (i = 0; i < q->nelts; ++i) {
+ if (sid == q->elts[(q->head + i) % q->nalloc]) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
/*******************************************************************************
* h2_util for apt_table_t
******************************************************************************/
Modified: httpd/httpd/trunk/modules/http2/h2_util.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_util.h?rev=1767180&r1=1767179&r2=1767180&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_util.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_util.h Sun Oct 30 20:38:50 2016
@@ -116,7 +116,7 @@ int h2_iq_count(h2_iqueue *q);
/**
* Add a stream id to the queue.
*
- * @param q the queue to append the task to
+ * @param q the queue to append the id to
* @param sid the stream id to add
* @param cmp the comparator for sorting
* @param ctx user data for comparator
@@ -124,6 +124,14 @@ int h2_iq_count(h2_iqueue *q);
void h2_iq_add(h2_iqueue *q, int sid, h2_iq_cmp *cmp, void *ctx);
/**
+ * Append the id to the queue if not already present.
+ *
+ * @param q the queue to append the id to
+ * @param sid the id to append
+ */
+void h2_iq_append(h2_iqueue *q, int sid);
+
+/**
* Remove the stream id from the queue. Return != 0 iff task
* was found in queue.
* @param q the task queue
@@ -148,14 +156,33 @@ void h2_iq_clear(h2_iqueue *q);
void h2_iq_sort(h2_iqueue *q, h2_iq_cmp *cmp, void *ctx);
/**
- * Get the first stream id from the queue or NULL if the queue is empty.
- * The task will be removed.
+ * Get the first id from the queue or 0 if the queue is empty.
+ * The id is being removed.
*
- * @param q the queue to get the first task from
- * @return the first stream id of the queue, 0 if empty
+ * @param q the queue to get the first id from
+ * @return the first id of the queue, 0 if empty
*/
int h2_iq_shift(h2_iqueue *q);
+/**
+ * Get the first max ids from the queue. All these ids will be removed.
+ *
+ * @param q the queue to get the first task from
+ * @param pint the int array to receive the values
+ * @param max the maximum number of ids to shift
+ * @return the actual number of ids shifted
+ */
+size_t h2_iq_mshift(h2_iqueue *q, int *pint, size_t max);
+
+/**
+ * Determine if int is in the queue already
+ *
+ * @parm q the queue
+ * @param sid the integer id to check for
+ * @return != 0 iff sid is already in the queue
+ */
+int h2_iq_contains(h2_iqueue *q, int sid);
+
/*******************************************************************************
* common helpers
******************************************************************************/