Skip to content

Add min. read-only index version compatible to DiscoveryNode #118744

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docs/reference/indices/shard-stores.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,9 @@ The API returns the following response:
"attributes": {},
"roles": [...],
"version": "8.10.0",
"min_index_version": 7000099,
"max_index_version": 8100099
"min_index_version": 8000099,
"min_read_only_index_version": 7000099,
"max_index_version": 9004000
},
"allocation_id": "2iNySv_OQVePRX-yaRH_lQ", <4>
"allocation" : "primary|replica|unused" <5>
Expand All @@ -193,6 +194,7 @@ The API returns the following response:
// TESTRESPONSE[s/"roles": \[[^]]*\]/"roles": $body.$_path/]
// TESTRESPONSE[s/"8.10.0"/\$node_version/]
// TESTRESPONSE[s/"min_index_version": 7000099/"min_index_version": $body.$_path/]
// TESTRESPONSE[s/"min_index_version": 7000099/"min_index_version": $body.$_path/]
// TESTRESPONSE[s/"max_index_version": 8100099/"max_index_version": $body.$_path/]


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ static TransportVersion def(int id) {
public static final TransportVersion SEMANTIC_QUERY_LENIENT = def(8_807_00_0);
public static final TransportVersion ESQL_QUERY_BUILDER_IN_SEARCH_FUNCTIONS = def(8_808_00_0);
public static final TransportVersion EQL_ALLOW_PARTIAL_SEARCH_RESULTS = def(8_809_00_0);
public static final TransportVersion NODE_VERSION_INFORMATION_WITH_MIN_READ_ONLY_INDEX_VERSION = def(8_810_00_0);

/*
* STOP! READ THIS FIRST! No, really,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import java.util.SortedSet;
import java.util.TreeSet;

import static org.elasticsearch.TransportVersions.NODE_VERSION_INFORMATION_WITH_MIN_READ_ONLY_INDEX_VERSION;
import static org.elasticsearch.node.NodeRoleSettings.NODE_ROLES_SETTING;

/**
Expand Down Expand Up @@ -325,7 +326,17 @@ public DiscoveryNode(StreamInput in) throws IOException {
}
}
this.roles = Collections.unmodifiableSortedSet(roles);
versionInfo = new VersionInformation(Version.readVersion(in), IndexVersion.readVersion(in), IndexVersion.readVersion(in));
Version version = Version.readVersion(in);
IndexVersion minIndexVersion = IndexVersion.readVersion(in);
IndexVersion minReadOnlyIndexVersion;
if (in.getTransportVersion().onOrAfter(NODE_VERSION_INFORMATION_WITH_MIN_READ_ONLY_INDEX_VERSION)) {
minReadOnlyIndexVersion = IndexVersion.readVersion(in);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is good, but perhaps you can confirm my thinking here. I originally worried a little about it persisting due to residing in cluster state such that it would depend on the master's version.

It should work though since we require a full upgrade to 8.18 before upgrading to 9.0 (at least in a rolling fashion). Hence on 8.18, any master here would then see a new 9.0 node, hence it would have the N-2 min-read-only-version.

All good I think, just overcomplicating it (I think).

Copy link
Member Author

@tlrx tlrx Dec 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is OK too, yet it is not an area I'm super confortable with.

My understanding is that a cluster on 8.17 with indices created in 7.x should reject join requests from 9.0 nodes since the node will only communicate a min. index compatible version on 8.

Once this PR is merged in main and backported to 8.18, a master on 8.18 will receive join requests from 9.0 nodes with both the N-1 and N-2 information but should still reject the node if 7.x indices exist in the cluster since 9.0 is not able to read andwrite such indices (I expect to change this soon for read-only searchable snapshot indices in #118785).

} else {
minReadOnlyIndexVersion = minIndexVersion;

}
IndexVersion maxIndexVersion = IndexVersion.readVersion(in);
versionInfo = new VersionInformation(version, minIndexVersion, minReadOnlyIndexVersion, maxIndexVersion);
if (in.getTransportVersion().onOrAfter(EXTERNAL_ID_VERSION)) {
this.externalId = readStringLiteral.read(in);
} else {
Expand Down Expand Up @@ -360,6 +371,9 @@ public void writeTo(StreamOutput out) throws IOException {
});
Version.writeVersion(versionInfo.nodeVersion(), out);
IndexVersion.writeVersion(versionInfo.minIndexVersion(), out);
if (out.getTransportVersion().onOrAfter(NODE_VERSION_INFORMATION_WITH_MIN_READ_ONLY_INDEX_VERSION)) {
IndexVersion.writeVersion(versionInfo.minReadOnlyIndexVersion(), out);
}
IndexVersion.writeVersion(versionInfo.maxIndexVersion(), out);
if (out.getTransportVersion().onOrAfter(EXTERNAL_ID_VERSION)) {
out.writeString(externalId);
Expand Down Expand Up @@ -478,6 +492,10 @@ public IndexVersion getMinIndexVersion() {
return versionInfo.minIndexVersion();
}

public IndexVersion getMinReadOnlyIndexVersion() {
return versionInfo.minReadOnlyIndexVersion();
}

public IndexVersion getMaxIndexVersion() {
return versionInfo.maxIndexVersion();
}
Expand Down Expand Up @@ -577,6 +595,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
builder.endArray();
builder.field("version", versionInfo.buildVersion().toString());
builder.field("min_index_version", versionInfo.minIndexVersion());
builder.field("min_read_only_index_version", versionInfo.minReadOnlyIndexVersion());
builder.field("max_index_version", versionInfo.maxIndexVersion());
builder.endObject();
return builder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public class DiscoveryNodes implements Iterable<DiscoveryNode>, SimpleDiffable<D
private final Version minNodeVersion;
private final IndexVersion maxDataNodeCompatibleIndexVersion;
private final IndexVersion minSupportedIndexVersion;
private final IndexVersion minReadOnlySupportedIndexVersion;

private final Map<String, Set<String>> tiersToNodeIds;

Expand All @@ -84,6 +85,7 @@ private DiscoveryNodes(
Version minNodeVersion,
IndexVersion maxDataNodeCompatibleIndexVersion,
IndexVersion minSupportedIndexVersion,
IndexVersion minReadOnlySupportedIndexVersion,
Map<String, Set<String>> tiersToNodeIds
) {
this.nodeLeftGeneration = nodeLeftGeneration;
Expand All @@ -100,6 +102,8 @@ private DiscoveryNodes(
this.maxNodeVersion = maxNodeVersion;
this.maxDataNodeCompatibleIndexVersion = maxDataNodeCompatibleIndexVersion;
this.minSupportedIndexVersion = minSupportedIndexVersion;
this.minReadOnlySupportedIndexVersion = minReadOnlySupportedIndexVersion;
assert minReadOnlySupportedIndexVersion.onOrBefore(minSupportedIndexVersion);
assert (localNodeId == null) == (localNode == null);
this.tiersToNodeIds = tiersToNodeIds;
}
Expand All @@ -118,6 +122,7 @@ public DiscoveryNodes withMasterNodeId(@Nullable String masterNodeId) {
minNodeVersion,
maxDataNodeCompatibleIndexVersion,
minSupportedIndexVersion,
minReadOnlySupportedIndexVersion,
tiersToNodeIds
);
}
Expand Down Expand Up @@ -374,6 +379,13 @@ public IndexVersion getMinSupportedIndexVersion() {
return minSupportedIndexVersion;
}

/**
* Returns the minimum index version for read-only indices supported by all nodes in the cluster
*/
public IndexVersion getMinReadOnlySupportedIndexVersion() {
return minReadOnlySupportedIndexVersion;
}

/**
* Return the node-left generation, which is the number of times the cluster membership has been updated by removing one or more nodes.
* <p>
Expand Down Expand Up @@ -840,6 +852,7 @@ public DiscoveryNodes build() {
Version maxNodeVersion = null;
IndexVersion maxDataNodeCompatibleIndexVersion = null;
IndexVersion minSupportedIndexVersion = null;
IndexVersion minReadOnlySupportedIndexVersion = null;
for (Map.Entry<String, DiscoveryNode> nodeEntry : nodes.entrySet()) {
DiscoveryNode discoNode = nodeEntry.getValue();
Version version = discoNode.getVersion();
Expand All @@ -849,6 +862,7 @@ public DiscoveryNodes build() {
minNodeVersion = min(minNodeVersion, version);
maxNodeVersion = max(maxNodeVersion, version);
minSupportedIndexVersion = max(minSupportedIndexVersion, discoNode.getMinIndexVersion());
minReadOnlySupportedIndexVersion = max(minReadOnlySupportedIndexVersion, discoNode.getMinReadOnlyIndexVersion());
}

final long newNodeLeftGeneration;
Expand Down Expand Up @@ -881,6 +895,7 @@ public DiscoveryNodes build() {
Objects.requireNonNullElse(minNodeVersion, Version.CURRENT.minimumCompatibilityVersion()),
Objects.requireNonNullElse(maxDataNodeCompatibleIndexVersion, IndexVersion.current()),
Objects.requireNonNullElse(minSupportedIndexVersion, IndexVersions.MINIMUM_COMPATIBLE),
Objects.requireNonNullElse(minReadOnlySupportedIndexVersion, IndexVersions.MINIMUM_READONLY_COMPATIBLE),
computeTiersToNodesMap(dataNodes)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,42 @@

/**
* Represents the versions of various aspects of an Elasticsearch node.
* @param buildVersion The node {@link BuildVersion}
* @param minIndexVersion The minimum {@link IndexVersion} supported by this node
* @param maxIndexVersion The maximum {@link IndexVersion} supported by this node
* @param buildVersion The node {@link BuildVersion}
* @param minIndexVersion The minimum {@link IndexVersion} supported by this node
* @param minReadOnlyIndexVersion The minimum {@link IndexVersion} for read-only indices supported by this node
* @param maxIndexVersion The maximum {@link IndexVersion} supported by this node
*/
public record VersionInformation(
BuildVersion buildVersion,
Version nodeVersion,
IndexVersion minIndexVersion,
IndexVersion minReadOnlyIndexVersion,
IndexVersion maxIndexVersion
) {

public static final VersionInformation CURRENT = new VersionInformation(
BuildVersion.current(),
IndexVersions.MINIMUM_COMPATIBLE,
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
IndexVersion.current()
);

public VersionInformation {
Objects.requireNonNull(buildVersion);
Objects.requireNonNull(nodeVersion);
Objects.requireNonNull(minIndexVersion);
Objects.requireNonNull(minReadOnlyIndexVersion);
Objects.requireNonNull(maxIndexVersion);
assert minReadOnlyIndexVersion.onOrBefore(minIndexVersion) : minReadOnlyIndexVersion + " > " + minIndexVersion;
}

public VersionInformation(BuildVersion version, IndexVersion minIndexVersion, IndexVersion maxIndexVersion) {
this(version, Version.CURRENT, minIndexVersion, maxIndexVersion);
public VersionInformation(
BuildVersion version,
IndexVersion minIndexVersion,
IndexVersion minReadOnlyIndexVersion,
IndexVersion maxIndexVersion
) {
this(version, Version.CURRENT, minIndexVersion, minReadOnlyIndexVersion, maxIndexVersion);
/*
* Whilst DiscoveryNode.getVersion exists, we need to be able to get a Version from VersionInfo
* This needs to be consistent - on serverless, BuildVersion has an id of -1, which translates
Expand All @@ -57,7 +67,17 @@ public VersionInformation(BuildVersion version, IndexVersion minIndexVersion, In

@Deprecated
public VersionInformation(Version version, IndexVersion minIndexVersion, IndexVersion maxIndexVersion) {
this(BuildVersion.fromVersionId(version.id()), version, minIndexVersion, maxIndexVersion);
this(version, minIndexVersion, minIndexVersion, maxIndexVersion);
}

@Deprecated
public VersionInformation(
Version version,
IndexVersion minIndexVersion,
IndexVersion minReadOnlyIndexVersion,
IndexVersion maxIndexVersion
) {
this(BuildVersion.fromVersionId(version.id()), version, minIndexVersion, minReadOnlyIndexVersion, maxIndexVersion);
}

@Deprecated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ private void openProbeConnection(ActionListener<Transport.Connection> listener)
new VersionInformation(
Version.CURRENT.minimumCompatibilityVersion(),
IndexVersions.MINIMUM_COMPATIBLE,
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
IndexVersion.current()
)
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ public void onFailure(Exception e) {
new VersionInformation(
Version.CURRENT.minimumCompatibilityVersion(),
IndexVersions.MINIMUM_COMPATIBLE,
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
IndexVersion.current()
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ private static DiscoveryNode resolveSeedNode(String clusterAlias, String address
var seedVersion = new VersionInformation(
Version.CURRENT.minimumCompatibilityVersion(),
IndexVersions.MINIMUM_COMPATIBLE,
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
IndexVersion.current()
);
if (proxyAddress == null || proxyAddress.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ public void testToXContentWithDeprecatedClusterState() {
],
"version": "%s",
"min_index_version": %s,
"min_read_only_index_version": %s,
"max_index_version": %s
}
},
Expand Down Expand Up @@ -218,6 +219,7 @@ public void testToXContentWithDeprecatedClusterState() {
clusterState.getNodes().get("node0").getEphemeralId(),
Version.CURRENT,
IndexVersions.MINIMUM_COMPATIBLE,
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
IndexVersion.current(),
IndexVersion.current(),
IndexVersion.current()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ public void testToXContent() throws IOException {
],
"version": "%s",
"min_index_version":%s,
"min_read_only_index_version":%s,
"max_index_version":%s
}
},
Expand Down Expand Up @@ -389,6 +390,7 @@ public void testToXContent() throws IOException {
ephemeralId,
Version.CURRENT,
IndexVersions.MINIMUM_COMPATIBLE,
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
IndexVersion.current(),
TransportVersion.current(),
IndexVersion.current(),
Expand Down Expand Up @@ -488,6 +490,7 @@ public void testToXContent_FlatSettingTrue_ReduceMappingFalse() throws IOExcepti
],
"version" : "%s",
"min_index_version" : %s,
"min_read_only_index_version" : %s,
"max_index_version" : %s
}
},
Expand Down Expand Up @@ -663,6 +666,7 @@ public void testToXContent_FlatSettingTrue_ReduceMappingFalse() throws IOExcepti
ephemeralId,
Version.CURRENT,
IndexVersions.MINIMUM_COMPATIBLE,
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
IndexVersion.current(),
TransportVersion.current(),
IndexVersion.current(),
Expand Down Expand Up @@ -762,6 +766,7 @@ public void testToXContent_FlatSettingFalse_ReduceMappingTrue() throws IOExcepti
],
"version" : "%s",
"min_index_version" : %s,
"min_read_only_index_version" : %s,
"max_index_version" : %s
}
},
Expand Down Expand Up @@ -943,6 +948,7 @@ public void testToXContent_FlatSettingFalse_ReduceMappingTrue() throws IOExcepti
ephemeralId,
Version.CURRENT,
IndexVersions.MINIMUM_COMPATIBLE,
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
IndexVersion.current(),
TransportVersion.current(),
IndexVersion.current(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import static java.util.Collections.emptySet;
import static org.elasticsearch.test.NodeRoles.nonRemoteClusterClientNode;
import static org.elasticsearch.test.NodeRoles.remoteClusterClientNode;
import static org.elasticsearch.test.TransportVersionUtils.getPreviousVersion;
import static org.elasticsearch.test.TransportVersionUtils.randomVersionBetween;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
Expand Down Expand Up @@ -221,13 +223,15 @@ public void testDiscoveryNodeToXContent() {
],
"version" : "%s",
"min_index_version" : %s,
"min_read_only_index_version" : %s,
"max_index_version" : %s
}
}""",
transportAddress,
withExternalId ? "test-external-id" : "test-name",
Version.CURRENT,
IndexVersions.MINIMUM_COMPATIBLE,
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
IndexVersion.current()
)
)
Expand All @@ -250,4 +254,61 @@ public void testDiscoveryNodeToString() {
assertThat(toString, containsString("{" + node.getBuildVersion() + "}"));
assertThat(toString, containsString("{test-attr=val}"));// attributes
}

public void testDiscoveryNodeMinReadOnlyVersionSerialization() throws Exception {
var node = DiscoveryNodeUtils.create("_id", buildNewFakeTransportAddress(), VersionInformation.CURRENT);

{
try (var out = new BytesStreamOutput()) {
out.setTransportVersion(TransportVersion.current());
node.writeTo(out);

try (var in = StreamInput.wrap(out.bytes().array())) {
in.setTransportVersion(TransportVersion.current());

var deserialized = new DiscoveryNode(in);
assertThat(deserialized.getId(), equalTo(node.getId()));
assertThat(deserialized.getAddress(), equalTo(node.getAddress()));
assertThat(deserialized.getMinIndexVersion(), equalTo(node.getMinIndexVersion()));
assertThat(deserialized.getMaxIndexVersion(), equalTo(node.getMaxIndexVersion()));
assertThat(deserialized.getMinReadOnlyIndexVersion(), equalTo(node.getMinReadOnlyIndexVersion()));
assertThat(deserialized.getVersionInformation(), equalTo(node.getVersionInformation()));
}
}
}

{
var oldVersion = randomVersionBetween(
random(),
TransportVersions.MINIMUM_COMPATIBLE,
getPreviousVersion(TransportVersions.NODE_VERSION_INFORMATION_WITH_MIN_READ_ONLY_INDEX_VERSION)
);
try (var out = new BytesStreamOutput()) {
out.setTransportVersion(oldVersion);
node.writeTo(out);

try (var in = StreamInput.wrap(out.bytes().array())) {
in.setTransportVersion(oldVersion);

var deserialized = new DiscoveryNode(in);
assertThat(deserialized.getId(), equalTo(node.getId()));
assertThat(deserialized.getAddress(), equalTo(node.getAddress()));
assertThat(deserialized.getMinIndexVersion(), equalTo(node.getMinIndexVersion()));
assertThat(deserialized.getMaxIndexVersion(), equalTo(node.getMaxIndexVersion()));
assertThat(deserialized.getMinReadOnlyIndexVersion(), equalTo(node.getMinIndexVersion()));
assertThat(
deserialized.getVersionInformation(),
equalTo(
new VersionInformation(
node.getBuildVersion(),
node.getMinIndexVersion(),
node.getMinIndexVersion(),
node.getMaxIndexVersion()
)
)
);
}
}
}
}
}
Loading