On Thu, Jun 30, 2022 at 7:28 PM <[email protected]> wrote:
>
> Author: ivan
> Date: Thu Jun 30 17:28:50 2022
> New Revision: 1902378
>
> URL: http://svn.apache.org/viewvc?rev=1902378&view=rev
> Log:
> On 1.8.x branch: Merge r1806299, r1806301, r1806308, r1806610:
> *) apr_file_write: Optimize large writes to buffered files on
> Windows.
[]
>
> --- apr/apr/branches/1.8.x/file_io/win32/readwrite.c (original)
> +++ apr/apr/branches/1.8.x/file_io/win32/readwrite.c Thu Jun 30 17:28:50 2022
> @@ -247,6 +247,91 @@ APR_DECLARE(apr_status_t) apr_file_read(
> return rv;
> }
>
> +/* Helper function that adapts WriteFile() to apr_size_t instead
> + * of DWORD. */
> +static apr_status_t write_helper(HANDLE filehand, const char *buf,
> + apr_size_t len, apr_size_t *pwritten)
> +{
> + apr_size_t remaining = len;
> +
> + *pwritten = 0;
> + do {
> + DWORD to_write;
> + DWORD written;
> +
> + if (remaining > APR_DWORD_MAX) {
> + to_write = APR_DWORD_MAX;
> + }
> + else {
> + to_write = (DWORD)remaining;
> + }
> +
> + if (!WriteFile(filehand, buf, to_write, &written, NULL)) {
> + *pwritten += written;
> + return apr_get_os_error();
> + }
> +
> + *pwritten += written;
> + remaining -= written;
> + buf += written;
> + } while (remaining);
So there's no writev() like syscall on Windows (something that
provides atomicity)?
I would stop the loop on written < to_write at least, apr_file_write()
should be prepared to get a short/partial write (for whatever reason),
or otherwise use apr_file_write_full().
> +
> + return APR_SUCCESS;
> +}
> +
> +static apr_status_t write_buffered(apr_file_t *thefile, const char *buf,
> + apr_size_t len, apr_size_t *pwritten)
> +{
> + apr_status_t rv;
> +
> + if (thefile->direction == 0) {
> + /* Position file pointer for writing at the offset we are logically
> reading from */
> + apr_off_t offset = thefile->filePtr - thefile->dataRead +
> thefile->bufpos;
> + DWORD offlo = (DWORD)offset;
> + LONG offhi = (LONG)(offset >> 32);
> + if (offset != thefile->filePtr)
> + SetFilePointer(thefile->filehand, offlo, &offhi, FILE_BEGIN);
> + thefile->bufpos = thefile->dataRead = 0;
> + thefile->direction = 1;
> + }
> +
> + *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;
> +
> + 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;
> + }
> + }
Likewise.
> +
> + return APR_SUCCESS;
> +}
Regards;
Yann.