apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bri...@apache.org
Subject cvs commit: apr-util/buckets apr_brigade.c
Date Sun, 29 Sep 2002 01:05:38 GMT
brianp      2002/09/28 18:05:38

  Modified:    buckets  apr_brigade.c
  Log:
  Rewrite of apr_brigade_writev().  It's now more efficient for
  both large and small inputs: zero-copy for data larger than 8KB,
  fewer operations (and fewer branches) per for-loop iteration
  for the <= 8KB case.
  
  Revision  Changes    Path
  1.53      +84 -46    apr-util/buckets/apr_brigade.c
  
  Index: apr_brigade.c
  ===================================================================
  RCS file: /home/cvs/apr-util/buckets/apr_brigade.c,v
  retrieving revision 1.52
  retrieving revision 1.53
  diff -u -r1.52 -r1.53
  --- apr_brigade.c	23 Sep 2002 02:17:37 -0000	1.52
  +++ apr_brigade.c	29 Sep 2002 01:05:37 -0000	1.53
  @@ -458,71 +458,109 @@
                                                const struct iovec *vec,
                                                apr_size_t nvec)
   {
  -    apr_bucket *e = APR_BRIGADE_LAST(b);
  -    apr_size_t remaining;
  -    char *buf;
  +    apr_bucket *e;
  +    apr_size_t total_len;
       apr_size_t i;
  -    apr_status_t rv;
  +    char *buf;
   
  -    /* Step 1: check if there is a heap bucket at the end
  -     * of the brigade already
  +    /* Compute the total length of the data to be written.
        */
  -    if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)) {
  -        apr_bucket_heap *h = e->data;
  -        remaining = h->alloc_len - (e->length + (apr_size_t)e->start);
  -        buf = h->base + e->start + e->length;
  +    total_len = 0;
  +    for (i = 0; i < nvec; i++) {
  +       total_len += vec[i].iov_len;
       }
  -    else {
  -        remaining = 0;
  -        buf = NULL;
  +
  +    /* If the data to be written is very large, convert
  +     * the iovec to transient buckets rather than copying.
  +     */
  +    if (total_len > APR_BUCKET_BUFF_SIZE) {
  +        for (i = 0; i < nvec; i++) {
  +            e = apr_bucket_transient_create(vec[i].iov_base, vec[i].iov_len,
  +                                            b->bucket_alloc);
  +            APR_BRIGADE_INSERT_TAIL(b, e);
  +        }
  +        if (flush) {
  +            return flush(b, ctx);
  +        }
  +        else {
  +            return APR_SUCCESS;
  +        }
       }
   
  -    /* Step 2: copy the data into the heap bucket, appending
  -     * a new heap bucket each time the old one becomes full
  +    i = 0;
  +
  +    /* If there is a heap bucket at the end of the brigade
  +     * already, copy into the existing bucket.
        */
  -    for (i = 0; i < nvec; i++) {
  -        apr_size_t nbyte = vec[i].iov_len;
  -        const char *str = (const char *)(vec[i].iov_base);
  +    e = APR_BRIGADE_LAST(b);
  +    if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)) {
  +        apr_bucket_heap *h = e->data;
  +        apr_size_t remaining = h->alloc_len -
  +            (e->length + (apr_size_t)e->start);
  +        buf = h->base + e->start + e->length;
   
  -        if (nbyte <= remaining) {
  -            /* Simple case: the data will fit in the current heap bucket */
  -            memcpy(buf, str, nbyte);
  -            e->length += nbyte;
  -            buf += nbyte;
  -            remaining -= nbyte;
  +        if (remaining >= total_len) {
  +            /* Simple case: all the data will fit in the
  +             * existing heap bucket
  +             */
  +            for (; i < nvec; i++) {
  +                apr_size_t len = vec[i].iov_len;
  +                memcpy(buf, (const void *) vec[i].iov_base, len);
  +                buf += len;
  +            }
  +            e->length += total_len;
  +            return APR_SUCCESS;
           }
  -        else if (nbyte < APR_BUCKET_BUFF_SIZE) {
  -            /* Flush the content written so far */
  -            if (flush && (i != 0) && !APR_BRIGADE_EMPTY(b)) {
  -                rv = flush(b, ctx);
  -                if (rv != APR_SUCCESS) {
  -                    return rv;
  +        else {
  +            /* More complicated case: not all of the data
  +             * will fit in the existing heap bucket.  The
  +             * total data size is <= APR_BUCKET_BUFF_SIZE,
  +             * so we'll need only one additional bucket.
  +             */
  +            const char *start_buf = buf;
  +            for (; i < nvec; i++) {
  +                apr_size_t len = vec[i].iov_len;
  +                if (len > remaining) {
  +                    break;
                   }
  +                memcpy(buf, (const void *) vec[i].iov_base, len);
  +                buf += len;
  +                remaining -= len;
               }
  +            e->length += (buf - start_buf);
  +            total_len -= (buf - start_buf);
   
  -            /* Allocate a new heap buffer */
  -            buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, b->bucket_alloc);
  -            e = apr_bucket_heap_create(buf, APR_BUCKET_BUFF_SIZE,
  -                                       apr_bucket_free, b->bucket_alloc);
  -            APR_BRIGADE_INSERT_TAIL(b, e);
  -            memcpy(buf, str, nbyte);
  -            e->length = nbyte;
  -            buf += nbyte;
  -            remaining = APR_BUCKET_BUFF_SIZE - nbyte;
  -
  -        }
  -        else { /* String larger than APR_BUCKET_BUFF_SIZE */
  -            e = apr_bucket_transient_create(str, nbyte, b->bucket_alloc);
  -            APR_BRIGADE_INSERT_TAIL(b, e);
               if (flush) {
  -                rv = flush(b, ctx);
  +                apr_status_t rv = flush(b, ctx);
                   if (rv != APR_SUCCESS) {
                       return rv;
                   }
               }
  -            remaining = 0; /* create a new heap bucket for the next write */
  +
  +            /* Now fall through into the case below to
  +             * allocate another heap bucket and copy the
  +             * rest of the array.  (Note that i is not
  +             * reset to zero here; it holds the index
  +             * of the first vector element to be
  +             * written to the new bucket.)
  +             */
           }
       }
  +
  +    /* Allocate a new heap bucket, and copy the data into it.
  +     * The checks above ensure that the amount of data to be
  +     * written here is no larger than APR_BUCKET_BUFF_SIZE.
  +     */
  +    buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, b->bucket_alloc);
  +    e = apr_bucket_heap_create(buf, APR_BUCKET_BUFF_SIZE,
  +                               apr_bucket_free, b->bucket_alloc);
  +    for (; i < nvec; i++) {
  +        apr_size_t len = vec[i].iov_len;
  +        memcpy(buf, (const void *) vec[i].iov_base, len);
  +        buf += len;
  +    }
  +    e->length = total_len;
  +    APR_BRIGADE_INSERT_TAIL(b, e);
   
       return APR_SUCCESS;
   }
  
  
  

Mime
View raw message