[infinispan-commits] Infinispan SVN: r998 - in trunk/core/src: main/java/org/infinispan/interceptors and 4 other directories.

infinispan-commits at lists.jboss.org infinispan-commits at lists.jboss.org
Fri Oct 23 13:28:09 EDT 2009


Author: galder.zamarreno at jboss.com
Date: 2009-10-23 13:28:08 -0400 (Fri, 23 Oct 2009)
New Revision: 998

Added:
   trunk/core/src/test/java/org/infinispan/api/lru/
   trunk/core/src/test/java/org/infinispan/api/lru/read_committed/
   trunk/core/src/test/java/org/infinispan/api/lru/read_committed/CacheAPIMVCCTest.java
Modified:
   trunk/core/src/main/java/org/infinispan/container/DataContainer.java
   trunk/core/src/main/java/org/infinispan/container/EntryFactory.java
   trunk/core/src/main/java/org/infinispan/container/EntryFactoryImpl.java
   trunk/core/src/main/java/org/infinispan/container/FIFODataContainer.java
   trunk/core/src/main/java/org/infinispan/container/SimpleDataContainer.java
   trunk/core/src/main/java/org/infinispan/interceptors/LockingInterceptor.java
   trunk/core/src/test/java/org/infinispan/api/CacheAPITest.java
   trunk/core/src/test/java/org/infinispan/container/SimpleDataContainerTest.java
Log:
[ISPN-235] (LRUDataContainer keySet() looping fails when inside there's a get call) Cache size is now correct after a clear. Fixed by looping through the entry set rather than the key set. Also added a peek() method to data container to allow cache retrieval without changing the order when iterating through the key set.

Modified: trunk/core/src/main/java/org/infinispan/container/DataContainer.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/DataContainer.java	2009-10-23 16:54:28 UTC (rev 997)
+++ trunk/core/src/main/java/org/infinispan/container/DataContainer.java	2009-10-23 17:28:08 UTC (rev 998)
@@ -44,6 +44,21 @@
     * @return entry, if it exists and has not expired, or null if not
     */
    InternalCacheEntry get(Object k);
+   
+   /**
+    * Retrieves a cache entry in the same way as {@link #get(Object)}}
+    * except that it does not update or reorder any of the internal constructs. 
+    * I.e., expiration does not happen, and in the case of the LRU container, 
+    * the entry is not moved to the end of the chain.
+    * 
+    * This method should be used instead of {@link #get(Object)}} when called
+    * while iterating through the data container using methods like {@link #keySet()} 
+    * to avoid changing the underlying collection's order.
+    * 
+    * @param k key under which entry is stored
+    * @return entry, if it exists, or null if not
+    */
+   InternalCacheEntry peek(Object k);
 
    /**
     * Puts an entry in the cache along with a lifespan and a maxIdle time
@@ -80,7 +95,11 @@
    void clear();
 
    /**
-    * @return a set of keys contained in the container
+    * Returns a set of keys in the container. When iterating through the container using this method,
+    * clients should never call {@link #get()} method but instead {@link #peek()}, in order to avoid
+    * changing the order of the underlying collection as a side of effect of iterating through it.
+    * 
+    * @return a set of keys
     */
    Set<Object> keySet();
 

Modified: trunk/core/src/main/java/org/infinispan/container/EntryFactory.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/EntryFactory.java	2009-10-23 16:54:28 UTC (rev 997)
+++ trunk/core/src/main/java/org/infinispan/container/EntryFactory.java	2009-10-23 17:28:08 UTC (rev 998)
@@ -22,6 +22,7 @@
 package org.infinispan.container;
 
 import org.infinispan.container.entries.CacheEntry;
+import org.infinispan.container.entries.InternalCacheEntry;
 import org.infinispan.container.entries.MVCCEntry;
 import org.infinispan.context.InvocationContext;
 import org.infinispan.util.concurrent.TimeoutException;
@@ -30,6 +31,7 @@
  * // TODO: MANIK: Document this
  *
  * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @author Galder Zamarreño
  * @since 4.0
  */
 public interface EntryFactory {
@@ -50,6 +52,8 @@
    boolean acquireLock(InvocationContext ctx, Object key) throws InterruptedException, TimeoutException;
 
    MVCCEntry wrapEntryForWriting(InvocationContext ctx, Object key, boolean createIfAbsent, boolean forceLockIfAbsent, boolean alreadyLocked, boolean forRemoval) throws InterruptedException;
+   
+   MVCCEntry wrapEntryForWriting(InvocationContext ctx, InternalCacheEntry entry, boolean createIfAbsent, boolean forceLockIfAbsent, boolean alreadyLocked, boolean forRemoval) throws InterruptedException;
 
    CacheEntry wrapEntryForReading(InvocationContext ctx, Object key) throws InterruptedException;
 }

Modified: trunk/core/src/main/java/org/infinispan/container/EntryFactoryImpl.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/EntryFactoryImpl.java	2009-10-23 16:54:28 UTC (rev 997)
+++ trunk/core/src/main/java/org/infinispan/container/EntryFactoryImpl.java	2009-10-23 17:28:08 UTC (rev 998)
@@ -23,6 +23,7 @@
 
 import org.infinispan.config.Configuration;
 import org.infinispan.container.entries.CacheEntry;
+import org.infinispan.container.entries.InternalCacheEntry;
 import org.infinispan.container.entries.MVCCEntry;
 import org.infinispan.container.entries.NullMarkerEntry;
 import org.infinispan.container.entries.NullMarkerEntryForRemoval;
@@ -99,8 +100,16 @@
          return cacheEntry;
       }
    }
+   
+   public final MVCCEntry wrapEntryForWriting(InvocationContext ctx, Object key, boolean createIfAbsent, boolean forceLockIfAbsent, boolean alreadyLocked, boolean forRemoval) throws InterruptedException {
+      return wrapEntryForWriting(ctx, key, null, createIfAbsent, forceLockIfAbsent, alreadyLocked, forRemoval);
+   }
 
-   public final MVCCEntry wrapEntryForWriting(InvocationContext ctx, Object key, boolean createIfAbsent, boolean forceLockIfAbsent, boolean alreadyLocked, boolean forRemoval) throws InterruptedException {
+   public MVCCEntry wrapEntryForWriting(InvocationContext ctx, InternalCacheEntry entry, boolean createIfAbsent, boolean forceLockIfAbsent, boolean alreadyLocked, boolean forRemoval) throws InterruptedException {
+      return wrapEntryForWriting(ctx, entry.getKey(), entry, createIfAbsent, forceLockIfAbsent, alreadyLocked, forRemoval);
+   }
+
+   private final MVCCEntry wrapEntryForWriting(InvocationContext ctx, Object key, InternalCacheEntry entry, boolean createIfAbsent, boolean forceLockIfAbsent, boolean alreadyLocked, boolean forRemoval) throws InterruptedException {
       CacheEntry cacheEntry = ctx.lookupEntry(key);
       MVCCEntry mvccEntry = null;
       if (createIfAbsent && cacheEntry != null && cacheEntry.isNull()) cacheEntry = null;
@@ -137,8 +146,8 @@
          if (!alreadyLocked) {
             lockAcquired = acquireLock(ctx, key);
          }
-         // else, fetch from dataContainer.
-         cacheEntry = container.get(key);
+         // else, fetch from dataContainer or used passed entry.
+         cacheEntry = entry != null ? entry : container.get(key);
          if (cacheEntry != null) {
             if (trace) log.trace("Retrieved from container.");
             // exists in cache!  Just acquire lock if needed, and wrap.

Modified: trunk/core/src/main/java/org/infinispan/container/FIFODataContainer.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/FIFODataContainer.java	2009-10-23 16:54:28 UTC (rev 997)
+++ trunk/core/src/main/java/org/infinispan/container/FIFODataContainer.java	2009-10-23 17:28:08 UTC (rev 998)
@@ -727,6 +727,18 @@
       return ice;
    }
 
+   public InternalCacheEntry peek(Object k) {
+      int h = hash(k.hashCode());
+      Segment s = segmentFor(h);
+      LinkedEntry le = s.get(k, h);
+      InternalCacheEntry ice = null;
+      if (le != null) {
+         ice = le.e;
+         if (isMarkedForRemoval(le)) unlink(le);
+      }
+      return ice;
+   }
+
    public void put(Object k, Object v, long lifespan, long maxIdle) {
       // do a normal put first.
       int h = hash(k.hashCode());

Modified: trunk/core/src/main/java/org/infinispan/container/SimpleDataContainer.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/SimpleDataContainer.java	2009-10-23 16:54:28 UTC (rev 997)
+++ trunk/core/src/main/java/org/infinispan/container/SimpleDataContainer.java	2009-10-23 17:28:08 UTC (rev 998)
@@ -39,13 +39,7 @@
       mortalEntries = new ConcurrentHashMap<Object, InternalCacheEntry>(64, 0.75f, concurrencyLevel);
    }
 
-   /**
-    * Like a get, but doesn't check for expired entries
-    *
-    * @param key key to retrieve
-    * @return an entry or null
-    */
-   private InternalCacheEntry peek(Object key) {
+   public InternalCacheEntry peek(Object key) {
       InternalCacheEntry e = immortalEntries.get(key);
       if (e == null) e = mortalEntries.get(key);
       return e;

Modified: trunk/core/src/main/java/org/infinispan/interceptors/LockingInterceptor.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/interceptors/LockingInterceptor.java	2009-10-23 16:54:28 UTC (rev 997)
+++ trunk/core/src/main/java/org/infinispan/interceptors/LockingInterceptor.java	2009-10-23 17:28:08 UTC (rev 998)
@@ -36,6 +36,7 @@
 import org.infinispan.container.DataContainer;
 import org.infinispan.container.EntryFactory;
 import org.infinispan.container.entries.CacheEntry;
+import org.infinispan.container.entries.InternalCacheEntry;
 import org.infinispan.context.Flag;
 import org.infinispan.context.InvocationContext;
 import org.infinispan.context.impl.TxInvocationContext;
@@ -163,8 +164,8 @@
    public Object visitClearCommand(InvocationContext ctx, ClearCommand command) throws Throwable {
       try {
          // get a snapshot of all keys in the data container
-         for (Object key : dataContainer.keySet())
-            entryFactory.wrapEntryForWriting(ctx, key, false, false, false, false);
+         for (InternalCacheEntry entry : dataContainer.entrySet())
+            entryFactory.wrapEntryForWriting(ctx, entry, false, false, false, false);
          return invokeNextInterceptor(ctx, command);
       } finally {
          doAfterCall(ctx);

Modified: trunk/core/src/test/java/org/infinispan/api/CacheAPITest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/api/CacheAPITest.java	2009-10-23 16:54:28 UTC (rev 997)
+++ trunk/core/src/test/java/org/infinispan/api/CacheAPITest.java	2009-10-23 17:28:08 UTC (rev 998)
@@ -32,6 +32,7 @@
       // start a single cache instance
       Configuration c = getDefaultStandaloneConfig(true);
       c.setIsolationLevel(getIsolationLevel());
+      c = addEviction(c);
       CacheManager cm = TestCacheManagerFactory.createLocalCacheManager();
       cm.defineConfiguration("test", c);
       cache = cm.getCache("test");
@@ -39,6 +40,10 @@
    }
 
    protected abstract IsolationLevel getIsolationLevel();
+   
+   protected Configuration addEviction(Configuration cfg) {
+      return cfg; // No eviction by default
+   }
 
    /**
     * Tests that the configuration contains the values expected, as well as immutability of certain elements
@@ -439,4 +444,13 @@
       }
    }
 
+   public void testSizeAfterClear() {
+      for (int i = 0; i < 10; i++) {
+         cache.put(i, "value" + i);
+      }
+      
+      cache.clear();
+      
+      assert 0 == cache.size();
+   }
 }

Added: trunk/core/src/test/java/org/infinispan/api/lru/read_committed/CacheAPIMVCCTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/api/lru/read_committed/CacheAPIMVCCTest.java	                        (rev 0)
+++ trunk/core/src/test/java/org/infinispan/api/lru/read_committed/CacheAPIMVCCTest.java	2009-10-23 17:28:08 UTC (rev 998)
@@ -0,0 +1,23 @@
+package org.infinispan.api.lru.read_committed;
+
+import org.infinispan.api.CacheAPITest;
+import org.infinispan.config.Configuration;
+import org.infinispan.eviction.EvictionStrategy;
+import org.infinispan.util.concurrent.IsolationLevel;
+import org.testng.annotations.Test;
+
+ at Test(groups = "functional", testName = "api.mvcc.read_committed.CacheAPIMVCCTest")
+public class CacheAPIMVCCTest extends CacheAPITest {
+   @Override
+   protected IsolationLevel getIsolationLevel() {
+      return IsolationLevel.READ_COMMITTED;
+   }
+
+   @Override
+   protected Configuration addEviction(Configuration cfg) {
+      cfg.setEvictionStrategy(EvictionStrategy.LRU);
+      cfg.setEvictionWakeUpInterval(60000);
+      cfg.setEvictionMaxEntries(1000);
+      return cfg;
+   }
+}

Modified: trunk/core/src/test/java/org/infinispan/container/SimpleDataContainerTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/container/SimpleDataContainerTest.java	2009-10-23 16:54:28 UTC (rev 997)
+++ trunk/core/src/test/java/org/infinispan/container/SimpleDataContainerTest.java	2009-10-23 17:28:08 UTC (rev 998)
@@ -215,7 +215,7 @@
 
       int i = 0;
       for (Object key : dc.keySet()) {
-         dc.get(key);
+         dc.peek(key); // calling get in this situations will result on corruption the iteration.
          i++;
       }
 



More information about the infinispan-commits mailing list