Hi there,

here is just another one from my stack of performance patches.
As suggested in http://svn.haxx.se/dev/archive-2010-03/0612.shtml,
I provided a patch to the APR reducing its runtime for typical usage
scenarios (https://issues.apache.org/bugzilla/show_bug.cgi?id=49085).

The patch below uses the now optimized single-char I/O functions
where appropriate. I also prevents the construction of temporary
error objects (expensive due to NLS) when hitting EOF.

-- Stefan^2.

[[[
Reduce file I/O overhead by using optimized single-char I/O functions
and eliminating unnecessary EOF error objects.

* subversion/include/svn_io.h:
 (svn_io_file_putc, svn_io_file_read_full2): declare new functions.

* subversion/libsvn_subr/io.c:
 (svn_io_file_putc, svn_io_file_read_full2): implement new functions.
 (svn_io_file_write_full): under Windows, call apr_file_write instead
 directly because we already implement the "read full" functionality
 (contents_identical_p): prevent temp. errors upon EOF

* subversion/libsvn_subr/stream.c:
 (read_handler_apr,): use optimized code for single chars;
 prevent temp. errors upon EOF
 (writer_handler_apr): use optimized code for single chars
]]]
Index: subversion/include/svn_io.h
===================================================================
--- subversion/include/svn_io.h (revision 937673)
+++ subversion/include/svn_io.h (working copy)
@@ -1726,6 +1726,15 @@
                  apr_pool_t *pool);
 
 
+/** Wrapper for apr_file_putc(). 
+  * @since New in 1.7
+  */
+svn_error_t *
+svn_io_file_putc(char ch,
+                 apr_file_t *file,
+                 apr_pool_t *pool);
+
+
 /** Wrapper for apr_file_info_get(). */
 svn_error_t *
 svn_io_file_info_get(apr_finfo_t *finfo,
@@ -1751,6 +1760,20 @@
                       apr_pool_t *pool);
 
 
+/** Wrapper for apr_file_read_full(). 
+ * If eof_is_ok is set, no svn_error_t error object
+ * will be created upon EOF.
+ * @since New in 1.7
+ */
+svn_error_t *
+svn_io_file_read_full2(apr_file_t *file,
+                       void *buf,
+                       apr_size_t nbytes,
+                       apr_size_t *bytes_read,
+                       svn_boolean_t eof_is_ok,
+                       apr_pool_t *pool);
+
+
 /** Wrapper for apr_file_seek(). */
 svn_error_t *
 svn_io_file_seek(apr_file_t *file,
Index: subversion/libsvn_subr/io.c
===================================================================
--- subversion/libsvn_subr/io.c (revision 937673)
+++ subversion/libsvn_subr/io.c (working copy)
@@ -2751,6 +2751,17 @@
 
 
 svn_error_t *
+svn_io_file_putc(char ch, apr_file_t *file, apr_pool_t *pool)
+{
+  return do_io_file_wrapper_cleanup
+    (file, apr_file_putc(ch, file),
+     N_("Can't write file '%s'"),
+     N_("Can't write stream"),
+     pool);
+}
+
+
+svn_error_t *
 svn_io_file_info_get(apr_finfo_t *finfo, apr_int32_t wanted,
                      apr_file_t *file, apr_pool_t *pool)
 {
@@ -2788,6 +2799,24 @@
 
 
 svn_error_t *
+svn_io_file_read_full2(apr_file_t *file, void *buf,
+                       apr_size_t nbytes, apr_size_t *bytes_read,
+                       svn_boolean_t eof_is_ok,
+                       apr_pool_t *pool)
+{
+  apr_status_t status = apr_file_read_full(file, buf, nbytes, bytes_read);
+  if (APR_STATUS_IS_EOF (status) && eof_is_ok)
+    return SVN_NO_ERROR;
+
+  return do_io_file_wrapper_cleanup
+    (file, status,
+     N_("Can't read file '%s'"),
+     N_("Can't read stream"),
+     pool);
+}
+
+
+svn_error_t *
 svn_io_file_seek(apr_file_t *file, apr_seek_where_t where,
                  apr_off_t *offset, apr_pool_t *pool)
 {
@@ -2816,25 +2845,24 @@
                        apr_size_t nbytes, apr_size_t *bytes_written,
                        apr_pool_t *pool)
 {
-  apr_status_t rv = apr_file_write_full(file, buf, nbytes, bytes_written);
-
 #ifdef WIN32
 #define MAXBUFSIZE 30*1024
-  if (rv == APR_FROM_OS_ERROR(ERROR_NOT_ENOUGH_MEMORY)
-      && nbytes > MAXBUFSIZE)
-    {
-      apr_size_t bw = 0;
-      *bytes_written = 0;
+  apr_status_t rv;
+  apr_size_t bw = 0;
+  apr_size_t to_write = nbytes;
 
-      do {
-        rv = apr_file_write_full(file, buf,
-                                 nbytes > MAXBUFSIZE ? MAXBUFSIZE : nbytes, 
&bw);
-        *bytes_written += bw;
-        buf = (char *)buf + bw;
-        nbytes -= bw;
-      } while (rv == APR_SUCCESS && nbytes > 0);
-    }
+  do {
+    bw = to_write > MAXBUFSIZE ? MAXBUFSIZE : to_write;
+    rv = apr_file_write(file, buf, &bw);
+    buf = (char *)buf + bw;
+    to_write -= bw;
+  } while (rv == APR_SUCCESS && to_write > 0);
+
+  if (bytes_written)
+    *bytes_written = nbytes - to_write;
 #undef MAXBUFSIZE
+#else
+  apr_status_t rv = apr_file_write_full(file, buf, nbytes, bytes_written);
 #endif
 
   return svn_error_return(do_io_file_wrapper_cleanup(
@@ -3455,8 +3483,6 @@
                      const char *file2,
                      apr_pool_t *pool)
 {
-  svn_error_t *err1;
-  svn_error_t *err2;
   apr_size_t bytes_read1, bytes_read2;
   char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
   char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
@@ -3471,30 +3497,21 @@
   *identical_p = TRUE;  /* assume TRUE, until disproved below */
   do
     {
-      err1 = svn_io_file_read_full(file1_h, buf1,
-                                   SVN__STREAM_CHUNK_SIZE, &bytes_read1, pool);
-      if (err1 && !APR_STATUS_IS_EOF(err1->apr_err))
-        return err1;
+      SVN_ERR(svn_io_file_read_full2(file1_h, buf1,
+                                     SVN__STREAM_CHUNK_SIZE, &bytes_read1, 
+                                     TRUE, pool));
+      SVN_ERR(svn_io_file_read_full2(file2_h, buf2,
+                                     SVN__STREAM_CHUNK_SIZE, &bytes_read2, 
+                                     TRUE, pool));
 
-      err2 = svn_io_file_read_full(file2_h, buf2,
-                                   SVN__STREAM_CHUNK_SIZE, &bytes_read2, pool);
-      if (err2 && !APR_STATUS_IS_EOF(err2->apr_err))
-        {
-          svn_error_clear(err1);
-          return err2;
-        }
-
       if ((bytes_read1 != bytes_read2)
           || (memcmp(buf1, buf2, bytes_read1)))
         {
           *identical_p = FALSE;
           break;
         }
-    } while (! err1 && ! err2);
+    } while (bytes_read1 == SVN__STREAM_CHUNK_SIZE);
 
-  svn_error_clear(err1);
-  svn_error_clear(err2);
-
   SVN_ERR(svn_io_file_close(file1_h, pool));
   return svn_io_file_close(file2_h, pool);
 }
Index: subversion/libsvn_subr/stream.c
===================================================================
--- subversion/libsvn_subr/stream.c     (revision 937673)
+++ subversion/libsvn_subr/stream.c     (working copy)
@@ -680,7 +680,16 @@
   struct baton_apr *btn = baton;
   svn_error_t *err;
 
-  err = svn_io_file_read_full(btn->file, buffer, *len, len, btn->pool);
+  if (*len == 1)
+    {
+      err = svn_io_file_getc (buffer, btn->file, btn->pool);
+      if (err)
+        *len = 0;
+    }
+    else
+      err = svn_io_file_read_full2(btn->file, buffer, *len, len, 
+                                   TRUE, btn->pool);
+
   if (err && APR_STATUS_IS_EOF(err->apr_err))
     {
       svn_error_clear(err);
@@ -694,8 +703,18 @@
 write_handler_apr(void *baton, const char *data, apr_size_t *len)
 {
   struct baton_apr *btn = baton;
+  svn_error_t *err;
 
-  return svn_io_file_write_full(btn->file, data, *len, len, btn->pool);
+  if (*len == 1)
+    {
+      err = svn_io_file_putc (*data, btn->file, btn->pool);
+      if (err)
+        *len = 0;
+    }
+    else
+      err = svn_io_file_write_full(btn->file, data, *len, len, btn->pool);
+
+  return err;
 }
 
 static svn_error_t *

Reply via email to