Skip to content

Commit

Permalink
feat(raft): configure request supports joint consensus
Browse files Browse the repository at this point in the history
  • Loading branch information
lenaschoenburg committed Aug 30, 2023
1 parent dc78662 commit d9dc21a
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
*/
package io.atomix.raft.protocol;

import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import io.atomix.cluster.MemberId;
import io.atomix.raft.cluster.RaftMember;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
* Configuration installation request.
Expand All @@ -39,18 +40,62 @@ public class ConfigureRequest extends AbstractRaftRequest {
private final long index;
private final long timestamp;
private final Collection<RaftMember> members;
private final Collection<RaftMember> oldMembers;

public ConfigureRequest(
final long term,
final String leader,
final long index,
final long timestamp,
final Collection<RaftMember> members) {
final Collection<RaftMember> newMembers,
final Collection<RaftMember> oldMembers) {
this.term = term;
this.leader = leader;
this.index = index;
this.timestamp = timestamp;
this.members = members;
members = newMembers;
this.oldMembers = oldMembers;
}

@Override
public int hashCode() {
return Objects.hash(term, leader, index, timestamp, members, oldMembers);
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final ConfigureRequest that = (ConfigureRequest) o;
return term == that.term
&& index == that.index
&& timestamp == that.timestamp
&& Objects.equals(leader, that.leader)
&& Objects.equals(members, that.members)
&& Objects.equals(oldMembers, that.oldMembers);
}

@Override
public String toString() {
return "ConfigureRequest{"
+ "term="
+ term
+ ", leader='"
+ leader
+ '\''
+ ", index="
+ index
+ ", timestamp="
+ timestamp
+ ", newMembers="
+ members
+ ", oldMembers="
+ oldMembers
+ '}';
}

/**
Expand Down Expand Up @@ -103,55 +148,17 @@ public long timestamp() {
*
* @return The configuration members.
*/
public Collection<RaftMember> members() {
public Collection<RaftMember> newMembers() {
return members;
}

@Override
public int hashCode() {
int result = (int) (term ^ (term >>> 32));
result = 31 * result + leader.hashCode();
result = 31 * result + (int) (index ^ (index >>> 32));
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
result = 31 * result + members.hashCode();
return result;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

final ConfigureRequest that = (ConfigureRequest) o;

if (term != that.term) {
return false;
}
if (index != that.index) {
return false;
}
if (timestamp != that.timestamp) {
return false;
}
if (!leader.equals(that.leader)) {
return false;
}
return members.equals(that.members);
}

@Override
public String toString() {
return toStringHelper(this)
.add("term", term)
.add("leader", leader)
.add("index", index)
.add("timestamp", timestamp)
.add("members", members)
.toString();
/**
* Returns the configuration members.
*
* @return The configuration members.
*/
public Collection<RaftMember> oldMembers() {
return oldMembers;
}

/** Heartbeat request builder. */
Expand All @@ -161,7 +168,8 @@ public static class Builder extends AbstractRaftRequest.Builder<Builder, Configu
private String leader;
private long index;
private long timestamp;
private Collection<RaftMember> members;
private Collection<RaftMember> newMembers;
private Collection<RaftMember> oldMembers = List.of();

/**
* Sets the request term.
Expand Down Expand Up @@ -215,12 +223,24 @@ public Builder withTime(final long timestamp) {
/**
* Sets the request members.
*
* @param members The request members.
* @param newMembers The request members.
* @return The request builder.
* @throws NullPointerException if {@code member} is null
*/
public Builder withNewMembers(final Collection<RaftMember> newMembers) {
this.newMembers = checkNotNull(newMembers, "members cannot be null");
return this;
}

/**
* Sets the request members.
*
* @param oldMembers The request members.
* @return The request builder.
* @throws NullPointerException if {@code member} is null
*/
public Builder withMembers(final Collection<RaftMember> members) {
this.members = checkNotNull(members, "members cannot be null");
public Builder withOldMembers(final Collection<RaftMember> oldMembers) {
this.oldMembers = checkNotNull(oldMembers, "members cannot be null");
return this;
}

Expand All @@ -230,7 +250,7 @@ public Builder withMembers(final Collection<RaftMember> members) {
@Override
public ConfigureRequest build() {
validate();
return new ConfigureRequest(term, leader, index, timestamp, members);
return new ConfigureRequest(term, leader, index, timestamp, newMembers, oldMembers);
}

@Override
Expand All @@ -240,7 +260,8 @@ protected void validate() {
checkNotNull(leader, "leader cannot be null");
checkArgument(index >= 0, "index must be positive");
checkArgument(timestamp > 0, "timestamp must be positive");
checkNotNull(members, "members cannot be null");
checkNotNull(newMembers, "newMembers cannot be null");
checkNotNull(oldMembers, "oldMembers cannot be null");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import io.atomix.raft.protocol.VoteRequest;
import io.atomix.raft.protocol.VoteResponse;
import io.atomix.raft.storage.system.Configuration;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/** Inactive state. */
Expand All @@ -57,7 +58,12 @@ public CompletableFuture<ConfigureResponse> onConfigure(final ConfigureRequest r
updateTermAndLeader(request.term(), request.leader());

final Configuration configuration =
new Configuration(request.index(), request.term(), request.timestamp(), request.members());
new Configuration(
request.index(),
request.term(),
request.timestamp(),
request.newMembers(),
request.oldMembers() != null ? request.oldMembers() : List.of());

// Configure the cluster membership. This will cause this server to transition to the
// appropriate state if its type has changed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,15 @@ private void resetSnapshotIndex(final RaftMemberContext member, final AppendResp

/** Builds a configure request for the given member. */
private ConfigureRequest buildConfigureRequest() {
final DefaultRaftMember leader = raft.getLeader();
final var leader = raft.getLeader();
final var configuration = raft.getCluster().getConfiguration();
return ConfigureRequest.builder()
.withTerm(raft.getTerm())
.withLeader(leader.memberId())
.withIndex(raft.getCluster().getConfiguration().index())
.withTime(raft.getCluster().getConfiguration().time())
.withMembers(raft.getCluster().getConfiguration().newMembers())
.withIndex(configuration.index())
.withTime(configuration.time())
.withNewMembers(configuration.newMembers())
.withOldMembers(configuration.oldMembers())
.build();
}

Expand Down

0 comments on commit d9dc21a

Please sign in to comment.