[jboss-cvs] JBossAS SVN: r77662 - in projects/cluster/ha-server-api/trunk/src: test/java/org/jboss/test/ha/framework/server and 1 other directory.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Fri Aug 29 15:29:15 EDT 2008
Author: pferraro
Date: 2008-08-29 15:29:15 -0400 (Fri, 29 Aug 2008)
New Revision: 77662
Modified:
projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/HASingletonImpl.java
projects/cluster/ha-server-api/trunk/src/test/java/org/jboss/test/ha/framework/server/HASingletonTestCase.java
Log:
[JBAS-2647] Remove potential deadlock condition from HASingletonSupport
Fixed assertions in test case to use JUnit's static methods.
Modified: projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/HASingletonImpl.java
===================================================================
--- projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/HASingletonImpl.java 2008-08-29 17:15:58 UTC (rev 77661)
+++ projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/HASingletonImpl.java 2008-08-29 19:29:15 UTC (rev 77662)
@@ -24,6 +24,7 @@
import java.util.EventObject;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
import org.jboss.ha.framework.interfaces.ClusterNode;
import org.jboss.ha.framework.interfaces.DistributedReplicantManager;
@@ -41,6 +42,8 @@
private final AtomicBoolean master = new AtomicBoolean(false);
private final HASingletonRpcHandler<E> rpcHandler = new RpcHandler();
private final HASingletonLifecycle singletonLifecycle;
+
+ AtomicReference<ReplicantView> viewReference = new AtomicReference<ReplicantView>();
private volatile HASingletonElectionPolicy electionPolicy;
private volatile boolean restartOnMerge = true;
@@ -85,6 +88,44 @@
}
/**
+ * @{inheritDoc}
+ * Overridden to circumvent deadlock in the unlikely scenario that the view changes between
+ * drm listener registration and drm replicant addition. See JBAS-2647 for details.
+ * @see org.jboss.ha.framework.server.HAServiceImpl#registerDRMListener()
+ */
+ @Override
+ protected void registerDRMListener() throws Exception
+ {
+ DistributedReplicantManager drm = this.getHAPartition().getDistributedReplicantManager();
+
+ final String key = this.getHAServiceKey();
+
+ // Temporary drm listener
+ RecordingReplicantListener listener = new RecordingReplicantListener();
+
+ // record replicant changes, but don't handle them just yet
+ drm.registerListener(key, listener);
+
+ // this ensures that the DRM knows that this node has the singleton deployed
+ drm.add(key, this.getReplicant());
+
+ // Now register the real listener
+ drm.registerListener(key, this);
+
+ // ...and unregister our temporary one
+ drm.unregisterListener(key, listener);
+
+ ReplicantView view = this.viewReference.getAndSet(null);
+
+ // Process the recorded replicant change
+ // Typically this will be the replicant change from drm.add(...)
+ if (view != null)
+ {
+ this.partitionTopologyChanged(view.getReplicants(), view.getId(), view.isMerge());
+ }
+ }
+
+ /**
* @see org.jboss.ha.framework.interfaces.HASingletonLifecycle#startSingleton()
*/
public void startSingleton()
@@ -108,13 +149,21 @@
* @see org.jboss.ha.framework.interfaces.DistributedReplicantManager#isMasterReplica(String)
*/
@Override
- protected void partitionTopologyChanged(List<?> newReplicants, int newViewID, boolean merge)
+ protected void partitionTopologyChanged(List<?> newReplicants, int newViewId, boolean merge)
{
+ ReplicantView view = this.viewReference.getAndSet(null);
+
+ // Pre-process any recorded replicant changes
+ if (view != null)
+ {
+ this.partitionTopologyChanged(view.getReplicants(), view.getId(), view.isMerge());
+ }
+
boolean isElectedNewMaster = this.elected();
boolean isMaster = this.master.get();
- this.log.debug("partitionTopologyChanged, isElectedNewMaster=" + isElectedNewMaster + ", isMasterNode=" + isMaster + ", viewID=" + newViewID);
+ this.log.debug("partitionTopologyChanged, isElectedNewMaster=" + isElectedNewMaster + ", isMasterNode=" + isMaster + ", viewID=" + newViewId);
if (isElectedNewMaster)
{
@@ -282,4 +331,46 @@
HASingletonImpl.this.stopIfMaster();
}
}
+
+ private static class ReplicantView
+ {
+ private List<?> replicants;
+ private int id;
+ private boolean merge;
+
+ public ReplicantView(List<?> replicants, int viewId, boolean merge)
+ {
+ this.replicants = replicants;
+ this.id = viewId;
+ this.merge = merge;
+ }
+
+ public List<?> getReplicants()
+ {
+ return this.replicants;
+ }
+
+ public int getId()
+ {
+ return this.id;
+ }
+
+ public boolean isMerge()
+ {
+ return this.merge;
+ }
+ }
+
+ class RecordingReplicantListener implements DistributedReplicantManager.ReplicantListener
+ {
+ @SuppressWarnings("unchecked")
+ public void replicantsChanged(String key, List newReplicants, int newReplicantsViewId, boolean merge)
+ {
+ if (key.equals(key))
+ {
+ // Record replicant change - overwriting any previously recorded view
+ HASingletonImpl.this.viewReference.set(new ReplicantView(newReplicants, newReplicantsViewId, merge));
+ }
+ }
+ }
}
Modified: projects/cluster/ha-server-api/trunk/src/test/java/org/jboss/test/ha/framework/server/HASingletonTestCase.java
===================================================================
--- projects/cluster/ha-server-api/trunk/src/test/java/org/jboss/test/ha/framework/server/HASingletonTestCase.java 2008-08-29 17:15:58 UTC (rev 77661)
+++ projects/cluster/ha-server-api/trunk/src/test/java/org/jboss/test/ha/framework/server/HASingletonTestCase.java 2008-08-29 19:29:15 UTC (rev 77662)
@@ -25,8 +25,10 @@
import java.util.Collections;
import java.util.List;
+import org.easymock.Capture;
import org.easymock.EasyMock;
import org.jboss.ha.framework.interfaces.ClusterNode;
+import org.jboss.ha.framework.interfaces.DistributedReplicantManager;
import org.jboss.ha.framework.interfaces.HASingletonElectionPolicy;
import org.jboss.ha.framework.interfaces.HASingletonLifecycle;
import org.jboss.ha.framework.server.HAServiceEvent;
@@ -48,11 +50,13 @@
private final HASingletonImpl<HAServiceEvent> customSingleton = new HASingletonImpl<HAServiceEvent>(new HAServiceEventFactory())
{
+ @Override
public void startSingleton()
{
HASingletonTestCase.this.lifecycle.startSingleton();
}
+ @Override
public void stopSingleton()
{
HASingletonTestCase.this.lifecycle.stopSingleton();
@@ -89,37 +93,86 @@
return EasyMock.isA(HASingletonRpcHandler.class);
}
+ @Override
+ public void testStart() throws Exception
+ {
+ Capture<DistributedReplicantManager.ReplicantListener> capturedListener1 = new Capture<DistributedReplicantManager.ReplicantListener>();
+ Capture<DistributedReplicantManager.ReplicantListener> capturedListener2 = new Capture<DistributedReplicantManager.ReplicantListener>();
+
+ // Test isRegisterThreadContextClassLoader() = default value
+ this.partition.registerRPCHandler(EasyMock.same(SERVICE_HA_NAME), this.getRpcHandler());
+
+ EasyMock.expect(this.partition.getDistributedReplicantManager()).andReturn(this.drm);
+
+ this.drm.registerListener(EasyMock.same(SERVICE_HA_NAME), EasyMock.capture(capturedListener1));
+ this.drm.add(SERVICE_HA_NAME, "");
+ this.drm.registerListener(SERVICE_HA_NAME, this.singleton);
+ this.drm.unregisterListener(EasyMock.same(SERVICE_HA_NAME), EasyMock.capture(capturedListener2));
+
+ EasyMock.replay(this.partition, this.drm);
+
+ this.singleton.start();
+
+ EasyMock.verify(this.partition, this.drm);
+
+ assertSame(capturedListener1.getValue(), capturedListener2.getValue());
+
+ EasyMock.reset(this.partition, this.drm);
+
+ // Test isRegisterThreadContextClassLoader() = true
+ this.singleton.setRegisterThreadContextClassLoader(true);
+
+ this.partition.registerRPCHandler(EasyMock.same(SERVICE_HA_NAME), this.getRpcHandler(), EasyMock.same(Thread.currentThread().getContextClassLoader()));
+
+ EasyMock.expect(this.partition.getDistributedReplicantManager()).andReturn(this.drm);
+
+ this.drm.registerListener(EasyMock.same(SERVICE_HA_NAME), EasyMock.capture(capturedListener1));
+ this.drm.add(SERVICE_HA_NAME, "");
+ this.drm.registerListener(SERVICE_HA_NAME, this.singleton);
+ this.drm.unregisterListener(EasyMock.same(SERVICE_HA_NAME), EasyMock.capture(capturedListener2));
+
+ EasyMock.replay(this.partition, this.drm);
+
+ this.singleton.start();
+
+ EasyMock.verify(this.partition, this.drm);
+
+ assertSame(capturedListener1.getValue(), capturedListener2.getValue());
+
+ EasyMock.reset(this.partition, this.drm);
+ }
+
public void testRestartOnMerge()
{
boolean restart = this.singleton.getRestartOnMerge();
- assert restart;
+ assertTrue(restart);
this.singleton.setRestartOnMerge(false);
restart = this.singleton.getRestartOnMerge();
-
- assert !restart;
+
+ assertFalse(restart);
}
public void testElectionPolicy()
{
HASingletonElectionPolicy policy = this.singleton.getElectionPolicy();
- assert policy == null;
+ assertNull(policy);
this.singleton.setElectionPolicy(this.electionPolicy);
policy = this.singleton.getElectionPolicy();
-
- assert policy == this.electionPolicy;
+
+ assertSame(this.electionPolicy, policy);
}
public void testIsMaster()
{
boolean master = this.singleton.isMasterNode();
- assert !master;
+ assertFalse(master);
}
public void testStopOldMaster() throws Exception
@@ -147,7 +200,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle);
- assert !this.singleton.isMasterNode();
+ assertFalse(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle);
@@ -163,7 +216,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle);
- assert !this.singleton.isMasterNode();
+ assertFalse(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle);
@@ -182,7 +235,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle);
- assert this.singleton.isMasterNode();
+ assertTrue(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle);
@@ -198,7 +251,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle);
- assert this.singleton.isMasterNode();
+ assertTrue(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle);
@@ -217,7 +270,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle);
- assert this.singleton.isMasterNode();
+ assertTrue(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle);
@@ -235,7 +288,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle);
- assert this.singleton.isMasterNode();
+ assertTrue(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle);
@@ -253,7 +306,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle);
- assert !this.singleton.isMasterNode();
+ assertFalse(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle);
@@ -274,7 +327,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle);
- assert !this.singleton.isMasterNode();
+ assertFalse(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle);
@@ -292,7 +345,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle);
- assert !this.singleton.isMasterNode();
+ assertFalse(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle);
@@ -314,7 +367,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle);
- assert !this.singleton.isMasterNode();
+ assertFalse(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle);
@@ -333,7 +386,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle, this.electionPolicy);
- assert !this.singleton.isMasterNode();
+ assertFalse(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle, this.electionPolicy);
@@ -354,7 +407,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle, this.electionPolicy);
- assert this.singleton.isMasterNode();
+ assertTrue(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle, this.electionPolicy);
@@ -374,7 +427,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle, this.electionPolicy);
- assert this.singleton.isMasterNode();
+ assertTrue(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle, this.electionPolicy);
@@ -393,7 +446,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle, this.electionPolicy);
- assert this.singleton.isMasterNode();
+ assertTrue(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle, this.electionPolicy);
@@ -415,7 +468,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle, this.electionPolicy);
- assert this.singleton.isMasterNode();
+ assertTrue(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle, this.electionPolicy);
@@ -427,7 +480,6 @@
EasyMock.expect(this.electionPolicy.elect(nodes)).andReturn(ourNode);
EasyMock.expect(this.partition.getClusterNode()).andReturn(ourNode);
- System.out.println("restart on merge = " + this.singleton.getRestartOnMerge());
this.lifecycle.stopSingleton();
this.lifecycle.startSingleton();
@@ -437,7 +489,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle, this.electionPolicy);
- assert this.singleton.isMasterNode();
+ assertTrue(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle, this.electionPolicy);
@@ -457,7 +509,7 @@
EasyMock.verify(this.partition, this.drm, this.lifecycle, this.electionPolicy);
- assert !this.singleton.isMasterNode();
+ assertFalse(this.singleton.isMasterNode());
EasyMock.reset(this.partition, this.drm, this.lifecycle, this.electionPolicy);
}
More information about the jboss-cvs-commits
mailing list