Hey,
did a little test (see code below) to check how much expensive is the
creation of a CacheKey, implementing 2 different algorithms
(MarshalledObject and reflection).
Here the results (running on laptop PII300 128MB WIN2K JDK 1.3) for the
creation of 10000 objects:
PK: 4.7-4.8 ms (for comparison)
MarshalledObject: 4245-4285 ms
Key (reflection): 2785-2825 ms
Well, not the fastest results IMHO, both for MO and reflection.
Given that a CacheKey is created for each bean creation or for each PK
returned by a finder method, a finder that returns a Collection of 10000
beans will take 4.2 (2.8) seconds more than what is needed. Is that
acceptable in your opinion ?
Marc, I've remember you talking about a sequencial-like CacheKey, is it
correct ? What is the idea ?
Simon
import java.lang.reflect.*;
public class CacheKeyTest
{
public static void main(String[] args)
{
int n = 10000;
PK pk = new PK(10, 100L, true, "SIMON", 1.0D, '1', 0.1F);
long start = System.currentTimeMillis();
for (int j = 0; j < n; ++j)
{
try
{
java.rmi.MarshalledObject mo = new
java.rmi.MarshalledObject(pk);
// int hash = mo.hashCode();
}
catch (java.io.IOException x) {}
}
long end = System.currentTimeMillis();
System.out.println(n + " MO creation took: " + (end-start));
int pkn = n * 1000;
start = System.currentTimeMillis();
for (int j = 0; j < pkn; ++j)
{
PK p = new PK(10, 100L, true, "SIMON", 1.0D, '1',
0.1F);
}
end = System.currentTimeMillis();
System.out.println(pkn + " PK creation took: " +
(end-start));
// System.out.println(new Key(pk));
int kn = n;
start = System.currentTimeMillis();
for (int j = 0; j < kn; ++j)
{
Key k = new Key(pk);
}
end = System.currentTimeMillis();
System.out.println(kn + " PK creation took: " +
(end-start));
}
}
class PK
{
public int m_i;
public long m_l;
public boolean m_b;
public String m_s;
public double m_d;
public char m_c;
public float m_f;
PK(int i, long l, boolean b, String s, double d, char c, float f)
{
m_i = i;
m_l = l;
m_b = b;
m_s = s;
m_d = d;
m_c = c;
m_f = f;
}
}
class Key
{
private int m_hash;
private Object m_id;
private StringBuffer m_buffer;
private static String m_separator = "|";
Key(Object id)
{
m_id = id;
Class cls = id.getClass();
if (cls == Object.class || isPrimitiveWrapperOrString(cls))
{
m_hash = id.hashCode();
}
else
{
m_buffer = new StringBuffer();
m_buffer.append(cls.getName());
computeHash(cls);
}
}
public int hashCode() {return m_hash;}
public boolean equals(Object o)
{
if (this == o) {return true;}
if (o instanceof Key)
{
Key other = (Key)o;
if (m_buffer != null && other.m_buffer != null)
{
return
m_buffer.toString().equals(other.m_buffer.toString());
}
return m_id.equals(other.m_id);
}
return false;
}
public String toString() {return m_buffer == null ? super.toString()
+ "#" + m_hash + "|" + m_id.toString(): m_buffer.toString() + "#" + m_hash +
"|" + m_id.toString();}
private void computeHash(Class cls)
{
if (cls == Object.class) {return;}
Field[] fields = cls.getFields();
int l = fields.length;
for (int i = 0; i < l; ++i)
{
Field f = fields[i];
Class c = f.getType();
if (c.isPrimitive() ||
isPrimitiveWrapperOrString(c))
{
m_buffer.append(m_separator);
try {m_buffer.append(f.get(m_id));}
catch (IllegalAccessException ignored) {}
}
else {computeHash(c);}
}
m_hash = m_buffer.toString().hashCode();
}
private boolean isPrimitiveWrapperOrString(Class c)
{
// Ordered by most common
if (c == String.class ||
c == Integer.class ||
c == Boolean.class ||
c == Long.class ||
c == Double.class ||
c == Float.class ||
c == Character.class ||
c == Byte.class ||
c == Short.class) {return true;}
return false;
}
}