Return-Path: Mailing-List: contact dev-help@apr.apache.org; run by ezmlm Delivered-To: mailing list dev@apr.apache.org Received: (qmail 22126 invoked from network); 25 Jan 2001 20:38:28 -0000 Received: from sfo-gw.covalent.net (HELO koj.covalent.net) (207.44.198.62) by h31.sny.collab.net with SMTP; 25 Jan 2001 20:38:28 -0000 Received: from rbb (helo=localhost) by koj.covalent.net with local-esmtp (Exim 3.16 #1) id 14LtDS-0001IT-00 for dev@apr.apache.org; Thu, 25 Jan 2001 12:41:58 -0800 Date: Thu, 25 Jan 2001 12:41:58 -0800 (PST) From: rbb@covalent.net X-Sender: rbb@koj To: dev@apr.apache.org Subject: [PATCH] brigade buffering. Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-Spam-Rating: h31.sny.collab.net 1.6.2 0/1000/N This general patch has been on new-httpd, but it really belongs here. This is my general concept for how brigades should be buffered. There are some bugs here, and it is not a full solution. These are basically meant as underlying functions, programs such as Apache would need to put wrappers around them for them to be specifically useful to those programs, but these functions form the core of the code. Ryan Index: buckets/apr_brigade.c =================================================================== RCS file: /home/cvs/apr-util/buckets/apr_brigade.c,v retrieving revision 1.3 diff -u -d -b -w -u -r1.3 apr_brigade.c --- buckets/apr_brigade.c 2001/01/19 07:01:59 1.3 +++ buckets/apr_brigade.c 2001/01/25 20:23:12 @@ -99,6 +99,9 @@ b = apr_palloc(p, sizeof(*b)); b->p = p; + + b->start = b->end = NULL; + APR_RING_INIT(&b->list, apr_bucket, link); apr_register_cleanup(b->p, b, apr_brigade_cleanup, apr_brigade_cleanup); @@ -185,12 +188,41 @@ return vec - orig; } +static int check_brigade_flush(char *start, char **end, const char *str, + apr_size_t *n, apr_bucket_brigade *b) +{ + if (*n > (APR_BUCKET_BUFF_SIZE - (*end - start))) { + if (start) { + memcpy(*end, str, APR_BUCKET_BUFF_SIZE - (*end - start)); + *n -= (APR_BUCKET_BUFF_SIZE - (*end - start)); + *end += (APR_BUCKET_BUFF_SIZE - (*end - start)); + apr_brigade_flush(b); + } + if (*n > APR_BUCKET_BUFF_SIZE) { + apr_bucket *e = apr_bucket_create_transient(str, *n); + APR_BRIGADE_INSERT_TAIL(b, e); + return 1; + } + } + return 0; +} + +APU_DECLARE(void) apr_brigade_flush(apr_bucket_brigade *b) +{ + apr_bucket *e; + apr_size_t i = b->end - b->start; + + if (i) { + e = apr_bucket_create_heap(b->start, i, 0, NULL); + APR_BRIGADE_INSERT_TAIL(b, e); + b->start = b->end = NULL; + } +} + APU_DECLARE(int) apr_brigade_vputstrs(apr_bucket_brigade *b, va_list va) { - apr_bucket *r; const char *x; int j, k; - apr_size_t i; for (k = 0;;) { x = va_arg(va, const char *); @@ -198,20 +230,52 @@ break; j = strlen(x); - /* XXX: copy or not? let the caller decide? */ - r = apr_bucket_create_heap(x, j, 1, &i); - if (i != j) { - /* Do we need better error reporting? */ - return -1; + k += apr_brigade_write(b, x, j); } - k += i; + return k; +} - APR_BRIGADE_INSERT_TAIL(b, r); +APU_DECLARE(int) apr_brigade_putc(apr_bucket_brigade *b, const char c) +{ + apr_size_t nbyte = 1; + + if (check_brigade_flush(b->start, &b->end, &c, &nbyte, b)) { + return 1; } - return k; + if (!b->start) { + b->start = b->end = malloc(APR_BUCKET_BUFF_SIZE); + } + + memcpy(b->end, &c, 1); + b->end++; + + return 1; +} + +APU_DECLARE(int) apr_brigade_write(apr_bucket_brigade *b, const char *str, apr_size_t nbyte) +{ + apr_size_t n = nbyte; + + if (check_brigade_flush(b->start, &b->end, str, &nbyte, b)) { + return n; } + if (!b->start) { + b->start = b->end = malloc(APR_BUCKET_BUFF_SIZE); + } + + memcpy(b->end, str, nbyte); + b->end += nbyte; + + return n; +} + +APU_DECLARE(int) apr_brigade_puts(apr_bucket_brigade *b, const char *str) +{ + return apr_brigade_write(b, str, strlen(str)); +} + APU_DECLARE_NONSTD(int) apr_brigade_putstrs(apr_bucket_brigade *b, ...) { va_list va; @@ -240,13 +304,9 @@ * directly into a bucket. I'm being lazy right now. RBB */ char buf[4096]; - apr_bucket *r; - int res; - res = apr_vsnprintf(buf, 4096, fmt, va); - - r = apr_bucket_create_heap(buf, strlen(buf), 1, NULL); - APR_BRIGADE_INSERT_TAIL(b, r); + apr_vsnprintf(buf, 4096, fmt, va); - return res; + return apr_brigade_puts(b, buf); } + Index: include/apr_buckets.h =================================================================== RCS file: /home/cvs/apr-util/include/apr_buckets.h,v retrieving revision 1.67 diff -u -d -b -w -u -r1.67 apr_buckets.h --- include/apr_buckets.h 2001/01/23 22:24:06 1.67 +++ include/apr_buckets.h 2001/01/25 20:23:31 @@ -78,6 +78,8 @@ * @package Bucket Brigades */ +#define APR_BUCKET_BUFF_SIZE 9000 + typedef enum {APR_BLOCK_READ, APR_NONBLOCK_READ} apr_read_type_e; /* @@ -237,6 +239,8 @@ * the destroying function is responsible for killing the cleanup. */ apr_pool_t *p; + char *start; + char *end; /** The buckets in the brigade are on this list. */ /* * XXX: the apr_bucket_list structure doesn't actually need a name tag @@ -628,9 +632,10 @@ APU_DECLARE(int) apr_brigade_to_iovec(apr_bucket_brigade *b, struct iovec *vec, int nvec); +APU_DECLARE(void) apr_brigade_flush(apr_bucket_brigade *b); + /** - * This function writes a list of strings into a bucket brigade. We just - * allocate a new heap bucket for each string. + * This function writes a list of strings into a bucket brigade. * @param b The bucket brigade to add to * @param va A list of strings to add * @return The number of bytes added to the brigade @@ -639,8 +644,34 @@ APU_DECLARE(int) apr_brigade_vputstrs(apr_bucket_brigade *b, va_list va); /** + * This function writes an string into a bucket brigade. + * @param b The bucket brigade to add to + * @param str The string to add + * @return The number of bytes added to the brigade + * @deffunc int apr_brigade_write(ap_bucket_brigade *b, const char *str) + */ +APU_DECLARE(int) apr_brigade_write(apr_bucket_brigade *b, const char *str, apr_size_t nbyte); + +/** + * This function writes an string into a bucket brigade. + * @param b The bucket brigade to add to + * @param str The string to add + * @return The number of bytes added to the brigade + * @deffunc int apr_brigade_puts(ap_bucket_brigade *b, const char *str) + */ +APU_DECLARE(int) apr_brigade_puts(apr_bucket_brigade *b, const char *str); + +/** + * This function writes a character into a bucket brigade. + * @param b The bucket brigade to add to + * @param c The character to add + * @return The number of bytes added to the brigade + * @deffunc int apr_brigade_putc(apr_bucket_brigade *b, const char c) + */ +APU_DECLARE(int) apr_brigade_putc(apr_bucket_brigade *b, const char c); + +/** * This function writes an unspecified number of strings into a bucket brigade. - * We just allocate a new heap bucket for each string. * @param b The bucket brigade to add to * @param ... The strings to add * @return The number of bytes added to the brigade @@ -649,7 +680,7 @@ APU_DECLARE_NONSTD(int) apr_brigade_putstrs(apr_bucket_brigade *b, ...); /** - * Evaluate a printf and put the resulting string into a bucket at the end + * Evaluate a printf and put the resulting string at the end * of the bucket brigade. * @param b The brigade to write to * @param fmt The format of the string to write @@ -661,7 +692,7 @@ const char *fmt, ...); /** - * Evaluate a printf and put the resulting string into a bucket at the end + * Evaluate a printf and put the resulting string at the end * of the bucket brigade. * @param b The brigade to write to * @param fmt The format of the string to write _______________________________________________________________________________ Ryan Bloom rbb@apache.org 406 29th St. San Francisco, CA 94131 -------------------------------------------------------------------------------