JDK-4711787 : RandomAccessFile synchronous write mode ignored on JDK1.4 on Windows
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 1.4.0
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2002-07-08
  • Updated: 2002-11-26
  • Resolved: 2002-11-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.2 mantisFixed
Description

Name: wm7046			Date: 07/08/2002


FULL PRODUCT VERSION :
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)

FULL OPERATING SYSTEM VERSION :    Any Windows, but tested
only on XP


A DESCRIPTION OF THE PROBLEM :
The 1.4 JDK introduces a new "synchronous write" mode flags
that can be specified in the java.io.RandomAccessFile
constructor.  This essentially is intended to open the file
in the equivalent of Solaris' "O_SYNC" and "O_DSYNC" modes.
These flags are apparently totally ignored on Windows XP,
and likely all other versions of Windows.

Please give this bug a high priority as there is no
easy or similarly performing work-around.  Also, this is a
"silent" bug, it is not detectable except by those that know
what the performance characteristics should be.  Also, this
but is a "very bad thing" for data integrity.


------------------------------------------------------------

THE FIX:

The Sun JDK apparently uses the Windows POSIX library for
file I/O.  Unfortunately, this library doesn't support
synchronous writes (i.e. O_SYNC or O_DSYNC), but I'm not
100% sure on this.  A fix may require use of the non-POSIX
Win32 "CreateFile" function to open the file with the Win32
flag "FILE_FLAG_WRITE_THROUGH".

At BEA I have written native code that does just this, it
was this work that led me to the JDK1.4 bug...
 


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run provided sample code on java 1.4 on Windows:
    "java TooFast"

Note that on Windows, unlike Solaris, the on-hard-drive
write-cache is enabled even for synchronous writes, unlike
Solaris.  The test failure above may require disabling this
cache to recreate, to do this:
  control panel
  administrative tools
  computer management
  device manager
  disk drives
  click on your hard-drive
  policies tab
  uncheck "enable write caching on disk"


EXPECTED VERSUS ACTUAL BEHAVIOR :
On my Windows XP laptop 5400 RPM IDE hard-drive, the result
was:
<src_jms fileio/test> java TooFast

83333.24723782427 synchronous-writes/sec

Exception in thread "main" java.io.IOException: WAY WAY WAY
TOO FAST,
    more than 5000 sync writes/sec,
    Expect lower than 1000 writes per second
     - (usually much lower).
        at TooFast.main(TooFast.java:29)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.*;
import java.util.*;

/**
 * Show something is wrong with JDK1.4 synchronous writes on Windows.
 */

public class TooFast {
  public static void main(String [] args) throws Exception {
    int NUMWRITES = 5000;
    RandomAccessFile f;
    Random r = new Random();

    File file = new File("TooFast.out");
    if (file.exists()) file.delete();
    f = new RandomAccessFile(file,"rwd");

    double before = (double)System.currentTimeMillis()/1000.0;
    for (int i = NUMWRITES; i > 0; i--) {
      f.seek(r.nextInt(100000));
      f.write(new byte[1000]);
    }
    double after = (double)System.currentTimeMillis()/1000.0;

    double writesPerSec = (NUMWRITES / (after - before));
    System.out.println("\n" + writesPerSec + " synchronous-writes/sec\n");

    if (writesPerSec > 5000)
      throw new IOException("WAY WAY WAY TOO FAST,\n "
               + "   more than 5000 sync writes/sec,\n "
               + "   Expect lower than 1000 writes per second\n "
               + "    - (usually much lower).");

    System.out.println();
  }
}



---------- END SOURCE ----------

CUSTOMER WORKAROUND :
Modify application to call fd.sync() after each write() - a
huge performance hit.  Alternatively, write your own native
code, which BEA has already done.
(Review ID: 158582) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mantis FIXED IN: mantis INTEGRATED IN: mantis mantis-b08 VERIFIED IN: mantis-beta
14-06-2004

EVALUATION Submitter is correct -- we need to rework RandomAccessFile.open to use the native CreateFile API. Unfortunately the changes required for this are fairly extensive, so this is far too risky for Hopper (1.4.1) at this late date. We'll fix this in Mantis (1.4.2). -- ###@###.### 2002/7/15
07-10-0181