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 *