[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] Reducing file I/O overhead

From: Stefan Fuhrmann <stefanfuhrmann_at_alice-dsl.de>
Date: Sun, 25 Apr 2010 00:49:31 +0200

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 *
Received on 2010-04-25 00:49:58 CEST

This is an archived mail posted to the Subversion Dev mailing list.