Add term and config to cluster state (#32100)

Adds the publication term and the last accepted and committed configurations to the cluster state,
following the formal model in
https://github.com/elastic/elasticsearch-formal-models/blob/master/ZenWithTerms/tla/ZenWithTerms.tla
The term represents the reign of a master, and the last committed / accepted configurations
represent the set of quorums that cluster state changes will require (If there's no reconfiguration,
last accepted and last committed configurations coincide).
This commit is contained in:
Yannick Welsch 2018-07-17 18:28:00 +02:00 committed by GitHub
parent e31a877a64
commit ad78f73942
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 283 additions and 11 deletions

View File

@ -173,8 +173,8 @@ task verifyVersions {
* the enabled state of every bwc task. It should be set back to true
* after the backport of the backcompat code is complete.
*/
final boolean bwc_tests_enabled = true
final String bwc_tests_disabled_issue = "" /* place a PR link here when committing bwc changes */
final boolean bwc_tests_enabled = false
final String bwc_tests_disabled_issue = "https://github.com/elastic/elasticsearch/issues/32006" // BWC handled at a later time
if (bwc_tests_enabled == false) {
if (bwc_tests_disabled_issue.isEmpty()) {
throw new GradleException("bwc_tests_disabled_issue must be set when bwc_tests_enabled == false")

View File

@ -76,8 +76,11 @@ public class TransportClusterStateAction extends TransportMasterNodeReadAction<C
ClusterState currentState = clusterService.state();
logger.trace("Serving cluster state request using version {}", currentState.version());
ClusterState.Builder builder = ClusterState.builder(currentState.getClusterName());
builder.term(currentState.term());
builder.version(currentState.version());
builder.stateUUID(currentState.stateUUID());
builder.lastCommittedConfiguration(currentState.getLastCommittedConfiguration());
builder.lastAcceptedConfiguration(currentState.getLastAcceptedConfiguration());
if (request.nodes()) {
builder.nodes(currentState.nodes());
}

View File

@ -22,6 +22,8 @@ package org.elasticsearch.cluster;
import com.carrotsearch.hppc.cursors.IntObjectCursor;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
import org.elasticsearch.Version;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.block.ClusterBlock;
import org.elasticsearch.cluster.block.ClusterBlocks;
@ -49,8 +51,10 @@ import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.io.stream.VersionedNamedWriteable;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.common.xcontent.ToXContentFragment;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
@ -58,10 +62,14 @@ import org.elasticsearch.discovery.Discovery;
import org.elasticsearch.discovery.zen.PublishClusterStateAction;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@ -154,6 +162,8 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
public static final long UNKNOWN_VERSION = -1;
private final long term;
private final long version;
private final String stateUUID;
@ -172,16 +182,23 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
private final boolean wasReadFromDiff;
private final VotingConfiguration lastCommittedConfiguration;
private final VotingConfiguration lastAcceptedConfiguration;
// built on demand
private volatile RoutingNodes routingNodes;
public ClusterState(long version, String stateUUID, ClusterState state) {
this(state.clusterName, version, stateUUID, state.metaData(), state.routingTable(), state.nodes(), state.blocks(), state.customs(),
false);
public ClusterState(long term, long version, String stateUUID, ClusterState state) {
this(state.clusterName, term, version, stateUUID, state.metaData(), state.routingTable(), state.nodes(), state.blocks(),
state.customs(), state.getLastCommittedConfiguration(), state.getLastAcceptedConfiguration(), false);
}
public ClusterState(ClusterName clusterName, long version, String stateUUID, MetaData metaData, RoutingTable routingTable,
DiscoveryNodes nodes, ClusterBlocks blocks, ImmutableOpenMap<String, Custom> customs, boolean wasReadFromDiff) {
public ClusterState(ClusterName clusterName, long term, long version, String stateUUID, MetaData metaData, RoutingTable routingTable,
DiscoveryNodes nodes, ClusterBlocks blocks, ImmutableOpenMap<String, Custom> customs,
VotingConfiguration lastCommittedConfiguration, VotingConfiguration lastAcceptedConfiguration,
boolean wasReadFromDiff) {
this.term = term;
this.version = version;
this.stateUUID = stateUUID;
this.clusterName = clusterName;
@ -190,9 +207,15 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
this.nodes = nodes;
this.blocks = blocks;
this.customs = customs;
this.lastCommittedConfiguration = lastCommittedConfiguration;
this.lastAcceptedConfiguration = lastAcceptedConfiguration;
this.wasReadFromDiff = wasReadFromDiff;
}
public long term() {
return term;
}
public long version() {
return this.version;
}
@ -257,6 +280,14 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
return this.clusterName;
}
public VotingConfiguration getLastAcceptedConfiguration() {
return lastAcceptedConfiguration;
}
public VotingConfiguration getLastCommittedConfiguration() {
return lastCommittedConfiguration;
}
// Used for testing and logging to determine how this cluster state was send over the wire
public boolean wasReadFromDiff() {
return wasReadFromDiff;
@ -277,8 +308,11 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("cluster uuid: ").append(metaData.clusterUUID()).append("\n");
sb.append("term: ").append(term).append("\n");
sb.append("version: ").append(version).append("\n");
sb.append("state uuid: ").append(stateUUID).append("\n");
sb.append("last committed config: ").append(getLastCommittedConfiguration()).append("\n");
sb.append("last accepted config: ").append(getLastAcceptedConfiguration()).append("\n");
sb.append("from_diff: ").append(wasReadFromDiff).append("\n");
sb.append("meta data version: ").append(metaData.version()).append("\n");
final String TAB = " ";
@ -386,8 +420,11 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
builder.field("cluster_uuid", metaData().clusterUUID());
if (metrics.contains(Metric.VERSION)) {
builder.field("term", term);
builder.field("version", version);
builder.field("state_uuid", stateUUID);
builder.field("last_committed_config", lastCommittedConfiguration);
builder.field("last_accepted_config", lastAcceptedConfiguration);
}
if (metrics.contains(Metric.MASTER_NODE)) {
@ -587,8 +624,11 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
public static class Builder {
private final ClusterName clusterName;
private long term = 0;
private long version = 0;
private String uuid = UNKNOWN_UUID;
private VotingConfiguration lastCommittedConfiguration = VotingConfiguration.EMPTY_CONFIG;
private VotingConfiguration lastAcceptedConfiguration = VotingConfiguration.EMPTY_CONFIG;
private MetaData metaData = MetaData.EMPTY_META_DATA;
private RoutingTable routingTable = RoutingTable.EMPTY_ROUTING_TABLE;
private DiscoveryNodes nodes = DiscoveryNodes.EMPTY_NODES;
@ -599,8 +639,11 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
public Builder(ClusterState state) {
this.clusterName = state.clusterName;
this.term = state.term();
this.version = state.version();
this.uuid = state.stateUUID();
this.lastCommittedConfiguration = state.getLastCommittedConfiguration();
this.lastAcceptedConfiguration = state.getLastAcceptedConfiguration();
this.nodes = state.nodes();
this.routingTable = state.routingTable();
this.metaData = state.metaData();
@ -650,6 +693,11 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
return this;
}
public Builder term(long term) {
this.term = term;
return this;
}
public Builder version(long version) {
this.version = version;
return this;
@ -666,6 +714,16 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
return this;
}
public Builder lastCommittedConfiguration(VotingConfiguration config) {
this.lastCommittedConfiguration = config;
return this;
}
public Builder lastAcceptedConfiguration(VotingConfiguration config) {
this.lastAcceptedConfiguration = config;
return this;
}
public Builder putCustom(String type, Custom custom) {
customs.put(type, custom);
return this;
@ -690,7 +748,8 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
if (UNKNOWN_UUID.equals(uuid)) {
uuid = UUIDs.randomBase64UUID();
}
return new ClusterState(clusterName, version, uuid, metaData, routingTable, nodes, blocks, customs.build(), fromDiff);
return new ClusterState(clusterName, term, version, uuid, metaData, routingTable, nodes, blocks, customs.build(),
lastCommittedConfiguration, lastAcceptedConfiguration, fromDiff);
}
public static byte[] toBytes(ClusterState state) throws IOException {
@ -722,8 +781,15 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
public static ClusterState readFrom(StreamInput in, DiscoveryNode localNode) throws IOException {
ClusterName clusterName = new ClusterName(in);
Builder builder = new Builder(clusterName);
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
builder.term = in.readLong();
}
builder.version = in.readLong();
builder.uuid = in.readString();
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
builder.lastCommittedConfiguration(new VotingConfiguration(in));
builder.lastAcceptedConfiguration(new VotingConfiguration(in));
}
builder.metaData = MetaData.readFrom(in);
builder.routingTable = RoutingTable.readFrom(in);
builder.nodes = DiscoveryNodes.readFrom(in, localNode);
@ -739,8 +805,15 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
@Override
public void writeTo(StreamOutput out) throws IOException {
clusterName.writeTo(out);
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
out.writeLong(term);
}
out.writeLong(version);
out.writeString(stateUUID);
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
lastCommittedConfiguration.writeTo(out);
lastAcceptedConfiguration.writeTo(out);
}
metaData.writeTo(out);
routingTable.writeTo(out);
nodes.writeTo(out);
@ -762,6 +835,8 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
private static class ClusterStateDiff implements Diff<ClusterState> {
private final long toTerm;
private final long toVersion;
private final String fromUuid;
@ -770,6 +845,10 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
private final ClusterName clusterName;
private final VotingConfiguration lastCommittedConfiguration;
private final VotingConfiguration lastAcceptedConfiguration;
private final Diff<RoutingTable> routingTable;
private final Diff<DiscoveryNodes> nodes;
@ -783,8 +862,11 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
ClusterStateDiff(ClusterState before, ClusterState after) {
fromUuid = before.stateUUID;
toUuid = after.stateUUID;
toTerm = after.term;
toVersion = after.version;
clusterName = after.clusterName;
lastCommittedConfiguration = after.lastCommittedConfiguration;
lastAcceptedConfiguration = after.lastAcceptedConfiguration;
routingTable = after.routingTable.diff(before.routingTable);
nodes = after.nodes.diff(before.nodes);
metaData = after.metaData.diff(before.metaData);
@ -796,7 +878,19 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
clusterName = new ClusterName(in);
fromUuid = in.readString();
toUuid = in.readString();
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
toTerm = in.readLong();
} else {
toTerm = 0L;
}
toVersion = in.readLong();
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
lastCommittedConfiguration = new VotingConfiguration(in);
lastAcceptedConfiguration = new VotingConfiguration(in);
} else {
lastCommittedConfiguration = VotingConfiguration.EMPTY_CONFIG;
lastAcceptedConfiguration = VotingConfiguration.EMPTY_CONFIG;
}
routingTable = RoutingTable.readDiffFrom(in);
nodes = DiscoveryNodes.readDiffFrom(in, localNode);
metaData = MetaData.readDiffFrom(in);
@ -809,7 +903,14 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
clusterName.writeTo(out);
out.writeString(fromUuid);
out.writeString(toUuid);
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
out.writeLong(toTerm);
}
out.writeLong(toVersion);
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
lastCommittedConfiguration.writeTo(out);
lastAcceptedConfiguration.writeTo(out);
}
routingTable.writeTo(out);
nodes.writeTo(out);
metaData.writeTo(out);
@ -828,7 +929,10 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
throw new IncompatibleClusterStateVersionException(state.version, state.stateUUID, toVersion, fromUuid);
}
builder.stateUUID(toUuid);
builder.term(toTerm);
builder.version(toVersion);
builder.lastCommittedConfiguration(lastCommittedConfiguration);
builder.lastAcceptedConfiguration(lastAcceptedConfiguration);
builder.routingTable(routingTable.apply(state.routingTable));
builder.nodes(nodes.apply(state.nodes));
builder.metaData(metaData.apply(state.metaData));
@ -840,4 +944,67 @@ public class ClusterState implements ToXContentFragment, Diffable<ClusterState>
}
/**
* A collection of persistent node ids, denoting the voting configuration for cluster state changes.
*/
public static class VotingConfiguration implements Writeable, ToXContentFragment {
public static final VotingConfiguration EMPTY_CONFIG = new VotingConfiguration(Collections.emptySet());
private final Set<String> nodeIds;
public VotingConfiguration(Set<String> nodeIds) {
this.nodeIds = Collections.unmodifiableSet(new HashSet<>(nodeIds));
}
public VotingConfiguration(StreamInput in) throws IOException {
nodeIds = Collections.unmodifiableSet(Sets.newHashSet(in.readStringArray()));
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeStringArray(nodeIds.toArray(new String[nodeIds.size()]));
}
public boolean hasQuorum(Collection<String> votes) {
final HashSet<String> intersection = new HashSet<>(nodeIds);
intersection.retainAll(votes);
return intersection.size() * 2 > nodeIds.size();
}
public Set<String> getNodeIds() {
return nodeIds;
}
@Override
public String toString() {
return "VotingConfiguration{" + String.join(",", nodeIds) + "}";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
VotingConfiguration that = (VotingConfiguration) o;
return Objects.equals(nodeIds, that.nodeIds);
}
@Override
public int hashCode() {
return Objects.hash(nodeIds);
}
public boolean isEmpty() {
return nodeIds.isEmpty();
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startArray();
for (String nodeId : nodeIds) {
builder.value(nodeId);
}
return builder.endArray();
}
}
}

View File

@ -70,8 +70,11 @@ public class ClusterRerouteResponseTests extends ESTestCase {
" \"acknowledged\" : true,\n" +
" \"state\" : {\n" +
" \"cluster_uuid\" : \"_na_\",\n" +
" \"term\" : 0,\n" +
" \"version\" : 0,\n" +
" \"state_uuid\" : \"" + clusterState.stateUUID() + "\",\n" +
" \"last_committed_config\" : [ ],\n" +
" \"last_accepted_config\" : [ ],\n" +
" \"master_node\" : \"node0\",\n" +
" \"blocks\" : { },\n" +
" \"nodes\" : {\n" +
@ -138,8 +141,11 @@ public class ClusterRerouteResponseTests extends ESTestCase {
" \"acknowledged\" : true,\n" +
" \"state\" : {\n" +
" \"cluster_uuid\" : \"_na_\",\n" +
" \"term\" : 0,\n" +
" \"version\" : 0,\n" +
" \"state_uuid\" : \"" + clusterState.stateUUID() + "\",\n" +
" \"last_committed_config\" : [ ],\n" +
" \"last_accepted_config\" : [ ],\n" +
" \"master_node\" : \"node0\"\n" +
" },\n" +
" \"explanations\" : [\n" +

View File

@ -97,7 +97,7 @@ public class ClusterStateDiffIT extends ESIntegTestCase {
if (i > 0) {
clusterState = builder.build();
}
switch (randomInt(4)) {
switch (randomInt(5)) {
case 0:
builder = randomNodes(clusterState);
break;
@ -113,11 +113,14 @@ public class ClusterStateDiffIT extends ESIntegTestCase {
case 4:
builder = randomMetaDataChanges(clusterState);
break;
case 5:
builder = randomVotingConfiguration(clusterState);
break;
default:
throw new IllegalArgumentException("Shouldn't be here");
}
}
clusterState = builder.incrementVersion().build();
clusterState = builder.incrementVersion().term(randomLong()).build();
if (randomIntBetween(0, 10) < 1) {
// Update cluster state via full serialization from time to time
@ -141,7 +144,10 @@ public class ClusterStateDiffIT extends ESIntegTestCase {
try {
// Check non-diffable elements
assertThat(clusterStateFromDiffs.version(), equalTo(clusterState.version()));
assertThat(clusterStateFromDiffs.term(), equalTo(clusterState.term()));
assertThat(clusterStateFromDiffs.stateUUID(), equalTo(clusterState.stateUUID()));
assertThat(clusterStateFromDiffs.getLastAcceptedConfiguration(), equalTo(clusterState.getLastAcceptedConfiguration()));
assertThat(clusterStateFromDiffs.getLastCommittedConfiguration(), equalTo(clusterState.getLastCommittedConfiguration()));
// Check nodes
assertThat(clusterStateFromDiffs.nodes().getNodes(), equalTo(clusterState.nodes().getNodes()));
@ -190,6 +196,20 @@ public class ClusterStateDiffIT extends ESIntegTestCase {
}
private ClusterState.Builder randomVotingConfiguration(ClusterState clusterState) {
ClusterState.Builder builder = ClusterState.builder(clusterState);
if (randomBoolean()) {
builder.lastCommittedConfiguration(
new ClusterState.VotingConfiguration(Sets.newHashSet(generateRandomStringArray(10, 10, false))));
}
if (randomBoolean()) {
builder.lastAcceptedConfiguration(
new ClusterState.VotingConfiguration(Sets.newHashSet(generateRandomStringArray(10, 10, false))));
}
return builder;
}
/**
* Randomly updates nodes in the cluster state
*/

View File

@ -19,10 +19,18 @@
package org.elasticsearch.cluster;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterState.VotingConfiguration;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.EqualsHashCodeTestUtils;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet;
@ -55,6 +63,70 @@ public class ClusterStateTests extends ESTestCase {
// state from the same master compare by version
assertThat(withMaster1a.supersedes(withMaster1b), equalTo(withMaster1a.version() > withMaster1b.version()));
}
public void testVotingConfiguration() {
VotingConfiguration config0 = new VotingConfiguration(Sets.newHashSet());
assertThat(config0, equalTo(VotingConfiguration.EMPTY_CONFIG));
assertThat(config0.getNodeIds(), equalTo(Sets.newHashSet()));
assertThat(config0.isEmpty(), equalTo(true));
assertThat(config0.hasQuorum(Sets.newHashSet()), equalTo(false));
assertThat(config0.hasQuorum(Sets.newHashSet("id1")), equalTo(false));
VotingConfiguration config1 = new VotingConfiguration(Sets.newHashSet("id1"));
assertThat(config1.getNodeIds(), equalTo(Sets.newHashSet("id1")));
assertThat(config1.isEmpty(), equalTo(false));
assertThat(config1.hasQuorum(Sets.newHashSet("id1")), equalTo(true));
assertThat(config1.hasQuorum(Sets.newHashSet("id1", "id2")), equalTo(true));
assertThat(config1.hasQuorum(Sets.newHashSet("id2")), equalTo(false));
assertThat(config1.hasQuorum(Sets.newHashSet()), equalTo(false));
VotingConfiguration config2 = new VotingConfiguration(Sets.newHashSet("id1", "id2"));
assertThat(config2.getNodeIds(), equalTo(Sets.newHashSet("id1", "id2")));
assertThat(config2.isEmpty(), equalTo(false));
assertThat(config2.hasQuorum(Sets.newHashSet("id1", "id2")), equalTo(true));
assertThat(config2.hasQuorum(Sets.newHashSet("id1", "id2", "id3")), equalTo(true));
assertThat(config2.hasQuorum(Sets.newHashSet("id1")), equalTo(false));
assertThat(config2.hasQuorum(Sets.newHashSet("id2")), equalTo(false));
assertThat(config2.hasQuorum(Sets.newHashSet("id3")), equalTo(false));
assertThat(config2.hasQuorum(Sets.newHashSet("id1", "id3")), equalTo(false));
assertThat(config2.hasQuorum(Sets.newHashSet()), equalTo(false));
VotingConfiguration config3 = new VotingConfiguration(Sets.newHashSet("id1", "id2", "id3"));
assertThat(config3.getNodeIds(), equalTo(Sets.newHashSet("id1", "id2", "id3")));
assertThat(config3.isEmpty(), equalTo(false));
assertThat(config3.hasQuorum(Sets.newHashSet("id1", "id2")), equalTo(true));
assertThat(config3.hasQuorum(Sets.newHashSet("id2", "id3")), equalTo(true));
assertThat(config3.hasQuorum(Sets.newHashSet("id1", "id3")), equalTo(true));
assertThat(config3.hasQuorum(Sets.newHashSet("id1", "id2", "id3")), equalTo(true));
assertThat(config3.hasQuorum(Sets.newHashSet("id1", "id2", "id4")), equalTo(true));
assertThat(config3.hasQuorum(Sets.newHashSet("id1")), equalTo(false));
assertThat(config3.hasQuorum(Sets.newHashSet("id2")), equalTo(false));
assertThat(config3.hasQuorum(Sets.newHashSet("id3")), equalTo(false));
assertThat(config3.hasQuorum(Sets.newHashSet("id1", "id4")), equalTo(false));
assertThat(config3.hasQuorum(Sets.newHashSet("id1", "id4", "id5")), equalTo(false));
assertThat(config3.hasQuorum(Sets.newHashSet()), equalTo(false));
}
public void testVotingConfigurationSerializationEqualsHashCode() {
VotingConfiguration initialConfig = new VotingConfiguration(
Sets.newHashSet(generateRandomStringArray(randomInt(10), 20, false)));
EqualsHashCodeTestUtils.checkEqualsAndHashCode(initialConfig,
orig -> ESTestCase.copyWriteable(orig, new NamedWriteableRegistry(Collections.emptyList()), VotingConfiguration::new),
cfg -> {
Set<String> newNodeIds = new HashSet<>(cfg.getNodeIds());
if (cfg.isEmpty() == false && randomBoolean()) {
// remove random element
newNodeIds.remove(randomFrom(cfg.getNodeIds()));
} else if (cfg.isEmpty() == false && randomBoolean()) {
// change random element
newNodeIds.remove(randomFrom(cfg.getNodeIds()));
newNodeIds.add(randomAlphaOfLength(20));
} else {
// add random element
newNodeIds.add(randomAlphaOfLength(20));
}
return new VotingConfiguration(newNodeIds);
});
}
}

View File

@ -487,7 +487,8 @@ public class PublishClusterStateActionTests extends ESTestCase {
clusterState = ClusterState.builder(clusterState).blocks(ClusterBlocks.builder()
.addGlobalBlock(MetaData.CLUSTER_READ_ONLY_BLOCK)).incrementVersion().build();
ClusterState unserializableClusterState = new ClusterState(clusterState.version(), clusterState.stateUUID(), clusterState) {
ClusterState unserializableClusterState = new ClusterState(clusterState.term(), clusterState.version(), clusterState.stateUUID(),
clusterState) {
@Override
public Diff<ClusterState> diff(ClusterState previousState) {
return new Diff<ClusterState>() {

View File

@ -504,8 +504,11 @@ public class ClusterStatsMonitoringDocTests extends BaseMonitoringDocTestCase<Cl
+ "\"nodes_hash\":1314980060,"
+ "\"status\":\"green\","
+ "\"cluster_uuid\":\"_cluster\","
+ "\"term\":0,"
+ "\"version\":12,"
+ "\"state_uuid\":\"_state_uuid\","
+ "\"last_committed_config\":[],"
+ "\"last_accepted_config\":[],"
+ "\"master_node\":\"_node\","
+ "\"nodes\":{"
+ "\"_node_id\":{"