[jbosscache-commits] JBoss Cache SVN: r4484 - in core/trunk/src: main/java/org/jboss/cache/interceptors and 3 other directories.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Tue Sep 18 12:43:18 EDT 2007


Author: manik.surtani at jboss.com
Date: 2007-09-18 12:43:17 -0400 (Tue, 18 Sep 2007)
New Revision: 4484

Added:
   core/trunk/src/test/java/org/jboss/cache/invalidation/VersionInconsistencyTest.java
Modified:
   core/trunk/src/main/java/org/jboss/cache/CacheImpl.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/marshall/MethodDeclarations.java
   core/trunk/src/main/java/org/jboss/cache/util/Util.java
Log:
JBCACHE-1155

Modified: core/trunk/src/main/java/org/jboss/cache/CacheImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheImpl.java	2007-09-18 03:43:06 UTC (rev 4483)
+++ core/trunk/src/main/java/org/jboss/cache/CacheImpl.java	2007-09-18 16:43:17 UTC (rev 4484)
@@ -2769,26 +2769,64 @@
       if (!exists(fqn))
          return true;// node does not exist
 
-      boolean create_undo_ops = false;
-      boolean sendNodeEvent = false;
-      boolean eviction = true;
       if (log.isTraceEnabled())
       {
          log.trace("_evict(" + fqn + ", " + version + ")");
       }
+
       if (hasChild(fqn))
       {
-         _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction, version);
+         _removeData(null, fqn, false, false, true, version);
          return false;
       }
       else
       {
-         _remove(null, fqn, create_undo_ops, sendNodeEvent, eviction, version);
+         _remove(null, fqn, false, false, true, version);
          return true;
       }
    }
 
    /**
+    * Very much like an evict(), except that regardless of whether there is a child present, this call will never
+    * remove the node from memory - just remove its contents.
+    *
+    * Also, potentially throws a cache exception if data versioning is used and the node in memory has a newer data
+    * version than what is passed in.
+    *
+    * Finally, the data version of the in-memory node is updated to the version being evicted to prevent versions
+    * going out of sync.
+    *
+    * @param fqn
+    * @param versionToInvalidate
+    */
+   public void invalidate(Fqn fqn, DataVersion versionToInvalidate)
+   {
+      Node node = get(fqn); // force interceptor chain, load if necessary from cache loader.
+
+      if (node != null)
+      {
+         _removeData(null, fqn, false, false, true, versionToInvalidate);
+         if (versionToInvalidate != null)
+         {
+            NodeSPI n = peek(fqn, false);
+            n.setVersion(versionToInvalidate);
+         }
+      }
+      else
+      {
+         // if pessimistic locking, just return.
+         if (!configuration.isNodeLockingOptimistic()) return;
+         // create the node we need.
+         Map<K, V> m = Collections.emptyMap();
+         getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
+         put(fqn, m);
+         getInvocationContext().getOptionOverrides().setCacheModeLocal(false);
+         NodeSPI nodeSPI = (NodeSPI) root.getChild(fqn);
+         nodeSPI.setVersion(versionToInvalidate);         
+      }
+   }
+
+   /**
     * Evicts a key/value pair from a node's attributes. Note that this is <em>local</em>, will not be replicated.
     * @param fqn
     * @param key

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java	2007-09-18 03:43:06 UTC (rev 4483)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java	2007-09-18 16:43:17 UTC (rev 4484)
@@ -191,9 +191,12 @@
          m_invalidations++;
 
       // only propagate version details if we're using explicit versioning.
+      /*
       MethodCall call = workspace != null && !workspace.isVersioningImplicit() ?
               MethodCallFactory.create(MethodDeclarations.evictVersionedNodeMethodLocal, fqn, workspace.getNode(fqn).getVersion()) :
               MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, fqn);
+              */
+      MethodCall call = MethodCallFactory.create(MethodDeclarations.invalidateMethodLocal, fqn, (workspace == null ? null : workspace.getNode(fqn).getVersion()));
 
       if (log.isDebugEnabled()) log.debug("Cache [" + cache.getLocalAddress() + "] replicating " + call);
       // voila, invalidated!

Modified: core/trunk/src/main/java/org/jboss/cache/marshall/MethodDeclarations.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/marshall/MethodDeclarations.java	2007-09-18 03:43:06 UTC (rev 4483)
+++ core/trunk/src/main/java/org/jboss/cache/marshall/MethodDeclarations.java	2007-09-18 16:43:17 UTC (rev 4484)
@@ -133,6 +133,8 @@
 
    public static final Method removeDataVersionedMethodLocal;
 
+   public static final Method invalidateMethodLocal;
+
    //not all of these are used for RPC - trim accordingly.
    public static final int putDataMethodLocal_id = 1;
 
@@ -223,7 +225,9 @@
 
    public static final int putForExternalReadVersionedMethodLocal_id = 46;
 
+   public static final int invalidateMethodLocal_id = 47;
 
+
    static
    {
       try
@@ -289,6 +293,8 @@
          removeKeyVersionedMethodLocal = CacheImpl.class.getDeclaredMethod("_remove", GlobalTransaction.class, Fqn.class, Object.class, boolean.class, DataVersion.class);
          removeDataVersionedMethodLocal = CacheImpl.class.getDeclaredMethod("_removeData", GlobalTransaction.class, Fqn.class, boolean.class, DataVersion.class);
 
+         invalidateMethodLocal = CacheImpl.class.getDeclaredMethod("invalidate", Fqn.class, DataVersion.class);
+
       }
       catch (NoSuchMethodException e)
       {
@@ -342,6 +348,8 @@
       methods.put(putForExternalReadVersionedMethodLocal_id, putForExternalReadVersionedMethodLocal);
       methods.put(putForExternalReadMethodLocal_id, putForExternalReadMethodLocal);
 
+      methods.put(invalidateMethodLocal_id, invalidateMethodLocal);
+
       for (Integer id : methods.keySet())
       {
          methodIds.put(methods.get(id), id);

Modified: core/trunk/src/main/java/org/jboss/cache/util/Util.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/Util.java	2007-09-18 03:43:06 UTC (rev 4483)
+++ core/trunk/src/main/java/org/jboss/cache/util/Util.java	2007-09-18 16:43:17 UTC (rev 4484)
@@ -60,9 +60,9 @@
    }
 
    /**
-    * Calculates the diffs between data maps passed in to {@link org.jboss.cache.CacheListener#nodeModified(org.jboss.cache.Fqn,boolean,boolean,org.jboss.cache.CacheListener.ModificationType,java.util.Map)}
-    * before and after modification.  This only makes sense if the modification type is {@link org.jboss.cache.CacheListener.ModificationType#PUT_MAP}.
-    * Refer to {@link org.jboss.cache.CacheListener#nodeModified(org.jboss.cache.Fqn,boolean,boolean,org.jboss.cache.CacheListener.ModificationType,Map)}.
+    * Calculates the diffs between data maps passed in to {@link org.jboss.cache.notifications.event.NodeModifiedEvent#getData()}
+    * before and after modification.  This only makes sense if the modification type is {@link org.jboss.cache.notifications.event.NodeModifiedEvent.ModificationType#PUT_MAP}.
+    * Refer to {@link org.jboss.cache.notifications.event.NodeModifiedEvent} and {@link org.jboss.cache.notifications.annotation.NodeModified}.
     *
     * @param pre  map of data before the node was modified
     * @param post Map of data after the node was modified

Added: core/trunk/src/test/java/org/jboss/cache/invalidation/VersionInconsistencyTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/invalidation/VersionInconsistencyTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/invalidation/VersionInconsistencyTest.java	2007-09-18 16:43:17 UTC (rev 4484)
@@ -0,0 +1,97 @@
+package org.jboss.cache.invalidation;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.AfterTest;
+import org.jboss.cache.Cache;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Node;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.optimistic.DefaultDataVersion;
+import org.jboss.cache.misc.TestingUtil;
+import org.jboss.cache.transaction.DummyTransactionManagerLookup;
+import org.jboss.cache.config.Configuration;
+
+import javax.transaction.TransactionManager;
+import javax.transaction.Transaction;
+
+/**
+ * This test simulates the problem described in JBCACHE-1155
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani</a>
+ * @since 2.1.0
+ */
+ at Test(groups = {"functional"})
+public class VersionInconsistencyTest
+{
+   private Cache cache1, cache2;
+   private TransactionManager tm1, tm2;
+   private Fqn node = Fqn.fromString("/a");
+
+   @BeforeTest
+   public void setUp()
+   {
+      cache1 = DefaultCacheFactory.getInstance().createCache(false);
+      cache2 = DefaultCacheFactory.getInstance().createCache(false);
+
+      cache1.getConfiguration().setCacheMode(Configuration.CacheMode.INVALIDATION_SYNC);
+      cache2.getConfiguration().setCacheMode(Configuration.CacheMode.INVALIDATION_SYNC);
+
+      cache1.getConfiguration().setNodeLockingScheme(Configuration.NodeLockingScheme.OPTIMISTIC);
+      cache2.getConfiguration().setNodeLockingScheme(Configuration.NodeLockingScheme.OPTIMISTIC);
+
+      cache1.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
+      cache2.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
+
+      cache1.start();
+      cache2.start();
+
+      tm1 = cache1.getConfiguration().getRuntimeConfig().getTransactionManager();
+      tm2 = cache2.getConfiguration().getRuntimeConfig().getTransactionManager();
+
+      TestingUtil.blockUntilViewsReceived(1000, cache1, cache2);
+   }
+
+   @AfterTest
+   public void tearDown()
+   {
+      cache1.stop();
+      cache2.stop();
+   }
+
+   public void dataInconsistency() throws Exception
+   {
+      tm1.begin();
+      cache1.put(node, "k", "v-older");
+      Transaction t1 = tm1.suspend();
+
+      tm2.begin();
+      cache2.put(node, "k", "v-newer");
+      tm2.commit();
+
+      tm1.resume(t1);
+      try
+      {
+         tm1.commit();
+         assert false : "Should not be allowed to commit with older data!!";
+      }
+      catch (Exception good)
+      {
+      }
+
+      // the NEWER version of the data should be available, not the OLDER one.
+
+      Object val = cache1.get(node, "k");
+      System.out.println("val = " + val);
+      assert val == null : "Older data should not have committed";
+
+      val = cache2.get(node, "k");
+      System.out.println("val = " + val);
+      assert val.equals("v-newer");
+
+      // test node versions
+      NodeSPI n = (NodeSPI) cache1.getRoot().getChild(node);
+      assert ((DefaultDataVersion) n.getVersion()).getRawVersion() == 1 : "Version should be 1";
+   }
+}




More information about the jbosscache-commits mailing list