Attached is a patch which makes the read/write buffer size configurable
on a per-file-descriptor basis, ie;

  apr_file_open(&fh, "/dev/zero", APR_WRITE | APR_BUFFERED, 
                APR_UREAD | APR_UWRITE | APR_GREAD, p);

  /* Increase the buffer size to 10k */ 
  apr_file_set_buffer_size(fh, 10240);

  /* Query the buffer size */
  current_bufsize = apr_file_get_buffer_size(filetest);

It supports increasing and decreasing the buffer size, as well as making
an unbuffered file handle buffered, and a buffered file unbuffered.

The patch also adds a new subpool to the file handle, for the buffer
itself, with the subpool being destroyed on buffer resizes.

Other things I'm thinking about;

        Destroying the subpool on apr_file_close, after all the lifetime
        of the buffer should be exactly concurrent with the lifetime of
        the file descriptor.

        Maybe making something like;

                apr_file_set_default_buffer_size(apr_off_t foo); 

        work. 

The implementation in buffer.c should be portable, with the only
changing the file->thlock to file->mutex being neccessary for some of
the other architectures, though I havn't done that porting just yet, I
want to be able to test it on win32 at least first, and maybe get some
feedback :-)

Apart from my immediate problem of needing a buffered stdin, I've done
some extensive benchmarking in the past of the efficiency of various
buffer sizes;

         http://www.stdlib.net/~colmmacc/Apachecon-EU2005/

See slides 18-21 of the presentation. There are definitely some major
real-world benefits to giving people the ability to tune the buffer
sizes. 

-- 
Colm MacCárthaigh                        Public Key: [EMAIL PROTECTED]
Index: test/testfile.c
===================================================================
--- test/testfile.c     (revision 279021)
+++ test/testfile.c     (working copy)
@@ -326,6 +326,33 @@
     apr_file_close(filetest);
 }
 
+static void test_buffer_size_set_get(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    apr_file_t *filetest = NULL;
+
+    rv = apr_file_open(&filetest, FILENAME, 
+                       APR_WRITE | APR_BUFFERED, 
+                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_get_buffer_size(filetest);
+    ABTS_INT_EQUAL(tc, APR_BUFFERSIZE, rv);
+ 
+    rv = apr_file_set_buffer_size(filetest, 10240);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+    
+    rv = apr_file_get_buffer_size(filetest);
+    ABTS_INT_EQUAL(tc, 10240, rv);
+    
+    rv = apr_file_set_buffer_size(filetest, 12);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+    
+    rv = apr_file_get_buffer_size(filetest);
+    ABTS_INT_EQUAL(tc, 12, rv);
+    
+    apr_file_close(filetest);
+}
 static void test_getc(abts_case *tc, void *data)
 {
     apr_file_t *f = NULL;
@@ -802,6 +829,7 @@
     abts_run_test(suite, test_bigfprintf, NULL);
     abts_run_test(suite, test_fail_write_flush, NULL);
     abts_run_test(suite, test_fail_read_flush, NULL);
+    abts_run_test(suite, test_buffer_size_set_get, NULL);
 
     return suite;
 }
Index: include/apr_file_io.h
===================================================================
--- include/apr_file_io.h       (revision 279021)
+++ include/apr_file_io.h       (working copy)
@@ -325,6 +325,23 @@
                                               apr_pool_t *pool);
 
 /**
+ * Change the buffer size for an existing apr file pointer.
+ * @param thefile The apr file pointer to tune
+ * @param bufsize The new buffer size
+ *
+ * @remark Setting the bufsize to zero will disable buffering for the
+ *         file. 
+ */
+APR_DECLARE(apr_status_t) apr_file_set_buffer_size(apr_file_t *thefile,
+                                                   apr_off_t bufsize);
+
+/**
+ * Return the buffer size for an existing apr file pointer.
+ * @param thefile The apr file pointer to query
+ */
+APR_DECLARE(apr_off_t) apr_file_get_buffer_size(apr_file_t *thefile);
+
+/**
  * Read data from the specified file.
  * @param thefile The file descriptor to read from.
  * @param buf The buffer to store the data to.
Index: include/arch/win32/apr_arch_file_io.h
===================================================================
--- include/arch/win32/apr_arch_file_io.h       (revision 279021)
+++ include/arch/win32/apr_arch_file_io.h       (working copy)
@@ -172,8 +172,10 @@
 
     /* Stuff for buffered mode */
     char *buffer;
+    apr_pool_p *bufsubpool;    // Subpool used for the buffer
     apr_size_t bufpos;         // Read/Write position in buffer
     apr_size_t dataRead;       // amount of valid data read into buffer
+    apr_size_t bufsize;        // The size of the buffer
     int direction;             // buffer being used for 0 = read, 1 = write
     apr_off_t filePtr;         // position in file of handle
     apr_thread_mutex_t *mutex; // mutex semaphore, must be owned to access the 
above fields
Index: include/arch/os2/apr_arch_file_io.h
===================================================================
--- include/arch/os2/apr_arch_file_io.h (revision 279021)
+++ include/arch/os2/apr_arch_file_io.h (working copy)
@@ -48,7 +48,9 @@
 
     /* Stuff for buffered mode */
     char *buffer;
+    apr_pool_p *bufsubpool;   // Subpool used for the buffer
     int bufpos;               // Read/Write position in buffer
+    apr_off_t bufsize;        // The size of the buffer
     unsigned long dataRead;   // amount of valid data read into buffer
     int direction;            // buffer being used for 0 = read, 1 = write
     unsigned long filePtr;    // position in file of handle
Index: include/arch/unix/apr_arch_file_io.h
===================================================================
--- include/arch/unix/apr_arch_file_io.h        (revision 279021)
+++ include/arch/unix/apr_arch_file_io.h        (working copy)
@@ -101,9 +101,11 @@
 #endif
     /* Stuff for buffered mode */
     char *buffer;
+    apr_pool_t *bufsubpool;   /* Subpool for the buffer */
     int bufpos;               /* Read/Write position in buffer */
     unsigned long dataRead;   /* amount of valid data read into buffer */
     int direction;            /* buffer being used for 0 = read, 1 = write */
+    apr_off_t bufsize;        /* The size of the buffer */
     unsigned long filePtr;    /* position in file of handle */
 #if APR_HAS_THREADS
     struct apr_thread_mutex_t *thlock;
Index: include/arch/netware/apr_arch_file_io.h
===================================================================
--- include/arch/netware/apr_arch_file_io.h     (revision 279021)
+++ include/arch/netware/apr_arch_file_io.h     (working copy)
@@ -95,7 +95,9 @@
 
     /* Stuff for buffered mode */
     char *buffer;
+    apr_pool_t *bufsubpool;   /* Subpool for the buffer */
     int bufpos;               /* Read/Write position in buffer */
+    apr_off_t bufsize;        /* The size of the buffer */
     apr_off_t dataRead;   /* amount of valid data read into buffer */
     int direction;            /* buffer being used for 0 = read, 1 = write */
     apr_off_t filePtr;    /* position in file of handle */
Index: file_io/win32/open.c
===================================================================
--- file_io/win32/open.c        (revision 279021)
+++ file_io/win32/open.c        (working copy)
@@ -387,6 +387,7 @@
     if (flag & APR_BUFFERED) {
         (*new)->buffered = 1;
         (*new)->buffer = apr_palloc(pool, APR_FILE_BUFSIZE);
+        (*new)->bufsize = APR_FILE_BUFSIZE;
     }
     /* Need the mutex to handled buffered and O_APPEND style file i/o */
     if ((*new)->buffered || (*new)->append) {
@@ -529,6 +530,7 @@
     if (flags & APR_BUFFERED) {
         (*file)->buffered = 1;
         (*file)->buffer = apr_palloc(pool, APR_FILE_BUFSIZE);
+        (*file)->bufsize = APR_FILE_BUFSIZE;
     }
 
     if ((*file)->append || (*file)->buffered) {
Index: file_io/win32/readwrite.c
===================================================================
--- file_io/win32/readwrite.c   (revision 279021)
+++ file_io/win32/readwrite.c   (working copy)
@@ -177,7 +177,7 @@
             if (thefile->bufpos >= thefile->dataRead) {
                 apr_size_t read;
                 rv = read_with_timeout(thefile, thefile->buffer, 
-                                       APR_FILE_BUFSIZE, &read);
+                                       thefile->bufsize, &read);
                 if (read == 0) {
                     if (rv == APR_EOF)
                         thefile->eof_hit = TRUE;
@@ -251,10 +251,11 @@
 
         rv = 0;
         while (rv == 0 && size > 0) {
-            if (thefile->bufpos == APR_FILE_BUFSIZE)   // write buffer is full
+            if (thefile->bufpos == thefile->bufsize)   // write buffer is full
                 rv = apr_file_flush(thefile);
 
-            blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ? 
APR_FILE_BUFSIZE - thefile->bufpos : size;
+            blocksize = size > thefile->bufsize - thefile->bufpos ? 
+                                    thefile->bufsize - thefile->bufpos : size;
             memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);
             thefile->bufpos += blocksize;
             pos += blocksize;
Index: file_io/win32/filedup.c
===================================================================
--- file_io/win32/filedup.c     (revision 279021)
+++ file_io/win32/filedup.c     (working copy)
@@ -145,7 +145,8 @@
     memcpy(*new_file, old_file, sizeof(apr_file_t));
     (*new_file)->pool = p;
     if (old_file->buffered) {
-        (*new_file)->buffer = apr_palloc(p, APR_FILE_BUFSIZE);
+        (*new_file)->buffer = apr_palloc(p, old_file->bufsize);
+        (*new_file)->bufsize = old_file->bufsize;
         if (old_file->direction == 1) {
             memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos);
         }
Index: file_io/os2/open.c
===================================================================
--- file_io/os2/open.c  (revision 279021)
+++ file_io/os2/open.c  (working copy)
@@ -60,6 +60,7 @@
 
     if (dafile->buffered) {
         dafile->buffer = apr_palloc(pool, APR_FILE_BUFSIZE);
+        dafile->bufsize = APR_FILE_BUFSIZE;
         rv = apr_thread_mutex_create(&dafile->mutex, 0, pool);
 
         if (rv)
@@ -194,6 +195,7 @@
         apr_status_t rv;
 
         (*file)->buffer = apr_palloc(pool, APR_FILE_BUFSIZE);
+        (*file)->bufsize = APR_FILE_BUFSIZE;
         rv = apr_thread_mutex_create(&(*file)->mutex, 0, pool);
 
         if (rv)
Index: file_io/os2/readwrite.c
===================================================================
--- file_io/os2/readwrite.c     (revision 279021)
+++ file_io/os2/readwrite.c     (working copy)
@@ -52,7 +52,7 @@
             if (thefile->bufpos >= thefile->dataRead) {
                 ULONG bytesread;
                 rc = DosRead(thefile->filedes, thefile->buffer,
-                             APR_FILE_BUFSIZE, &bytesread);
+                             thefile->bufsize, &bytesread);
 
                 if (bytesread == 0) {
                     if (rc == 0)
@@ -143,10 +143,11 @@
         }
 
         while (rc == 0 && size > 0) {
-            if (thefile->bufpos == APR_FILE_BUFSIZE)   // write buffer is full
+            if (thefile->bufpos == thefile->bufsize)   // write buffer is full
                 rc = apr_file_flush(thefile);
 
-            blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ? 
APR_FILE_BUFSIZE - thefile->bufpos : size;
+            blocksize = size > thefile->bufsize - thefile->bufpos ? 
+                                    thefile->bufsize - thefile->bufpos : size;
             memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);
             thefile->bufpos += blocksize;
             pos += blocksize;
Index: file_io/os2/filedup.c
===================================================================
--- file_io/os2/filedup.c       (revision 279021)
+++ file_io/os2/filedup.c       (working copy)
@@ -91,7 +91,8 @@
     (*new_file)->pool = p;
 
     if (old_file->buffered) {
-        (*new_file)->buffer = apr_palloc(p, APR_FILE_BUFSIZE);
+        (*new_file)->buffer = apr_palloc(p, old_file->bufsize);
+        (*new_file)->bufsize = old_file->bufsize;
 
         if (old_file->direction == 1) {
             memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos);
Index: file_io/unix/open.c
===================================================================
--- file_io/unix/open.c (revision 279021)
+++ file_io/unix/open.c (working copy)
@@ -150,7 +150,9 @@
     (*new)->buffered = (flag & APR_BUFFERED) > 0;
 
     if ((*new)->buffered) {
-        (*new)->buffer = apr_palloc(pool, APR_FILE_BUFSIZE);
+        apr_pool_create(&(*new)->bufsubpool, pool);
+        (*new)->buffer = apr_palloc((*new)->bufsubpool, APR_FILE_BUFSIZE);
+        (*new)->bufsize = APR_FILE_BUFSIZE;
 #if APR_HAS_THREADS
         if ((*new)->flags & APR_XTHREAD) {
             (*new)->thlock = thlock;
@@ -239,7 +241,9 @@
 #endif
 
     if ((*file)->buffered) {
-        (*file)->buffer = apr_palloc(pool, APR_FILE_BUFSIZE);
+        apr_pool_create(&(*file)->bufsubpool, pool);
+        (*file)->buffer = apr_palloc((*file)->bufsubpool, APR_FILE_BUFSIZE);
+        (*file)->bufsize = APR_FILE_BUFSIZE;
 #if APR_HAS_THREADS
         if ((*file)->flags & APR_XTHREAD) {
             apr_status_t rv;
Index: file_io/unix/buffer.c
===================================================================
--- file_io/unix/buffer.c       (revision 0)
+++ file_io/unix/buffer.c       (revision 0)
@@ -0,0 +1,98 @@
+/* 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 "apr_arch_file_io.h"
+#include "apr_pools.h"
+#include "apr_thread_mutex.h"
+
+APR_DECLARE(apr_status_t) apr_file_set_buffer_size(apr_file_t *file, 
+                                                   apr_off_t newbufsize)
+{
+    apr_status_t rv;
+
+#if APR_HAS_THREADS
+     if (file->thlock) {
+         apr_thread_mutex_lock(file->thlock);
+     }
+#endif
+ 
+    if(file->buffered) {
+        /* Flush the existing buffer */
+        rv = apr_file_flush(file);
+        if (rv != APR_SUCCESS) {
+#if APR_HAS_THREADS
+            if (file->thlock) {
+                apr_thread_mutex_lock(file->thlock);
+            }
+#endif
+            return rv;
+        }
+        
+        file->buffer = NULL;
+        file->bufsize = 0;
+        file->buffered = 0;
+        file->bufpos = 0;
+        file->direction = 0;
+        file->dataRead = 0;
+ 
+        if (newbufsize == 0) {
+            /* Setting the buffer size to zero is equivalent to turning 
+             * buffering off. 
+             */
+#if APR_HAS_THREADS
+            if (file->thlock) {
+                apr_thread_mutex_unlock(file->thlock);
+            }
+#endif
+            return APR_SUCCESS;
+        }
+        else {
+            /* Destroy the existing pool */
+            apr_pool_destroy(file->bufsubpool);
+        }
+    }
+    
+    if (newbufsize > 0) {
+        /* Create a new subpool, and the buffer */
+        rv = apr_pool_create(&file->bufsubpool, file->pool);
+        if (rv != APR_SUCCESS) {
+#if APR_HAS_THREADS
+            if (file->thlock) {
+                apr_thread_mutex_unlock(file->thlock);
+            }
+#endif
+            return rv;
+        }
+        file->buffer = apr_palloc(file->bufsubpool, newbufsize);
+        file->bufsize = newbufsize;
+        file->buffered = 1;
+        file->bufpos = 0;
+        file->direction = 0;
+        file->dataRead = 0;
+    }
+ 
+#if APR_HAS_THREADS
+    if (file->thlock) {
+        apr_thread_mutex_unlock(file->thlock);
+    }
+#endif
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_off_t) apr_file_get_buffer_size(apr_file_t *file)
+{
+    return file->bufsize;
+}
Index: file_io/unix/readwrite.c
===================================================================
--- file_io/unix/readwrite.c    (revision 279021)
+++ file_io/unix/readwrite.c    (working copy)
@@ -70,7 +70,7 @@
         }
         while (rv == 0 && size > 0) {
             if (thefile->bufpos >= thefile->dataRead) {
-                int bytesread = read(thefile->filedes, thefile->buffer, 
APR_FILE_BUFSIZE);
+                int bytesread = read(thefile->filedes, thefile->buffer, 
thefile->bufsize);
                 if (bytesread == 0) {
                     thefile->eof_hit = TRUE;
                     rv = APR_EOF;
@@ -177,11 +177,11 @@
 
         rv = 0;
         while (rv == 0 && size > 0) {
-            if (thefile->bufpos == APR_FILE_BUFSIZE)   /* write buffer is 
full*/
+            if (thefile->bufpos == thefile->bufsize)   /* write buffer is 
full*/
                 rv = apr_file_flush(thefile);
 
-            blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ? 
-                        APR_FILE_BUFSIZE - thefile->bufpos : size;
+            blocksize = size > thefile->bufsize - thefile->bufpos ? 
+                        thefile->bufsize - thefile->bufpos : size;
             memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);         
             
             thefile->bufpos += blocksize;
             pos += blocksize;
Index: file_io/unix/filedup.c
===================================================================
--- file_io/unix/filedup.c      (revision 279021)
+++ file_io/unix/filedup.c      (working copy)
@@ -62,7 +62,8 @@
      * got one.
      */
     if ((*new_file)->buffered && !(*new_file)->buffer) {
-        (*new_file)->buffer = apr_palloc(p, APR_FILE_BUFSIZE);
+        (*new_file)->buffer = apr_palloc(p, old_file->bufsize);
+        (*new_file)->bufsize = old_file->bufsize;
     }
 
     /* this is the way dup() works */
@@ -121,7 +122,8 @@
     memcpy(*new_file, old_file, sizeof(apr_file_t));
     (*new_file)->pool = p;
     if (old_file->buffered) {
-        (*new_file)->buffer = apr_palloc(p, APR_FILE_BUFSIZE);
+        (*new_file)->buffer = apr_palloc(p, old_file->bufsize);
+        (*new_file)->bufsize = old_file->bufsize;
         if (old_file->direction == 1) {
             memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos);
         }

Reply via email to