You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2006/05/24 04:56:20 UTC
svn commit: r409046 -
/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/ObjectId.java
Author: aadamchik
Date: Tue May 23 19:56:20 2006
New Revision: 409046
URL: http://svn.apache.org/viewvc?rev=409046&view=rev
Log:
CAY-525 - optimizing the most common ObjectId case - a single key OID. Performance of hashCode and constructor is improved ~2x to 3x
Modified:
incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/ObjectId.java
Modified: incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/ObjectId.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/ObjectId.java?rev=409046&r1=409045&r2=409046&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/ObjectId.java (original)
+++ incubator/cayenne/main/trunk/cayenne/cayenne-java/src/cayenne/java/org/objectstyle/cayenne/ObjectId.java Tue May 23 19:56:20 2006
@@ -80,6 +80,10 @@
protected String entityName;
protected Map objectIdKeys;
+
+ private String singleKey;
+ private Object singleValue;
+
protected byte[] key;
@@ -148,10 +152,8 @@
public ObjectId(String entityName, String key, Object value) {
this.entityName = entityName;
- // don't use Collections.singletonMap() as we need a mutable single level map
- // internally (for things like Hessian serialization).
- this.objectIdKeys = new HashMap(1);
- objectIdKeys.put(key, value);
+ this.singleKey = key;
+ this.singleValue = value;
}
/**
@@ -162,9 +164,21 @@
public ObjectId(String entityName, Map idMap) {
this.entityName = entityName;
- // we have to create a copy of the map, otherwise we may run into serialization
- // problems with hessian
- this.objectIdKeys = idMap != null && !idMap.isEmpty() ? new HashMap(idMap) : null;
+ if (idMap == null || idMap.size() == 0) {
+
+ }
+ else if (idMap.size() == 1) {
+ Map.Entry e = (Map.Entry) idMap.entrySet().iterator().next();
+ this.singleKey = String.valueOf(e.getKey());
+ this.singleValue = e.getValue();
+ }
+ else {
+
+ // we have to create a copy of the map, otherwise we may run into
+ // serialization
+ // problems with hessian
+ this.objectIdKeys = new HashMap(idMap);
+ }
}
/**
@@ -226,7 +240,14 @@
* @deprecated since 1.2
*/
protected void setIdKeys(Map idKeys) {
- this.objectIdKeys = idKeys;
+ if (idKeys != null && idKeys.size() == 1) {
+ Map.Entry e = (Map.Entry) idKeys.entrySet().iterator().next();
+ this.singleKey = String.valueOf(e.getKey());
+ this.singleValue = e.getValue();
+ }
+ else {
+ this.objectIdKeys = idKeys;
+ }
}
/**
@@ -240,6 +261,10 @@
.unmodifiableMap(replacementIdMap);
}
+ if(singleKey != null) {
+ return Collections.singletonMap(singleKey, singleValue);
+ }
+
return objectIdKeys != null
? Collections.unmodifiableMap(objectIdKeys)
: Collections.EMPTY_MAP;
@@ -274,19 +299,19 @@
return new EqualsBuilder().append(key, id.key).isEquals();
}
- if (id.objectIdKeys == null && objectIdKeys == null) {
- return true;
+ if (singleKey != null) {
+ return Util.nullSafeEquals(singleKey, id.singleKey)
+ && valueEquals(singleValue, id.singleValue);
}
- if (id.objectIdKeys == null || objectIdKeys == null) {
- return false;
+ if (id.objectIdKeys == null) {
+ return objectIdKeys == null;
}
if (id.objectIdKeys.size() != objectIdKeys.size()) {
return false;
}
- EqualsBuilder builder = new EqualsBuilder();
Iterator entries = objectIdKeys.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry) entries.next();
@@ -300,31 +325,35 @@
}
}
else {
- Object otherValue = id.objectIdKeys.get(entryKey);
-
- // normalize all numeric types
- if (entryValue instanceof Number) {
- if (!(otherValue instanceof Number)) {
- return false;
- }
-
- if (((Number) entryValue).longValue() != ((Number) otherValue)
- .longValue()) {
- return false;
- }
- }
- else {
- // takes care of comparing primitive arrays, such as byte[]
- builder.append(entryValue, otherValue);
- if (!builder.isEquals()) {
- return false;
- }
+ if (!valueEquals(entryValue, id.objectIdKeys.get(entryKey))) {
+ return false;
}
}
}
return true;
}
+
+ private final boolean valueEquals(Object o1, Object o2) {
+ if (o1 == o2) {
+ return true;
+ }
+
+ if (o1 == null) {
+ return o2 == null;
+ }
+
+ if (o1 instanceof Number) {
+ return o2 instanceof Number
+ && ((Number) o1).longValue() == ((Number) o2).longValue();
+ }
+
+ if (o1.getClass().isArray()) {
+ return new EqualsBuilder().append(o1, o2).isEquals();
+ }
+
+ return Util.nullSafeEquals(o1, o2);
+ }
public int hashCode() {
@@ -336,45 +365,40 @@
if (key != null) {
builder.append(key);
}
+ else if(singleKey != null) {
+ builder.append(singleKey);
+
+ // must reconcile all possible numeric types
+ if (singleValue instanceof Number) {
+ builder.append(((Number) singleValue).longValue());
+ }
+ else {
+ builder.append(singleValue);
+ }
+ }
else if (objectIdKeys != null) {
int len = objectIdKeys.size();
- // handle cheap and most common case - single key
- if (len == 1) {
- Iterator entries = objectIdKeys.entrySet().iterator();
- Map.Entry entry = (Map.Entry) entries.next();
+ // handle multiple keys - must sort the keys to use with HashCodeBuilder
- builder.append(entry.getKey());
+ Object[] keys = objectIdKeys.keySet().toArray();
+ Arrays.sort(keys);
+ for (int i = 0; i < len; i++) {
+ // HashCodeBuilder will take care of processing object if it
+ // happens to be a primitive array such as byte[]
+
+ // also we don't have to append the key hashcode, its index will
+ // work
+ builder.append(i);
+
+ Object value = objectIdKeys.get(keys[i]);
// must reconcile all possible numeric types
- if (entry.getValue() instanceof Number) {
- builder.append(((Number) entry.getValue()).longValue());
+ if (value instanceof Number) {
+ builder.append(((Number) value).longValue());
}
else {
- builder.append(entry.getValue());
- }
- }
- // handle multiple keys - must sort the keys to use with HashCodeBuilder
- else {
- Object[] keys = objectIdKeys.keySet().toArray();
- Arrays.sort(keys);
-
- for (int i = 0; i < len; i++) {
- // HashCodeBuilder will take care of processing object if it
- // happens to be a primitive array such as byte[]
-
- // also we don't have to append the key hashcode, its index will
- // work
- builder.append(i);
-
- Object value = objectIdKeys.get(keys[i]);
- // must reconcile all possible numeric types
- if (value instanceof Number) {
- builder.append(((Number) value).longValue());
- }
- else {
- builder.append(value);
- }
+ builder.append(value);
}
}
}
@@ -459,6 +483,10 @@
for (int i = 0; i < key.length; i++) {
IDUtil.appendFormattedByte(buffer, key[i]);
}
+ }
+ else if(singleKey != null) {
+ buffer.append(String.valueOf(singleKey)).append("=").append(
+ singleValue);
}
else if (objectIdKeys != null) {
Iterator it = objectIdKeys.entrySet().iterator();