[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