httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Brian Havard" <bri...@kheldar.apana.org.au>
Subject Re: Buffered APR files
Date Sat, 29 Apr 2000 08:34:43 GMT
On Sat, 29 Apr 2000 00:42:00 +1100 (EDT), Brian Havard wrote:

>On Fri, 28 Apr 2000 07:34:49 -0400 (EDT), rbb@covalent.net wrote:
>
>>On Fri, 28 Apr 2000, Brian Havard wrote:
>>
>>> Is the buffered I/O stuff working on all platforms now? If so, we should
>>> turn it on where appropriate. EG mod_include benefits greatly from
>>> buffering the input file (>150% improvement in a simple test I did though
>>> that will vary greatly between platforms).
>>
>>Please wait until after the alpha, and turn it on.  If it doesn't work
>>someplace, we'[ll find out, and we can fix it before the next alpha.
>
>Fair enough. I may even take a stab at the windows version. The class I
>originally derived the code from has OS/2, Win32 & DOS implementations so
>it shouldn't be too hard.

Ok, this compiles (though I compiled it with Watcom C++, I don't have MSVC) 
but isn't tested. If I'm lucky it might actually work :)



Index: filedup.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/file_io/win32/filedup.c,v
retrieving revision 1.16
diff -u -r1.16 filedup.c
--- filedup.c	2000/04/28 15:24:40	1.16
+++ filedup.c	2000/04/29 09:25:16
@@ -111,6 +111,7 @@
     (*new_file)->atime = old_file->atime;    
     (*new_file)->mtime = old_file->mtime;
     (*new_file)->ctime = old_file->ctime;
+    (*new_file)->buffered = FALSE;
     ap_register_cleanup((*new_file)->cntxt, (void *)(*new_file), file_cleanup,
                         ap_null_cleanup);
 
Index: fileio.h
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/file_io/win32/fileio.h,v
retrieving revision 1.21
diff -u -r1.21 fileio.h
--- fileio.h	2000/04/28 18:27:38	1.21
+++ fileio.h	2000/04/29 09:25:16
@@ -79,9 +79,12 @@
 #include "apr_private.h"
 #include "apr_pools.h"
 #include "apr_general.h"
+#include "apr_lock.h"
 #include "apr_file_io.h"
 #include "apr_errno.h"
 
+#define APR_FILE_BUFSIZE 4096
+
 /* quick run-down of fields in windows' ap_file_t structure that may have 
  * obvious uses.
  * fname --  the filename as passed to the open call.
@@ -114,6 +117,14 @@
     ap_time_t atime;
     ap_time_t mtime;
     ap_time_t ctime;
+
+    /* Stuff for buffered mode */
+    char *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
+    unsigned long filePtr;    // position in file of handle
+    ap_lock_t *mutex;         // mutex semaphore, must be owned to access the above fields
 };
 
 struct ap_dir_t {
Index: open.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/file_io/win32/open.c,v
retrieving revision 1.38
diff -u -r1.38 open.c
--- open.c	2000/04/27 20:25:01	1.38
+++ open.c	2000/04/29 09:25:16
@@ -82,6 +82,7 @@
     DWORD attributes = 0;
     DWORD sharemode = FILE_SHARE_READ | FILE_SHARE_WRITE;
     ap_oslevel_e level;
+    ap_status_t rv;
 
     (*dafile) = (ap_file_t *)ap_pcalloc(cont, sizeof(ap_file_t));
 
@@ -98,6 +99,16 @@
         return APR_EACCES;
     }
 
+    (*dafile)->buffered = (flag & APR_BUFFERED) > 0;
+
+    if ((*dafile)->buffered) {
+        (*dafile)->buffer = ap_palloc(cont, APR_FILE_BUFSIZE);
+        rv = ap_create_lock(&(*dafile)->mutex, APR_MUTEX, APR_INTRAPROCESS, NULL,
cont);
+
+        if (rv)
+            return rv;
+    }
+
     (*dafile)->fname = ap_pstrdup(cont, fname);
 
     (*dafile)->demonfname = canonical_filename((*dafile)->cntxt, fname);
@@ -164,6 +175,10 @@
     ap_status_t stat;
     if ((stat = file_cleanup(file)) == APR_SUCCESS) {
         ap_kill_cleanup(file->cntxt, file, file_cleanup);
+
+        if (file->buffered)
+            ap_destroy_lock(file->mutex);
+
         return APR_SUCCESS;
     }
     return stat;
Index: readwrite.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/file_io/win32/readwrite.c,v
retrieving revision 1.31
diff -u -r1.31 readwrite.c
--- readwrite.c	2000/04/28 18:27:39	1.31
+++ readwrite.c	2000/04/29 09:25:16
@@ -68,19 +68,58 @@
     DWORD bread;
     int lasterror;
 
-    if (ReadFile(thefile->filehand, buf, *nbytes, &bread, NULL)) {
-        *nbytes = bread;
-        return APR_SUCCESS;
-    }
+    if (thefile->buffered) {
+        char *pos = (char *)buf;
+        ULONG blocksize;
+        ULONG size = *nbytes;
+
+        ap_lock(thefile->mutex);
+
+        if (thefile->direction == 1) {
+            ap_flush(thefile);
+            thefile->bufpos = 0;
+            thefile->direction = 0;
+            thefile->dataRead = 0;
+        }
 
-    *nbytes = 0;
-    lasterror = GetLastError();
-    if (lasterror == ERROR_BROKEN_PIPE) {
-        /* Assume ERROR_BROKEN_PIPE signals an EOF reading from a pipe */
-        return APR_SUCCESS;
-    } else if (lasterror == ERROR_NO_DATA) {
-        /* Receive this error on a read to a pipe in nonblocking mode */
-        return APR_EAGAIN;
+        while (lasterror == 0 && size > 0) {
+            if (thefile->bufpos >= thefile->dataRead) {
+                lasterror = ReadFile(thefile->filehand, thefile->buffer, APR_FILE_BUFSIZE,
&thefile->dataRead, NULL ) ? 0 : GetLastError();
+
+                if (thefile->dataRead == 0) {
+                    if (lasterror == 0)
+                        thefile->eof_hit = TRUE;
+                    break;
+                }
+
+                thefile->filePtr += thefile->dataRead;
+                thefile->bufpos = 0;
+            }
+
+            blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead
- thefile->bufpos : size;
+            memcpy(pos, thefile->buffer + thefile->bufpos, blocksize);
+            thefile->bufpos += blocksize;
+            pos += blocksize;
+            size -= blocksize;
+        }
+
+        *nbytes = lasterror == 0 ? pos - (char *)buf : 0;
+        ap_unlock(thefile->mutex);
+    } else {
+        if (ReadFile(thefile->filehand, buf, *nbytes, &bread, NULL)) {
+            *nbytes = bread;
+            return APR_SUCCESS;
+        }
+
+        *nbytes = 0;
+        lasterror = GetLastError();
+        if (lasterror == ERROR_BROKEN_PIPE) {
+            /* Assume ERROR_BROKEN_PIPE signals an EOF reading from a pipe */
+            return APR_SUCCESS;
+        } else if (lasterror == ERROR_NO_DATA) {
+            /* Receive this error on a read to a pipe in nonblocking mode */
+            return APR_EAGAIN;
+        }
     }
 
     return lasterror;
@@ -91,22 +130,53 @@
     ap_status_t rv;
     DWORD bwrote;
 
-    if (!thefile->pipe && thefile->append) {
-        SetFilePointer(thefile->filehand, 0, NULL, FILE_END);
-    }
-    if (WriteFile(thefile->filehand, buf, *nbytes, &bwrote, NULL)) {
-        *nbytes = bwrote;
-        rv = APR_SUCCESS;
-    } 
-    else {
-        (*nbytes) = 0;
-        rv = GetLastError();
+    if (thefile->buffered) {
+        char *pos = (char *)buf;
+        int blocksize;
+        int size = *nbytes;
+
+        ap_lock(thefile->mutex);
+
+        if (thefile->direction == 0) {
+            // Position file pointer for writing at the offset we are logically reading from
+            ULONG offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
+            if (offset != thefile->filePtr)
+                SetFilePointer(thefile->filehand, offset, NULL, FILE_BEGIN);
+            thefile->bufpos = thefile->dataRead = 0;
+            thefile->direction = 1;
+        }
+
+        while (rv == 0 && size > 0) {
+            if (thefile->bufpos == APR_FILE_BUFSIZE)   // write buffer is full
+                rv = ap_flush(thefile);
+
+            blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ? APR_FILE_BUFSIZE
- thefile->bufpos : size;
+            memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);
+            thefile->bufpos += blocksize;
+            pos += blocksize;
+            size -= blocksize;
+        }
+
+        ap_unlock(thefile->mutex);
+        return rv;
+    } else {
+        if (!thefile->pipe && thefile->append) {
+            SetFilePointer(thefile->filehand, 0, NULL, FILE_END);
+        }
+        if (WriteFile(thefile->filehand, buf, *nbytes, &bwrote, NULL)) {
+            *nbytes = bwrote;
+            rv = APR_SUCCESS;
+        }
+        else {
+            (*nbytes) = 0;
+            rv = GetLastError();
+        }
     }
 
     return rv;
 }
 /*
- * Too bad WriteFileGather() is not supported on 95&98 (or NT prior to SP2) 
+ * Too bad WriteFileGather() is not supported on 95&98 (or NT prior to SP2)
  */
 ap_status_t ap_writev(ap_file_t *thefile, const struct iovec *vec, ap_size_t nvec, 
                       ap_ssize_t *nbytes)
@@ -156,11 +226,18 @@
     if (GetFileType(thefile->filehand) != FILE_TYPE_DISK) {
         return GetLastError();
     }
-    /* and the file pointer is not pointing to the start of the file. */
-    if (GetFilePointer(thefile->filehand)) {
-        if (SetFilePointer(thefile->filehand, -1, NULL, FILE_CURRENT) 
-            == 0xFFFFFFFF) {
-            return GetLastError();
+
+    if (thefile->buffered) {
+        ap_off_t offset = -1;
+        return ap_seek(thefile, APR_CUR, &offset);
+    }
+    else {
+        /* and the file pointer is not pointing to the start of the file. */
+        if (GetFilePointer(thefile->filehand)) {
+            if (SetFilePointer(thefile->filehand, -1, NULL, FILE_CURRENT)
+                == 0xFFFFFFFF) {
+                return GetLastError();
+            }
         }
     }
 
@@ -219,8 +296,23 @@
 }
 ap_status_t ap_flush(ap_file_t *thefile)
 {
-    FlushFileBuffers(thefile->filehand);
-    return APR_SUCCESS; 
+    if (thefile->buffered) {
+        DWORD written = 0;
+        ap_status_t rc = 0;
+
+        if (thefile->direction == 1 && thefile->bufpos) {
+            rc = WriteFile(thefile->filehand, thefile->buffer, thefile->bufpos,
&written, NULL ) ? 0 : GetLastError();
+            thefile->filePtr += written;
+
+            if (rc == 0)
+                thefile->bufpos = 0;
+        }
+
+        return rc;
+    } else {
+        FlushFileBuffers(thefile->filehand);
+        return APR_SUCCESS;
+    }
 }
 
 static int printf_flush(ap_vformatter_buff_t *vbuff)
Index: seek.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/file_io/win32/seek.c,v
retrieving revision 1.6
diff -u -r1.6 seek.c
--- seek.c	2000/04/03 19:44:37	1.6
+++ seek.c	2000/04/29 09:25:16
@@ -57,33 +57,86 @@
 #include <errno.h>
 #include <string.h>
 
+static ap_status_t setptr(ap_file_t *thefile, unsigned long pos )
+{
+    long newbufpos;
+    DWORD rc;
+
+    if (thefile->direction == 1) {
+        ap_flush(thefile);
+        thefile->bufpos = thefile->direction = thefile->dataRead = 0;
+    }
+
+    newbufpos = pos - (thefile->filePtr - thefile->dataRead);
+
+    if (newbufpos >= 0 && newbufpos <= thefile->dataRead) {
+        thefile->bufpos = newbufpos;
+        rc = 0;
+    } else {
+        rc = SetFilePointer(thefile->filehand, pos, NULL, FILE_BEGIN);
+
+        if ( rc == 0xFFFFFFFF )
+            rc = GetLastError();
+        else
+            rc = thefile->bufpos = thefile->dataRead = 0;
+    }
+
+    return rc;
+}
+
+
+
 ap_status_t ap_seek(ap_file_t *thefile, ap_seek_where_t where, ap_off_t *offset)
 {
     DWORD howmove;
     DWORD rv;
 
-    switch(where) {
-    case APR_SET: {
-        howmove = FILE_BEGIN;
-        break;
-    }
-    case APR_CUR: {
-        howmove = FILE_CURRENT;
-        break;
-    }
-    case APR_END: {
-        howmove = FILE_END;
-        break;
-    }
-    }
+    if (thefile->buffered) {
+        int rc = APR_EINVAL;
+        ap_finfo_t finfo;
 
-    rv = SetFilePointer(thefile->filehand, *offset, NULL, howmove);
-    if (rv == -1) {
-        *offset = -1;
-        return APR_EEXIST;
-    }
-    else {
-        *offset = rv;
-        return APR_SUCCESS;
+        switch (where) {
+        case APR_SET:
+            rc = setptr(thefile, *offset);
+            break;
+
+        case APR_CUR:
+            rc = setptr(thefile, thefile->filePtr - thefile->dataRead + thefile->bufpos
+ *offset);
+            break;
+
+        case APR_END:
+            rc = ap_getfileinfo(&finfo, thefile);
+            if (rc == APR_SUCCESS)
+                rc = setptr(thefile, finfo.size - *offset);
+            break;
+        }
+
+        *offset = thefile->filePtr + thefile->bufpos;
+        return rc;
+    } else {
+        switch(where) {
+        case APR_SET: {
+            howmove = FILE_BEGIN;
+            break;
+        }
+        case APR_CUR: {
+            howmove = FILE_CURRENT;
+            break;
+        }
+        case APR_END: {
+            howmove = FILE_END;
+            break;
+        }
+        }
+
+        rv = SetFilePointer(thefile->filehand, *offset, NULL, howmove);
+        if (rv == -1) {
+            *offset = -1;
+            return APR_EEXIST;
+        }
+        else {
+            *offset = rv;
+            return APR_SUCCESS;
+        }
     }
 }

-- 
 ______________________________________________________________________________
 |  Brian Havard                 |  "He is not the messiah!                   |
 |  brianh@kheldar.apana.org.au  |  He's a very naughty boy!" - Life of Brian |
 ------------------------------------------------------------------------------


Mime
View raw message