diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/Locks.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/Locks.java index 8092c0867633..d80e9d894f3f 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/Locks.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/Locks.java @@ -99,12 +99,10 @@ interface Client extends AutoCloseable /** Release a set of exclusive locks */ void releaseExclusive( ResourceType resourceType, long resourceId ); - /** Release all locks. */ - void releaseAll(); - /** * Stop all active lock waiters and release them. All already held locks remains. * All new attempts to acquire any locks will cause exceptions. + * This client can and should only be {@link #close() closed} afterwards. */ void stop(); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/NoOpClient.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/NoOpClient.java index 44994998e923..e8d637dbd7bb 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/NoOpClient.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/NoOpClient.java @@ -53,11 +53,6 @@ public void releaseExclusive( Locks.ResourceType resourceType, long resourceId ) { } - @Override - public void releaseAll() - { - } - @Override public void stop() { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/community/CommunityLockClient.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/community/CommunityLockClient.java index d40a2b9d8e55..f43eef63af49 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/community/CommunityLockClient.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/locking/community/CommunityLockClient.java @@ -234,20 +234,6 @@ public void releaseExclusive( Locks.ResourceType resourceType, long resourceId ) } } - @Override - public void releaseAll() - { - stateHolder.incrementActiveClients( this ); - try - { - releaseLocks(); - } - finally - { - stateHolder.decrementActiveClients(); - } - } - @Override public void stop() { diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/AcquireAndReleaseLocksCompatibility.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/AcquireAndReleaseLocksCompatibility.java index 2a4e7870d282..cfb991b32573 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/AcquireAndReleaseLocksCompatibility.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/AcquireAndReleaseLocksCompatibility.java @@ -91,23 +91,6 @@ public void sharedShouldWaitForExclusive() throws Exception assertNotWaiting( clientB, clientBLock ); } - @Test - public void shouldReleaseAllLocks() throws Exception - { - // When - clientA.acquireExclusive( NODE, 1L ); - clientA.acquireShared( NODE, 2l ); - - // Then shared locks should wait - Future clientBLock = acquireShared( clientB, NODE, 1L ).callAndAssertWaiting(); - - // And when - clientA.releaseAll(); - - // Then this should not block - assertNotWaiting( clientB, clientBLock ); - } - @Test public void shouldTrySharedLock() throws Exception { diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/CloseCompatibility.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/CloseCompatibility.java index aa114948c475..ef208642ce98 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/CloseCompatibility.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/CloseCompatibility.java @@ -101,11 +101,17 @@ public void shouldNotBeAbleToAcquireExclusiveLockFromClosedClient() clientA.acquireExclusive( NODE, 1l ); } - @Test - public void shouldNotBeAbleToAcquireLocksUsingTryFromClosedClient() + @Test( expected = LockClientStoppedException.class ) + public void shouldNotBeAbleToTryAcquireSharedLockFromClosedClient() + { + clientA.close(); + clientA.trySharedLock( NODE, 1L ); + } + + @Test( expected = LockClientStoppedException.class ) + public void shouldNotBeAbleToTryAcquireExclusiveLockFromClosedClient() { clientA.close(); - Assert.assertFalse( clientA.trySharedLock( NODE, 1l ) ); - Assert.assertFalse( clientA.tryExclusiveLock( NODE, 1l ) ); + clientA.tryExclusiveLock( NODE, 1L ); } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/LockReentrancyCompatibility.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/LockReentrancyCompatibility.java index 0443b984d9ed..71ab79ede469 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/LockReentrancyCompatibility.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/LockReentrancyCompatibility.java @@ -217,7 +217,7 @@ public void shouldUpgradeAndDowngradeSameSharedLock() throws InterruptedExceptio Future exclusiveLockFuture = acquireExclusive( clientB, NODE, 1L ).callAndAssertWaiting(); // and when - clientA.releaseAll(); + clientA.releaseShared( NODE, 1L ); // exclusive lock should be received assertNotWaiting( clientB, exclusiveLockFuture ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/StopCompatibility.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/StopCompatibility.java index 4b54b2c7b219..1345db14d5b6 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/StopCompatibility.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/locking/StopCompatibility.java @@ -153,12 +153,6 @@ public void releaseExclusiveThrowsWhenClientStopped() stoppedClient().releaseExclusive( ResourceTypes.NODE, 1 ); } - @Test( expected = LockClientStoppedException.class ) - public void releaseAllThrowsWhenClientStopped() - { - stoppedClient().releaseAll(); - } - @Test public void sharedLockCanBeStopped() throws Exception { @@ -186,7 +180,7 @@ public void exclusiveLockCanBeStopped() throws Exception @Test public void acquireSharedLockAfterSharedLockStoppedOtherThread() throws Exception { - acquireExclusiveLockInThisThread(); + AcquiredLock thisThreadsExclusiveLock = acquireExclusiveLockInThisThread(); LockAcquisition sharedLockAcquisition1 = acquireSharedLockInAnotherThread(); assertThreadIsWaitingForLock( sharedLockAcquisition1 ); @@ -194,7 +188,7 @@ public void acquireSharedLockAfterSharedLockStoppedOtherThread() throws Exceptio sharedLockAcquisition1.stop(); assertLockAcquisitionFailed( sharedLockAcquisition1 ); - releaseAllLocksInThisThread(); + thisThreadsExclusiveLock.release(); LockAcquisition sharedLockAcquisition2 = acquireSharedLockInAnotherThread(); assertLockAcquisitionSucceeded( sharedLockAcquisition2 ); @@ -203,7 +197,7 @@ public void acquireSharedLockAfterSharedLockStoppedOtherThread() throws Exceptio @Test public void acquireExclusiveLockAfterExclusiveLockStoppedOtherThread() throws Exception { - acquireExclusiveLockInThisThread(); + AcquiredLock thisThreadsExclusiveLock = acquireExclusiveLockInThisThread(); LockAcquisition exclusiveLockAcquisition1 = acquireExclusiveLockInAnotherThread(); assertThreadIsWaitingForLock( exclusiveLockAcquisition1 ); @@ -211,7 +205,7 @@ public void acquireExclusiveLockAfterExclusiveLockStoppedOtherThread() throws Ex exclusiveLockAcquisition1.stop(); assertLockAcquisitionFailed( exclusiveLockAcquisition1 ); - releaseAllLocksInThisThread(); + thisThreadsExclusiveLock.release(); LockAcquisition exclusiveLockAcquisition2 = acquireExclusiveLockInAnotherThread(); assertLockAcquisitionSucceeded( exclusiveLockAcquisition2 ); @@ -220,7 +214,7 @@ public void acquireExclusiveLockAfterExclusiveLockStoppedOtherThread() throws Ex @Test public void acquireSharedLockAfterExclusiveLockStoppedOtherThread() throws Exception { - acquireExclusiveLockInThisThread(); + AcquiredLock thisThreadsExclusiveLock = acquireExclusiveLockInThisThread(); LockAcquisition exclusiveLockAcquisition = acquireExclusiveLockInAnotherThread(); assertThreadIsWaitingForLock( exclusiveLockAcquisition ); @@ -228,7 +222,7 @@ public void acquireSharedLockAfterExclusiveLockStoppedOtherThread() throws Excep exclusiveLockAcquisition.stop(); assertLockAcquisitionFailed( exclusiveLockAcquisition ); - releaseAllLocksInThisThread(); + thisThreadsExclusiveLock.release(); LockAcquisition sharedLockAcquisition = acquireSharedLockInAnotherThread(); assertLockAcquisitionSucceeded( sharedLockAcquisition ); @@ -237,7 +231,7 @@ public void acquireSharedLockAfterExclusiveLockStoppedOtherThread() throws Excep @Test public void acquireExclusiveLockAfterSharedLockStoppedOtherThread() throws Exception { - acquireExclusiveLockInThisThread(); + AcquiredLock thisThreadsExclusiveLock = acquireExclusiveLockInThisThread(); LockAcquisition sharedLockAcquisition = acquireSharedLockInAnotherThread(); assertThreadIsWaitingForLock( sharedLockAcquisition ); @@ -245,7 +239,7 @@ public void acquireExclusiveLockAfterSharedLockStoppedOtherThread() throws Excep sharedLockAcquisition.stop(); assertLockAcquisitionFailed( sharedLockAcquisition ); - releaseAllLocksInThisThread(); + thisThreadsExclusiveLock.release(); LockAcquisition exclusiveLockAcquisition = acquireExclusiveLockInAnotherThread(); assertLockAcquisitionSucceeded( exclusiveLockAcquisition ); @@ -290,7 +284,7 @@ public void closeClientAfterExclusiveLockStopped() throws Exception @Test public void acquireExclusiveLockWhileHoldingSharedLockCanBeStopped() throws Exception { - acquireSharedLockInThisThread(); + AcquiredLock thisThreadsSharedLock = acquireSharedLockInThisThread(); CountDownLatch sharedLockAcquired = new CountDownLatch( 1 ); CountDownLatch startExclusiveLock = new CountDownLatch( 1 ); @@ -304,7 +298,7 @@ public void acquireExclusiveLockWhileHoldingSharedLockCanBeStopped() throws Exce acquisition.stop(); assertLockAcquisitionFailed( acquisition ); - releaseAllLocksInThisThread(); + thisThreadsSharedLock.release(); assertNoLocksHeld(); } @@ -323,7 +317,7 @@ private Locks.Client stoppedClient() private void closeClientAfterLockStopped( boolean shared ) throws Exception { - acquireExclusiveLockInThisThread(); + AcquiredLock thisThreadsExclusiveLock = acquireExclusiveLockInThisThread(); CountDownLatch firstLockAcquired = new CountDownLatch( 1 ); LockAcquisition @@ -337,14 +331,14 @@ private void closeClientAfterLockStopped( boolean shared ) throws Exception assertLockAcquisitionFailed( acquisition ); assertLocksHeld( RESOURCE_ID ); - releaseAllLocksInThisThread(); + thisThreadsExclusiveLock.release(); assertNoLocksHeld(); } private void acquireLockAfterOtherLockStoppedSameThread( boolean firstLockShared, boolean secondLockShared ) throws Exception { - acquireExclusiveLockInThisThread(); + AcquiredLock thisThreadsExclusiveLock = acquireExclusiveLockInThisThread(); CountDownLatch firstLockFailed = new CountDownLatch( 1 ); CountDownLatch startSecondLock = new CountDownLatch( 1 ); @@ -356,27 +350,24 @@ private void acquireLockAfterOtherLockStoppedSameThread( boolean firstLockShared lockAcquisition.stop(); await( firstLockFailed ); - releaseAllLocksInThisThread(); + thisThreadsExclusiveLock.release(); startSecondLock.countDown(); assertLockAcquisitionSucceeded( lockAcquisition ); } - private void acquireSharedLockInThisThread() + private AcquiredLock acquireSharedLockInThisThread() { client.acquireShared( RESOURCE_TYPE, RESOURCE_ID ); assertLocksHeld( RESOURCE_ID ); + return AcquiredLock.shared( client, RESOURCE_TYPE, RESOURCE_ID ); } - private void acquireExclusiveLockInThisThread() + private AcquiredLock acquireExclusiveLockInThisThread() { client.acquireExclusive( RESOURCE_TYPE, RESOURCE_ID ); assertLocksHeld( RESOURCE_ID ); - } - - private void releaseAllLocksInThisThread() - { - client.releaseAll(); + return AcquiredLock.exclusive( client, RESOURCE_TYPE, RESOURCE_ID ); } private LockAcquisition acquireSharedLockInAnotherThread() @@ -684,4 +675,42 @@ void stop() getClient().stop(); } } + + private static class AcquiredLock + { + final Locks.Client client; + final boolean shared; + final Locks.ResourceType resourceType; + final long resourceId; + + AcquiredLock( Locks.Client client, boolean shared, Locks.ResourceType resourceType, long resourceId ) + { + this.client = client; + this.shared = shared; + this.resourceType = resourceType; + this.resourceId = resourceId; + } + + static AcquiredLock shared( Locks.Client client, Locks.ResourceType resourceType, long resourceId ) + { + return new AcquiredLock( client, true, resourceType, resourceId ); + } + + static AcquiredLock exclusive( Locks.Client client, Locks.ResourceType resourceType, long resourceId ) + { + return new AcquiredLock( client, false, resourceType, resourceId ); + } + + void release() + { + if ( shared ) + { + client.releaseShared( resourceType, resourceId ); + } + else + { + client.releaseExclusive( resourceType, resourceId ); + } + } + } } diff --git a/enterprise/ha/src/main/java/org/neo4j/kernel/ha/lock/SlaveLocksClient.java b/enterprise/ha/src/main/java/org/neo4j/kernel/ha/lock/SlaveLocksClient.java index 2d33f1ba254f..35e53a62ea34 100644 --- a/enterprise/ha/src/main/java/org/neo4j/kernel/ha/lock/SlaveLocksClient.java +++ b/enterprise/ha/src/main/java/org/neo4j/kernel/ha/lock/SlaveLocksClient.java @@ -33,6 +33,7 @@ import org.neo4j.kernel.ha.com.RequestContextFactory; import org.neo4j.kernel.ha.com.master.Master; import org.neo4j.kernel.impl.locking.AcquireLockTimeoutException; +import org.neo4j.kernel.impl.locking.LockClientStoppedException; import org.neo4j.kernel.impl.locking.Locks; import org.neo4j.kernel.impl.locking.ResourceTypes; @@ -59,7 +60,8 @@ class SlaveLocksClient implements Locks.Client private final Map> sharedLocks; private final Map> exclusiveLocks; private final boolean txTerminationAwareLocks; - private boolean initialized = false; + private boolean initialized; + private volatile boolean stopped; public SlaveLocksClient( Master master, @@ -95,6 +97,8 @@ private Map getLockMap( @Override public void acquireShared( Locks.ResourceType resourceType, long resourceId ) throws AcquireLockTimeoutException { + assertNotStopped(); + Map lockMap = getLockMap( sharedLocks, resourceType ); AtomicInteger preExistingLock = lockMap.get( resourceId ); if ( preExistingLock != null ) @@ -120,6 +124,8 @@ else if ( getReadLockOnMaster( resourceType, resourceId ) ) public void acquireExclusive( Locks.ResourceType resourceType, long resourceId ) throws AcquireLockTimeoutException { + assertNotStopped(); + Map lockMap = getLockMap( exclusiveLocks, resourceType ); AtomicInteger preExistingLock = lockMap.get( resourceId ); @@ -156,6 +162,8 @@ public boolean trySharedLock( Locks.ResourceType resourceType, long resourceId ) @Override public void releaseShared( Locks.ResourceType resourceType, long resourceId ) { + assertNotStopped(); + Map lockMap = getLockMap( sharedLocks, resourceType ); AtomicInteger counter = lockMap.get( resourceId ); if ( counter == null ) @@ -173,6 +181,8 @@ public void releaseShared( Locks.ResourceType resourceType, long resourceId ) @Override public void releaseExclusive( Locks.ResourceType resourceType, long resourceId ) { + assertNotStopped(); + Map lockMap = getLockMap( exclusiveLocks, resourceType ); AtomicInteger counter = lockMap.get( resourceId ); if ( counter == null ) @@ -187,37 +197,14 @@ public void releaseExclusive( Locks.ResourceType resourceType, long resourceId ) } } - @Override - public void releaseAll() - { - sharedLocks.clear(); - exclusiveLocks.clear(); - client.releaseAll(); - if ( initialized ) - { - try ( Response ignored = master.endLockSession( newRequestContextFor( client ), true ) ) - { - // Lock session is closed on master at this point - } - catch ( ComException e ) - { - throw new DistributedLockFailureException( - "Failed to end the lock session on the master (which implies releasing all held locks)", - master, e ); - } - initialized = false; - } - } - @Override public void stop() { if ( txTerminationAwareLocks ) { - try ( Response ignore = master.endLockSession( newRequestContextFor( client ), false ) ) - { - client.stop(); - } + client.stop(); + endLockSessionOnMaster( false ); + stopped = true; } else { @@ -228,22 +215,41 @@ public void stop() @Override public void close() { - try - { - releaseAll(); - } - finally + client.close(); + sharedLocks.clear(); + exclusiveLocks.clear(); + if ( initialized ) { - client.close(); + if ( !stopped ) + { + endLockSessionOnMaster( true ); + stopped = false; + } + initialized = false; } } @Override public int getLockSessionId() { + assertNotStopped(); return initialized ? client.getLockSessionId() : -1; } + private void endLockSessionOnMaster( boolean success ) + { + try ( Response ignored = master.endLockSession( newRequestContextFor( client ), success ) ) + { + // Lock session is closed on master at this point + } + catch ( ComException e ) + { + throw new DistributedLockFailureException( + "Failed to end the lock session on the master (which implies releasing all held locks)", + master, e ); + } + } + private boolean getReadLockOnMaster( Locks.ResourceType resourceType, long resourceId ) { if ( resourceType == ResourceTypes.NODE @@ -348,4 +354,12 @@ private UnsupportedOperationException newUnsupportedDirectTryLockUsageException( return new UnsupportedOperationException( "Distributed tryLocks are not supported. They only work with local lock managers." ); } + + private void assertNotStopped() + { + if ( stopped ) + { + throw new LockClientStoppedException( this ); + } + } } diff --git a/enterprise/ha/src/test/java/org/neo4j/kernel/ha/lock/SlaveLocksClientTest.java b/enterprise/ha/src/test/java/org/neo4j/kernel/ha/lock/SlaveLocksClientTest.java index 8968a9983388..ef121d47972f 100644 --- a/enterprise/ha/src/test/java/org/neo4j/kernel/ha/lock/SlaveLocksClientTest.java +++ b/enterprise/ha/src/test/java/org/neo4j/kernel/ha/lock/SlaveLocksClientTest.java @@ -22,6 +22,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.mockito.InOrder; import org.mockito.Matchers; import org.mockito.stubbing.OngoingStubbing; @@ -38,6 +39,7 @@ import org.neo4j.kernel.api.exceptions.TransactionFailureException; import org.neo4j.kernel.ha.com.RequestContextFactory; import org.neo4j.kernel.ha.com.master.Master; +import org.neo4j.kernel.impl.locking.LockClientStoppedException; import org.neo4j.kernel.impl.locking.Locks; import org.neo4j.kernel.impl.locking.ResourceTypes; import org.neo4j.kernel.impl.locking.community.CommunityLockManger; @@ -48,10 +50,13 @@ import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.neo4j.kernel.impl.locking.ResourceTypes.NODE; @@ -80,7 +85,9 @@ public void setUp() throws Exception whenMasterAcquireExclusive().thenReturn( responseOk ); - client = new SlaveLocksClient( master, local, lockManager, requestContextFactory, availabilityGuard, false ); + client = new SlaveLocksClient( master, local, lockManager, mock( RequestContextFactory.class ), + availabilityGuard, + true ); } private OngoingStubbing> whenMasterAcquireShared() @@ -257,15 +264,6 @@ public void trySharedMustBeUnsupported() throws Exception client.trySharedLock( NODE, 1 ); } - @Test( expected = DistributedLockFailureException.class ) - public void releaseAllMustThrowIfMasterThrows() throws Exception - { - when( master.endLockSession( any( RequestContext.class ), anyBoolean() ) ).thenThrow( new ComException() ); - - client.acquireExclusive( NODE, 1 ); // initialise - client.releaseAll(); - } - @Test( expected = DistributedLockFailureException.class ) public void closeMustThrowIfMasterThrows() throws Exception { @@ -317,4 +315,84 @@ public void shouldFailWithTransientErrorOnDbUnavailable() throws Exception // THEN Good } } + + @Test( expected = LockClientStoppedException.class ) + public void acquireSharedFailsWhenClientStopped() + { + stoppedClient().acquireShared( NODE, 1 ); + } + + @Test( expected = LockClientStoppedException.class ) + public void releaseSharedFailsWhenClientStopped() + { + stoppedClient().releaseShared( NODE, 1 ); + } + + @Test( expected = LockClientStoppedException.class ) + public void acquireExclusiveFailsWhenClientStopped() + { + stoppedClient().acquireExclusive( NODE, 1 ); + } + + @Test( expected = LockClientStoppedException.class ) + public void releaseExclusiveFailsWhenClientStopped() + { + stoppedClient().releaseExclusive( NODE, 1 ); + } + + @Test( expected = LockClientStoppedException.class ) + public void getLockSessionIdWhenClientStopped() + { + stoppedClient().getLockSessionId(); + } + + @Test + public void stopLocalLocksAndEndLockSessionOnMasterWhenStopped() + { + client.acquireShared( NODE, 1 ); + + client.stop(); + + verify( local ).stop(); + verify( master ).endLockSession( any( RequestContext.class ), eq( false ) ); + } + + @Test + public void closeLocalLocksAndEndLockSessionOnMasterWhenClosed() + { + client.acquireShared( NODE, 1 ); + + client.close(); + + verify( local ).close(); + verify( master ).endLockSession( any( RequestContext.class ), eq( true ) ); + } + + @Test + public void closeAfterStopped() + { + client.acquireShared( NODE, 1 ); + + client.stop(); + client.close(); + + InOrder inOrder = inOrder( master, local ); + inOrder.verify( master ).endLockSession( any( RequestContext.class ), eq( false ) ); + inOrder.verify( local ).close(); + } + + @Test + public void closeWhenNotInitialized() + { + client.close(); + + verify( local ).close(); + verifyNoMoreInteractions( master ); + } + + private SlaveLocksClient stoppedClient() + { + client.stop(); + return client; + } } diff --git a/enterprise/kernel/src/main/java/org/neo4j/kernel/impl/enterprise/lock/forseti/ForsetiClient.java b/enterprise/kernel/src/main/java/org/neo4j/kernel/impl/enterprise/lock/forseti/ForsetiClient.java index dedb6ad8aa22..98b132a1fa6d 100644 --- a/enterprise/kernel/src/main/java/org/neo4j/kernel/impl/enterprise/lock/forseti/ForsetiClient.java +++ b/enterprise/kernel/src/main/java/org/neo4j/kernel/impl/enterprise/lock/forseti/ForsetiClient.java @@ -470,21 +470,6 @@ public void releaseExclusive( Locks.ResourceType resourceType, long resourceId ) } } - @Override - public void releaseAll() - { - stateHolder.incrementActiveClients( this ); - - try - { - releaseAllClientLocks(); - } - finally - { - stateHolder.decrementActiveClients(); - } - } - private void releaseAllClientLocks() { // Force the release of all locks held.