This is the mail archive of the java-discuss@sourceware.cygnus.com mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: java.net: Classpath vs. libgcj Comparison


Thanks for these comparisons, they should be very useful.

"Aaron M. Renn" wrote:

> java.net.InetAddress

> Really liked the caching mechanism of the classpath implementation, this classpath class seems very strong, and is preferable to the libgcj version. This comparison should
> definitely include some real world testing, but unfortunaltely, i don't have time.

I disagree with this. Caching inside InetAddress is a misfeature. The underlying OS already caches DNS entries. This cache is shared with other processes, and the OS in a better
position to make decisions about what adresses are cacheable, and for how long. This caching would be very annoying for some applications if we don't provide a way to bypass it, for
example, what happens if you are trying to connect to a server with a revolving DNS? With the classpath cache implementation, getByName() will allways return the same address, until
it expires from the cache.

In environments where native calls are expensive, there is an argument that a cache will provide better performance. But well written Java applications tend to call getByName() once,
and keep the returned InetAddress object around for as long as they need it. In any case, I think the possibility of getting stale results (and being out of sync with other
applications on the system), outweighs any benefits here.

Merging the two codebases is something that should really be considered on a method-by-method (and line-by-line!) basis rather than class-by-class. Here's a few examples of why this
is important, taken from java.net.InetAddress:

Example 1 - from the classpath's InetAddress:

int[] my_ip;

This is inefficient. IP addresses should be represented as byte[], as libgcj does.

String hostname_alias;
long lookup_time;

I'm not sure what hostname_alias is for, but it looks like it something to do with reverse-lookup on cached entries? Its important to consider that this along with lookup_time is
adding extra bulk to every InetAddress object that gets created, and in some applications could add up to significant additional memory consumption.

Example 2: equals() implementation

from libgcj:

  public boolean equals (Object obj)
  {
    if (obj == null || ! (obj instanceof InetAddress))
      return false;
    // "The Java Class Libraries" 2nd edition says "If a machine has
    // multiple names instances of InetAddress for different name of
    // that same machine are not equal.  This is because they have
    // different host names."  This violates the description in the
    // JDK 1.2 API documentation.  A little experiementation
    // shows that the latter is correct.
    byte[] addr1 = address;
    byte[] addr2 = ((InetAddress) obj).address;
    if (addr1.length != addr2.length)
      return false;
    for (int i = addr1.length;  --i >= 0;  )
      if (addr1[i] != addr2[i])
        return false;
    return true;
  }

from classpath:

public boolean
equals(Object addr)
{
  if (!(addr instanceof InetAddress))
    return(false);

  byte[] test_ip = ((InetAddress)addr).getAddress();

  if (test_ip.length != my_ip.length)
    return(false);

  for (int i = 0; i < my_ip.length; i++)
    if (test_ip[i] != (byte)my_ip[i])
       return(false);

  return(true);
}

Although the classpath implementation perhaps looks a bit nicer here, there are a few problems with it. It is slower, because it makes an unneccesary call to getAddress(), and it has
to cast my_ip(i) to byte because my_ip was declared wrong to begin with. The libgcj implementation isn't perfect either - it has a redundant check for null (instanceof will return
false if given a null operand). The comment in libgcj provides useful insight, and should be included in the merged version.

Example 3: getAddress()

libgcj implementation:

  public byte[] getAddress ()
  {
    // An experiment shows that JDK1.2 returns a different byte array each
    // time.  This makes sense, in terms of security.
    return (byte[]) address.clone();
  }

classpath implementation:

public byte[]
getAddress()
{
  byte[] addr = new byte[my_ip.length];

  for (int i = 0; i < my_ip.length; i++)
    {
      addr[i] = (byte)my_ip[i];
    }

  return(addr);
}

Its difficult to say which would be faster here - its a question of the overhead of an extra method call (to clone()) vs. the looping and setting of classpath. In the absence of hard
benchmarks, I would go with the libgcj implementation here. It provides a useful comment, and the implementation is simpler as well as probibly being faster.

These are just some arbritary examples I came up with because I happened to have the two InetAddress implementations open on my screen, but the types of issues here apply to all the
classes that need to be merged. I jsut want to stress that merging shouldn't a case of "well take this class from libgcj, that one from classpath", but something that needs to be
done on a lower level than that.

regards

  [ bryce ]



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]