JDK-4170047 : java.io.RandomAccessFile: Performance enhancement broke compatibility (beta4.1)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 1.2.0
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 1998-08-28
  • Updated: 1999-01-15
  • Resolved: 1999-01-15
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.2.0 1.2fcsFixed
Related Reports
Relates :  
Relates :  
Description
To: ###@###.###
Cc: ###@###.###, ken.arnold@east
Subject: changes to java.io.RandomAccessFile.readUnsignedShort()
Date: Wed, 26 Aug 1998 21:45:35 -0400
From: Charlie Lamb <###@###.###>

The following program produces different results when run with the JDK
1.2 beta4 and the JDK 1.2 beta4.1.  The reason is because of the
(presumably) performance enhancement made to
java.io.RandomAccessFile.readUnsignedShort() whereby it calls
readTwoBytes(), a native method instead of sequential calls to read().

Changing the internal implementation of java.io.RandomAccessFile is
probably well within your rights.  I will grant you that it was never
part of the published contract of java.io.RandomAccessFile that
readByte, readShort, readInt, etc. would necessarily use one of the
three overloadings of read() to gather their bytes, but one might
have surmised this from the following facts:

(1) java.io.RandomAccessFile was/is not a final class and is therefore
meant to be extended,

(2) readByte, readShort, readInt, etc. are declared to be final
methods, and

(3) read(), read(byte[]), and read(byte[], int, int) are not declared
to be final methods meaning that they are allowed to be extended.

The example below is admittedly contrived, but we do in fact extend
RandomAccessFile in ObjectStore PSE (used by JINI's ObjectSpaces) to
provide buffering on top of RandomAccessFile.  Yes, I can recode this
so that I provide my own implementations of readFully, readByte,
readInt, readShort, and readUTF, but I can't make strict overloadings
of the method signatures declared for RandomAccessFile (since they're
final).

It also means we'll have to ship a new release of PSE in order to have
it work with the JDK 1.2 beta 4.1.

So, is there some really good performance improvement that comes with
this change from read(), read() to readTwoBytes() (ditto for
writeUnsignedShort())?

Thanks for your comments on this.


import java.io.*;

public class ReadOT {
  class ExtendedRAF extends java.io.RandomAccessFile {
    ExtendedRAF(String name, String mode) throws IOException {
      super(name, mode);
    }

    private byte[] rb = new byte[1];
    public int read() throws IOException {
      System.out.println("ERAF read() called");
      int ret = read(rb, 0, 1);
      if (ret < 0)
	return -1;
      else
	return (rb[0] & 0xff);
    }

    public int read(byte[] b, int off, int len) throws IOException {
      System.out.println("ERAF read(byte[], int, int) called");
      return super.read(b, off, len);
    }

    public int read(byte b[]) throws IOException {
      System.out.println("ERAF read(byte[]) called");
      return read(b, 0, b.length);
    }
  }

  static public void main(String argv[]) throws IOException {
    ReadOT rot = new ReadOT();
    ExtendedRAF eraf = rot.new ExtendedRAF("foo", "rw");
    eraf.writeShort(123);
    eraf.seek(0);
    System.out.println(eraf.readShort());
  }
}

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.2fcs FIXED IN: 1.2fcs INTEGRATED IN: 1.2fcs
14-06-2004

EVALUATION The performance improvements obtained by the recent changes to RandomAccessFile were significant. For the record, here are some timings: Solaris 2.6 Windows NT 4.0 166MHz Ultra-1 266MHz Pentium-II old new old new writeLong 9540 1435 3135 441 writeInt 4790 1316 1682 451 writeChar 2485 1275 842 481 writeShort 2422 1276 841 471 readInt 4435 1114 1592 371 readChar 2263 1156 771 430 readUnsignedShort 2258 1178 791 410 readShort 2259 1169 771 401 Each line measures the time, in milliseconds, required to invoke the named method 50000 times against an existing 400000-byte file. With the new native methods the times change very little with the length of the data type being written, while with the old pure Java code the times are directly proportional to the length. Despite these improvements, compatibility dictates that these optimizations be backed out. The original suggestion in RFE 4137835 was to reduce the number of kernel calls by creating small temporary byte arrays. We did not adopt that approach because it can lead to vastly increased object-allocation rates. If we were to adopt that approach now, it would not work very well with the buffered RandomAccessFile subclass described in this bug report either. Developers can achieve better performance by buffering data themselves, either by subclassing RandomAccessFile or by buffering data before invoking the methods of a RandomAccessFile object. Therefore it's probably best to close 4137835 as "will not fix," and address random-access file performance with a new class in a future feature release. -- mr@eng 8/31/1998
31-08-1998