[infinispan-commits] Infinispan SVN: r1045 - in trunk/core/src: main/java/org/infinispan/context/impl and 8 other directories.

infinispan-commits at lists.jboss.org infinispan-commits at lists.jboss.org
Wed Oct 28 06:17:13 EDT 2009


Author: mircea.markus
Date: 2009-10-28 06:17:13 -0400 (Wed, 28 Oct 2009)
New Revision: 1045

Added:
   trunk/core/src/test/java/org/infinispan/api/ForceWriteLockTest.java
Modified:
   trunk/core/src/main/java/org/infinispan/container/entries/ImmortalCacheEntry.java
   trunk/core/src/main/java/org/infinispan/container/entries/MortalCacheEntry.java
   trunk/core/src/main/java/org/infinispan/container/entries/TransientCacheEntry.java
   trunk/core/src/main/java/org/infinispan/context/impl/AbstractInvocationContext.java
   trunk/core/src/main/java/org/infinispan/context/impl/LocalTxInvocationContext.java
   trunk/core/src/main/java/org/infinispan/factories/InterceptorChainFactory.java
   trunk/core/src/main/java/org/infinispan/interceptors/DistributionInterceptor.java
   trunk/core/src/test/java/org/infinispan/api/mvcc/repeatable_read/RepeatableReadLockTest.java
   trunk/core/src/test/java/org/infinispan/distribution/DistSyncTxFuncTest.java
   trunk/core/src/test/java/org/infinispan/loaders/decorators/AsyncTest.java
   trunk/core/src/test/java/org/infinispan/stress/PutIfAbsentStressTest.java
   trunk/core/src/test/java/org/infinispan/test/AbstractCacheTest.java
   trunk/core/src/test/java/org/infinispan/test/MultipleCacheManagersTest.java
Log:
[ISPN-236]-(cache.putIfAbsent() is not atomic) - fixed by placing locking interceptor before repl interceptor

Modified: trunk/core/src/main/java/org/infinispan/container/entries/ImmortalCacheEntry.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/entries/ImmortalCacheEntry.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/main/java/org/infinispan/container/entries/ImmortalCacheEntry.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -1,12 +1,12 @@
 package org.infinispan.container.entries;
 
+import org.infinispan.marshall.Ids;
+import org.infinispan.marshall.Marshallable;
+
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 
-import org.infinispan.marshall.Ids;
-import org.infinispan.marshall.Marshallable;
-
 /**
  * A cache entry that is immortal/cannot expire
  *
@@ -122,4 +122,11 @@
          return new ImmortalCacheEntry(k, v);
       }
    }
+
+   @Override
+   public String toString() {
+      return "ImmortalCacheEntry{" +
+            "cacheValue=" + cacheValue +
+            "} " + super.toString();
+   }
 }

Modified: trunk/core/src/main/java/org/infinispan/container/entries/MortalCacheEntry.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/entries/MortalCacheEntry.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/main/java/org/infinispan/container/entries/MortalCacheEntry.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -1,13 +1,13 @@
 package org.infinispan.container.entries;
 
+import org.infinispan.io.UnsignedNumeric;
+import org.infinispan.marshall.Ids;
+import org.infinispan.marshall.Marshallable;
+
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 
-import org.infinispan.io.UnsignedNumeric;
-import org.infinispan.marshall.Ids;
-import org.infinispan.marshall.Marshallable;
-
 /**
  * A cache entry that is mortal.  I.e., has a lifespan.
  *
@@ -137,4 +137,11 @@
          return new MortalCacheEntry(k, v, lifespan, created);
       }      
    }
+
+   @Override
+   public String toString() {
+      return "MortalCacheEntry{" +
+            "cacheValue=" + cacheValue +
+            "} " + super.toString();
+   }
 }

Modified: trunk/core/src/main/java/org/infinispan/container/entries/TransientCacheEntry.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/entries/TransientCacheEntry.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/main/java/org/infinispan/container/entries/TransientCacheEntry.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -1,13 +1,13 @@
 package org.infinispan.container.entries;
 
+import org.infinispan.io.UnsignedNumeric;
+import org.infinispan.marshall.Ids;
+import org.infinispan.marshall.Marshallable;
+
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 
-import org.infinispan.io.UnsignedNumeric;
-import org.infinispan.marshall.Ids;
-import org.infinispan.marshall.Marshallable;
-
 /**
  * A cache entry that is transient, i.e., it can be considered expired afer a period of not being used.
  *
@@ -139,4 +139,11 @@
          return new TransientCacheEntry(k, v, maxIdle, lastUsed);
       }      
    }
+
+   @Override
+   public String toString() {
+      return "TransientCacheEntry{" +
+            "cacheValue=" + cacheValue +
+            "} " + super.toString();
+   }
 }

Modified: trunk/core/src/main/java/org/infinispan/context/impl/AbstractInvocationContext.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/context/impl/AbstractInvocationContext.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/main/java/org/infinispan/context/impl/AbstractInvocationContext.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -116,7 +116,11 @@
 
    public boolean hasLockedKey(Object key) {
       CacheEntry e = lookupEntry(key);
-      return e != null && e.isChanged();
+      if (e == null) {
+         return getLookedUpEntries().containsKey(key); // this will chk if the key is present
+      } else {
+         return e.isChanged();
+      }
    }
 
    public boolean hasLockedEntries() {
@@ -124,7 +128,6 @@
       boolean result = false;
       for (CacheEntry e : lookedUpEntries.values()) {
          if (e.isChanged()) {
-            System.out.println("Entry is locked = " + e);
             result = true;
          }
       }

Modified: trunk/core/src/main/java/org/infinispan/context/impl/LocalTxInvocationContext.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/context/impl/LocalTxInvocationContext.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/main/java/org/infinispan/context/impl/LocalTxInvocationContext.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -71,4 +71,9 @@
    public void clearLookedUpEntries() {
       xaAdapter.clearLookedUpEntries();
    }
+
+   @Override
+   public boolean hasLockedKey(Object key) {
+      return xaAdapter != null && super.hasLockedKey(key);
+   }
 }

Modified: trunk/core/src/main/java/org/infinispan/factories/InterceptorChainFactory.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/factories/InterceptorChainFactory.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/main/java/org/infinispan/factories/InterceptorChainFactory.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -82,7 +82,7 @@
          interceptorChain.appendIntereceptor(createInterceptor(DistTxInterceptor.class));
       else
          interceptorChain.appendIntereceptor(createInterceptor(TxInterceptor.class));
-      
+
       if(configuration.isUseEagerLocking())
          interceptorChain.appendIntereceptor(createInterceptor(ImplicitEagerLockingInterceptor.class));
 
@@ -95,23 +95,6 @@
          interceptorChain.appendIntereceptor(createInterceptor(DeadlockDetectingInterceptor.class));
       }
 
-      switch (configuration.getCacheMode()) {
-         case REPL_SYNC:
-         case REPL_ASYNC:
-            interceptorChain.appendIntereceptor(createInterceptor(ReplicationInterceptor.class));
-            break;
-         case INVALIDATION_SYNC:
-         case INVALIDATION_ASYNC:
-            interceptorChain.appendIntereceptor(createInterceptor(InvalidationInterceptor.class));
-            break;
-         case DIST_SYNC:
-         case DIST_ASYNC:
-            interceptorChain.appendIntereceptor(createInterceptor(DistributionInterceptor.class));
-            break;
-         case LOCAL:
-            //Nothing...
-      }
-
       if (configuration.isUsingCacheLoaders()) {
          if (configuration.getCacheLoaderManagerConfig().isPassivation()) {
             interceptorChain.appendIntereceptor(createInterceptor(ActivationInterceptor.class));
@@ -130,11 +113,30 @@
          }
       }
 
+
       if (configuration.getCacheMode().isDistributed())
          interceptorChain.appendIntereceptor(createInterceptor(DistLockingInterceptor.class));
       else
          interceptorChain.appendIntereceptor(createInterceptor(LockingInterceptor.class));
 
+      switch (configuration.getCacheMode()) {
+         case REPL_SYNC:
+         case REPL_ASYNC:
+            interceptorChain.appendIntereceptor(createInterceptor(ReplicationInterceptor.class));
+            break;
+         case INVALIDATION_SYNC:
+         case INVALIDATION_ASYNC:
+            interceptorChain.appendIntereceptor(createInterceptor(InvalidationInterceptor.class));
+            break;
+         case DIST_SYNC:
+         case DIST_ASYNC:
+            interceptorChain.appendIntereceptor(createInterceptor(DistributionInterceptor.class));
+            break;
+         case LOCAL:
+            //Nothing...
+      }
+
+
       CommandInterceptor callInterceptor = createInterceptor(CallInterceptor.class);
       interceptorChain.appendIntereceptor(callInterceptor);
       if (log.isTraceEnabled()) log.trace("Finished building default interceptor chain.");

Modified: trunk/core/src/main/java/org/infinispan/interceptors/DistributionInterceptor.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/interceptors/DistributionInterceptor.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/main/java/org/infinispan/interceptors/DistributionInterceptor.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -15,6 +15,7 @@
 import org.infinispan.commands.write.ReplaceCommand;
 import org.infinispan.commands.write.WriteCommand;
 import org.infinispan.container.DataContainer;
+import org.infinispan.container.EntryFactory;
 import org.infinispan.container.entries.InternalCacheEntry;
 import org.infinispan.context.Flag;
 import org.infinispan.context.InvocationContext;
@@ -48,6 +49,7 @@
    CommandsFactory cf;
    DataContainer dataContainer;
    boolean isL1CacheEnabled, needReliableReturnValues;
+   EntryFactory entryFactory;
 
 
    static final RecipientGenerator CLEAR_COMMAND_GENERATOR = new RecipientGenerator() {
@@ -63,10 +65,11 @@
    };
 
    @Inject
-   public void injectDependencies(DistributionManager distributionManager, CommandsFactory cf, DataContainer dataContainer) {
+   public void injectDependencies(DistributionManager distributionManager, CommandsFactory cf, DataContainer dataContainer, EntryFactory entryFactory) {
       this.dm = distributionManager;
       this.cf = cf;
       this.dataContainer = dataContainer;
+      this.entryFactory = entryFactory;
    }
 
    @Start
@@ -114,6 +117,7 @@
                if (trace) log.trace("Caching remotely retrieved entry for key {0} in L1", key);
                long lifespan = ice.getLifespan() < 0 ? configuration.getL1Lifespan() : Math.min(ice.getLifespan(), configuration.getL1Lifespan());
                PutKeyValueCommand put = cf.buildPutKeyValueCommand(ice.getKey(), ice.getValue(), lifespan, -1);
+               entryFactory.wrapEntryForWriting(ctx, key, true, false, ctx.hasLockedKey(key), false);
                invokeNextInterceptor(ctx, put);
             } else {
                if (trace) log.trace("Not caching remotely retrieved entry for key {0} in L1", key);
@@ -306,7 +310,7 @@
    private boolean isSingleOwnerAndLocal(RecipientGenerator recipientGenerator) {
       return configuration.getNumOwners() == 1 && recipientGenerator.generateRecipients().get(0).equals(rpcManager.getTransport().getAddress());
    }
-   
+
    interface KeyGenerator {
       Object[] getKeys();
    }

Added: trunk/core/src/test/java/org/infinispan/api/ForceWriteLockTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/api/ForceWriteLockTest.java	                        (rev 0)
+++ trunk/core/src/test/java/org/infinispan/api/ForceWriteLockTest.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -0,0 +1,45 @@
+package org.infinispan.api;
+
+import org.infinispan.AdvancedCache;
+import org.infinispan.container.entries.CacheEntry;
+import org.infinispan.container.entries.ReadCommittedEntry;
+import org.infinispan.context.Flag;
+import org.infinispan.context.InvocationContext;
+import org.infinispan.manager.CacheManager;
+import org.infinispan.test.SingleCacheManagerTest;
+import org.infinispan.test.TestingUtil;
+import org.infinispan.test.fwk.TestCacheManagerFactory;
+import org.testng.annotations.Test;
+
+import javax.transaction.TransactionManager;
+
+/**
+ * @author Mircea.Markus at jboss.com
+ */
+ at Test(groups = "functional", testName = "api.ForceWriteLockTest")
+public class ForceWriteLockTest extends SingleCacheManagerTest {
+   private TransactionManager tm;
+   private AdvancedCache advancedCache;
+
+   protected CacheManager createCacheManager() throws Exception {
+      CacheManager cacheManager = TestCacheManagerFactory.createLocalCacheManager(true);
+      advancedCache = cacheManager.getCache().getAdvancedCache();
+      tm = TestingUtil.getTransactionManager(advancedCache);
+      return cacheManager;
+   }
+
+   public void testWriteLockIsAcquired() throws Exception {
+      advancedCache.put("k","v");
+      assertNotLocked(advancedCache,"k");
+      tm.begin();
+      advancedCache.get("k", Flag.FORCE_WRITE_LOCK);
+
+      InvocationContext ic = advancedCache.getInvocationContextContainer().getInvocationContext();
+      CacheEntry cacheEntry = ic.getLookedUpEntries().get("k");
+      assert (cacheEntry instanceof ReadCommittedEntry && cacheEntry.isChanged());
+
+      assertLocked(advancedCache,"k");
+      tm.commit();
+      assertNotLocked(advancedCache,"k");
+   }
+}

Modified: trunk/core/src/test/java/org/infinispan/api/mvcc/repeatable_read/RepeatableReadLockTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/api/mvcc/repeatable_read/RepeatableReadLockTest.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/test/java/org/infinispan/api/mvcc/repeatable_read/RepeatableReadLockTest.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -110,7 +110,7 @@
       tm.resume(tx);
       cache.remove("a");
       tx.commit();
-      assert cache.get("a") == null;
+      assert cache.get("a") == null : "expected null but received " + cache.get("a");
    }
 
    public void testLocksOnPutKeyVal() throws Exception {
@@ -126,6 +126,8 @@
 
       tm.begin();
       assert cache.get("k").equals("v");
+
+
       assertNotLocked("k");
       tm.commit();
 

Modified: trunk/core/src/test/java/org/infinispan/distribution/DistSyncTxFuncTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/distribution/DistSyncTxFuncTest.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/test/java/org/infinispan/distribution/DistSyncTxFuncTest.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -201,7 +201,13 @@
       MagicKey k2 = new MagicKey(c2, "k2"); // maps on to c2 and c3
 
       init(k1, k2);
+      asserLocked(c1, false, k1, k2);
+      asserLocked(c2, false, k1, k2);
+      asserLocked(c3, false, k1, k2);
+      asserLocked(c4, false, k1, k2);
+      
 
+      log.info("***** Here it starts!");
       TransactionManager tm4 = getTransactionManager(c4);
       tm4.begin();
       Object ret = c4.remove(k1);
@@ -212,20 +218,39 @@
       assert !c4.containsKey(k1);
       assert !c4.containsKey(k2);
       tm4.rollback();
+      log.info("----- Here it ends!");
 
+      asserLocked(c1, false, k1, k2);
+      asserLocked(c2, false, k1, k2);
+      asserLocked(c3, false, k1, k2);
+      asserLocked(c4, false, k1 );
+      asserLocked(c4, false, k2 );
+
       assertIsInContainerImmortal(c1, k1);
       assertIsInContainerImmortal(c2, k1);
       assertIsInContainerImmortal(c2, k2);
       assertIsInContainerImmortal(c3, k2);
 
+      asserLocked(c1, false, k1, k2);
+      asserLocked(c2, false, k1, k2);
+      asserLocked(c3, false, k1, k2);
+      asserLocked(c4, false, k1, k2);
+
+
       assertIsNotInL1(c4, k1);
       assertIsNotInL1(c4, k2);
       assertIsNotInL1(c1, k2);
       assertIsNotInL1(c3, k1);
 
+      asserLocked(c1, false, k1, k2);
+      asserLocked(c2, false, k1, k2);
+      asserLocked(c3, false, k1, k2);
+      asserLocked(c4, false, k1, k2);
+      
       checkOwnership(k1, k2, "value1", "value2");
    }
 
+
    public void testConditionalRemoveFromNonOwner() throws Exception {
       // we need 2 keys that reside on different caches...
       MagicKey k1 = new MagicKey(c1, "k1"); // maps on to c1 and c2

Modified: trunk/core/src/test/java/org/infinispan/loaders/decorators/AsyncTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/loaders/decorators/AsyncTest.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/test/java/org/infinispan/loaders/decorators/AsyncTest.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -68,7 +68,6 @@
       String value = "testMultiplePutsOnSameKey-v-";
       doTestSameKeyPut(number, key, value);
       doTestSameKeyRemove(key);
-      
    }
 
    public void testRestrictionOnAddingToAsyncQueue() throws Exception {
@@ -121,15 +120,20 @@
    }
    
    private void doTestSameKeyPut(int number, String key, String value) throws Exception {
-      for (int i = 0; i < number; i++) store.store(InternalEntryFactory.create(key, value + i));
-      
+      for (int i = 0; i < number; i++)
+         store.store(InternalEntryFactory.create(key, value + i));
+
       InternalCacheEntry entry;
-      do {
+      boolean success = false;
+      for (int i = 0; i < 120; i++) {
          TestingUtil.sleepRandom(1000);
          entry = store.load(key);
-      } while (!entry.getValue().equals(value + (number-1)));
+         success = entry.getValue().equals(value + (number-1));
+         if (success) break;
+      }
+      assert success;
    }
-   
+
    private void doTestRemove(int number, String key) throws Exception {
       for (int i = 0; i < number; i++) store.remove(key + i);
       
@@ -156,9 +160,9 @@
       do {
          TestingUtil.sleepRandom(1000);
          entry = store.load(key);
-      } while (entry != null);      
+      } while (entry != null);
    }
-   
+
    private void doTestClear(int number, String key) throws Exception {
       store.clear();
       TestingUtil.sleepRandom(1000);

Modified: trunk/core/src/test/java/org/infinispan/stress/PutIfAbsentStressTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/stress/PutIfAbsentStressTest.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/test/java/org/infinispan/stress/PutIfAbsentStressTest.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -47,7 +47,7 @@
  * @see java.util.concurrent.ConcurrentMap#putIfAbsent(Object, Object)
  * @author Sanne Grinovero
  */
- at Test(groups = "stress", testName = "atomic.PutIfAbsentStressTest")
+ at Test(groups = "stress", testName = "stress.PutIfAbsentStressTest")
 public class PutIfAbsentStressTest {
 
    private static final int NODES_NUM = 5;
@@ -123,7 +123,7 @@
       } finally {
          for (CacheManager cm : cacheManagers) {
             try {
-               TestingUtil.clearContent(cm);
+               TestingUtil.killCacheManagers(cm);
             } catch (Exception e) {
                // try cleaning up the other cacheManagers too
             }

Modified: trunk/core/src/test/java/org/infinispan/test/AbstractCacheTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/test/AbstractCacheTest.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/test/java/org/infinispan/test/AbstractCacheTest.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -6,6 +6,7 @@
 import org.infinispan.test.fwk.TestCacheManagerFactory;
 import org.infinispan.util.logging.Log;
 import org.infinispan.util.logging.LogFactory;
+import org.infinispan.util.concurrent.locks.LockManager;
 
 import java.util.Set;
 
@@ -61,4 +62,14 @@
    protected boolean xor(boolean b1, boolean b2) {
       return (b1 || b2) && !(b1 && b2);
    }
+
+   protected void assertNotLocked(Cache cache, Object key) {
+      LockManager lockManager = TestingUtil.extractLockManager(cache);
+      assert !lockManager.isLocked(key) : "expected key '" + key + "' not to be locked, and it is by: " + lockManager.getOwner(key);
+   }
+
+   protected void assertLocked(Cache cache, Object key) {
+      LockManager lockManager = TestingUtil.extractLockManager(cache);
+      assert lockManager.isLocked(key) : "expected key '" + key + "' to be locked, but it is not";
+   }
 }

Modified: trunk/core/src/test/java/org/infinispan/test/MultipleCacheManagersTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/test/MultipleCacheManagersTest.java	2009-10-27 19:35:38 UTC (rev 1044)
+++ trunk/core/src/test/java/org/infinispan/test/MultipleCacheManagersTest.java	2009-10-28 10:17:13 UTC (rev 1045)
@@ -4,7 +4,6 @@
 import org.infinispan.config.Configuration;
 import org.infinispan.manager.CacheManager;
 import org.infinispan.test.fwk.TestCacheManagerFactory;
-import org.infinispan.util.concurrent.locks.LockManager;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeClass;
@@ -173,15 +172,4 @@
     * {@link #addClusterEnabledCacheManager()}
     */
    protected abstract void createCacheManagers() throws Throwable;
-
-
-   protected void assertNotLocked(Cache cache, Object key) {
-      LockManager lockManager = TestingUtil.extractLockManager(cache);
-      assert !lockManager.isLocked(key) : "expected key '" + key + "' not to be locked, and it is by: " + lockManager.getOwner(key);
-   }
-
-   protected void assertLocked(Cache cache, Object key) {
-      LockManager lockManager = TestingUtil.extractLockManager(cache);
-      assert lockManager.isLocked(key) : "expected key '" + key + "' to be locked, but it is not";
-   }
 }



More information about the infinispan-commits mailing list