Author: galder.zamarreno(a)jboss.com
Date: 2009-09-24 07:32:13 -0400 (Thu, 24 Sep 2009)
New Revision: 8238
Added:
core/branches/1.4.X/etc/META-INF/optimistic-replicated-eviction.xml
core/branches/1.4.X/tests/functional/org/jboss/cache/eviction/OptimisticReplicatedEvictionTest.java
Modified:
core/branches/1.4.X/src/org/jboss/cache/interceptors/OptimisticNodeInterceptor.java
core/branches/1.4.X/tests/functional/org/jboss/cache/optimistic/NodeInterceptorRemoveNodeTest.java
Log:
[JBCACHE-1545] OL queues removal modifications even if the node was not present locally.
Added: core/branches/1.4.X/etc/META-INF/optimistic-replicated-eviction.xml
===================================================================
--- core/branches/1.4.X/etc/META-INF/optimistic-replicated-eviction.xml
(rev 0)
+++ core/branches/1.4.X/etc/META-INF/optimistic-replicated-eviction.xml 2009-09-24
11:32:13 UTC (rev 8238)
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Sample TreeCache Service Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<server>
+
+ <classpath codebase="./lib" archives="jboss-cache.jar,
jgroups.jar"/>
+
+
+ <!-- ==================================================================== -->
+ <!-- Defines TreeCache configuration -->
+ <!-- ==================================================================== -->
+
+ <mbean code="org.jboss.cache.TreeCache"
+ name="jboss.cache:service=TreeCache">
+
+ <depends>jboss:service=Naming</depends>
+ <depends>jboss:service=TransactionManager</depends>
+
+ <!--
+ Configure the TransactionManager
+ -->
+ <attribute
name="TransactionManagerLookupClass">org.jboss.cache.DummyTransactionManagerLookup</attribute>
+
+ <attribute name="FetchInMemoryState">false</attribute>
+ <attribute name="FetchPersistentState">false</attribute>
+ <!-- Whether each interceptor should have an mbean
+ registered to capture and display its statistics. -->
+ <attribute name="UseInterceptorMbeans">true</attribute>
+
+ <!--
+ Node locking scheme:
+ OPTIMISTIC
+ PESSIMISTIC (default)
+ -->
+ <attribute name="NodeLockingScheme">Optimistic</attribute>
+
+ <!--
+ Node locking level : SERIALIZABLE
+ REPEATABLE_READ (default)
+ READ_COMMITTED
+ READ_UNCOMMITTED
+ NONE
+ -->
+ <attribute
name="IsolationLevel">READ_COMMITTED</attribute>
+
+
+ <!--
+ Valid modes are LOCAL
+ REPL_ASYNC
+ REPL_SYNC
+ -->
+ <attribute name="CacheMode">REPL_SYNC</attribute>
+
+ <!-- Name of cluster. Needs to be the same for all clusters, in order
+ to find each other
+ -->
+ <attribute
name="ClusterName">Infa-Cache-Cluster</attribute>
+
+ <attribute name="ClusterConfig">
+ <config>
+ <!-- UDP: if you have a multihomed machine,
+ set the bind_addr attribute to the appropriate NIC IP address, e.g
bind_addr="192.168.0.2"
+ -->
+ <!-- UDP: On Windows machines, because of the media sense feature
+ being broken with multicast (even after disabling media sense)
+ set the loopback attribute to true -->
+ <UDP mcast_addr="228.1.2.3" mcast_port="48866"
+ ip_ttl="64" ip_mcast="true"
+ mcast_send_buf_size="150000"
mcast_recv_buf_size="80000"
+ ucast_send_buf_size="150000"
ucast_recv_buf_size="80000"
+ loopback="false"/>
+ <PING timeout="2000" num_initial_members="3"
+ up_thread="false" down_thread="false"/>
+ <MERGE2 min_interval="10000"
max_interval="20000"/>
+ <!-- <FD shun="true" up_thread="true"
down_thread="true" />-->
+ <FD_SOCK/>
+ <VERIFY_SUSPECT timeout="1500"
+ up_thread="false" down_thread="false"/>
+ <pbcast.NAKACK gc_lag="50"
retransmit_timeout="600,1200,2400,4800"
+ max_xmit_size="8192" up_thread="false"
down_thread="false"/>
+ <UNICAST timeout="600,1200,2400" window_size="100"
min_threshold="10"
+ down_thread="false"/>
+ <pbcast.STABLE desired_avg_gossip="20000"
+ up_thread="false" down_thread="false"/>
+ <FRAG frag_size="8192"
+ down_thread="false" up_thread="false"/>
+ <pbcast.GMS join_timeout="5000"
join_retry_timeout="2000"
+ shun="true" print_local_addr="true"/>
+ <pbcast.STATE_TRANSFER up_thread="true"
down_thread="true"/>
+ </config>
+ </attribute>
+
+ <!-- Max number of milliseconds to wait for a lock acquisition -->
+ <attribute name="LockAcquisitionTimeout">1000</attribute>
+
+ <!-- Name of the eviction policy class.-->
+ <attribute
name="EvictionPolicyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+ <attribute name="EvictionPolicyConfig">
+ <config>
+ <attribute
name="wakeUpIntervalSeconds">1</attribute>
+ <region name="/_default_">
+ <attribute name="maxNodes">10</attribute>
+ <attribute
name="timeToLiveSeconds">0</attribute>
+ <attribute name="maxAgeSeconds">0</attribute>
+ </region>
+ <region name="/testingRegion">
+ <attribute name="maxNodes">10</attribute>
+ <attribute
name="timeToLiveSeconds">0</attribute>
+ <attribute name="maxAgeSeconds">0</attribute>
+ </region>
+ <region name="/timeBased">
+ <attribute name="maxNodes">10</attribute>
+ <attribute
name="timeToLiveSeconds">1</attribute>
+ <attribute name="maxAgeSeconds">1</attribute>
+ </region>
+ <region name="/timeToLiveBased">
+ <attribute name="maxNodes">10</attribute>
+ <attribute
name="timeToLiveSeconds">5</attribute>
+ <attribute name="maxAgeSeconds">0</attribute>
+ </region>
+ </config>
+ </attribute>
+
+ </mbean>
+</server>
Modified:
core/branches/1.4.X/src/org/jboss/cache/interceptors/OptimisticNodeInterceptor.java
===================================================================
---
core/branches/1.4.X/src/org/jboss/cache/interceptors/OptimisticNodeInterceptor.java 2009-09-24
10:28:05 UTC (rev 8237)
+++
core/branches/1.4.X/src/org/jboss/cache/interceptors/OptimisticNodeInterceptor.java 2009-09-24
11:32:13 UTC (rev 8238)
@@ -101,6 +101,14 @@
else
{
log.trace("Workspace node is null. Perhaps it has been
deleted?");
+ // However, if a removal was requested to a node we don't have, we
should still propagate it!!
+ Option opt = ctx.getOptionOverrides();
+ if ((opt == null || !opt.isCacheModeLocal()) && m.getMethodId() ==
MethodDeclarations.removeNodeMethodLocal_id)
+ {
+ txTable.addModification(gtx, m);
+ if (log.isDebugEnabled()) log.debug("Adding Method " + m +
" to modification list");
+ }
+ if (cache.getCacheLoaderManager() != null)
txTable.addCacheLoaderModification(gtx, m);
return null;
}
}
Added:
core/branches/1.4.X/tests/functional/org/jboss/cache/eviction/OptimisticReplicatedEvictionTest.java
===================================================================
---
core/branches/1.4.X/tests/functional/org/jboss/cache/eviction/OptimisticReplicatedEvictionTest.java
(rev 0)
+++
core/branches/1.4.X/tests/functional/org/jboss/cache/eviction/OptimisticReplicatedEvictionTest.java 2009-09-24
11:32:13 UTC (rev 8238)
@@ -0,0 +1,182 @@
+package org.jboss.cache.eviction;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.AbstractTreeCacheListener;
+import org.jboss.cache.CacheException;
+import org.jboss.cache.ExtendedTreeCacheListener;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.PropertyConfigurator;
+import org.jboss.cache.TreeCache;
+
+import EDU.oswego.cs.dl.util.concurrent.BoundedLinkedQueue;
+import EDU.oswego.cs.dl.util.concurrent.Callable;
+import EDU.oswego.cs.dl.util.concurrent.Executor;
+import EDU.oswego.cs.dl.util.concurrent.FutureResult;
+import EDU.oswego.cs.dl.util.concurrent.ThreadedExecutor;
+
+public class OptimisticReplicatedEvictionTest extends TestCase
+{
+ private static final Log log =
LogFactory.getLog(OptimisticReplicatedEvictionTest.class);
+
+ private TreeCache cache1;
+ private TreeCache cache2;
+
+ private BoundedLinkedQueue queue = new BoundedLinkedQueue();
+ private static final Fqn SHUTDOWN_FQN = new Fqn("time-to-shutdown");
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ cache1 = new TreeCache();
+ PropertyConfigurator config1 = new PropertyConfigurator();
+ config1.configure(cache1,
"META-INF/optimistic-replicated-eviction.xml");
+ cache1.startService();
+
+ cache2 = new TreeCache();
+ PropertyConfigurator config2 = new PropertyConfigurator();
+ config2.configure(cache2,
"META-INF/optimistic-replicated-eviction.xml");
+ RemovalThread removalThread = new RemovalThread(cache2);
+ log.trace("Starting the removal thread...");
+ removalThread.start();
+ EvictionListener listener = new EvictionListener();
+ log.trace("Listening for evictions...");
+ cache2.addTreeCacheListener(listener);
+ cache2.startService();
+ }
+
+ protected void tearDown() throws Exception
+ {
+ if (cache1 != null)
+ {
+ cache1.stopService();
+ cache1 = null;
+ }
+ super.tearDown();
+ }
+
+ public void testClusteredEvictionToClearVersionInfo() throws Exception
+ {
+ cache1.put( "/timeToLiveBased/test000", "k-allele",
"v1-allele" ); // this could be from any node
+ cache1.put( "/timeToLiveBased/test000", "k-allele",
"v2-allele" ); // v2
+
+ Callable c = new Callable() {
+ public Object call() throws Exception {
+ Thread.sleep(8 * 1000);
+ Object ret = cache2.put("/timeToLiveBased/test000",
"k-allele", "v3-allele" ); // will always fail during replication to
A:
+ if (ret instanceof Exception) throw (Exception) ret;
+ return null;
+ }
+ };
+
+ Executor executor = new ThreadedExecutor();
+ FutureResult f = new FutureResult();
+ Runnable command = f.setter(c);
+ executor.execute(command);
+
+ for (;;)
+ {
+ if (f.isReady())
+ {
+ f.get();
+ break;
+ }
+ else
+ {
+ Thread.sleep(2 * 1000);
+ }
+ cache1.get("/timeToLiveBased/test000", "k-allele"); //
refresh the eviction timer so the node will never be evicted on A
+ }
+
+ assertEquals(cache1.get("/timeToLiveBased/test000",
"k-allele"), "v3-allele");
+ assertEquals(cache2.get("/timeToLiveBased/test000",
"k-allele"), "v3-allele");
+ }
+
+ // Jimmy's cluster wide removal workaround
+ /**
+ * An inner class that serves as a listener for cache eviction events.
+ */
+ private class EvictionListener extends AbstractTreeCacheListener implements
ExtendedTreeCacheListener
+ {
+ public void nodeEvict(Fqn fqn, boolean pre)
+ {
+ // make sure we act *after* eviction takes place
+ if (!pre)
+ {
+ if (log.isTraceEnabled())
+ {
+ StringBuilder builder = new StringBuilder("Adding ");
+ builder.append(fqn);
+ builder.append(" for removal...");
+ log.trace(builder);
+ }
+ try {
+ queue.put(fqn);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ /**
+ * An inner class that serves as the thread that calls the cluster-wide
+ * remove operation as cache listener event message threads are cache
+ * blocking.
+ */
+ private class RemovalThread extends Thread
+ {
+ private final TreeCache cache;
+
+ public RemovalThread(TreeCache cache)
+ {
+ setName("Cache Eviction Remover");
+ this.cache = cache;
+ }
+
+ public void run()
+ {
+ log.trace("The cache eviction remover thread is starting...");
+
+ while (! isInterrupted())
+ {
+ Fqn fqn = null;
+
+ try
+ {
+ fqn = (Fqn) queue.take();
+
+ // if we're shutting down, do nothing...
+ if (fqn != SHUTDOWN_FQN)
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("Removing " + fqn);
+ }
+
+ cache.remove(fqn);
+ }
+ }
+ catch (CacheException ce)
+ {
+ // if this happens, data will remain in remote caches so
+ // indicate it as WARN or even ERROR
+ StringBuilder builder = new StringBuilder("Failed to remove
");
+ builder.append(fqn);
+ builder.append(" from remote caches:");
+ log.warn(builder, ce);
+ }
+ catch (InterruptedException ie)
+ {
+ Thread.currentThread().interrupt();
+ // we were interrupted in queue.take() so stop
+ break;
+ }
+ }
+ log.trace("The cache eviction remover thread is stopping...");
+ }
+ }
+}
Modified:
core/branches/1.4.X/tests/functional/org/jboss/cache/optimistic/NodeInterceptorRemoveNodeTest.java
===================================================================
---
core/branches/1.4.X/tests/functional/org/jboss/cache/optimistic/NodeInterceptorRemoveNodeTest.java 2009-09-24
10:28:05 UTC (rev 8237)
+++
core/branches/1.4.X/tests/functional/org/jboss/cache/optimistic/NodeInterceptorRemoveNodeTest.java 2009-09-24
11:32:13 UTC (rev 8238)
@@ -77,7 +77,8 @@
assertEquals(0, workspace.getNodes().size());
assertTrue(entry.getLocks().isEmpty());
- assertEquals(0, entry.getModifications().size());
+ // JBCACHE-1545 modifications are still queued even though removed node does not
exist
+ assertEquals(1, entry.getModifications().size());
assertTrue(!cache.exists("/one/two"));
assertEquals(null, dummy.getCalled());
Show replies by date