On Fri, Jul 1, 2022 at 12:00 AM Yann Ylavic <ylavic....@gmail.com> wrote: > > 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 found WriteFileGather (https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefilegather). Maybe it can help with some logic à la apr_socket_sendv()? > 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.