javafileioexceptionrandomaccessfilefilechannel

Why does Java FileChannel.truncate fail predictably on Windows only?


I have a web application running in Wildfly, and part of the application uses a temporary file via: File.createTempFile(...). That temporary file is then used as the destination file for a read-write java.io.RandomAccessFile stream. The java.nio.channels.FileChannel for that RandomAccessFile is what is interacted with and eventually truncated (when I'm done with it). Portions of the file do get read-write mapped via FileChannel.map()

After all interaction with the file is done, the file is truncated to the proper size using fileChannel.truncate(size). This is where an IOException is always thrown
at sun.nio.ch.FileDispatcherImpl.truncate0(Native Method)

The IOException message is generic:
java.io.IOException: The requested operation cannot be performed on a file with a user-mapped section open.

This is a temp file created explicitly by the same process and it has remained open for the duration of work with it, a matter of a few seconds probably. Googling around suggests maybe AV software has a handle on the file, or some other application is using it, but I've tried running this on various VM's and regular windows boxes with different configurations and the problem are reliably reproducible. I think there must be some real abuse of the File facilities occurring, but I'm at a loss.

Also, this exception is never seen on a Linux machine, the truncation works reliably. There is no file locking being performed, this is the only file in use, things are being buffered and written to the channel, but nothing very strange is going on.

For the record, I have created some sample test apps creating streams, channels, temp files, performing truncations, etc and I am unable to reproduce the problem in a standalone app. Unfortunately, I can't share the source directly, so I am doing my best to describe what's occurring in the hopes that someone has run into something similar and can offer some guidance.


Solution

  • There doesn't appear to be a proper answer / solution to my question, but at least I came across some details which inform the problem, thanks to the link @diginoise posted as a comment.

    I was getting the exception because I was trying to truncate a file for which there was a memory mapped byte buffer still "active". Apparently there is no way for a user to manually unmap / release Windows' handle on that memory (see JDK bug in oracle's bug database).

    In the end, I think the answer is simply to NOT try truncate / delete these files when I'm done with them but rather keep track of them and process them next time the application starts, that way they're guaranteed to not have active memory maps.

    By the way, a File.deleteOnExit() also fails under these memory mapped file conditions.

    Until I implement the more permanent fix of handling the files on next startup, I've elected to manually unmap the memory via reflection.

    This mitigation does function without throwing errors, it does allow truncation, and does allow deleteOnExit, but this is a short-term unsustainable workaround. It's not good practice to be using reflection to invoke a method that may not be there depending on the FileChannel implementation. With another implementation of FilChannel I might have broken temp files laying around that never get cleaned up.