On Thu, Jun 30, 2022 at 7:28 PM <i...@apache.org> 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.

Reply via email to