diff options
author | ivan <ivan@13f79535-47bb-0310-9956-ffa450edef68> | 2017-08-26 15:20:02 +0000 |
---|---|---|
committer | ivan <ivan@13f79535-47bb-0310-9956-ffa450edef68> | 2017-08-26 15:20:02 +0000 |
commit | 0ddf0fcb2d039b0f14eab348744d57a8f13ad184 (patch) | |
tree | be20c6f6b6469d96ccbedc4b27d29af92036e69c /file_io | |
parent | 24dbfffd60dd755bebaaf1bfbe815dc06bdc966d (diff) | |
download | libapr-0ddf0fcb2d039b0f14eab348744d57a8f13ad184.tar.gz |
Win32: Improve apr_file_write() performance on buffered files by reducing
the amount of WriteFile() calls for large writes.
Previously, writing has been implemented with a loop that keeps copying the
data to the internal 4KB buffer and writing this buffer to disk by calling
WriteFile(4096). This patch reduces the amount of syscalls for large writes
by performing them with a single syscall, if possible. If the buffer is
not empty at the moment when the large write occurs, it is first filled
up to its 4KB capacity, flushed, and the remaining part of the data is
written with a single syscall.
* file_io/win32/readwrite.c
(write_buffered): Within the write loop, check if we have a situation
with an empty buffer and a large chunk pending to be written. In this
case, bypass the buffering and write the remaining chunk with a single
syscall. Return an appropriate number of written bytes to satisfy
the apr_file_write() function contract.
(apr_file_write): Adjust call to write_buffered().
* test/testfile.c
(test_large_write_buffered,
test_two_large_writes_buffered,
test_small_and_large_writes_buffered,
test_write_buffered_spanning_over_bufsize): New tests.
(testfile): Run the new tests.
Patch by: Evgeny Kotkov <evgeny.kotkov {at} visualsvn.com>
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@1806308 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'file_io')
-rw-r--r-- | file_io/win32/readwrite.c | 44 |
1 files changed, 32 insertions, 12 deletions
diff --git a/file_io/win32/readwrite.c b/file_io/win32/readwrite.c index ee36afc6f..8e9ab6f47 100644 --- a/file_io/win32/readwrite.c +++ b/file_io/win32/readwrite.c @@ -290,9 +290,8 @@ static apr_status_t write_helper(HANDLE filehand, const char *buf, } static apr_status_t write_buffered(apr_file_t *thefile, const char *buf, - apr_size_t len) + apr_size_t len, apr_size_t *pwritten) { - apr_size_t blocksize; apr_status_t rv; if (thefile->direction == 0) { @@ -306,20 +305,41 @@ static apr_status_t write_buffered(apr_file_t *thefile, const char *buf, thefile->direction = 1; } - rv = 0; - while (rv == 0 && len > 0) { - if (thefile->bufpos == thefile->bufsize) /* write buffer is full */ + *pwritten = 0; + + while (len > 0) { + if (thefile->bufpos == thefile->bufsize) { /* write buffer is full */ rv = apr_file_flush(thefile); + if (rv) { + return rv; + } + } + /* If our buffer is empty, and we cannot fit the remaining chunk + * into it, write the chunk with a single syscall and return. + */ + if (thefile->bufpos == 0 && len > thefile->bufsize) { + apr_size_t written; - blocksize = len > thefile->bufsize - thefile->bufpos ? - thefile->bufsize - thefile->bufpos : len; - memcpy(thefile->buffer + thefile->bufpos, buf, blocksize); - thefile->bufpos += blocksize; - buf += blocksize; - len -= blocksize; + rv = write_helper(thefile->filehand, buf, len, &written); + thefile->filePtr += written; + *pwritten += written; + return rv; + } + else { + apr_size_t blocksize = len; + + if (blocksize > thefile->bufsize - thefile->bufpos) { + blocksize = thefile->bufsize - thefile->bufpos; + } + memcpy(thefile->buffer + thefile->bufpos, buf, blocksize); + thefile->bufpos += blocksize; + buf += blocksize; + len -= blocksize; + *pwritten += blocksize; + } } - return rv; + return APR_SUCCESS; } APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes) |