summaryrefslogtreecommitdiff
path: root/file_io
diff options
context:
space:
mode:
authorivan <ivan@13f79535-47bb-0310-9956-ffa450edef68>2017-08-26 15:20:02 +0000
committerivan <ivan@13f79535-47bb-0310-9956-ffa450edef68>2017-08-26 15:20:02 +0000
commit0ddf0fcb2d039b0f14eab348744d57a8f13ad184 (patch)
treebe20c6f6b6469d96ccbedc4b27d29af92036e69c /file_io
parent24dbfffd60dd755bebaaf1bfbe815dc06bdc966d (diff)
downloadlibapr-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.c44
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)