[infinispan-commits] Infinispan SVN: r2349 - in trunk/core/src: main/java/org/infinispan/marshall and 1 other directories.
infinispan-commits at lists.jboss.org
infinispan-commits at lists.jboss.org
Mon Sep 13 06:48:55 EDT 2010
Author: galder.zamarreno at jboss.com
Date: 2010-09-13 06:48:55 -0400 (Mon, 13 Sep 2010)
New Revision: 2349
Added:
trunk/core/src/test/java/org/infinispan/marshall/InvalidatedMarshalledValueTest.java
Modified:
trunk/core/src/main/java/org/infinispan/interceptors/MarshalledValueInterceptor.java
trunk/core/src/main/java/org/infinispan/marshall/MarshalledValue.java
trunk/core/src/test/java/org/infinispan/marshall/MarshalledValueTest.java
Log:
[ISPN-637] (MarshalledValue.equals(...) causing ClassNotFoundException during remote invalidation handling) Fixed by making remote calls do raw equality by default.
Modified: trunk/core/src/main/java/org/infinispan/interceptors/MarshalledValueInterceptor.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/interceptors/MarshalledValueInterceptor.java 2010-09-12 21:05:16 UTC (rev 2348)
+++ trunk/core/src/main/java/org/infinispan/interceptors/MarshalledValueInterceptor.java 2010-09-13 10:48:55 UTC (rev 2349)
@@ -26,6 +26,7 @@
import org.infinispan.commands.read.GetKeyValueCommand;
import org.infinispan.commands.read.KeySetCommand;
import org.infinispan.commands.read.ValuesCommand;
+import org.infinispan.commands.write.InvalidateCommand;
import org.infinispan.commands.write.PutKeyValueCommand;
import org.infinispan.commands.write.PutMapCommand;
import org.infinispan.commands.write.RemoveCommand;
@@ -113,10 +114,23 @@
value = createMarshalledValue(command.getValue(), ctx);
command.setValue(value);
}
- Object retVal = invokeNextInterceptor(ctx, command);
- compact(key);
- compact(value);
- return processRetVal(retVal);
+
+ // If origin is remote, set equality preference for raw so that deserialization is avoided
+ // Don't do this for local invocations so that unnecessary serialization is avoided.
+ boolean isRawComparisonRequired = !ctx.isOriginLocal() && command.getKey() instanceof MarshalledValue;
+ if (isRawComparisonRequired)
+ ((MarshalledValue) command.getKey()).setEqualityPreferenceForInstance(false);
+
+ try {
+ Object retVal = invokeNextInterceptor(ctx, command);
+ compact(key);
+ compact(value);
+ return processRetVal(retVal);
+ } finally {
+ // Regardless of what happens with the remote key update, revert to equality for instance
+ if (isRawComparisonRequired)
+ ((MarshalledValue) command.getKey()).setEqualityPreferenceForInstance(true);
+ }
}
@Override
@@ -224,6 +238,29 @@
return processRetVal(retVal);
}
+ @Override
+ public Object visitInvalidateCommand(InvocationContext ctx, InvalidateCommand command) throws Throwable {
+ // If origin is remote, set equality preference for raw so that deserialization is avoided
+ // Don't do this for local invocations so that unnecessary serialization is avoided.
+ boolean isRemote = !ctx.isOriginLocal();
+ if (isRemote)
+ forceComparison(false, command);
+
+ try {
+ return invokeNextInterceptor(ctx, command);
+ } finally {
+ if (isRemote)
+ forceComparison(true, command);
+ }
+ }
+
+ private void forceComparison(boolean isCompareInstance, InvalidateCommand command) {
+ for (Object key : command.getKeys()) {
+ if (key instanceof MarshalledValue)
+ ((MarshalledValue) key).setEqualityPreferenceForInstance(isCompareInstance);
+ }
+ }
+
private Object compactAndProcessRetVal(Set<MarshalledValue> marshalledValues, Object retVal)
throws IOException, ClassNotFoundException {
if (trace) log.trace("Compacting MarshalledValues created");
Modified: trunk/core/src/main/java/org/infinispan/marshall/MarshalledValue.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/marshall/MarshalledValue.java 2010-09-12 21:05:16 UTC (rev 2348)
+++ trunk/core/src/main/java/org/infinispan/marshall/MarshalledValue.java 2010-09-13 10:48:55 UTC (rev 2349)
@@ -54,7 +54,7 @@
volatile protected byte[] raw;
volatile private int cachedHashCode = 0;
// by default equals() will test on the instance rather than the byte array if conversion is required.
- private transient boolean equalityPreferenceForInstance = true;
+ private transient volatile boolean equalityPreferenceForInstance = true;
private final StreamingMarshaller marshaller;
public MarshalledValue(Object instance, boolean equalityPreferenceForInstance, StreamingMarshaller marshaller) throws NotSerializableException {
@@ -180,7 +180,7 @@
if (instance != null && that.instance != null) return instance.equals(that.instance);
// if conversion of one representation to the other is necessary, then see which we prefer converting.
- if (equalityPreferenceForInstance) {
+ if (equalityPreferenceForInstance && that.equalityPreferenceForInstance) {
if (instance == null) deserialize();
if (that.instance == null) that.deserialize();
return instance.equals(that.instance);
@@ -216,6 +216,11 @@
return sb.toString();
}
+ public MarshalledValue setEqualityPreferenceForInstance(boolean equalityPreferenceForInstance) {
+ this.equalityPreferenceForInstance = equalityPreferenceForInstance;
+ return this;
+ }
+
/**
* Tests whether the type should be excluded from MarshalledValue wrapping.
*
Added: trunk/core/src/test/java/org/infinispan/marshall/InvalidatedMarshalledValueTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/marshall/InvalidatedMarshalledValueTest.java (rev 0)
+++ trunk/core/src/test/java/org/infinispan/marshall/InvalidatedMarshalledValueTest.java 2010-09-13 10:48:55 UTC (rev 2349)
@@ -0,0 +1,72 @@
+package org.infinispan.marshall;
+
+import org.infinispan.Cache;
+import org.infinispan.config.Configuration;
+import org.infinispan.interceptors.InterceptorChain;
+import org.infinispan.interceptors.MarshalledValueInterceptor;
+import org.infinispan.test.MultipleCacheManagersTest;
+import org.infinispan.test.TestingUtil;
+import org.testng.annotations.Test;
+
+import static org.infinispan.marshall.MarshalledValueTest.*;
+
+/**
+ * // TODO: Document this
+ *
+ * @author Galder Zamarre�o
+ * @since // TODO
+ */
+ at Test(groups = "functional", testName = "marshall.InvalidatedMarshalledValueTest")
+public class InvalidatedMarshalledValueTest extends MultipleCacheManagersTest {
+
+ protected void createCacheManagers() throws Throwable {
+ Cache cache1, cache2;
+ Configuration invlSync = getDefaultClusteredConfig(Configuration.CacheMode.INVALIDATION_SYNC);
+ invlSync.setUseLazyDeserialization(true);
+
+ createClusteredCaches(2, "invlSync", invlSync);
+
+ cache1 = cache(0, "invlSync");
+ cache2 = cache(1, "invlSync");
+
+ assertMarshalledValueInterceptorPresent(cache1);
+ assertMarshalledValueInterceptorPresent(cache2);
+ }
+
+ private void assertMarshalledValueInterceptorPresent(Cache c) {
+ InterceptorChain ic1 = TestingUtil.extractComponent(c, InterceptorChain.class);
+ assert ic1.containsInterceptorType(MarshalledValueInterceptor.class);
+ }
+
+ public void testModificationsOnSameCustomKey() {
+ Cache cache1 = cache(0, "invlSync");
+ Cache cache2 = cache(1, "invlSync");
+
+ InvalidatedPojo key = new InvalidatedPojo();
+ cache2.put(key, "1");
+ cache1.put(key, "2");
+ assertSerializationCounts(3, 0);
+ cache1.put(key, "3");
+ assertSerializationCounts(4, 0);
+ }
+
+ public static class InvalidatedPojo extends Pojo {
+ static int serializationCount, deserializationCount;
+
+ @Override
+ public int updateSerializationCount() {
+ return ++serializationCount;
+ }
+
+ @Override
+ public int updateDeserializationCount() {
+ return ++deserializationCount;
+ }
+ }
+
+ private void assertSerializationCounts(int serializationCount, int deserializationCount) {
+ assert InvalidatedPojo.serializationCount == serializationCount : "Serialization count: expected " + serializationCount + " but was " + InvalidatedPojo.serializationCount;
+ assert InvalidatedPojo.deserializationCount == deserializationCount : "Deserialization count: expected " + deserializationCount + " but was " + InvalidatedPojo.deserializationCount;
+ }
+
+}
Modified: trunk/core/src/test/java/org/infinispan/marshall/MarshalledValueTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/marshall/MarshalledValueTest.java 2010-09-12 21:05:16 UTC (rev 2348)
+++ trunk/core/src/test/java/org/infinispan/marshall/MarshalledValueTest.java 2010-09-13 10:48:55 UTC (rev 2349)
@@ -63,6 +63,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Tests implicit marshalled values
@@ -256,7 +257,7 @@
Cache cache1 = cache(0, "replSync");
Cache cache2 = cache(1, "replSync");
- Pojo key1 = new Pojo(), value1 = new Pojo(), key2 = new Pojo(), value2 = new Pojo();
+ Pojo key1 = new Pojo(1), value1 = new Pojo(11), key2 = new Pojo(2), value2 = new Pojo(22);
String key3 = "3", value3 = "three";
cache1.put(key1, value1);
cache1.put(key2, value2);
@@ -461,6 +462,8 @@
cache2.addListener(l);
try {
Pojo pojo = new Pojo();
+ // Mock listener will force deserialization on transport thread. Ignore this by setting b to false.
+ pojo.b = false;
cache1.put("key", pojo);
assert l.newValue instanceof Pojo;
assertSerializationCounts(1, 1);
@@ -478,6 +481,19 @@
assert !cache1.containsKey(pojo);
}
+ public void testModificationsOnSameCustomKey() {
+ Cache cache1 = cache(0, "replSync");
+ Cache cache2 = cache(1, "replSync");
+
+ Pojo key = new Pojo();
+
+ cache1.put(key, "1");
+ cache2.put(key, "2");
+
+ // Deserialization only occurs when the cache2.put occurs, not during transport thread execution.
+ assertSerializationCounts(3, 1);
+ }
+
@Listener
public static class MockListener {
Object newValue;
@@ -506,11 +522,18 @@
public static class Pojo implements Externalizable {
public int i;
- boolean b;
+ boolean b = true;
static int serializationCount, deserializationCount;
final Log log = LogFactory.getLog(Pojo.class);
private static final long serialVersionUID = -2888014339659501395L;
+ public Pojo(int i) {
+ this.i = i;
+ }
+
+ public Pojo() {
+ }
+
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@@ -533,16 +556,28 @@
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(i);
out.writeBoolean(b);
- serializationCount++;
- log.trace("serializationCount=" + serializationCount);
+ int serCount = updateSerializationCount();
+ log.trace("serializationCount=" + serCount);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
i = in.readInt();
b = in.readBoolean();
- deserializationCount++;
- log.trace("deserializationCount=" + deserializationCount);
+ if (b) {
+ // TODO: Find a better way to make sure a transport (JGroups) thread is not attempting to deserialize stuff
+ assert !Thread.currentThread().getName().startsWith("OOB") : "Transport (JGroups) thread is trying to deserialize stuff!!";
+ }
+ int deserCount = updateDeserializationCount();
+ log.trace("deserializationCount=" + deserCount);
}
+
+ public int updateSerializationCount() {
+ return ++serializationCount;
+ }
+
+ public int updateDeserializationCount() {
+ return ++deserializationCount;
+ }
}
public static class ObjectThatContainsACustomReadObjectMethod implements Serializable {
More information about the infinispan-commits
mailing list