OPERATING SYSTEM(S):
Windows
FULL JDK VERSION(S):
All 5.0 and 6 JDKs
DESCRIPTION:
1. Compile the provided testcase ForceFlushTest.java
2. Start Filemon.exe utility (Can be downloaded from
   http://technet.microsoft.com/en-us/sysinternals/bb896642.aspx)
3. Run "java ForceFlushTest 1" to create a file and use
   MappedByteBuffer.force() to ensure all data is written to it.
4. Observe that there is no call to FLUSH in the filemon output
5. Run "java ForceFlushTest 2" to create a file and use
   FileChannel.force() to ensure all data is written to it.
6. Observe that there *is* a call to FLUSH in the filemon output
The behaviour of MappedByteBuffer.force() does not tally with its Javadoc, which states:
 "Forces any changes made to this buffer's content to be written to the
  storage device containing the mapped file. If the file mapped into
  this buffer resides on a local storage device then when this method
  returns it is guaranteed that all changes made to the buffer since it
  was created, or since this method was last invoked, will have been
  written to that device."
The problem seems to be that the implementation for MappedByteBuffer.force() on Windows does not follow the Windows API documentation, which states:
 "To flush all the dirty pages plus the metadata for the file and ensure
  that they are physically written to disk, call FlushViewOfFile and
  then call the FlushFileBuffers function."
The MappedByteBuffer.force() implementation calls FlushViewOfFile(), but does not call FlushFileBuffers() immediately afterwards.
This could cause serious problems with applications that require content to be written to files to guarantee consistency in the event of power failures etc.
TESTCASE SOURCE:
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.Arrays;
public class ForceFlushTest {
    private static final String filename = "c:\\temp\\file1";
    public static void main(String[] args) throws Exception {
        if (args.length != 1 || 1 > Integer.parseInt(args[0]) || Integer.parseInt(args[0]) > 2 ) {
            System.out.println("Usage: java ForceFlushTest 1|2");
            System.out.println("Where: 1 = use MappedByteBuffer.force(), 2 = use FileChannel.force()");
            System.exit(1);
        }
        int mode = Integer.parseInt(args[0]);
        
        ByteBuffer buff = ByteBuffer.allocate(4096);
        Arrays.fill(buff.array(), (byte)' ');
        
        RandomAccessFile mapFile = new RandomAccessFile(filename, "rw");
        FileChannel mapChl = mapFile.getChannel();
        MappedByteBuffer mappedBuffer = mapChl.map(MapMode.READ_WRITE, 0, 1024*1024);
        byte[] writeBuff = new byte[1024];
        for (int i = 0; i < writeBuff.length; i++) {
            writeBuff[i] = (byte)('a' + i%26);
        }
        for (int i = 0; i<1024; i++) {
            mappedBuffer.rewind();
            mappedBuffer.put(writeBuff);
            switch (mode) {
            case 1:
                mappedBuffer.force(); // Doesn't cause a FLUSH
                break;
            case 2:
                mapChl.force(false); // Does cause a FLUSH
                break;
            }
        }
    }
}