Skip to content

Commit b629fc9

Browse files
metanetmdogan
authored andcommitted
Implement configurable reentrancy for FencedLock
1 parent 4214776 commit b629fc9

69 files changed

Lines changed: 2214 additions & 1062 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

hazelcast-client/src/main/java/com/hazelcast/client/cp/internal/datastructures/lock/RaftFencedLockProxy.java

Lines changed: 18 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import com.hazelcast.client.spi.impl.ClientInvocationFuture;
2525
import com.hazelcast.client.util.ClientDelegatingFuture;
2626
import com.hazelcast.cp.CPGroupId;
27-
import com.hazelcast.cp.FencedLock;
27+
import com.hazelcast.cp.lock.FencedLock;
2828
import com.hazelcast.cp.internal.RaftGroupId;
2929
import com.hazelcast.cp.internal.datastructures.lock.RaftLockOwnershipState;
3030
import com.hazelcast.cp.internal.datastructures.lock.RaftLockService;
@@ -40,7 +40,6 @@
4040
import static com.hazelcast.client.impl.protocol.util.ParameterUtil.calculateDataSize;
4141
import static com.hazelcast.cp.internal.RaftGroupId.dataSize;
4242
import static com.hazelcast.cp.internal.datastructures.lock.client.LockMessageTaskFactoryProvider.DESTROY_TYPE;
43-
import static com.hazelcast.cp.internal.datastructures.lock.client.LockMessageTaskFactoryProvider.FORCE_UNLOCK_TYPE;
4443
import static com.hazelcast.cp.internal.datastructures.lock.client.LockMessageTaskFactoryProvider.LOCK_OWNERSHIP_STATE;
4544
import static com.hazelcast.cp.internal.datastructures.lock.client.LockMessageTaskFactoryProvider.LOCK_TYPE;
4645
import static com.hazelcast.cp.internal.datastructures.lock.client.LockMessageTaskFactoryProvider.TRY_LOCK_TYPE;
@@ -53,6 +52,7 @@ class RaftFencedLockProxy extends ClientProxy implements FencedLock {
5352

5453
private static final ClientMessageDecoder BOOLEAN_RESPONSE_DECODER = new BooleanResponseDecoder();
5554
private static final ClientMessageDecoder LOCK_OWNERSHIP_STATE_RESPONSE_DECODER = new RaftLockOwnershipStateResponseDecoder();
55+
private static final ClientMessageDecoder LONG_RESPONSE_DECODER = new LongResponseDecoder();
5656

5757

5858
private final FencedLockImpl lock;
@@ -102,11 +102,6 @@ public void unlock() {
102102
lock.unlock();
103103
}
104104

105-
@Override
106-
public void forceUnlock() {
107-
lock.forceUnlock();
108-
}
109-
110105
@Override
111106
public long getFence() {
112107
return lock.getFence();
@@ -123,8 +118,8 @@ public boolean isLockedByCurrentThread() {
123118
}
124119

125120
@Override
126-
public int getLockCountIfLockedByCurrentThread() {
127-
return lock.getLockCountIfLockedByCurrentThread();
121+
public int getLockCount() {
122+
return lock.getLockCount();
128123
}
129124

130125
@Override
@@ -166,17 +161,6 @@ private static ClientMessage encodeRequest(int messageTypeId, CPGroupId groupId,
166161
return msg;
167162
}
168163

169-
private static ClientMessage encodeRequest(int messageTypeId, CPGroupId groupId, String name, long sessionId,
170-
long threadId, UUID invUid, int val) {
171-
int dataSize = ClientMessage.HEADER_SIZE + dataSize(groupId) + calculateDataSize(name) + Bits.LONG_SIZE_IN_BYTES * 4
172-
+ Bits.INT_SIZE_IN_BYTES;
173-
ClientMessage msg = prepareClientMessage(groupId, name, dataSize, messageTypeId);
174-
setRequestParams(msg, sessionId, threadId, invUid);
175-
msg.set(val);
176-
msg.updateFrameLength();
177-
return msg;
178-
}
179-
180164
private static ClientMessage encodeRequest(int messageTypeId, CPGroupId groupId, String name, long sessionId,
181165
long threadId, UUID invUid, long val) {
182166
int dataSize = ClientMessage.HEADER_SIZE + dataSize(groupId) + calculateDataSize(name) + Bits.LONG_SIZE_IN_BYTES * 5;
@@ -231,35 +215,35 @@ public RaftLockOwnershipState decodeClientMessage(ClientMessage msg) {
231215
}
232216
}
233217

218+
private static class LongResponseDecoder implements ClientMessageDecoder {
219+
@Override
220+
public Long decodeClientMessage(ClientMessage msg) {
221+
return msg.getLong();
222+
}
223+
}
224+
234225
private class FencedLockImpl extends AbstractRaftFencedLockProxy {
235226
FencedLockImpl(AbstractProxySessionManager sessionManager, CPGroupId groupId, String proxyName, String objectName) {
236227
super(sessionManager, groupId, proxyName, objectName);
237228
}
238229

239230
@Override
240-
protected InternalCompletableFuture<RaftLockOwnershipState> doLock(long sessionId, long threadId, UUID invocationUid) {
231+
protected InternalCompletableFuture<Long> doLock(long sessionId, long threadId, UUID invocationUid) {
241232
ClientMessage msg = encodeRequest(LOCK_TYPE, groupId, objectName, sessionId, threadId, invocationUid);
242-
return invoke(objectName, msg, LOCK_OWNERSHIP_STATE_RESPONSE_DECODER);
233+
return invoke(objectName, msg, LONG_RESPONSE_DECODER);
243234
}
244235

245236
@Override
246-
protected InternalCompletableFuture<RaftLockOwnershipState> doTryLock(long sessionId, long threadId, UUID invocationUid,
247-
long timeoutMillis) {
237+
protected InternalCompletableFuture<Long> doTryLock(long sessionId, long threadId, UUID invocationUid,
238+
long timeoutMillis) {
248239
ClientMessage msg = encodeRequest(TRY_LOCK_TYPE, groupId, objectName, sessionId, threadId, invocationUid,
249240
timeoutMillis);
250-
return invoke(objectName, msg, LOCK_OWNERSHIP_STATE_RESPONSE_DECODER);
251-
}
252-
253-
@Override
254-
protected InternalCompletableFuture<Object> doUnlock(long sessionId, long threadId, UUID invocationUid,
255-
int releaseCount) {
256-
ClientMessage msg = encodeRequest(UNLOCK_TYPE, groupId, objectName, sessionId, threadId, invocationUid, releaseCount);
257-
return invoke(objectName, msg, BOOLEAN_RESPONSE_DECODER);
241+
return invoke(objectName, msg, LONG_RESPONSE_DECODER);
258242
}
259243

260244
@Override
261-
protected InternalCompletableFuture<Object> doForceUnlock(UUID invocationUid, long expectedFence) {
262-
ClientMessage msg = encodeRequest(FORCE_UNLOCK_TYPE, groupId, objectName, -1, -1, invocationUid, expectedFence);
245+
protected InternalCompletableFuture<Boolean> doUnlock(long sessionId, long threadId, UUID invocationUid) {
246+
ClientMessage msg = encodeRequest(UNLOCK_TYPE, groupId, objectName, sessionId, threadId, invocationUid);
263247
return invoke(objectName, msg, BOOLEAN_RESPONSE_DECODER);
264248
}
265249

hazelcast-client/src/main/java/com/hazelcast/client/cp/internal/datastructures/lock/RaftFencedLockProxyFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,15 @@
2929
import com.hazelcast.cp.CPGroupId;
3030
import com.hazelcast.cp.internal.RaftGroupId;
3131
import com.hazelcast.cp.internal.datastructures.spi.client.RaftGroupTaskFactoryProvider;
32+
import com.hazelcast.cp.lock.FencedLock;
3233
import com.hazelcast.spi.InternalCompletableFuture;
3334

3435
import static com.hazelcast.client.impl.protocol.util.ParameterUtil.calculateDataSize;
3536
import static com.hazelcast.cp.internal.RaftService.getObjectNameForProxy;
3637

3738
/**
3839
* Creates client-side proxies for
39-
* Raft-based {@link com.hazelcast.cp.FencedLock}
40+
* Raft-based {@link FencedLock}
4041
*/
4142
public class RaftFencedLockProxyFactory extends ClientProxyFactoryWithContext implements ClientProxyFactory {
4243

hazelcast-client/src/main/java/com/hazelcast/client/cp/internal/datastructures/lock/package-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616

1717
/**
1818
* Contains client-side proxy impl of
19-
* Raft-based {@link com.hazelcast.cp.FencedLock}
19+
* Raft-based {@link com.hazelcast.cp.lock.FencedLock}
2020
*/
2121
package com.hazelcast.client.cp.internal.datastructures.lock;

hazelcast-client/src/main/java/com/hazelcast/client/cp/internal/session/ClientProxySessionManager.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,36 @@
2626
import com.hazelcast.client.util.ClientDelegatingFuture;
2727
import com.hazelcast.core.ICompletableFuture;
2828
import com.hazelcast.cp.CPGroupId;
29+
import com.hazelcast.cp.lock.exception.LockAcquireLimitExceededException;
30+
import com.hazelcast.cp.lock.exception.LockOwnershipLostException;
2931
import com.hazelcast.cp.internal.RaftGroupId;
3032
import com.hazelcast.cp.internal.datastructures.exception.WaitKeyCancelledException;
3133
import com.hazelcast.cp.internal.session.AbstractProxySessionManager;
3234
import com.hazelcast.cp.internal.session.SessionExpiredException;
3335
import com.hazelcast.cp.internal.session.SessionResponse;
3436
import com.hazelcast.cp.internal.session.client.SessionMessageTaskFactoryProvider;
37+
import com.hazelcast.logging.ILogger;
3538
import com.hazelcast.nio.Bits;
3639
import com.hazelcast.spi.InternalCompletableFuture;
3740

41+
import java.util.Map;
3842
import java.util.concurrent.ScheduledFuture;
3943
import java.util.concurrent.TimeUnit;
4044

45+
import static com.hazelcast.client.impl.protocol.ClientProtocolErrorCodes.LOCK_ACQUIRE_LIMIT_EXCEEDED_EXCEPTION;
46+
import static com.hazelcast.client.impl.protocol.ClientProtocolErrorCodes.LOCK_OWNERSHIP_LOST_EXCEPTION;
4147
import static com.hazelcast.client.impl.protocol.ClientProtocolErrorCodes.SESSION_EXPIRED_EXCEPTION;
4248
import static com.hazelcast.client.impl.protocol.ClientProtocolErrorCodes.WAIT_KEY_CANCELLED_EXCEPTION;
4349
import static com.hazelcast.cp.internal.datastructures.semaphore.client.SemaphoreMessageTaskFactoryProvider.GENERATE_THREAD_ID_TYPE;
50+
import static java.util.concurrent.TimeUnit.MILLISECONDS;
4451

4552
/**
4653
* Client-side implementation of Raft proxy session manager
4754
*/
4855
public class ClientProxySessionManager extends AbstractProxySessionManager {
4956

57+
public static final long SHUTDOWN_TIMEOUT_SECONDS = 60;
58+
public static final long SHUTDOWN_WAIT_SLEEP_MILLIS = 10;
5059
private static final ClientMessageDecoder SESSION_RESPONSE_DECODER = new SessionResponseDecoder();
5160
private static final ClientMessageDecoder BOOLEAN_RESPONSE_DECODER = new BooleanResponseDecoder();
5261

@@ -67,6 +76,18 @@ public Throwable createException(String message, Throwable cause) {
6776
return new WaitKeyCancelledException(message, cause);
6877
}
6978
});
79+
factory.register(LOCK_ACQUIRE_LIMIT_EXCEEDED_EXCEPTION, LockAcquireLimitExceededException.class, new ExceptionFactory() {
80+
@Override
81+
public Throwable createException(String message, Throwable cause) {
82+
return new LockAcquireLimitExceededException(message);
83+
}
84+
});
85+
factory.register(LOCK_OWNERSHIP_LOST_EXCEPTION, LockOwnershipLostException.class, new ExceptionFactory() {
86+
@Override
87+
public Throwable createException(String message, Throwable cause) {
88+
return new LockOwnershipLostException(message);
89+
}
90+
});
7091
}
7192

7293
@Override
@@ -137,6 +158,49 @@ protected ICompletableFuture<Object> closeSession(CPGroupId groupId, Long sessio
137158
return invoke(msg, BOOLEAN_RESPONSE_DECODER);
138159
}
139160

161+
@Override
162+
public Map<CPGroupId, ICompletableFuture<Object>> shutdown() {
163+
Map<CPGroupId, ICompletableFuture<Object>> futures = super.shutdown();
164+
165+
ILogger logger = client.getLoggingService().getLogger(getClass());
166+
167+
long remainingTimeNanos = TimeUnit.SECONDS.toNanos(SHUTDOWN_TIMEOUT_SECONDS);
168+
169+
while (remainingTimeNanos > 0) {
170+
int closed = 0;
171+
172+
for (Map.Entry<CPGroupId, ICompletableFuture<Object>> entry : futures.entrySet()) {
173+
CPGroupId groupId = entry.getKey();
174+
ICompletableFuture<Object> f = entry.getValue();
175+
if (f.isDone()) {
176+
closed++;
177+
try {
178+
f.get();
179+
logger.fine("Session closed for " + groupId);
180+
} catch (Exception e) {
181+
logger.warning("Close session failed for " + groupId, e);
182+
183+
}
184+
}
185+
}
186+
187+
if (closed == futures.size()) {
188+
break;
189+
}
190+
191+
try {
192+
Thread.sleep(SHUTDOWN_WAIT_SLEEP_MILLIS);
193+
} catch (InterruptedException e) {
194+
Thread.currentThread().interrupt();
195+
return futures;
196+
}
197+
198+
remainingTimeNanos -= MILLISECONDS.toNanos(SHUTDOWN_WAIT_SLEEP_MILLIS);
199+
}
200+
201+
return futures;
202+
}
203+
140204
private <T> InternalCompletableFuture<T> invoke(ClientMessage msg, ClientMessageDecoder decoder) {
141205
ClientInvocationFuture future = new ClientInvocation(client, msg, "session").invoke();
142206
return new ClientDelegatingFuture<T>(future, client.getSerializationService(), decoder);

hazelcast-client/src/main/java/com/hazelcast/client/impl/clientside/CPSubsystemImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import com.hazelcast.core.ISemaphore;
2323
import com.hazelcast.cp.CPSubsystem;
2424
import com.hazelcast.cp.CPSubsystemManagementService;
25-
import com.hazelcast.cp.FencedLock;
25+
import com.hazelcast.cp.lock.FencedLock;
2626
import com.hazelcast.cp.CPSessionManagementService;
2727
import com.hazelcast.cp.internal.datastructures.atomiclong.RaftAtomicLongService;
2828
import com.hazelcast.cp.internal.datastructures.atomicref.RaftAtomicRefService;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.hazelcast.client.cp.internal.datastructures.lock;
18+
19+
import com.hazelcast.client.test.TestHazelcastFactory;
20+
import com.hazelcast.core.HazelcastInstance;
21+
import com.hazelcast.cp.internal.datastructures.lock.BoundedReentrantFencedLockTest;
22+
import com.hazelcast.test.HazelcastSerialClassRunner;
23+
import com.hazelcast.test.TestHazelcastInstanceFactory;
24+
import com.hazelcast.test.annotation.ParallelTest;
25+
import com.hazelcast.test.annotation.QuickTest;
26+
import org.junit.experimental.categories.Category;
27+
import org.junit.runner.RunWith;
28+
29+
@RunWith(HazelcastSerialClassRunner.class)
30+
@Category({QuickTest.class, ParallelTest.class})
31+
public class BoundedReentrantFencedLockClientTest extends BoundedReentrantFencedLockTest {
32+
33+
@Override
34+
protected TestHazelcastInstanceFactory createTestFactory() {
35+
return new TestHazelcastFactory();
36+
}
37+
38+
@Override
39+
protected HazelcastInstance[] createInstances() {
40+
HazelcastInstance[] instances = super.createInstances();
41+
TestHazelcastFactory f = (TestHazelcastFactory) factory;
42+
lockInstance = f.newHazelcastClient();
43+
return instances;
44+
}
45+
46+
}

hazelcast-client/src/test/java/com/hazelcast/client/cp/internal/datastructures/lock/RaftFencedLockClientBasicTest.java renamed to hazelcast-client/src/test/java/com/hazelcast/client/cp/internal/datastructures/lock/FencedLockClientBasicTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import com.hazelcast.client.impl.clientside.HazelcastClientProxy;
2020
import com.hazelcast.client.test.TestHazelcastFactory;
2121
import com.hazelcast.core.HazelcastInstance;
22-
import com.hazelcast.cp.internal.datastructures.lock.RaftFencedLockBasicTest;
22+
import com.hazelcast.cp.internal.datastructures.lock.FencedLockBasicTest;
2323
import com.hazelcast.cp.internal.session.AbstractProxySessionManager;
2424
import com.hazelcast.test.HazelcastSerialClassRunner;
2525
import com.hazelcast.test.TestHazelcastInstanceFactory;
@@ -33,7 +33,7 @@
3333

3434
@RunWith(HazelcastSerialClassRunner.class)
3535
@Category({QuickTest.class, ParallelTest.class})
36-
public class RaftFencedLockClientBasicTest extends RaftFencedLockBasicTest {
36+
public class FencedLockClientBasicTest extends FencedLockBasicTest {
3737

3838
@Override
3939
protected TestHazelcastInstanceFactory createTestFactory() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.hazelcast.client.cp.internal.datastructures.lock;
18+
19+
import com.hazelcast.client.test.TestHazelcastFactory;
20+
import com.hazelcast.core.HazelcastInstance;
21+
import com.hazelcast.cp.internal.datastructures.lock.NonReentrantFencedLockTest;
22+
import com.hazelcast.test.HazelcastSerialClassRunner;
23+
import com.hazelcast.test.TestHazelcastInstanceFactory;
24+
import com.hazelcast.test.annotation.ParallelTest;
25+
import com.hazelcast.test.annotation.QuickTest;
26+
import org.junit.experimental.categories.Category;
27+
import org.junit.runner.RunWith;
28+
29+
@RunWith(HazelcastSerialClassRunner.class)
30+
@Category({QuickTest.class, ParallelTest.class})
31+
public class NonReentrantFencedLockClientTest extends NonReentrantFencedLockTest {
32+
33+
@Override
34+
protected TestHazelcastInstanceFactory createTestFactory() {
35+
return new TestHazelcastFactory();
36+
}
37+
38+
@Override
39+
protected HazelcastInstance[] createInstances() {
40+
HazelcastInstance[] instances = super.createInstances();
41+
TestHazelcastFactory f = (TestHazelcastFactory) factory;
42+
lockInstance = f.newHazelcastClient();
43+
return instances;
44+
}
45+
46+
}

0 commit comments

Comments
 (0)