You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by gs...@apache.org on 2001/01/24 02:31:00 UTC

cvs commit: httpd-2.0/modules/http http_core.c http_protocol.c

gstein      01/01/23 17:31:00

  Modified:    include  http_protocol.h
               modules/http http_core.c http_protocol.c
  Log:
  Improve the performance of the ap_r* functions by buffering their data in
  [the context of] a new filter ("OLD_WRITE").
  
  Further information/discussion of this patch is available on new-httpd
  between Jan 16 and Jan 23, 2001.
  
  Revision  Changes    Path
  1.45      +1 -0      httpd-2.0/include/http_protocol.h
  
  Index: http_protocol.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/include/http_protocol.h,v
  retrieving revision 1.44
  retrieving revision 1.45
  diff -u -u -r1.44 -r1.45
  --- http_protocol.h	2001/01/22 23:07:23	1.44
  +++ http_protocol.h	2001/01/24 01:30:59	1.45
  @@ -107,6 +107,7 @@
   AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, apr_bucket_brigade *b);
   AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_length_filter(ap_filter_t *, 
                                                                 apr_bucket_brigade *);
  +AP_CORE_DECLARE_NONSTD(apr_status_t) ap_old_write_filter(ap_filter_t *f, apr_bucket_brigade *b);
   
   /* Send the response to special method requests */
   
  
  
  
  1.244     +2 -0      httpd-2.0/modules/http/http_core.c
  
  Index: http_core.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/http/http_core.c,v
  retrieving revision 1.243
  retrieving revision 1.244
  diff -u -u -r1.243 -r1.244
  --- http_core.c	2001/01/23 23:23:37	1.243
  +++ http_core.c	2001/01/24 01:31:00	1.244
  @@ -3562,6 +3562,8 @@
                                 AP_FTYPE_CONTENT);
       ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_TRANSCODE);
       ap_register_output_filter("COALESCE", coalesce_filter, AP_FTYPE_CONTENT);
  +    ap_register_output_filter("OLD_WRITE", ap_old_write_filter,
  +                              AP_FTYPE_CONTENT - 1);
   }
   
   AP_DECLARE_DATA module core_module = {
  
  
  
  1.272     +154 -37   httpd-2.0/modules/http/http_protocol.c
  
  Index: http_protocol.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/http/http_protocol.c,v
  retrieving revision 1.271
  retrieving revision 1.272
  diff -u -u -r1.271 -r1.272
  --- http_protocol.c	2001/01/23 07:30:11	1.271
  +++ http_protocol.c	2001/01/24 01:31:00	1.272
  @@ -2945,28 +2945,146 @@
   }
   #endif /* APR_HAS_MMAP */
   
  +typedef struct {
  +    char *buf;
  +    char *cur;
  +    apr_size_t avail;
  +} old_write_filter_ctx;
  +
  +AP_CORE_DECLARE_NONSTD(apr_status_t) ap_old_write_filter(
  +    ap_filter_t *f, apr_bucket_brigade *bb)
  +{
  +    old_write_filter_ctx *ctx = f->ctx;
  +
  +    AP_DEBUG_ASSERT(ctx);
  +
  +    if (ctx->buf != NULL) {
  +        apr_size_t nbyte = ctx->cur - ctx->buf;
  +
  +        if (nbyte != 0) {
  +            /* whatever is coming down the pipe (we don't care), we
  +               can simply insert our buffered data at the front and
  +               pass the whole bundle down the chain. */
  +            apr_bucket *b = apr_bucket_create_heap(ctx->buf, nbyte, 0, NULL);
  +            APR_BRIGADE_INSERT_HEAD(bb, b);
  +            ctx->buf = NULL;
  +        }
  +    }
  +
  +    return ap_pass_brigade(f->next, bb);
  +}
  +
  +static apr_status_t flush_buffer(request_rec *r, old_write_filter_ctx *ctx,
  +                                 const char *extra, apr_size_t extra_len)
  +{
  +    apr_bucket_brigade *bb = apr_brigade_create(r->pool);
  +    apr_size_t nbyte = ctx->cur - ctx->buf;
  +    apr_bucket *b = apr_bucket_create_heap(ctx->buf, nbyte, 0, NULL);
  +
  +    APR_BRIGADE_INSERT_TAIL(bb, b);
  +    ctx->buf = NULL;
  +
  +    /* if there is extra data, then send that, too */
  +    if (extra != NULL) {
  +        b = apr_bucket_create_transient(extra, extra_len);
  +        APR_BRIGADE_INSERT_TAIL(bb, b);
  +    }
  +
  +    return ap_pass_brigade(r->output_filters, bb);
  +}
  +
  +static apr_status_t buffer_output(request_rec *r,
  +                                  const char *str, apr_size_t len)
  +{
  +    ap_filter_t *f;
  +    old_write_filter_ctx *ctx;
  +    apr_size_t amt;
  +    apr_status_t status;
  +
  +    if (len == 0)
  +        return APR_SUCCESS;
  +
  +    /* ### future optimization: record some flags in the request_rec to
  +       ### say whether we've added our filter, and whether it is first. */
  +
  +    /* this will typically exit on the first test */
  +    for (f = r->output_filters; f != NULL; f = f->next)
  +        if (strcmp("OLD_WRITE", f->frec->name) == 0)
  +            break;
  +    if (f == NULL) {
  +        /* our filter hasn't been added yet */
  +        ctx = apr_pcalloc(r->pool, sizeof(*ctx));
  +        ap_add_output_filter("OLD_WRITE", ctx, r, r->connection);
  +    }
  +
  +    /* if the first filter is not our buffering filter, then we have to
  +       deliver the content through the normal filter chain */
  +    if (strcmp("OLD_WRITE", r->output_filters->frec->name) != 0) {
  +        apr_bucket_brigade *bb = apr_brigade_create(r->pool);
  +        apr_bucket *b = apr_bucket_create_transient(str, len);
  +        APR_BRIGADE_INSERT_TAIL(bb, b);
  +
  +        return ap_pass_brigade(r->output_filters, bb);
  +    }
  +
  +    /* grab the context from our filter */
  +    ctx = r->output_filters->ctx;
  +
  +    /* if there isn't a buffer in the context yet, put one there. */
  +    if (ctx->buf == NULL) {
  +        /* use the heap so it will get free'd after being flushed */
  +        ctx->avail = AP_MIN_BYTES_TO_WRITE;
  +        ctx->buf = ctx->cur = malloc(ctx->avail);
  +    }
  +
  +    /* squeeze the data into the existing buffer */
  +    if (len <= ctx->avail) {
  +        memcpy(ctx->cur, str, len);
  +        ctx->cur += len;
  +        if ((ctx->avail -= len) == 0)
  +            return flush_buffer(r, ctx, NULL, 0);
  +        return APR_SUCCESS;
  +    }
  +
  +    /* the new content can't fit in the existing buffer */
  +
  +    if (len >= AP_MIN_BYTES_TO_WRITE) {
  +        /* it is really big. send what we have, and the new stuff. */
  +        return flush_buffer(r, ctx, str, len);
  +    }
  +
  +    /* the new data is small. put some into the current buffer, flush it,
  +       and then drop the remaining into a new buffer. */
  +    amt = ctx->avail;
  +    memcpy(ctx->cur, str, amt);
  +    ctx->cur += amt;
  +    ctx->avail = 0;
  +    if ((status = flush_buffer(r, ctx, NULL, 0)) != APR_SUCCESS)
  +        return status;
  +
  +    ctx->buf = malloc(AP_MIN_BYTES_TO_WRITE);
  +    memcpy(ctx->buf, str + amt, len - amt);
  +    ctx->cur = ctx->buf + (len - amt);
  +    ctx->avail = AP_MIN_BYTES_TO_WRITE - (len - amt);
  +
  +    return APR_SUCCESS;
  +}
  +
   AP_DECLARE(int) ap_rputc(int c, request_rec *r)
   {
  -    apr_bucket_brigade *bb = NULL;
  -    apr_bucket *b;
       char c2 = (char)c;
   
       if (r->connection->aborted) {
   	return EOF;
       }
   
  -    bb = apr_brigade_create(r->pool);
  -    b = apr_bucket_create_transient(&c2, 1);
  -    APR_BRIGADE_INSERT_TAIL(bb, b);
  -    ap_pass_brigade(r->output_filters, bb);
  +    (void) buffer_output(r, &c2, 1);
   
       return c;
   }
   
   AP_DECLARE(int) ap_rputs(const char *str, request_rec *r)
   {
  -    apr_bucket_brigade *bb = NULL;
  -    apr_bucket *b;
       apr_size_t len;
   
       if (r->connection->aborted)
  @@ -2974,50 +3092,36 @@
       if (*str == '\0')
           return 0;
   
  -    len = strlen(str);
  -    bb = apr_brigade_create(r->pool);
  -    b = apr_bucket_create_transient(str, len);
  -    APR_BRIGADE_INSERT_TAIL(bb, b);
  -    ap_pass_brigade(r->output_filters, bb);
  +    (void) buffer_output(r, str, len = strlen(str));
   
       return len;
   }
   
   AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
   {
  -    apr_bucket_brigade *bb = NULL;
  -    apr_bucket *b;
  -
       if (r->connection->aborted)
           return EOF;
  -    if (nbyte == 0)
  -        return 0;
   
  -    bb = apr_brigade_create(r->pool);
  -    b = apr_bucket_create_transient(buf, nbyte);
  -    APR_BRIGADE_INSERT_TAIL(bb, b);
  -    ap_pass_brigade(r->output_filters, bb);
  +    (void) buffer_output(r, buf, nbyte);
  +
       return nbyte;
   }
   
   AP_DECLARE(int) ap_vrprintf(request_rec *r, const char *fmt, va_list va)
   {
  -    apr_bucket_brigade *bb = NULL;
  +    char buf[4096];
       apr_size_t written;
   
       if (r->connection->aborted)
           return EOF;
  +
  +    /* ### fix this mechanism to allow more than 4K of output */
  +    written = apr_vsnprintf(buf, sizeof(buf), fmt, va);
  +    (void) buffer_output(r, buf, written);
   
  -    bb = apr_brigade_create(r->pool);
  -    written = apr_brigade_vprintf(bb, fmt, va);
  -    if (written != 0)
  -        ap_pass_brigade(r->output_filters, bb);
       return written;
   }
   
  -/* TODO:  Make ap pa_bucket_vprintf that printfs directly into a
  - * bucket.
  - */
   AP_DECLARE_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt, ...)
   {
       va_list va;
  @@ -3035,24 +3139,37 @@
   
   AP_DECLARE_NONSTD(int) ap_rvputs(request_rec *r, ...)
   {
  -    apr_bucket_brigade *bb = NULL;
  -    apr_size_t written;
       va_list va;
  +    const char *s;
  +    apr_size_t len;
  +    apr_size_t written;
   
       if (r->connection->aborted)
           return EOF;
  -    bb = apr_brigade_create(r->pool);
  +
  +    /* ### TODO: if the total output is large, put all the strings
  +       ### into a single brigade, rather than flushing each time we
  +       ### fill the buffer */
       va_start(va, r);
  -    written = apr_brigade_vputstrs(bb, va);
  +    while (1) {
  +        s = va_arg(va, const char *);
  +        if (s == NULL)
  +            break;
  +
  +        len = strlen(s);
  +        if (buffer_output(r, s, len) != APR_SUCCESS) {
  +            return -1;
  +        }
  +
  +        written += len;
  +    }
       va_end(va);
  -    if (written != 0)
  -        ap_pass_brigade(r->output_filters, bb);
  +
       return written;
   }
   
   AP_DECLARE(int) ap_rflush(request_rec *r)
   {
  -    /* we should be using a flush bucket to flush the stack, not buff code. */
       apr_bucket_brigade *bb;
       apr_bucket *b;