summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjerenkrantz <jerenkrantz@13f79535-47bb-0310-9956-ffa450edef68>2004-08-02 09:47:48 +0000
committerjerenkrantz <jerenkrantz@13f79535-47bb-0310-9956-ffa450edef68>2004-08-02 09:47:48 +0000
commita9a4c27a2be8524b0de8b7d80060fa452b19dd21 (patch)
treeb06153ee5dcfdc285096a0534ea9beb12f4a459b
parent054658eb7d0be25c6b0d5622591055b1daa304e8 (diff)
downloadlibapr-a9a4c27a2be8524b0de8b7d80060fa452b19dd21.tar.gz
Improve apr_file_gets() performance on buffered files by not calling
apr_file_read() on each byte if we don't have to. (mod_negotiation requests call apr_file_gets() for each line in the map file, which can get to be quite expensive to have repeated memcpy()'s for one byte!) git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@65294 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--CHANGES3
-rw-r--r--file_io/unix/readwrite.c66
2 files changed, 58 insertions, 11 deletions
diff --git a/CHANGES b/CHANGES
index 6a871e3f9..70a71eb2d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,7 @@
Changes for APR 1.1 [Deferring these features when 1.0 is rolled out.]
+
+ *) Improve apr_file_gets() performance on buffered files. [Justin Erenkrantz]
+
*) Win32: Fix bug in apr_socket_sendfile that interferred with
Win32 LSPs. PR 23982 [Jan Bilek, Bill Stoddard]
diff --git a/file_io/unix/readwrite.c b/file_io/unix/readwrite.c
index 1e6a6e665..98a11421d 100644
--- a/file_io/unix/readwrite.c
+++ b/file_io/unix/readwrite.c
@@ -24,9 +24,6 @@
#define USE_WAIT_FOR_IO
#endif
-/* problems:
- * 1) ungetchar not used for buffered files
- */
APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes)
{
apr_ssize_t rv;
@@ -311,18 +308,65 @@ APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile)
return APR_SUCCESS;
}
- while (str < final) { /* leave room for trailing '\0' */
- nbytes = 1;
- rv = apr_file_read(thefile, str, &nbytes);
- if (rv != APR_SUCCESS) {
- break;
+ /* If we have an underlying buffer, we can be *much* more efficient
+ * and skip over the apr_file_read calls.
+ */
+ if (thefile->buffered) {
+
+#if APR_HAS_THREADS
+ if (thefile->thlock) {
+ apr_thread_mutex_lock(thefile->thlock);
+ }
+#endif
+
+ if (thefile->direction == 1) {
+ apr_file_flush(thefile);
+ thefile->direction = 0;
+ thefile->bufpos = 0;
+ thefile->dataRead = 0;
}
- if (*str == '\n') {
+
+ while (str < final) { /* leave room for trailing '\0' */
+ /* Force ungetc leftover to call apr_file_read. */
+ if (thefile->bufpos < thefile->dataRead &&
+ thefile->ungetchar == -1) {
+ *str = thefile->buffer[thefile->bufpos++];
+ }
+ else {
+ nbytes = 1;
+ rv = apr_file_read(thefile, str, &nbytes);
+ if (rv != APR_SUCCESS) {
+ break;
+ }
+ }
+ if (*str == '\n') {
+ ++str;
+ break;
+ }
+ ++str;
+ }
+
+#if APR_HAS_THREADS
+ if (thefile->thlock) {
+ apr_thread_mutex_unlock(thefile->thlock);
+ }
+#endif
+ }
+ else {
+ while (str < final) { /* leave room for trailing '\0' */
+ nbytes = 1;
+ rv = apr_file_read(thefile, str, &nbytes);
+ if (rv != APR_SUCCESS) {
+ break;
+ }
+ if (*str == '\n') {
+ ++str;
+ break;
+ }
++str;
- break;
}
- ++str;
}
+
/* We must store a terminating '\0' if we've stored any chars. We can
* get away with storing it if we hit an error first.
*/