[jboss-cvs] JBossAS SVN: r105080 - in projects/cluster/ha-server-api/trunk/src: test/java/org/jboss/test/ha/framework/server/lock and 1 other directory.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Thu May 20 19:54:35 EDT 2010
Author: bstansberry at jboss.com
Date: 2010-05-20 19:54:33 -0400 (Thu, 20 May 2010)
New Revision: 105080
Modified:
projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/AbstractClusterLockSupport.java
projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/NonGloballyExclusiveClusterLockSupport.java
projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/SharedLocalYieldingClusterLockManager.java
projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/YieldingGloballyExclusiveClusterLockSupport.java
projects/cluster/ha-server-api/trunk/src/test/java/org/jboss/test/ha/framework/server/lock/SharedLocalYieldingClusterLockManagerUnitTestCase.java
projects/cluster/ha-server-api/trunk/src/test/java/org/jboss/test/ha/framework/server/lock/YieldingGloballyExclusiveClusterLockSupportUnitTestCase.java
Log:
[JBCLUSTER-268] Finish up session ownership locking
Modified: projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/AbstractClusterLockSupport.java
===================================================================
--- projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/AbstractClusterLockSupport.java 2010-05-20 23:25:11 UTC (rev 105079)
+++ projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/AbstractClusterLockSupport.java 2010-05-20 23:54:33 UTC (rev 105080)
@@ -369,6 +369,8 @@
protected abstract RemoteLockResponse yieldLock(ClusterLockState lockState, ClusterNode caller, long timeout);
+ protected abstract RemoteLockResponse getRemoteLockResponseForUnknownLock(Serializable lockName, ClusterNode caller, long timeout);
+
protected void recordLockHolder(ClusterLockState lockState, ClusterNode caller)
{
if (lockState.holder != null)
@@ -423,8 +425,7 @@
ClusterLockState lockState = getClusterLockState(lockName);
if (lockState == null)
{
- // unknown == OK
- return new RemoteLockResponse(me, RemoteLockResponse.Flag.OK);
+ return getRemoteLockResponseForUnknownLock(lockName, caller, timeout);
}
switch (lockState.state.get())
Modified: projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/NonGloballyExclusiveClusterLockSupport.java
===================================================================
--- projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/NonGloballyExclusiveClusterLockSupport.java 2010-05-20 23:25:11 UTC (rev 105079)
+++ projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/NonGloballyExclusiveClusterLockSupport.java 2010-05-20 23:54:33 UTC (rev 105080)
@@ -116,6 +116,13 @@
recordLockHolder(lockState, caller);
return new RemoteLockResponse(getLocalClusterNode(), RemoteLockResponse.Flag.OK);
}
+
+ @Override
+ protected RemoteLockResponse getRemoteLockResponseForUnknownLock(Serializable lockName, ClusterNode caller, long timeout)
+ {
+ // unknown == OK
+ return new RemoteLockResponse(getLocalClusterNode(), RemoteLockResponse.Flag.OK);
+ }
// ----------------------------------------------------------------- Private
}
Modified: projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/SharedLocalYieldingClusterLockManager.java
===================================================================
--- projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/SharedLocalYieldingClusterLockManager.java 2010-05-20 23:25:11 UTC (rev 105079)
+++ projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/SharedLocalYieldingClusterLockManager.java 2010-05-20 23:54:33 UTC (rev 105080)
@@ -216,7 +216,7 @@
LockState newState = null;
for (;;)
{
- newState = current.register();
+ newState = current.register(SharedLocalYieldingClusterLockManager.this.localNode);
if (lockState.compareAndSet(current, newState))
{
break;
@@ -238,12 +238,14 @@
private static class LockState
{
/** The standard initial state */
- private static final LockState AVAILABLE = new LockState(0, null, null, false);
+ private static final LockState AVAILABLE = new LockState(0, null, null, null, false);
/** Number of local callers that have locked or want to lock */
private final int localLockCount;
/** The node that holds the lock */
private final ClusterNode lockHolder;
+ /** The node that last held the lock, if currently unheld */
+ private final ClusterNode lastHolder;
/**
* Most recent thread to call {@link LocalLock#registerForLocalLock()}.
* Used by a thread that asks the cluster for the lock to detect if other
@@ -254,23 +256,28 @@
/** Flag indicating the lock object is no longer valid and callers should obtain a new one */
private final boolean invalid;
- private LockState(int localLockCount, ClusterNode lockHolder, Thread latestRegistrant, boolean invalid)
+ private LockState(int localLockCount, ClusterNode lockHolder, ClusterNode lastHolder, Thread latestRegistrant, boolean invalid)
{
this.localLockCount = localLockCount;
this.lockHolder = lockHolder;
+ this.lastHolder = lastHolder;
this.latestRegistrant = latestRegistrant;
this.invalid = invalid;
}
/**
- * Record interest in obtaining the lock.
+ * Record interest in obtaining the lock. If the lock is unheld and
+ * <code>registrant</code> was the last holder of the lock, then
+ * <code>registrant</code> will be made holder of the lock.
*
* @return a LockState with a lock count one higher than this one and with
* the current thread as latestRegistrant
*/
- private LockState register()
+ private LockState register(ClusterNode registrant)
{
- return new LockState(localLockCount + 1, lockHolder, Thread.currentThread(), invalid);
+ ClusterNode newHolder = (lockHolder == null && lastHolder == registrant) ? registrant : lockHolder;
+ ClusterNode newLast = newHolder == null ? lastHolder : null;
+ return new LockState(localLockCount + 1, newHolder, newLast, Thread.currentThread(), invalid);
}
/**
@@ -288,7 +295,8 @@
private LockState unregister(boolean decrement)
{
Thread registrant = (latestRegistrant == Thread.currentThread() ? null : latestRegistrant);
- return new LockState(localLockCount - 1, lockHolder, registrant, invalid);
+ int newCount = decrement ? localLockCount - 1 : localLockCount;
+ return new LockState(newCount, lockHolder, lastHolder, registrant, invalid);
}
/**
@@ -303,7 +311,7 @@
private LockState takeLocal(ClusterNode owner)
{
Thread registrant = (latestRegistrant == Thread.currentThread() ? null : latestRegistrant);
- return new LockState(localLockCount + 1, owner, registrant, invalid);
+ return new LockState(localLockCount + 1, owner, null, registrant, invalid);
}
/**
@@ -316,8 +324,8 @@
private LockState releaseLock()
{
return localLockCount == 1
- ? (latestRegistrant == null && !invalid ? AVAILABLE : new LockState(0, null, latestRegistrant, invalid))
- : new LockState(localLockCount - 1, lockHolder, latestRegistrant, invalid);
+ ? new LockState(0, null, lockHolder, latestRegistrant, invalid)
+ : new LockState(localLockCount - 1, lockHolder, lastHolder, latestRegistrant, invalid);
}
/**
@@ -330,19 +338,19 @@
*/
private LockState takeRemote(ClusterNode owner)
{
- return new LockState(localLockCount, owner, latestRegistrant, invalid);
+ return new LockState(localLockCount, owner, null, latestRegistrant, invalid);
}
// BES -- this would be called if it was valid for ClusterHandler.unlock
// to be called from a remote caller
// private LockState release()
// {
-// return new LockState(localLockCount, null, latestRegistrant);
+// return new LockState(localLockCount, null, null, latestRegistrant, invalid);
// }
private LockState invalidate()
{
- return new LockState(localLockCount, lockHolder, latestRegistrant, true);
+ return new LockState(localLockCount, lockHolder, null, latestRegistrant, true);
}
}
Modified: projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/YieldingGloballyExclusiveClusterLockSupport.java
===================================================================
--- projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/YieldingGloballyExclusiveClusterLockSupport.java 2010-05-20 23:25:11 UTC (rev 105079)
+++ projects/cluster/ha-server-api/trunk/src/main/java/org/jboss/ha/framework/server/lock/YieldingGloballyExclusiveClusterLockSupport.java 2010-05-20 23:54:33 UTC (rev 105080)
@@ -121,7 +121,32 @@
}
return new RemoteLockResponse(getLocalClusterNode(), RemoteLockResponse.Flag.OK);
}
+
+ @Override
+ protected RemoteLockResponse getRemoteLockResponseForUnknownLock(Serializable lockName, ClusterNode caller,
+ long timeout)
+ {
+ RemoteLockResponse response;
+ try
+ {
+ getLocalHandler().lockFromCluster(lockName, caller, timeout);
+ return new RemoteLockResponse(getLocalClusterNode(), RemoteLockResponse.Flag.OK);
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ log.error("Caught InterruptedException; Failing request by " + caller + " to lock " + lockName);
+ response = new RemoteLockResponse(getLocalClusterNode(), RemoteLockResponse.Flag.FAIL, getLocalHandler().getLockHolder(lockName));
+ }
+ catch (TimeoutException t)
+ {
+ response = new RemoteLockResponse(getLocalClusterNode(), RemoteLockResponse.Flag.FAIL, t.getOwner());
+ }
+ return response;
+ }
+
+
// ----------------------------------------------------------------- Private
}
Modified: projects/cluster/ha-server-api/trunk/src/test/java/org/jboss/test/ha/framework/server/lock/SharedLocalYieldingClusterLockManagerUnitTestCase.java
===================================================================
--- projects/cluster/ha-server-api/trunk/src/test/java/org/jboss/test/ha/framework/server/lock/SharedLocalYieldingClusterLockManagerUnitTestCase.java 2010-05-20 23:25:11 UTC (rev 105079)
+++ projects/cluster/ha-server-api/trunk/src/test/java/org/jboss/test/ha/framework/server/lock/SharedLocalYieldingClusterLockManagerUnitTestCase.java 2010-05-20 23:54:33 UTC (rev 105080)
@@ -25,7 +25,6 @@
import static org.easymock.EasyMock.anyInt;
import static org.easymock.EasyMock.aryEq;
import static org.easymock.EasyMock.capture;
-import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.isA;
@@ -119,9 +118,12 @@
assertEquals(LockResult.ACQUIRED_FROM_CLUSTER, ts.testee.lock("test", 1000, false));
- assertEquals(LockResult.ALREADY_HELD, ts.testee.lock("test", 1000, true));
+ assertEquals(LockResult.ALREADY_HELD, ts.testee.lock("test", 1000, false));
ts.testee.unlock("test", false);
- ts.testee.unlock("test", true);
+ ts.testee.unlock("test", false);
+
+ // Even though we fully released, we can still reacquire without asking cluster
+ assertEquals(LockResult.ALREADY_HELD, ts.testee.lock("test", 1000, false));
}
public void testNewLock() throws Exception
@@ -132,9 +134,111 @@
ts.testee.unlock("test", false);
ts.testee.unlock("test", false);
+ // Even though we fully released, we can still reacquire without asking cluster
+ assertEquals(LockResult.ALREADY_HELD, ts.testee.lock("test", 1000, true));
+ }
+
+ public void testUnlockAndRemove() throws Exception
+ {
+ TesteeSet ts = getTesteeSet(node1, 0, 3);
+ assertEquals(LockResult.NEW_LOCK, ts.testee.lock("test", 1000, true));
+ ts.testee.unlock("test", true);
+
+ assertEquals(LockResult.NEW_LOCK, ts.testee.lock("test", 1000, true));
+ assertEquals(LockResult.ALREADY_HELD, ts.testee.lock("test", 1000, true));
+ ts.testee.unlock("test", false);
+ ts.testee.unlock("test", true);
+
+ assertEquals(LockResult.NEW_LOCK, ts.testee.lock("test", 1000, true));
+ assertEquals(LockResult.ALREADY_HELD, ts.testee.lock("test", 1000, true));
+ ts.testee.unlock("test", true);
+ assertEquals(LockResult.ALREADY_HELD, ts.testee.lock("test", 1000, true));
+ ts.testee.unlock("test", false);
+ ts.testee.unlock("test", false);
+
+ assertEquals(LockResult.NEW_LOCK, ts.testee.lock("test", 1000, true));
+ ts.testee.unlock("test", true);
+
resetToStrict(ts.partition);
+ expect(ts.partition.getMethodCallTimeout()).andReturn(60000l);
List<RemoteLockResponse> rspList = getOKResponses(2);
+ expect(ts.partition.callMethodOnCluster(eq("test"),
+ eq("remoteLock"),
+ eqLockParams(node1, 200000),
+ aryEq(AbstractClusterLockSupport.REMOTE_LOCK_TYPES),
+ eq(RemoteLockResponse.class),
+ eq(true),
+ eq(NULL_FILTER),
+ anyInt(),
+ eq(false))).andReturn(rspList);
+
+ replay(ts.partition);
+
+ assertEquals(LockResult.ACQUIRED_FROM_CLUSTER, ts.testee.lock("test", 1000, false));
+ }
+
+ public void testRejectRemoteCaller() throws Exception
+ {
+ TesteeSet ts = getTesteeSet(node1, 0, 3);
+ assertEquals(LockResult.NEW_LOCK, ts.testee.lock("test", 1000, true));
+ RemoteLockResponse rsp = ts.target.remoteLock("test", node2, 100);
+ assertNotNull(rsp);
+ assertEquals(RemoteLockResponse.Flag.FAIL, rsp.flag);
+ assertEquals(node1, rsp.holder);
+ }
+
+ public void testRemoteCallerTakesUnknownLock() throws Exception
+ {
+ TesteeSet ts = getTesteeSet(node1, 0, 3);
+ RemoteLockResponse rsp = ts.target.remoteLock("test", node2, 100);
+ assertNotNull(rsp);
+ assertEquals(RemoteLockResponse.Flag.OK, rsp.flag);
+ assertNull(rsp.holder);
+ }
+
+ public void testRemoteCallerTakesKnownLock() throws Exception
+ {
+ remoteCallerTakesTest(getTesteeSet(node1, 0, 3), false);
+ }
+
+ public void testRemoteCallerTakesRemovedLock() throws Exception
+ {
+ remoteCallerTakesTest(getTesteeSet(node1, 0, 3), true);
+ }
+
+ private void remoteCallerTakesTest(TesteeSet ts, boolean localRemoves) throws Exception
+ {
+ assertEquals(LockResult.NEW_LOCK, ts.testee.lock("test", 1000, true));
+
+ CountDownLatch readyLatch = new CountDownLatch(1);
+ CountDownLatch endLatch = new CountDownLatch(1);
+
+ RemoteLocker locker = new RemoteLocker(ts, node2, readyLatch, endLatch);
+ Executors.newSingleThreadExecutor().execute(locker);
+
+ readyLatch.await(5, TimeUnit.SECONDS);
+ Thread.sleep(500);
+ ts.testee.unlock("test", localRemoves);
+ endLatch.await(5, TimeUnit.SECONDS);
+
+ if (locker.exception != null)
+ {
+ throw locker.exception;
+ }
+
+ assertNotNull(locker.result);
+ assertEquals(RemoteLockResponse.Flag.OK, locker.result.flag);
+ }
+
+ public void testLocalCallTakesLockBack() throws Exception
+ {
+ TesteeSet ts = getTesteeSet(node1, 0, 3);
+ remoteCallerTakesTest(ts, false);
+
+ resetToStrict(ts.partition);
+
+ List<RemoteLockResponse> rspList = getOKResponses(2);
expect(ts.partition.getMethodCallTimeout()).andReturn(60000l);
expect(ts.partition.callMethodOnCluster(eq("test"),
eq("remoteLock"),
@@ -148,7 +252,8 @@
replay(ts.partition);
- assertEquals(LockResult.ACQUIRED_FROM_CLUSTER, ts.testee.lock("test", 1000, true));
+ assertEquals(LockResult.ACQUIRED_FROM_CLUSTER, ts.testee.lock("test", 1000, false));
+
}
public void testConcurrentLocalLocks() throws Exception
@@ -392,5 +497,40 @@
}
}
}
+
+ private class RemoteLocker implements Runnable
+ {
+ private final TesteeSet ts;
+ private final ClusterNode caller;
+ private final CountDownLatch readyLatch;
+ private final CountDownLatch endLatch;
+ private RemoteLockResponse result;
+ private Exception exception;
+
+ private RemoteLocker(TesteeSet ts, ClusterNode caller, CountDownLatch readyLatch, CountDownLatch endLatch)
+ {
+ this.ts = ts;
+ this.caller = caller;
+ this.readyLatch = readyLatch;
+ this.endLatch = endLatch;
+ }
+
+ public void run()
+ {
+ try
+ {
+ readyLatch.countDown();
+ result = ts.target.remoteLock("test", caller, 2000);
+ }
+ catch (Exception e)
+ {
+ this.exception = e;
+ }
+ finally
+ {
+ endLatch.countDown();
+ }
+ }
+ }
}
Modified: projects/cluster/ha-server-api/trunk/src/test/java/org/jboss/test/ha/framework/server/lock/YieldingGloballyExclusiveClusterLockSupportUnitTestCase.java
===================================================================
--- projects/cluster/ha-server-api/trunk/src/test/java/org/jboss/test/ha/framework/server/lock/YieldingGloballyExclusiveClusterLockSupportUnitTestCase.java 2010-05-20 23:25:11 UTC (rev 105079)
+++ projects/cluster/ha-server-api/trunk/src/test/java/org/jboss/test/ha/framework/server/lock/YieldingGloballyExclusiveClusterLockSupportUnitTestCase.java 2010-05-20 23:54:33 UTC (rev 105080)
@@ -22,6 +22,7 @@
package org.jboss.test.ha.framework.server.lock;
+import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.resetToStrict;
import static org.easymock.EasyMock.verify;
@@ -71,7 +72,8 @@
ClusterNode caller = testee.getCurrentView().get(0);
assertFalse(node1.equals(caller));
- resetToStrict(handler);
+ resetToStrict(handler);
+ handler.lockFromCluster("test", caller, 1000);
replay(handler);
RemoteLockResponse rsp = target.remoteLock("test", caller, 1000);
@@ -82,7 +84,8 @@
verify(handler);
// Do it again; should still work
- resetToStrict(handler);
+ resetToStrict(handler);
+ handler.lockFromCluster("test", caller, 1000);
replay(handler);
rsp = target.remoteLock("test", caller, 1000);
@@ -106,7 +109,8 @@
ClusterNode caller2 = testee.getCurrentView().get(2);
assertFalse(node1.equals(caller2));
- resetToStrict(handler);
+ resetToStrict(handler);
+ handler.lockFromCluster("test", caller1, 1000);
replay(handler);
RemoteLockResponse rsp = target.remoteLock("test", caller1, 1000);
@@ -119,6 +123,7 @@
// A call from a different caller should still work as
// w/ supportLockOnly==false we only reject if WE hold the lock
resetToStrict(handler);
+ handler.lockFromCluster("test", caller2, 1000);
replay(handler);
rsp = target.remoteLock("test", caller2, 1000);
@@ -150,7 +155,8 @@
ClusterNode caller2 = members.get(2);
assertFalse(node1.equals(caller2));
- resetToStrict(handler);
+ resetToStrict(handler);
+ handler.lockFromCluster("test", caller1, 1000);
replay(handler);
RemoteLockResponse rsp = target.remoteLock("test", caller1, 1000);
@@ -176,6 +182,7 @@
// A call from a different caller should work
resetToStrict(handler);
+ handler.lockFromCluster("test", caller2, 1000);
replay(handler);
rsp = target.remoteLock("test", caller2, 1000);
More information about the jboss-cvs-commits
mailing list