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.