]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Redesign of request cleanup:
authorBrian Pane <brianp@apache.org>
Sun, 9 Oct 2005 01:37:11 +0000 (01:37 +0000)
committerBrian Pane <brianp@apache.org>
Sun, 9 Oct 2005 01:37:11 +0000 (01:37 +0000)
  - A new End-Of-Request bucket is pushed through the output filter
    chain after the last bucket of the response.
  - This bucket gets destroyed by ap_core_output_filter() after the
    buckets in front of it have been sent.
  - The destroy callback of the EOR bucket invokes the access logger
    and frees the request's pool.

With this change, the request logger now runs after the last byte of
the response is _sent_, rather than after the last byte of the response
is _generated_.  This should make the bytes-sent count in the access
log more accurate in cases where the client closes the connection
midway through the sending of the response.

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

CHANGES
include/http_request.h
modules/http/http_core.c
modules/http/http_request.c
server/Makefile.in
server/eor_bucket.c [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 3dc1066bce9c97bb62fecd17290795faaa4c41eb..337c5ea8a5a2572d5da07eee4844dafaf0a2f5ad 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,12 @@
                                                         -*- coding: utf-8 -*-
 Changes in Apache 2.3.0 async-dev R&D branch
 
+  *) 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
+     of the response is sent; ap_core_output_filter() calls the access logger
+     indirectly when it destroys the EOR bucket. [Brian Pane]
+
   *) Rewrite of ap_core_output_filter to do nonblocking writes [Brian Pane]
 
   *) Added new connection states for handler and write completion
index b158714a601bfaab5e1ce6dea3f319eaf6dd1921..f5b285996fae2035954d1fa193348564c4867957 100644 (file)
@@ -354,6 +354,36 @@ AP_DECLARE(int) ap_location_walk(request_rec *r);
 AP_DECLARE(int) ap_directory_walk(request_rec *r);
 AP_DECLARE(int) ap_file_walk(request_rec *r);
 
+/** End Of REQUEST (EOR) bucket */
+AP_DECLARE_DATA extern const apr_bucket_type_t ap_bucket_type_eor;
+
+/**
+ * Determine if a bucket is an End Of REQUEST (EOR) bucket
+ * @param e The bucket to inspect
+ * @return true or false
+ */
+#define AP_BUCKET_IS_EOR(e)         (e->type == &ap_bucket_type_eor)
+
+/**
+ * Make the bucket passed in an End Of REQUEST (EOR) bucket
+ * @param b The bucket to make into an EOR bucket
+ * @param r The request to destroy when this bucket is destroyed
+ * @return The new bucket, or NULL if allocation failed
+ */
+AP_DECLARE(apr_bucket *) ap_bucket_eor_make(apr_bucket *b, request_rec *r);
+
+/**
+ * Create a bucket referring to an End Of REQUEST (EOR). This bucket
+ * holds a pointer to the request_rec, so that the request can be
+ * destroyed right after all of the output has been sent to the client.
+ *
+ * @param list The freelist from which this bucket should be allocated
+ * @param r The request to destroy when this bucket is destroyed
+ * @return The new bucket, or NULL if allocation failed
+ */
+AP_DECLARE(apr_bucket *) ap_bucket_eor_create(apr_bucket_alloc_t *list,
+                                              request_rec *r);
+
 #ifdef __cplusplus
 }
 #endif
index 894edd2d34fbe0cb04270a38d4a7c983e759848d..968c35add76c66ab3e4a38436640d2c1174a7979 100644 (file)
@@ -143,8 +143,6 @@ static int ap_process_http_async_connection(conn_rec *c)
                  */
                 cs->state = CONN_STATE_READ_REQUEST_LINE;
             }
-
-            apr_pool_destroy(r->pool);
         }
         else {   /* ap_read_request failed - client may have closed */
             cs->state = CONN_STATE_LINGER;
@@ -181,7 +179,6 @@ static int ap_process_http_connection(conn_rec *c)
             break;
  
         ap_update_child_status(c->sbh, SERVER_BUSY_KEEPALIVE, r);
-        apr_pool_destroy(r->pool);
  
         if (ap_graceful_stop_signalled())
             break;
index 22c23af6da6d785023352512fc3f10af0467cff9..27ccb313480ce8992b6cb0dd4103c433d3560aaf 100644 (file)
@@ -234,6 +234,8 @@ static void check_pipeline_flush(request_rec *r)
 void ap_process_request(request_rec *r)
 {
     int access_status;
+    apr_bucket_brigade *bb;
+    apr_bucket *b;
 
     /* Give quick handlers a shot at serving the request on the fast
      * path, bypassing all of the other Apache hooks.
@@ -271,6 +273,15 @@ void ap_process_request(request_rec *r)
         ap_die(access_status, r);
     }
     
+    /* Send an EOR bucket through the output filter chain.  When
+     * this bucket is destroyed, the request will be logged and
+     * its pool will be freed
+     */
+    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+    b = ap_bucket_eor_create(r->connection->bucket_alloc, r);
+    APR_BRIGADE_INSERT_HEAD(bb, b);
+    ap_pass_brigade(r->connection->output_filters, bb);
+
     /*
      * 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
@@ -280,7 +291,6 @@ void ap_process_request(request_rec *r)
      */
     check_pipeline_flush(r);
     ap_update_child_status(r->connection->sbh, SERVER_BUSY_LOG, r);
-    ap_run_log_transaction(r);
     if (ap_extended_status)
         ap_time_process_request(r->connection->sbh, STOP_PREQUEST);
 }
index 8efcb419d4047f30c4189b0d18a431d153fc00c0..a4da96f5484094eb163b3779b6bb2e0f2d0fb358 100644 (file)
@@ -14,7 +14,7 @@ LTLIBRARY_SOURCES = \
        mpm_common.c util_charset.c util_debug.c util_xml.c \
        util_filter.c util_pcre.c exports.c \
        scoreboard.c error_bucket.c protocol.c core.c request.c provider.c \
-       eoc_bucket.c core_filters.c
+       eoc_bucket.c eor_bucket.c core_filters.c
 
 TARGETS = delete-exports $(LTLIBRARY_NAME) $(CORE_IMPLIB_FILE) export_vars.h httpd.exp
 
diff --git a/server/eor_bucket.c b/server/eor_bucket.c
new file mode 100644 (file)
index 0000000..84e5bd2
--- /dev/null
@@ -0,0 +1,66 @@
+/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
+ * applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "httpd.h"
+#include "http_request.h"
+
+static apr_status_t eor_bucket_read(apr_bucket *b, const char **str, 
+                                    apr_size_t *len, apr_read_type_e block)
+{
+    *str = NULL;
+    *len = 0;
+    return APR_SUCCESS;
+}
+
+AP_DECLARE(apr_bucket *) ap_bucket_eor_make(apr_bucket *b, request_rec *r)
+{
+    b->length      = 0;
+    b->start       = 0;
+    b->data        = r;
+    b->type        = &ap_bucket_type_eor;
+    
+    return b;
+}
+
+AP_DECLARE(apr_bucket *) ap_bucket_eor_create(apr_bucket_alloc_t *list,
+                                              request_rec *r)
+{
+    apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
+
+    APR_BUCKET_INIT(b);
+    b->free = apr_bucket_free;
+    b->list = list;
+    return ap_bucket_eor_make(b, r);
+}
+
+static void eor_bucket_destroy(void *data)
+{
+    request_rec *r = (request_rec *)data;
+    if (r != NULL) {
+        ap_run_log_transaction(r);
+        apr_pool_destroy(r->pool);
+    }
+}
+
+AP_DECLARE_DATA const apr_bucket_type_t ap_bucket_type_eor = {
+    "EOR", 5, APR_BUCKET_METADATA,
+    eor_bucket_destroy,
+    eor_bucket_read,
+    apr_bucket_setaside_noop,
+    apr_bucket_split_notimpl,
+    apr_bucket_simple_copy
+};
+