[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