]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Refactored ap_process_request() so that in async MPMs, the MPM (and not
authorBrian Pane <brianp@apache.org>
Sun, 9 Oct 2005 04:49:52 +0000 (04:49 +0000)
committerBrian Pane <brianp@apache.org>
Sun, 9 Oct 2005 04:49:52 +0000 (04:49 +0000)
the httpd core) is responsible for write completion.

Note that, with this commit, the Event MPM is still doing write
completion synchronously.  I'll add async write completion as a
separate commit.

Note also that this commit breaks the (experimental) Leader/Followers
MPM on the (equally experimental) async-dev branch.  The fix is to add
either synchronous or asynchronous write completion to that MPM.  Rather
than hack in synchronous write completion, I'll revisit Leader/Followers
once I have async working in Event.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/async-dev@307362 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
include/http_request.h
modules/http/http_core.c
modules/http/http_request.c
server/mpm/experimental/event/event.c

diff --git a/CHANGES b/CHANGES
index 337c5ea8a5a2572d5da07eee4844dafaf0a2f5ad..d2a71f7c07b0e88ba5a3c86fb52fa8de2e3885d3 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                         -*- coding: utf-8 -*-
 Changes in Apache 2.3.0 async-dev R&D branch
 
+  *) For asynchronous MPMs, moved responsibility for write completion from
+     the core to the MPM.  [Brian Pane]
+
   *) Added an End-Of-Request bucket type.  The logging of a request and
      the freeing of its pool are now done when the EOR bucket is destroyed.
      This has the effect of delaying the logging until right after the last
index b36e8266bd4573f172fb634bfa79f67ea90b0bee..c76219bb43e0893b23c89f697246695590bf21c6 100644 (file)
@@ -237,11 +237,20 @@ AP_DECLARE(void) ap_allow_standard_methods(request_rec *r, int reset, ...);
 
 #ifdef CORE_PRIVATE
 /**
- * Process a top-level request from a client
+ * Process a top-level request from a client, and synchronously write
+ * the response to the client
  * @param r The current request
  */
 void ap_process_request(request_rec *);
 
+/**
+ * Process a top-level request from a client, allowing some or all of
+ * the response to remain buffered in the core output filter for later,
+ * asynchronous write completion
+ * @param r The current request
+ */
+void ap_process_async_request(request_rec *);
+
 /**
  * Kill the current request
  * @param type Why the request is dieing
index 968c35add76c66ab3e4a38436640d2c1174a7979..1e9438836032e481cb558db35a4e5eda7b3a3e6d 100644 (file)
@@ -130,19 +130,10 @@ static int ap_process_http_async_connection(conn_rec *c)
             if (ap_extended_status)
                 ap_increment_counts(c->sbh, r);
 
-            if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted 
-                    || ap_graceful_stop_signalled()) {
+            if (cs->state != CONN_STATE_WRITE_COMPLETION) {
+                /* Something went wrong; close the connection */
                 cs->state = CONN_STATE_LINGER;
             }
-            else if (!c->data_in_input_filters) {
-                cs->state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
-            }
-            else {
-                /* else we are pipelining.  Return to READ_REQUEST_LINE state
-                 *  and stay in the loop
-                 */
-                cs->state = CONN_STATE_READ_REQUEST_LINE;
-            }
         }
         else {   /* ap_read_request failed - client may have closed */
             cs->state = CONN_STATE_LINGER;
index 27ccb313480ce8992b6cb0dd4103c433d3560aaf..b8a3a2cc75958dc3f4d683aa178189ef8c4d2773 100644 (file)
@@ -191,51 +191,29 @@ AP_DECLARE(void) ap_die(int type, request_rec *r)
     ap_send_error_response(r_1st_err, recursive_error);
 }
 
-static void check_pipeline_flush(request_rec *r)
+/* Check whether there's another request ready to be read
+ */
+static void check_pipeline(conn_rec *c)
 {
-    apr_bucket *e;
-    apr_bucket_brigade *bb;
-    conn_rec *c = r->connection;
-    /* ### if would be nice if we could PEEK without a brigade. that would
-       ### allow us to defer creation of the brigade to when we actually
-       ### need to send a FLUSH. */
-    bb = apr_brigade_create(r->pool, c->bucket_alloc);
-
-    /* Flush the filter contents if:
-     *
-     *   1) the connection will be closed
-     *   2) there isn't a request ready to be read
-     */
-    /* ### shouldn't this read from the connection input filters? */
     /* ### is zero correct? that means "read one line" */
-    if (r->connection->keepalive != AP_CONN_CLOSE) {
-        if (ap_get_brigade(r->input_filters, bb, AP_MODE_EATCRLF, 
+    if (c->keepalive != AP_CONN_CLOSE) {
+        apr_bucket_brigade *bb = apr_brigade_create(c->pool, c->bucket_alloc);
+        if (ap_get_brigade(c->input_filters, bb, AP_MODE_EATCRLF, 
                        APR_NONBLOCK_READ, 0) != APR_SUCCESS) {
             c->data_in_input_filters = 0;  /* we got APR_EOF or an error */
         }
         else {
             c->data_in_input_filters = 1;
-            return;    /* don't flush */
         }
     }
-
-        e = apr_bucket_flush_create(c->bucket_alloc);
-
-        /* We just send directly to the connection based filters.  At
-         * this point, we know that we have seen all of the data
-         * (request finalization sent an EOS bucket, which empties all
-         * of the request filters). We just want to flush the buckets
-         * if something hasn't been sent to the network yet.
-         */
-        APR_BRIGADE_INSERT_HEAD(bb, e);
-        ap_pass_brigade(r->connection->output_filters, bb);
 }
 
-void ap_process_request(request_rec *r)
+void ap_process_async_request(request_rec *r)
 {
     int access_status;
     apr_bucket_brigade *bb;
     apr_bucket *b;
+    conn_rec *c = r->connection;
 
     /* Give quick handlers a shot at serving the request on the fast
      * path, bypassing all of the other Apache hooks.
@@ -281,18 +259,28 @@ void ap_process_request(request_rec *r)
     b = ap_bucket_eor_create(r->connection->bucket_alloc, r);
     APR_BRIGADE_INSERT_HEAD(bb, b);
     ap_pass_brigade(r->connection->output_filters, bb);
+    c->cs->state = CONN_STATE_WRITE_COMPLETION;
+    check_pipeline(c);
+}
 
-    /*
-     * We want to flush the last packet if this isn't a pipelining connection
-     * *before* we start into logging.  Suppose that the logging causes a DNS
-     * lookup to occur, which may have a high latency.  If we hold off on
-     * this packet, then it'll appear like the link is stalled when really
-     * it's the application that's stalled.
-     */
-    check_pipeline_flush(r);
-    ap_update_child_status(r->connection->sbh, SERVER_BUSY_LOG, r);
-    if (ap_extended_status)
+void ap_process_request(request_rec *r)
+{
+    apr_bucket_brigade *bb;
+    apr_bucket *b;
+    conn_rec *c = r->connection;
+
+    ap_process_async_request(r);
+
+    if (!c->data_in_input_filters) {
+        bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+        b = apr_bucket_flush_create(c->bucket_alloc);
+        APR_BRIGADE_INSERT_HEAD(bb, b);
+        ap_pass_brigade(r->connection->output_filters, bb);
+        ap_update_child_status(r->connection->sbh, SERVER_BUSY_LOG, r);
+    }
+    if (ap_extended_status) {
         ap_time_process_request(r->connection->sbh, STOP_PREQUEST);
+    }
 }
 
 static apr_table_t *rename_original_env(apr_pool_t *p, apr_table_t *t)
index 72ba228b095f5c23f8d11c247ed08970cd512532..6bee16cb07f622316e41d8e28fa0327d44d2e7ae 100644 (file)
@@ -636,6 +636,27 @@ static int process_socket(apr_pool_t * p, apr_socket_t * sock,
             cs->state = CONN_STATE_LINGER;
         }
     }
+    
+    if (cs->state == CONN_STATE_WRITE_COMPLETION) {
+        /* For now, do blocking writes in this thread to transfer the
+         * rest of the response.  TODO: Hand off this connection to a
+         * pollset for asynchronous write completion.
+         */
+        apr_bucket_brigade *bb = apr_brigade_create(c->pool, c->bucket_alloc);
+        apr_bucket *b = apr_bucket_flush_create(c->bucket_alloc);
+        APR_BRIGADE_INSERT_HEAD(bb, b);
+        ap_pass_brigade(c->output_filters, bb);
+        if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted || 
+            ap_graceful_stop_signalled()) {
+            c->cs->state = CONN_STATE_LINGER;
+        }
+        else if (c->data_in_input_filters) {
+            cs->state = CONN_STATE_READ_REQUEST_LINE;
+        }
+        else {
+            cs->state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
+        }
+    }
 
     if (cs->state == CONN_STATE_LINGER) {
         ap_lingering_close(c);