Skip to content

Commit d547f0d

Browse files
metanetmdogan
authored andcommitted
New FencedLock proxy implementation with local reentrancy
1 parent f160d0b commit d547f0d

27 files changed

+1062
-506
lines changed

hazelcast-raft-client/src/main/java/com/hazelcast/raft/service/lock/client/RaftFencedLockProxy.java

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.hazelcast.raft.RaftGroupId;
2727
import com.hazelcast.raft.impl.RaftGroupIdImpl;
2828
import com.hazelcast.raft.service.lock.FencedLock;
29+
import com.hazelcast.raft.service.lock.RaftLockOwnershipState;
2930
import com.hazelcast.raft.service.lock.proxy.AbstractRaftFencedLockProxy;
3031
import com.hazelcast.raft.service.session.SessionManagerProvider;
3132
import com.hazelcast.spi.InternalCompletableFuture;
@@ -36,14 +37,12 @@
3637
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.CREATE_TYPE;
3738
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.DESTROY_TYPE;
3839
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.FORCE_UNLOCK_TYPE;
39-
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.LOCK_COUNT_TYPE;
40-
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.LOCK_FENCE_TYPE;
40+
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.LOCK_OWNERSHIP_STATE;
4141
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.LOCK_TYPE;
4242
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.TRY_LOCK_TYPE;
4343
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.UNLOCK_TYPE;
4444
import static com.hazelcast.raft.service.lock.client.RaftLockProxy.BOOLEAN_RESPONSE_DECODER;
45-
import static com.hazelcast.raft.service.lock.client.RaftLockProxy.INT_RESPONSE_DECODER;
46-
import static com.hazelcast.raft.service.lock.client.RaftLockProxy.LONG_RESPONSE_DECODER;
45+
import static com.hazelcast.raft.service.lock.client.RaftLockProxy.LOCK_OWNERSHIP_STATE_RESPONSE_DECODER;
4746
import static com.hazelcast.raft.service.lock.client.RaftLockProxy.encodeRequest;
4847
import static com.hazelcast.raft.service.lock.client.RaftLockProxy.invoke;
4948
import static com.hazelcast.raft.service.lock.client.RaftLockProxy.prepareClientMessage;
@@ -86,40 +85,41 @@ private RaftFencedLockProxy(HazelcastInstance instance, RaftGroupId groupId, Str
8685
}
8786

8887
@Override
89-
protected InternalCompletableFuture<Long> doLock(RaftGroupId groupId, String name, long sessionId, long threadId, UUID invocationUid) {
88+
protected final InternalCompletableFuture<RaftLockOwnershipState> doLock(RaftGroupId groupId, String name,
89+
long sessionId, long threadId,
90+
UUID invocationUid) {
9091
ClientMessage msg = encodeRequest(LOCK_TYPE, groupId, name, sessionId, threadId, invocationUid);
91-
return invoke(client, name, msg, LONG_RESPONSE_DECODER);
92+
return invoke(client, name, msg, LOCK_OWNERSHIP_STATE_RESPONSE_DECODER);
9293
}
9394

9495
@Override
95-
protected InternalCompletableFuture<Long> doTryLock(RaftGroupId groupId, String name, long sessionId, long threadId, UUID invocationUid,
96-
long timeoutMillis) {
96+
protected final InternalCompletableFuture<RaftLockOwnershipState> doTryLock(RaftGroupId groupId, String name,
97+
long sessionId, long threadId,
98+
UUID invocationUid, long timeoutMillis) {
9799
ClientMessage msg = encodeRequest(TRY_LOCK_TYPE, groupId, name, sessionId, threadId, invocationUid, timeoutMillis);
98-
return invoke(client, name, msg, LONG_RESPONSE_DECODER);
100+
return invoke(client, name, msg, LOCK_OWNERSHIP_STATE_RESPONSE_DECODER);
99101
}
100102

101103
@Override
102-
protected InternalCompletableFuture<Object> doUnlock(RaftGroupId groupId, String name, long sessionId, long threadId, UUID invocationUid) {
103-
ClientMessage msg = encodeRequest(UNLOCK_TYPE, groupId, name, sessionId, threadId, invocationUid);
104+
protected final InternalCompletableFuture<Object> doUnlock(RaftGroupId groupId, String name,
105+
long sessionId, long threadId,
106+
UUID invocationUid, int releaseCount) {
107+
ClientMessage msg = encodeRequest(UNLOCK_TYPE, groupId, name, sessionId, threadId, invocationUid, releaseCount);
104108
return invoke(client, name, msg, BOOLEAN_RESPONSE_DECODER);
105109
}
106110

107111
@Override
108-
protected InternalCompletableFuture<Object> doForceUnlock(RaftGroupId groupId, String name, long expectedFence, UUID invocationUid) {
112+
protected final InternalCompletableFuture<Object> doForceUnlock(RaftGroupId groupId, String name,
113+
UUID invocationUid, long expectedFence) {
109114
ClientMessage msg = encodeRequest(FORCE_UNLOCK_TYPE, groupId, name, -1, -1, invocationUid, expectedFence);
110115
return invoke(client, name, msg, BOOLEAN_RESPONSE_DECODER);
111116
}
112117

113118
@Override
114-
protected InternalCompletableFuture<Long> doGetLockFence(RaftGroupId groupId, String name, long sessionId, long threadId) {
115-
ClientMessage msg = encodeRequest(LOCK_FENCE_TYPE, groupId, name, sessionId, threadId);
116-
return invoke(client, name, msg, LONG_RESPONSE_DECODER);
117-
}
118-
119-
@Override
120-
protected InternalCompletableFuture<Integer> doGetLockCount(RaftGroupId groupId, String name, long sessionId, long threadId) {
121-
ClientMessage msg = encodeRequest(LOCK_COUNT_TYPE, groupId, name, sessionId, threadId);
122-
return invoke(client, name, msg, INT_RESPONSE_DECODER);
119+
protected final InternalCompletableFuture<RaftLockOwnershipState> doGetLockOwnershipState(RaftGroupId groupId,
120+
String name) {
121+
ClientMessage msg = encodeRequest(LOCK_OWNERSHIP_STATE, groupId, name, -1, -1);
122+
return invoke(client, name, msg, LOCK_OWNERSHIP_STATE_RESPONSE_DECODER);
123123
}
124124

125125
@Override

hazelcast-raft-client/src/main/java/com/hazelcast/raft/service/lock/client/RaftLockProxy.java

Lines changed: 53 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,40 +29,38 @@
2929
import com.hazelcast.raft.RaftGroupId;
3030
import com.hazelcast.raft.impl.RaftGroupIdImpl;
3131
import com.hazelcast.raft.impl.session.SessionExpiredException;
32-
import com.hazelcast.raft.service.lock.RaftLockService;
3332
import com.hazelcast.raft.service.exception.WaitKeyCancelledException;
33+
import com.hazelcast.raft.service.lock.RaftLockOwnershipState;
34+
import com.hazelcast.raft.service.lock.RaftLockService;
3435
import com.hazelcast.raft.service.session.SessionAwareProxy;
3536
import com.hazelcast.raft.service.session.SessionManagerProvider;
3637
import com.hazelcast.spi.InternalCompletableFuture;
37-
import com.hazelcast.util.UuidUtil;
3838

3939
import java.util.UUID;
4040
import java.util.concurrent.TimeUnit;
4141
import java.util.concurrent.locks.Condition;
4242

4343
import static com.hazelcast.client.impl.protocol.util.ParameterUtil.calculateDataSize;
4444
import static com.hazelcast.raft.impl.RaftGroupIdImpl.dataSize;
45-
import static com.hazelcast.raft.service.lock.RaftLockService.INVALID_FENCE;
4645
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.CREATE_TYPE;
4746
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.DESTROY_TYPE;
4847
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.FORCE_UNLOCK_TYPE;
49-
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.LOCK_COUNT_TYPE;
50-
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.LOCK_FENCE_TYPE;
48+
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.LOCK_OWNERSHIP_STATE;
5149
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.LOCK_TYPE;
5250
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.TRY_LOCK_TYPE;
5351
import static com.hazelcast.raft.service.lock.client.LockMessageTaskFactoryProvider.UNLOCK_TYPE;
5452
import static com.hazelcast.raft.service.session.AbstractSessionManager.NO_SESSION_ID;
5553
import static com.hazelcast.raft.service.util.ClientAccessor.getClient;
5654
import static com.hazelcast.util.ThreadUtil.getThreadId;
55+
import static com.hazelcast.util.UuidUtil.newUnsecureUUID;
5756

5857
/**
5958
* TODO: Javadoc Pending...
6059
*/
6160
public class RaftLockProxy extends SessionAwareProxy implements ILock {
6261

63-
static final ClientMessageDecoder INT_RESPONSE_DECODER = new IntResponseDecoder();
6462
static final ClientMessageDecoder BOOLEAN_RESPONSE_DECODER = new BooleanResponseDecoder();
65-
static final ClientMessageDecoder LONG_RESPONSE_DECODER = new LongResponseDecoder();
63+
static final ClientMessageDecoder LOCK_OWNERSHIP_STATE_RESPONSE_DECODER = new RaftLockOwnershipStateResponseDecoder();
6664

6765
public static ILock create(HazelcastInstance instance, String name) {
6866
int dataSize = ClientMessage.HEADER_SIZE + calculateDataSize(name);
@@ -101,12 +99,14 @@ private RaftLockProxy(HazelcastInstance instance, RaftGroupId groupId, String na
10199

102100
@Override
103101
public void lock() {
104-
UUID invUid = UuidUtil.newUnsecureUUID();
102+
UUID invUid = newUnsecureUUID();
105103
for (;;) {
106104
long sessionId = acquireSession();
107105
ClientMessage msg = encodeRequest(LOCK_TYPE, groupId, name, sessionId, getThreadId(), invUid);
108106
try {
109-
invoke(client, name, msg, LONG_RESPONSE_DECODER).join();
107+
RaftLockOwnershipState ownership = RaftLockProxy.<RaftLockOwnershipState>invoke(client, name, msg,
108+
LOCK_OWNERSHIP_STATE_RESPONSE_DECODER).join();
109+
assert ownership.isLocked();
110110
break;
111111
} catch (SessionExpiredException e) {
112112
invalidateSession(sessionId);
@@ -121,18 +121,18 @@ public boolean tryLock() {
121121

122122
@Override
123123
public boolean tryLock(long time, TimeUnit unit) {
124-
UUID invUid = UuidUtil.newUnsecureUUID();
124+
UUID invUid = newUnsecureUUID();
125125
long timeoutMs = Math.max(0, unit.toMillis(time));
126126
for (;;) {
127127
long sessionId = acquireSession();
128128
ClientMessage msg = encodeRequest(TRY_LOCK_TYPE, groupId, name, sessionId, getThreadId(), invUid, timeoutMs);
129129
try {
130-
InternalCompletableFuture<Long> future = invoke(client, name, msg, LONG_RESPONSE_DECODER);
131-
boolean locked = (future.join() != INVALID_FENCE);
132-
if (!locked) {
133-
releaseSession(sessionId);
130+
RaftLockOwnershipState ownership = RaftLockProxy.<RaftLockOwnershipState>invoke(client, name, msg,
131+
LOCK_OWNERSHIP_STATE_RESPONSE_DECODER).join();
132+
if (ownership.isLocked()) {
133+
return ownership.isLocked();
134134
}
135-
return locked;
135+
releaseSession(sessionId);
136136
} catch (WaitKeyCancelledException e) {
137137
return false;
138138
} catch (SessionExpiredException e) {
@@ -147,8 +147,8 @@ public void unlock() {
147147
if (sessionId == NO_SESSION_ID) {
148148
throw new IllegalMonitorStateException();
149149
}
150-
UUID invUid = UuidUtil.newUnsecureUUID();
151-
ClientMessage msg = encodeRequest(UNLOCK_TYPE, groupId, name, sessionId, getThreadId(), invUid);
150+
UUID invUid = newUnsecureUUID();
151+
ClientMessage msg = encodeRequest(UNLOCK_TYPE, groupId, name, sessionId, getThreadId(), invUid, 1);
152152
try {
153153
invoke(client, name, msg, BOOLEAN_RESPONSE_DECODER).join();
154154
} catch (SessionExpiredException e) {
@@ -169,20 +169,23 @@ public boolean isLockedByCurrentThread() {
169169
if (sessionId == NO_SESSION_ID) {
170170
return false;
171171
}
172-
ClientMessage msg = encodeRequest(LOCK_COUNT_TYPE, groupId, name, sessionId, getThreadId());
173-
InternalCompletableFuture<Integer> future = invoke(client, name, msg, INT_RESPONSE_DECODER);
174-
return future.join() > 0;
172+
173+
ClientMessage msg = encodeRequest(LOCK_OWNERSHIP_STATE, groupId, name, -1, -1);
174+
InternalCompletableFuture<RaftLockOwnershipState> f = invoke(client, name, msg, LOCK_OWNERSHIP_STATE_RESPONSE_DECODER);
175+
RaftLockOwnershipState ownership = f.join();
176+
return (ownership.getSessionId() == sessionId && ownership.getThreadId() == getThreadId());
175177
}
176178

177179
@Override
178180
public int getLockCount() {
179-
ClientMessage msg = encodeRequest(LOCK_COUNT_TYPE, groupId, name, NO_SESSION_ID, 0);
180-
InternalCompletableFuture<Integer> future = invoke(client, name, msg, INT_RESPONSE_DECODER);
181-
return future.join();
181+
ClientMessage msg = encodeRequest(LOCK_OWNERSHIP_STATE, groupId, name, -1, -1);
182+
InternalCompletableFuture<RaftLockOwnershipState> f = invoke(client, name, msg, LOCK_OWNERSHIP_STATE_RESPONSE_DECODER);
183+
RaftLockOwnershipState ownership = f.join();
184+
return ownership.getLockCount();
182185
}
183186

184187
@Override
185-
public boolean tryLock(long time, TimeUnit unit, long leaseTime, TimeUnit leaseUnit) throws InterruptedException {
188+
public boolean tryLock(long time, TimeUnit unit, long leaseTime, TimeUnit leaseUnit) {
186189
throw new UnsupportedOperationException();
187190
}
188191

@@ -193,15 +196,14 @@ public void lock(long leaseTime, TimeUnit timeUnit) {
193196

194197
@Override
195198
public void forceUnlock() {
196-
ClientMessage msg = encodeRequest(LOCK_FENCE_TYPE, groupId, name, -1, -1);
197-
long fence = RaftLockProxy.<Long>invoke(client, name, msg, LONG_RESPONSE_DECODER).join();
198-
199-
int dataSize = ClientMessage.HEADER_SIZE + dataSize(groupId) + calculateDataSize(name) + Bits.LONG_SIZE_IN_BYTES * 5;
200-
msg = prepareClientMessage(groupId, name, dataSize, FORCE_UNLOCK_TYPE);
201-
setRequestParams(msg, -1, -1, UuidUtil.newUnsecureUUID());
202-
msg.set(fence);
203-
msg.updateFrameLength();
199+
ClientMessage msg = encodeRequest(LOCK_OWNERSHIP_STATE, groupId, name, -1, -1);
200+
RaftLockOwnershipState ownership = RaftLockProxy.<RaftLockOwnershipState>invoke(client, name, msg,
201+
LOCK_OWNERSHIP_STATE_RESPONSE_DECODER).join();
202+
if (!ownership.isLocked()) {
203+
throw new IllegalMonitorStateException("Lock[" + name + "] has no owner!");
204+
}
204205

206+
msg = encodeRequest(FORCE_UNLOCK_TYPE, groupId, name, -1, -1, newUnsecureUUID(), ownership.getFence());
205207
invoke(client, name, msg, BOOLEAN_RESPONSE_DECODER).join();
206208
}
207209

@@ -221,7 +223,7 @@ public long getRemainingLeaseTime() {
221223
}
222224

223225
@Override
224-
public void lockInterruptibly() throws InterruptedException {
226+
public void lockInterruptibly() {
225227
throw new UnsupportedOperationException();
226228
}
227229

@@ -270,6 +272,17 @@ static ClientMessage encodeRequest(int messageTypeId, RaftGroupId groupId, Strin
270272
return msg;
271273
}
272274

275+
static ClientMessage encodeRequest(int messageTypeId, RaftGroupId groupId, String name, long sessionId,
276+
long threadId, UUID invUid, int val) {
277+
int dataSize = ClientMessage.HEADER_SIZE
278+
+ dataSize(groupId) + calculateDataSize(name) + Bits.LONG_SIZE_IN_BYTES * 4 + Bits.INT_SIZE_IN_BYTES;
279+
ClientMessage msg = prepareClientMessage(groupId, name, dataSize, messageTypeId);
280+
setRequestParams(msg, sessionId, threadId, invUid);
281+
msg.set(val);
282+
msg.updateFrameLength();
283+
return msg;
284+
}
285+
273286
static ClientMessage encodeRequest(int messageTypeId, RaftGroupId groupId, String name, long sessionId,
274287
long threadId, UUID invUid, long val) {
275288

@@ -309,24 +322,21 @@ static ClientMessage prepareClientMessage(RaftGroupId groupId, String name, int
309322
return msg;
310323
}
311324

312-
private static class IntResponseDecoder implements ClientMessageDecoder {
313-
@Override
314-
public Integer decodeClientMessage(ClientMessage msg) {
315-
return msg.getInt();
316-
}
317-
}
318-
319325
private static class BooleanResponseDecoder implements ClientMessageDecoder {
320326
@Override
321327
public Boolean decodeClientMessage(ClientMessage msg) {
322328
return msg.getBoolean();
323329
}
324330
}
325331

326-
private static class LongResponseDecoder implements ClientMessageDecoder {
332+
private static class RaftLockOwnershipStateResponseDecoder implements ClientMessageDecoder {
327333
@Override
328-
public Long decodeClientMessage(ClientMessage msg) {
329-
return msg.getLong();
334+
public RaftLockOwnershipState decodeClientMessage(ClientMessage msg) {
335+
long fence = msg.getLong();
336+
int lockCount = msg.getInt();
337+
long sessionId = msg.getLong();
338+
long threadId = msg.getLong();
339+
return new RaftLockOwnershipState(fence, lockCount, sessionId, threadId);
330340
}
331341
}
332342
}

hazelcast-raft-dataservices/src/main/java/com/hazelcast/raft/service/lock/FencedLock.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ public interface FencedLock extends DistributedObject {
4343

4444
boolean isLockedByCurrentThread();
4545

46+
// returns the true lock count if the lock is acquired by the caller endpoint
47+
// returns 1 if the lock is acquired by another endpoint because reentrant acquires are local
48+
// returns 0 otherwise
4649
int getLockCount();
4750

4851
RaftGroupId getGroupId();

hazelcast-raft-dataservices/src/main/java/com/hazelcast/raft/service/lock/LockRegistry.java

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424

2525
import java.util.UUID;
2626

27-
import static com.hazelcast.raft.service.lock.RaftLockService.INVALID_FENCE;
28-
2927
/**
3028
* TODO: Javadoc Pending...
3129
*/
@@ -56,26 +54,25 @@ AcquireResult acquire(String name, LockEndpoint endpoint, long commitIndex, UUID
5654
AcquireResult tryAcquire(String name, LockEndpoint endpoint, long commitIndex, UUID invocationUid, long timeoutMs) {
5755
boolean wait = (timeoutMs > 0);
5856
AcquireResult result = getOrInitResource(name).acquire(endpoint, commitIndex, invocationUid, wait);
59-
long fence = result.fence;
6057

6158
for (LockInvocationKey waitKey : result.cancelled) {
6259
removeWaitKey(waitKey);
6360
}
6461

65-
if (wait && fence == INVALID_FENCE) {
62+
if (wait && !result.ownership.isLocked()) {
6663
addWaitKey(new LockInvocationKey(name, endpoint, commitIndex, invocationUid), timeoutMs);
6764
}
6865

6966
return result;
7067
}
7168

72-
ReleaseResult release(String name, LockEndpoint endpoint, UUID invocationUid) {
69+
ReleaseResult release(String name, LockEndpoint endpoint, UUID invocationUid, int lockCount) {
7370
RaftLock lock = getResourceOrNull(name);
7471
if (lock == null) {
7572
return ReleaseResult.FAILED;
7673
}
7774

78-
ReleaseResult result = lock.release(endpoint, invocationUid);
75+
ReleaseResult result = lock.release(endpoint, invocationUid, lockCount);
7976
for (LockInvocationKey key : result.notifications) {
8077
removeWaitKey(key);
8178
}
@@ -97,34 +94,9 @@ ReleaseResult forceRelease(String name, long expectedFence, UUID invocationUid)
9794
return result;
9895
}
9996

100-
int getLockCount(String name, LockEndpoint endpoint) {
101-
RaftLock lock = getResourceOrNull(name);
102-
if (lock == null) {
103-
return 0;
104-
}
105-
106-
if (endpoint != null) {
107-
LockInvocationKey owner = lock.owner();
108-
return (owner != null && endpoint.equals(owner.endpoint())) ? lock.lockCount() : 0;
109-
}
110-
111-
return lock.lockCount();
112-
}
113-
114-
long getLockFence(String name, LockEndpoint endpoint) {
97+
RaftLockOwnershipState getLockOwnershipState(String name) {
11598
RaftLock lock = getResourceOrNull(name);
116-
if (lock == null) {
117-
throw new IllegalMonitorStateException();
118-
}
119-
120-
LockInvocationKey owner = lock.owner();
121-
if (owner == null) {
122-
throw new IllegalMonitorStateException("Lock[" + name + "] has no owner!");
123-
} else if (endpoint != null && !owner.endpoint().equals(endpoint)) {
124-
throw new IllegalMonitorStateException("Lock[" + name + "] is owned by " + owner.endpoint() + "!");
125-
}
126-
127-
return owner.commitIndex();
99+
return lock != null ? lock.lockOwnershipState() : RaftLockOwnershipState.NOT_LOCKED;
128100
}
129101

130102
@Override

0 commit comments

Comments
 (0)