Skip to content

Commit 550ddb4

Browse files
metanetmdogan
authored andcommitted
Introduce InvocationTargetLeaveAware for raft operations
InvocationTargetLeaveAware is used for determining if a raft operation is safe to retry on leader leave and it is ok to commit the operation multiple times. If the operation is safe, it is retried automatically if the leader returns commit response of the invoked operation. If the operation is not known to be safe, i.e. it either does not implement InvocationTargetLeaveAware or returns false from InvocationTargetLeaveAware#isSafeToRetryOnTargetLeave(), then retry is decided based on the RaftAlgorithmConfig#failOnIndeterminateOperationState config parameter. Safe to retry raft operations are expected to be idempotent. For instance, lock, session-aware semaphore, and count down latch operations are idempotent. It does not make a difference to commit an idempotent operation once or multiple times. However, although some raft operations are idempotent in terms of state changes they cause, they may not return the same response on duplicate commits. They can be still considered to be safe to retry on leader node leave, depending on their context and how they are used.
1 parent 4427c9c commit 550ddb4

File tree

50 files changed

+589
-87
lines changed

Some content is hidden

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

50 files changed

+589
-87
lines changed

hazelcast-raft-dataservices/src/main/java/com/hazelcast/raft/service/atomiclong/operation/AddAndGetOp.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.hazelcast.nio.ObjectDataInput;
2020
import com.hazelcast.nio.ObjectDataOutput;
2121
import com.hazelcast.raft.RaftGroupId;
22+
import com.hazelcast.raft.impl.service.proxy.InvocationTargetLeaveAware;
2223
import com.hazelcast.raft.service.atomiclong.RaftAtomicLongDataSerializerHook;
2324
import com.hazelcast.raft.service.atomiclong.RaftAtomicLong;
2425

@@ -27,7 +28,7 @@
2728
/**
2829
* TODO: Javadoc Pending...
2930
*/
30-
public class AddAndGetOp extends AbstractAtomicLongOp {
31+
public class AddAndGetOp extends AbstractAtomicLongOp implements InvocationTargetLeaveAware {
3132

3233
private long delta;
3334

@@ -45,6 +46,11 @@ public Object run(RaftGroupId groupId, long commitIndex) {
4546
return atomic.addAndGet(delta);
4647
}
4748

49+
@Override
50+
public boolean isSafeToRetryOnTargetLeave() {
51+
return delta == 0;
52+
}
53+
4854
@Override
4955
public void writeData(ObjectDataOutput out) throws IOException {
5056
super.writeData(out);

hazelcast-raft-dataservices/src/main/java/com/hazelcast/raft/service/atomiclong/operation/GetAndAddOp.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.hazelcast.nio.ObjectDataInput;
2020
import com.hazelcast.nio.ObjectDataOutput;
2121
import com.hazelcast.raft.RaftGroupId;
22+
import com.hazelcast.raft.impl.service.proxy.InvocationTargetLeaveAware;
2223
import com.hazelcast.raft.service.atomiclong.RaftAtomicLongDataSerializerHook;
2324
import com.hazelcast.raft.service.atomiclong.RaftAtomicLong;
2425

@@ -27,7 +28,7 @@
2728
/**
2829
* TODO: Javadoc Pending...
2930
*/
30-
public class GetAndAddOp extends AbstractAtomicLongOp {
31+
public class GetAndAddOp extends AbstractAtomicLongOp implements InvocationTargetLeaveAware {
3132

3233
private long delta;
3334

@@ -45,6 +46,11 @@ public Object run(RaftGroupId groupId, long commitIndex) {
4546
return atomic.getAndAdd(delta);
4647
}
4748

49+
@Override
50+
public boolean isSafeToRetryOnTargetLeave() {
51+
return delta == 0;
52+
}
53+
4854
@Override
4955
public void writeData(ObjectDataOutput out) throws IOException {
5056
super.writeData(out);

hazelcast-raft-dataservices/src/main/java/com/hazelcast/raft/service/atomicref/operation/ContainsOp.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.hazelcast.nio.serialization.Data;
2222
import com.hazelcast.nio.serialization.IdentifiedDataSerializable;
2323
import com.hazelcast.raft.RaftGroupId;
24+
import com.hazelcast.raft.impl.service.proxy.InvocationTargetLeaveAware;
2425
import com.hazelcast.raft.service.atomicref.RaftAtomicReferenceDataSerializerHook;
2526
import com.hazelcast.raft.service.atomicref.RaftAtomicRef;
2627

@@ -29,7 +30,7 @@
2930
/**
3031
* TODO: Javadoc Pending...
3132
*/
32-
public class ContainsOp extends AbstractAtomicRefOp implements IdentifiedDataSerializable {
33+
public class ContainsOp extends AbstractAtomicRefOp implements InvocationTargetLeaveAware, IdentifiedDataSerializable {
3334

3435
private Data value;
3536

@@ -47,6 +48,11 @@ public Object run(RaftGroupId groupId, long commitIndex) {
4748
return ref.contains(value);
4849
}
4950

51+
@Override
52+
public boolean isSafeToRetryOnTargetLeave() {
53+
return true;
54+
}
55+
5056
@Override
5157
public int getId() {
5258
return RaftAtomicReferenceDataSerializerHook.CONTAINS_OP;

hazelcast-raft-dataservices/src/main/java/com/hazelcast/raft/service/atomicref/operation/GetOp.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818

1919
import com.hazelcast.nio.serialization.IdentifiedDataSerializable;
2020
import com.hazelcast.raft.RaftGroupId;
21+
import com.hazelcast.raft.impl.service.proxy.InvocationTargetLeaveAware;
2122
import com.hazelcast.raft.service.atomicref.RaftAtomicReferenceDataSerializerHook;
2223

2324
/**
2425
* TODO: Javadoc Pending...
2526
*/
26-
public class GetOp extends AbstractAtomicRefOp implements IdentifiedDataSerializable {
27+
public class GetOp extends AbstractAtomicRefOp implements InvocationTargetLeaveAware, IdentifiedDataSerializable {
2728

2829
public GetOp() {
2930
}
@@ -37,6 +38,10 @@ public Object run(RaftGroupId groupId, long commitIndex) {
3738
return getAtomicRef(groupId).get();
3839
}
3940

41+
public boolean isSafeToRetryOnTargetLeave() {
42+
return true;
43+
}
44+
4045
@Override
4146
public int getId() {
4247
return RaftAtomicReferenceDataSerializerHook.GET_OP;

hazelcast-raft-dataservices/src/main/java/com/hazelcast/raft/service/countdownlatch/operation/AwaitOp.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.hazelcast.nio.ObjectDataInput;
2020
import com.hazelcast.nio.ObjectDataOutput;
2121
import com.hazelcast.raft.RaftGroupId;
22+
import com.hazelcast.raft.impl.service.proxy.InvocationTargetLeaveAware;
2223
import com.hazelcast.raft.impl.util.PostponedResponse;
2324
import com.hazelcast.raft.service.countdownlatch.RaftCountDownLatchDataSerializerHook;
2425
import com.hazelcast.raft.service.countdownlatch.RaftCountDownLatchService;
@@ -28,7 +29,7 @@
2829
/**
2930
* TODO: Javadoc Pending...
3031
*/
31-
public class AwaitOp extends AbstractCountDownLatchOp {
32+
public class AwaitOp extends AbstractCountDownLatchOp implements InvocationTargetLeaveAware {
3233

3334
private long timeoutMillis;
3435

@@ -50,6 +51,11 @@ public Object run(RaftGroupId groupId, long commitIndex) {
5051
return timeoutMillis > 0 ? PostponedResponse.INSTANCE : false;
5152
}
5253

54+
@Override
55+
public boolean isSafeToRetryOnTargetLeave() {
56+
return true;
57+
}
58+
5359
@Override
5460
public int getId() {
5561
return RaftCountDownLatchDataSerializerHook.AWAIT_OP;

hazelcast-raft-dataservices/src/main/java/com/hazelcast/raft/service/countdownlatch/operation/CountDownOp.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.hazelcast.nio.ObjectDataInput;
2020
import com.hazelcast.nio.ObjectDataOutput;
2121
import com.hazelcast.raft.RaftGroupId;
22+
import com.hazelcast.raft.impl.service.proxy.InvocationTargetLeaveAware;
2223
import com.hazelcast.raft.service.countdownlatch.RaftCountDownLatchDataSerializerHook;
2324
import com.hazelcast.raft.service.countdownlatch.RaftCountDownLatchService;
2425

@@ -28,7 +29,7 @@
2829
/**
2930
* TODO: Javadoc Pending...
3031
*/
31-
public class CountDownOp extends AbstractCountDownLatchOp {
32+
public class CountDownOp extends AbstractCountDownLatchOp implements InvocationTargetLeaveAware {
3233

3334
private int expectedRound;
3435
private UUID invocationUid;
@@ -48,6 +49,11 @@ public Object run(RaftGroupId groupId, long commitIndex) {
4849
return service.countDown(groupId, name, expectedRound, invocationUid);
4950
}
5051

52+
@Override
53+
public boolean isSafeToRetryOnTargetLeave() {
54+
return true;
55+
}
56+
5157
@Override
5258
public int getId() {
5359
return RaftCountDownLatchDataSerializerHook.COUNT_DOWN_OP;

hazelcast-raft-dataservices/src/main/java/com/hazelcast/raft/service/countdownlatch/operation/GetRemainingCountOp.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
package com.hazelcast.raft.service.countdownlatch.operation;
1818

1919
import com.hazelcast.raft.RaftGroupId;
20+
import com.hazelcast.raft.impl.service.proxy.InvocationTargetLeaveAware;
2021
import com.hazelcast.raft.service.countdownlatch.RaftCountDownLatchDataSerializerHook;
2122
import com.hazelcast.raft.service.countdownlatch.RaftCountDownLatchService;
2223

2324
/**
2425
* TODO: Javadoc Pending...
2526
*/
26-
public class GetRemainingCountOp extends AbstractCountDownLatchOp {
27+
public class GetRemainingCountOp extends AbstractCountDownLatchOp implements InvocationTargetLeaveAware {
2728

2829
public GetRemainingCountOp() {
2930
}
@@ -38,6 +39,11 @@ public Object run(RaftGroupId groupId, long commitIndex) {
3839
return service.getRemainingCount(groupId, name);
3940
}
4041

42+
@Override
43+
public boolean isSafeToRetryOnTargetLeave() {
44+
return true;
45+
}
46+
4147
@Override
4248
public int getId() {
4349
return RaftCountDownLatchDataSerializerHook.GET_REMAINING_COUNT_OP;

hazelcast-raft-dataservices/src/main/java/com/hazelcast/raft/service/countdownlatch/operation/GetRoundOp.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
package com.hazelcast.raft.service.countdownlatch.operation;
1818

1919
import com.hazelcast.raft.RaftGroupId;
20+
import com.hazelcast.raft.impl.service.proxy.InvocationTargetLeaveAware;
2021
import com.hazelcast.raft.service.countdownlatch.RaftCountDownLatchDataSerializerHook;
2122
import com.hazelcast.raft.service.countdownlatch.RaftCountDownLatchService;
2223

2324
/**
2425
* TODO: Javadoc Pending...
2526
*/
26-
public class GetRoundOp extends AbstractCountDownLatchOp {
27+
public class GetRoundOp extends AbstractCountDownLatchOp implements InvocationTargetLeaveAware {
2728

2829
public GetRoundOp() {
2930
}
@@ -38,6 +39,11 @@ public Object run(RaftGroupId groupId, long commitIndex) {
3839
return service.getRound(groupId, name);
3940
}
4041

42+
@Override
43+
public boolean isSafeToRetryOnTargetLeave() {
44+
return true;
45+
}
46+
4147
@Override
4248
public int getId() {
4349
return RaftCountDownLatchDataSerializerHook.GET_ROUND_OP;

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.hazelcast.nio.serialization.IdentifiedDataSerializable;
2222
import com.hazelcast.raft.RaftGroupId;
2323
import com.hazelcast.raft.impl.RaftOp;
24+
import com.hazelcast.raft.impl.service.proxy.InvocationTargetLeaveAware;
2425
import com.hazelcast.raft.service.lock.RaftLockDataSerializerHook;
2526
import com.hazelcast.raft.service.lock.RaftLockService;
2627

@@ -30,7 +31,7 @@
3031
/**
3132
* TODO: Javadoc Pending...
3233
*/
33-
public class ForceUnlockOp extends RaftOp implements IdentifiedDataSerializable {
34+
public class ForceUnlockOp extends RaftOp implements InvocationTargetLeaveAware, IdentifiedDataSerializable {
3435

3536
private String name;
3637
private long expectedFence;
@@ -52,6 +53,11 @@ public Object run(RaftGroupId groupId, long commitIndex) {
5253
return true;
5354
}
5455

56+
@Override
57+
public boolean isSafeToRetryOnTargetLeave() {
58+
return true;
59+
}
60+
5561
@Override
5662
public final String getServiceName() {
5763
return RaftLockService.SERVICE_NAME;

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,36 @@
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+
117
package com.hazelcast.raft.service.lock.operation;
218

319
import com.hazelcast.nio.ObjectDataInput;
420
import com.hazelcast.nio.ObjectDataOutput;
521
import com.hazelcast.nio.serialization.IdentifiedDataSerializable;
622
import com.hazelcast.raft.RaftGroupId;
723
import com.hazelcast.raft.impl.RaftOp;
24+
import com.hazelcast.raft.impl.service.proxy.InvocationTargetLeaveAware;
825
import com.hazelcast.raft.service.lock.RaftLockDataSerializerHook;
926
import com.hazelcast.raft.service.lock.RaftLockService;
1027

1128
import java.io.IOException;
1229

13-
public class GetLockOwnershipStateOp extends RaftOp implements IdentifiedDataSerializable {
30+
/**
31+
* TODO: Javadoc Pending...
32+
*/
33+
public class GetLockOwnershipStateOp extends RaftOp implements InvocationTargetLeaveAware, IdentifiedDataSerializable {
1434

1535
private String name;
1636

@@ -27,6 +47,11 @@ public Object run(RaftGroupId groupId, long commitIndex) {
2747
return service.getLockOwnershipState(groupId, name);
2848
}
2949

50+
@Override
51+
public boolean isSafeToRetryOnTargetLeave() {
52+
return true;
53+
}
54+
3055
@Override
3156
public final String getServiceName() {
3257
return RaftLockService.SERVICE_NAME;

0 commit comments

Comments
 (0)