On 28 August 2017 at 13:44, Evgeny Kotkov <evgeny.kot...@visualsvn.com> wrote: > Hi everyone, > > Currently, appending data to a file opened with APR_FOPEN_APPEND > that has been locked by apr_file_lock() will cause a deadlock on Windows. > > [See PR50058, https://bz.apache.org/bugzilla/show_bug.cgi?id=50058] > > This issue happens because atomic O_APPEND-style appends on Windows > are implemented using file locks. An append happens while holding the > file lock acquired with LockFile(), which is required to avoid a race > condition between seeking to the end of file and writing data. The > race is possible when multiple threads or processes are appending > data to the same file. > > This approach causes a deadlock if the file has been previously locked > with apr_file_lock(). (Note that it's perfectly legit to lock the file or > its portion and perform the append after that.) > > Apart from this, using file locks for file appends impacts their speed and > robustness. There is an overhead associated with locking the file, especially > if the file is not local. The robustness is affected, because other writes > to the same file may fail due to it being locked. Also, if a process is > terminated in the middle of the append operation, it might take some time > for the OS to release the file lock. During this time, the file would be > inaccessible to other processes. This may affect applications such as > httpd (with a multi-process MPM) that use APR_FOPEN_APPEND files for > logging. > > This patch series fixes the issue by switching to the documented way to > atomically append data with a single WriteFile() call. It requires passing > special OVERLAPPED.Offset and OffsetHigh values (0xFFFFFFFF). On the > ZwWriteFile() layer, this maps to a FILE_WRITE_TO_END_OF_FILE constant > that instructs the OS (the corresponding file system driver) to write data > to the file's end. > > Note that this approach is only used for files opened for synchronous I/O > because in this case the I/O Manager maintains the current file position. > Otherwise, the file offset returned or changed by the SetFilePointer() API is > not guaranteed to be valid and that could, for instance, break apr_file_seek() > calls after appending data. Sadly, if a file is opened for asynchronous I/O, > this call to WriteFile() doesn't update the OVERLAPPED.Offset member to > reflect the actual offset used when appending the data (which we could > then use to make seeking and other operations involving filePtr work). > Therefore, when appending to files opened for asynchronous I/O, we still > use the old LockFile + SetFilePointer + WriteFile approach. > > Additional details on this can be found in: > > https://msdn.microsoft.com/en-us/library/windows/desktop/aa365747 > https://msdn.microsoft.com/en-us/library/windows/hardware/ff567121 > > > The implementation is split into four dependent patches. The first three > patches are minor refactorings to the apr_file_write() function and lay the > necessary groundwork for the core change. The fourth patch is the core > change that fixes the issue in the described way and also includes the > tests. > > The log messages are included in the beginning of each patch file. > > 1-file-write-simplify-local-vars-v1.patch.txt Committed in r1806592.
> 2-file-write-simplify-fileptr-inc-v1.patch.txt Committed in r1806603. > 3-file-write-invert-if-condition-v1.patch.txt Committed in r1806604. > 4-fix-locked-append-deadlock-v1.patch.txt Committed in r1806608. Thanks! -- Ivan Zhakov