Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4170047
Votes 0
Synopsis java.io.RandomAccessFile: Performance enhancement broke compatibility (beta4.1)
Category java:classes_io
Reported Against 1.2fcs
Release Fixed 1.2(1.2fcs)
State 11-Closed, Unverified, bug
Priority: 3-Medium
Related Bugs 4137835 , 4193259
Submit Date 28-AUG-1998
Description

Subject: changes to java.io.RandomAccessFile.readUnsignedShort()
Date: Wed, 26 Aug 1998 21:45:35 -0400


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());
  }
}
Work Around
N/A
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.

--  xxxxx@xxxxx  8/31/1998
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang