-
Notifications
You must be signed in to change notification settings - Fork 414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RATIS-1594. Support ADD mode to SetConfiguration #658
Conversation
@szetszwo @SzyWilliam Can you help review this patch, thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM : )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codings-dan , thanks a lot for working on this! Some comments inlined.
We should think about what should happen in ADD mode when a new peer already exists in the current peer list? Should the request fail? Cc @SzyWilliam .
RaftClientReply setConfiguration(List<RaftPeer> serversInNewConf, SetConfigurationRequest.Mode mode) | ||
throws IOException; | ||
|
||
/** Set the configuration request to the raft service. */ | ||
RaftClientReply setConfiguration(List<RaftPeer> serversInNewConf, List<RaftPeer> listenersInNewConf) | ||
throws IOException; | ||
|
||
RaftClientReply setConfiguration(List<RaftPeer> serversInNewConf, List<RaftPeer> listenersInNewConf, | ||
SetConfigurationRequest.Mode mode) throws IOException; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With ADD and CAS modes, the combination of arguments becomes complicated. Let's add a SetConfigurationArguments class and a Builder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I have refactored this part of the interface related code, please take a look, thank you!
@@ -23,19 +23,26 @@ | |||
import java.util.List; | |||
|
|||
public class SetConfigurationRequest extends RaftClientRequest { | |||
|
|||
public enum Mode { | |||
NORMAL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's call it SET_UNCONDITIONALLY.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -409,6 +409,12 @@ message SetConfigurationRequestProto { | |||
RaftRpcRequestProto rpcRequest = 1; | |||
repeated RaftPeerProto peers = 2; | |||
repeated RaftPeerProto listeners = 3; | |||
enum RaftConfigurationMode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to SetConfigurationRequest, let's simply call it "Mode". Also, please move the enum to the top.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
List<RaftPeer> peers = Stream.of(peersInNewConf, new ArrayList<>(current.getAllPeers())) | ||
.flatMap(List :: stream).distinct().collect(Collectors.toList()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What should happen in ADD mode when a new peer already exists in the current peer list? Should the request fail?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emm, I think if the new peer already exists in the current peer list, we could return success, I have change the related code, PTAL, thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the new peer may have a different priority. Should we allow it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we only check peers that are not in the current list, other semantics do not change, what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When ADD an existing peer with a different priority, we may either
- return failure and the configuration remains unchanged, or
- return success and the configuration changes to the new server priority.
If we do the following, then the user request (priority change) is ignored silently. It sounds like a bug.
- return success and the configuration remains unchanged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current code already implements the second point:
- return success and the configuration changes to the new server priority.
Please take a look at RaftConfigurationImpl#hasNoChange
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codings-dan , But we use distinct()
so that we are not sure whether the existing or the new server is used.
BTW, RaftConfigurationImpl#hasNoChange does not check listeners at all. It is a bug.
Below are some rough ideas. Forgot to post it previously.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codings-dan , thanks for the update. Some comments inlined.
RaftClientReply setConfiguration(List<RaftPeer> serversInNewConf, List<RaftPeer> listenersInNewConf) | ||
throws IOException; | ||
|
||
/** The same as setConfiguration(Arrays.asList(serversInNewConf), Arrays.asList(listenersInNewConf)). */ | ||
default RaftClientReply setConfiguration(RaftPeer[] serversInNewConf, RaftPeer[] listenersInNewConf) | ||
throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot remove these methods. Otherwise, it will become an incompatible change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing this out, I have fixed it
private final List<RaftPeer> peers; | ||
private final List<RaftPeer> listeners; | ||
private Mode mode; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make it final in order to keep it immutable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
List<RaftPeer> peers = Stream.of(peersInNewConf, new ArrayList<>(current.getAllPeers())) | ||
.flatMap(List :: stream).distinct().collect(Collectors.toList()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the new peer may have a different priority. Should we allow it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codings-dan , thanks for the update. For the detailed comments, see https://issues.apache.org/jira/secure/attachment/13045825/658_review.patch
List<RaftPeer> peers = Stream.of(peersInNewConf, new ArrayList<>(current.getAllPeers())) | ||
.flatMap(List :: stream).distinct().collect(Collectors.toList()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codings-dan , But we use distinct()
so that we are not sure whether the existing or the new server is used.
BTW, RaftConfigurationImpl#hasNoChange does not check listeners at all. It is a bug.
@@ -31,24 +32,108 @@ | |||
* such as setting raft configuration and transferring leadership. | |||
*/ | |||
public interface AdminApi { | |||
|
|||
class SetConfigurationArguments { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move it to SetConfigurationRequest so that it can be used everywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codings-dan , thanks for the update. Some minor comments inlined.
if (!isStable() || conf.size() != newMembers.size()) { | ||
boolean hasNoChange(Collection<RaftPeer> newMembers, Collection<RaftPeer> newListeners) { | ||
if (!isStable() || conf.size() != newMembers.size() | ||
|| conf.getPeers(RaftPeerRole.LISTENER).size() != newListeners.size()) { | ||
return false; | ||
} | ||
for (RaftPeer peer : newMembers) { | ||
if (!conf.contains(peer.getId()) || conf.getPeer(peer.getId()).getPriority() != peer.getPriority()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This if-statement is no longer needed since the protos are compared below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -23,6 +23,7 @@ | |||
import org.apache.ratis.RaftTestUtil.SimpleMessage; | |||
import org.apache.ratis.client.RaftClient; | |||
import org.apache.ratis.client.RaftClientRpc; | |||
import org.apache.ratis.client.api.AdminApi; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have remove the extra code
private List<RaftPeer> serversInNewConf; | ||
private List<RaftPeer> listenersInNewConf; | ||
private Mode mode; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add final so that the class becomes immutable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@codings-dan , there are some test failures. Please take a look. |
if (!inConf.getRaftPeerProto().equals(peer.getRaftPeerProto())) { | ||
if (inConf.getPriority() != peer.getPriority()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codings-dan , I guess comparing protos has caused test failures. Why it is not working? It seems comparing protos is correct since it will compare all the fields.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see now. The hostnames could be different
- inConf:
id: "s0"
address: "localhost:59232"
dataStreamAddress: "localhost:59235"
clientAddress: "localhost:59234"
adminAddress: "localhost:59233"
- peer :
id: "s0"
address: "0.0.0.0:59232"
clientAddress: "0.0.0.0:59234"
adminAddress: "0.0.0.0:59233"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codings-dan, Let's compare only the priority as you have already done. We should think about how to support updating hostnames and ports. Perhaps it needs a new mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@szetszwo Yean, the hostname could be different, so I only compare the priority.
We should think about how to support updating hostnames and ports
I will try, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 the change looks good.
see https://issues.apache.org/jira/browse/RATIS-1594