Skip to content

Commit f0217c1

Browse files
tlrxrjernst
authored andcommitted
Add min. read-only index version compatible to DiscoveryNode (elastic#118744)
elastic#118443 added a new index version for indices that can be opened in read-only mode by Lucene. This change adds this information to the discovery node's VersionInformation and the transport serialization logic. In a short future we'd like to use this information in methods like IndexMetadataVerifier#checkSupportedVersion and NodeJoineExecutor to allow opening indices in N-2 versions as read-only indices on ES V9.
1 parent c31b8e1 commit f0217c1

File tree

13 files changed

+152
-12
lines changed

13 files changed

+152
-12
lines changed

docs/reference/indices/shard-stores.asciidoc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,9 @@ The API returns the following response:
172172
"attributes": {},
173173
"roles": [...],
174174
"version": "8.10.0",
175-
"min_index_version": 7000099,
176-
"max_index_version": 8100099
175+
"min_index_version": 8000099,
176+
"min_read_only_index_version": 7000099,
177+
"max_index_version": 9004000
177178
},
178179
"allocation_id": "2iNySv_OQVePRX-yaRH_lQ", <4>
179180
"allocation" : "primary|replica|unused" <5>
@@ -193,6 +194,7 @@ The API returns the following response:
193194
// TESTRESPONSE[s/"roles": \[[^]]*\]/"roles": $body.$_path/]
194195
// TESTRESPONSE[s/"8.10.0"/\$node_version/]
195196
// TESTRESPONSE[s/"min_index_version": 7000099/"min_index_version": $body.$_path/]
197+
// TESTRESPONSE[s/"min_index_version": 7000099/"min_index_version": $body.$_path/]
196198
// TESTRESPONSE[s/"max_index_version": 8100099/"max_index_version": $body.$_path/]
197199

198200

server/src/main/java/org/elasticsearch/TransportVersions.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ static TransportVersion def(int id) {
139139
public static final TransportVersion SEMANTIC_QUERY_LENIENT = def(8_807_00_0);
140140
public static final TransportVersion ESQL_QUERY_BUILDER_IN_SEARCH_FUNCTIONS = def(8_808_00_0);
141141
public static final TransportVersion EQL_ALLOW_PARTIAL_SEARCH_RESULTS = def(8_809_00_0);
142+
public static final TransportVersion NODE_VERSION_INFORMATION_WITH_MIN_READ_ONLY_INDEX_VERSION = def(8_810_00_0);
142143

143144
/*
144145
* STOP! READ THIS FIRST! No, really,

server/src/main/java/org/elasticsearch/cluster/node/DiscoveryNode.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.util.SortedSet;
3838
import java.util.TreeSet;
3939

40+
import static org.elasticsearch.TransportVersions.NODE_VERSION_INFORMATION_WITH_MIN_READ_ONLY_INDEX_VERSION;
4041
import static org.elasticsearch.node.NodeRoleSettings.NODE_ROLES_SETTING;
4142

4243
/**
@@ -325,7 +326,17 @@ public DiscoveryNode(StreamInput in) throws IOException {
325326
}
326327
}
327328
this.roles = Collections.unmodifiableSortedSet(roles);
328-
versionInfo = new VersionInformation(Version.readVersion(in), IndexVersion.readVersion(in), IndexVersion.readVersion(in));
329+
Version version = Version.readVersion(in);
330+
IndexVersion minIndexVersion = IndexVersion.readVersion(in);
331+
IndexVersion minReadOnlyIndexVersion;
332+
if (in.getTransportVersion().onOrAfter(NODE_VERSION_INFORMATION_WITH_MIN_READ_ONLY_INDEX_VERSION)) {
333+
minReadOnlyIndexVersion = IndexVersion.readVersion(in);
334+
} else {
335+
minReadOnlyIndexVersion = minIndexVersion;
336+
337+
}
338+
IndexVersion maxIndexVersion = IndexVersion.readVersion(in);
339+
versionInfo = new VersionInformation(version, minIndexVersion, minReadOnlyIndexVersion, maxIndexVersion);
329340
if (in.getTransportVersion().onOrAfter(EXTERNAL_ID_VERSION)) {
330341
this.externalId = readStringLiteral.read(in);
331342
} else {
@@ -360,6 +371,9 @@ public void writeTo(StreamOutput out) throws IOException {
360371
});
361372
Version.writeVersion(versionInfo.nodeVersion(), out);
362373
IndexVersion.writeVersion(versionInfo.minIndexVersion(), out);
374+
if (out.getTransportVersion().onOrAfter(NODE_VERSION_INFORMATION_WITH_MIN_READ_ONLY_INDEX_VERSION)) {
375+
IndexVersion.writeVersion(versionInfo.minReadOnlyIndexVersion(), out);
376+
}
363377
IndexVersion.writeVersion(versionInfo.maxIndexVersion(), out);
364378
if (out.getTransportVersion().onOrAfter(EXTERNAL_ID_VERSION)) {
365379
out.writeString(externalId);
@@ -478,6 +492,10 @@ public IndexVersion getMinIndexVersion() {
478492
return versionInfo.minIndexVersion();
479493
}
480494

495+
public IndexVersion getMinReadOnlyIndexVersion() {
496+
return versionInfo.minReadOnlyIndexVersion();
497+
}
498+
481499
public IndexVersion getMaxIndexVersion() {
482500
return versionInfo.maxIndexVersion();
483501
}
@@ -577,6 +595,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
577595
builder.endArray();
578596
builder.field("version", versionInfo.buildVersion().toString());
579597
builder.field("min_index_version", versionInfo.minIndexVersion());
598+
builder.field("min_read_only_index_version", versionInfo.minReadOnlyIndexVersion());
580599
builder.field("max_index_version", versionInfo.maxIndexVersion());
581600
builder.endObject();
582601
return builder;

server/src/main/java/org/elasticsearch/cluster/node/DiscoveryNodes.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public class DiscoveryNodes implements Iterable<DiscoveryNode>, SimpleDiffable<D
6969
private final Version minNodeVersion;
7070
private final IndexVersion maxDataNodeCompatibleIndexVersion;
7171
private final IndexVersion minSupportedIndexVersion;
72+
private final IndexVersion minReadOnlySupportedIndexVersion;
7273

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

@@ -84,6 +85,7 @@ private DiscoveryNodes(
8485
Version minNodeVersion,
8586
IndexVersion maxDataNodeCompatibleIndexVersion,
8687
IndexVersion minSupportedIndexVersion,
88+
IndexVersion minReadOnlySupportedIndexVersion,
8789
Map<String, Set<String>> tiersToNodeIds
8890
) {
8991
this.nodeLeftGeneration = nodeLeftGeneration;
@@ -100,6 +102,8 @@ private DiscoveryNodes(
100102
this.maxNodeVersion = maxNodeVersion;
101103
this.maxDataNodeCompatibleIndexVersion = maxDataNodeCompatibleIndexVersion;
102104
this.minSupportedIndexVersion = minSupportedIndexVersion;
105+
this.minReadOnlySupportedIndexVersion = minReadOnlySupportedIndexVersion;
106+
assert minReadOnlySupportedIndexVersion.onOrBefore(minSupportedIndexVersion);
103107
assert (localNodeId == null) == (localNode == null);
104108
this.tiersToNodeIds = tiersToNodeIds;
105109
}
@@ -118,6 +122,7 @@ public DiscoveryNodes withMasterNodeId(@Nullable String masterNodeId) {
118122
minNodeVersion,
119123
maxDataNodeCompatibleIndexVersion,
120124
minSupportedIndexVersion,
125+
minReadOnlySupportedIndexVersion,
121126
tiersToNodeIds
122127
);
123128
}
@@ -374,6 +379,13 @@ public IndexVersion getMinSupportedIndexVersion() {
374379
return minSupportedIndexVersion;
375380
}
376381

382+
/**
383+
* Returns the minimum index version for read-only indices supported by all nodes in the cluster
384+
*/
385+
public IndexVersion getMinReadOnlySupportedIndexVersion() {
386+
return minReadOnlySupportedIndexVersion;
387+
}
388+
377389
/**
378390
* Return the node-left generation, which is the number of times the cluster membership has been updated by removing one or more nodes.
379391
* <p>
@@ -840,6 +852,7 @@ public DiscoveryNodes build() {
840852
Version maxNodeVersion = null;
841853
IndexVersion maxDataNodeCompatibleIndexVersion = null;
842854
IndexVersion minSupportedIndexVersion = null;
855+
IndexVersion minReadOnlySupportedIndexVersion = null;
843856
for (Map.Entry<String, DiscoveryNode> nodeEntry : nodes.entrySet()) {
844857
DiscoveryNode discoNode = nodeEntry.getValue();
845858
Version version = discoNode.getVersion();
@@ -849,6 +862,7 @@ public DiscoveryNodes build() {
849862
minNodeVersion = min(minNodeVersion, version);
850863
maxNodeVersion = max(maxNodeVersion, version);
851864
minSupportedIndexVersion = max(minSupportedIndexVersion, discoNode.getMinIndexVersion());
865+
minReadOnlySupportedIndexVersion = max(minReadOnlySupportedIndexVersion, discoNode.getMinReadOnlyIndexVersion());
852866
}
853867

854868
final long newNodeLeftGeneration;
@@ -881,6 +895,7 @@ public DiscoveryNodes build() {
881895
Objects.requireNonNullElse(minNodeVersion, Version.CURRENT.minimumCompatibilityVersion()),
882896
Objects.requireNonNullElse(maxDataNodeCompatibleIndexVersion, IndexVersion.current()),
883897
Objects.requireNonNullElse(minSupportedIndexVersion, IndexVersions.MINIMUM_COMPATIBLE),
898+
Objects.requireNonNullElse(minReadOnlySupportedIndexVersion, IndexVersions.MINIMUM_READONLY_COMPATIBLE),
884899
computeTiersToNodesMap(dataNodes)
885900
);
886901
}

server/src/main/java/org/elasticsearch/cluster/node/VersionInformation.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,42 @@
1818

1919
/**
2020
* Represents the versions of various aspects of an Elasticsearch node.
21-
* @param buildVersion The node {@link BuildVersion}
22-
* @param minIndexVersion The minimum {@link IndexVersion} supported by this node
23-
* @param maxIndexVersion The maximum {@link IndexVersion} supported by this node
21+
* @param buildVersion The node {@link BuildVersion}
22+
* @param minIndexVersion The minimum {@link IndexVersion} supported by this node
23+
* @param minReadOnlyIndexVersion The minimum {@link IndexVersion} for read-only indices supported by this node
24+
* @param maxIndexVersion The maximum {@link IndexVersion} supported by this node
2425
*/
2526
public record VersionInformation(
2627
BuildVersion buildVersion,
2728
Version nodeVersion,
2829
IndexVersion minIndexVersion,
30+
IndexVersion minReadOnlyIndexVersion,
2931
IndexVersion maxIndexVersion
3032
) {
3133

3234
public static final VersionInformation CURRENT = new VersionInformation(
3335
BuildVersion.current(),
3436
IndexVersions.MINIMUM_COMPATIBLE,
37+
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
3538
IndexVersion.current()
3639
);
3740

3841
public VersionInformation {
3942
Objects.requireNonNull(buildVersion);
4043
Objects.requireNonNull(nodeVersion);
4144
Objects.requireNonNull(minIndexVersion);
45+
Objects.requireNonNull(minReadOnlyIndexVersion);
4246
Objects.requireNonNull(maxIndexVersion);
47+
assert minReadOnlyIndexVersion.onOrBefore(minIndexVersion) : minReadOnlyIndexVersion + " > " + minIndexVersion;
4348
}
4449

45-
public VersionInformation(BuildVersion version, IndexVersion minIndexVersion, IndexVersion maxIndexVersion) {
46-
this(version, Version.CURRENT, minIndexVersion, maxIndexVersion);
50+
public VersionInformation(
51+
BuildVersion version,
52+
IndexVersion minIndexVersion,
53+
IndexVersion minReadOnlyIndexVersion,
54+
IndexVersion maxIndexVersion
55+
) {
56+
this(version, Version.CURRENT, minIndexVersion, minReadOnlyIndexVersion, maxIndexVersion);
4757
/*
4858
* Whilst DiscoveryNode.getVersion exists, we need to be able to get a Version from VersionInfo
4959
* This needs to be consistent - on serverless, BuildVersion has an id of -1, which translates
@@ -57,7 +67,17 @@ public VersionInformation(BuildVersion version, IndexVersion minIndexVersion, In
5767

5868
@Deprecated
5969
public VersionInformation(Version version, IndexVersion minIndexVersion, IndexVersion maxIndexVersion) {
60-
this(BuildVersion.fromVersionId(version.id()), version, minIndexVersion, maxIndexVersion);
70+
this(version, minIndexVersion, minIndexVersion, maxIndexVersion);
71+
}
72+
73+
@Deprecated
74+
public VersionInformation(
75+
Version version,
76+
IndexVersion minIndexVersion,
77+
IndexVersion minReadOnlyIndexVersion,
78+
IndexVersion maxIndexVersion
79+
) {
80+
this(BuildVersion.fromVersionId(version.id()), version, minIndexVersion, minReadOnlyIndexVersion, maxIndexVersion);
6181
}
6282

6383
@Deprecated

server/src/main/java/org/elasticsearch/discovery/HandshakingTransportAddressConnector.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ private void openProbeConnection(ActionListener<Transport.Connection> listener)
110110
new VersionInformation(
111111
Version.CURRENT.minimumCompatibilityVersion(),
112112
IndexVersions.MINIMUM_COMPATIBLE,
113+
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
113114
IndexVersion.current()
114115
)
115116
),

server/src/main/java/org/elasticsearch/transport/ProxyConnectionStrategy.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ public void onFailure(Exception e) {
303303
new VersionInformation(
304304
Version.CURRENT.minimumCompatibilityVersion(),
305305
IndexVersions.MINIMUM_COMPATIBLE,
306+
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
306307
IndexVersion.current()
307308
)
308309
);

server/src/main/java/org/elasticsearch/transport/SniffConnectionStrategy.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@ private static DiscoveryNode resolveSeedNode(String clusterAlias, String address
505505
var seedVersion = new VersionInformation(
506506
Version.CURRENT.minimumCompatibilityVersion(),
507507
IndexVersions.MINIMUM_COMPATIBLE,
508+
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
508509
IndexVersion.current()
509510
);
510511
if (proxyAddress == null || proxyAddress.isEmpty()) {

server/src/test/java/org/elasticsearch/action/admin/cluster/reroute/ClusterRerouteResponseTests.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ public void testToXContentWithDeprecatedClusterState() {
127127
],
128128
"version": "%s",
129129
"min_index_version": %s,
130+
"min_read_only_index_version": %s,
130131
"max_index_version": %s
131132
}
132133
},
@@ -218,6 +219,7 @@ public void testToXContentWithDeprecatedClusterState() {
218219
clusterState.getNodes().get("node0").getEphemeralId(),
219220
Version.CURRENT,
220221
IndexVersions.MINIMUM_COMPATIBLE,
222+
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
221223
IndexVersion.current(),
222224
IndexVersion.current(),
223225
IndexVersion.current()

server/src/test/java/org/elasticsearch/cluster/ClusterStateTests.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ public void testToXContent() throws IOException {
213213
],
214214
"version": "%s",
215215
"min_index_version":%s,
216+
"min_read_only_index_version":%s,
216217
"max_index_version":%s
217218
}
218219
},
@@ -389,6 +390,7 @@ public void testToXContent() throws IOException {
389390
ephemeralId,
390391
Version.CURRENT,
391392
IndexVersions.MINIMUM_COMPATIBLE,
393+
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
392394
IndexVersion.current(),
393395
TransportVersion.current(),
394396
IndexVersion.current(),
@@ -488,6 +490,7 @@ public void testToXContent_FlatSettingTrue_ReduceMappingFalse() throws IOExcepti
488490
],
489491
"version" : "%s",
490492
"min_index_version" : %s,
493+
"min_read_only_index_version" : %s,
491494
"max_index_version" : %s
492495
}
493496
},
@@ -663,6 +666,7 @@ public void testToXContent_FlatSettingTrue_ReduceMappingFalse() throws IOExcepti
663666
ephemeralId,
664667
Version.CURRENT,
665668
IndexVersions.MINIMUM_COMPATIBLE,
669+
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
666670
IndexVersion.current(),
667671
TransportVersion.current(),
668672
IndexVersion.current(),
@@ -762,6 +766,7 @@ public void testToXContent_FlatSettingFalse_ReduceMappingTrue() throws IOExcepti
762766
],
763767
"version" : "%s",
764768
"min_index_version" : %s,
769+
"min_read_only_index_version" : %s,
765770
"max_index_version" : %s
766771
}
767772
},
@@ -943,6 +948,7 @@ public void testToXContent_FlatSettingFalse_ReduceMappingTrue() throws IOExcepti
943948
ephemeralId,
944949
Version.CURRENT,
945950
IndexVersions.MINIMUM_COMPATIBLE,
951+
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
946952
IndexVersion.current(),
947953
TransportVersion.current(),
948954
IndexVersion.current(),

server/src/test/java/org/elasticsearch/cluster/node/DiscoveryNodeTests.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import static java.util.Collections.emptySet;
3232
import static org.elasticsearch.test.NodeRoles.nonRemoteClusterClientNode;
3333
import static org.elasticsearch.test.NodeRoles.remoteClusterClientNode;
34+
import static org.elasticsearch.test.TransportVersionUtils.getPreviousVersion;
35+
import static org.elasticsearch.test.TransportVersionUtils.randomVersionBetween;
3436
import static org.hamcrest.Matchers.allOf;
3537
import static org.hamcrest.Matchers.containsString;
3638
import static org.hamcrest.Matchers.equalTo;
@@ -221,13 +223,15 @@ public void testDiscoveryNodeToXContent() {
221223
],
222224
"version" : "%s",
223225
"min_index_version" : %s,
226+
"min_read_only_index_version" : %s,
224227
"max_index_version" : %s
225228
}
226229
}""",
227230
transportAddress,
228231
withExternalId ? "test-external-id" : "test-name",
229232
Version.CURRENT,
230233
IndexVersions.MINIMUM_COMPATIBLE,
234+
IndexVersions.MINIMUM_READONLY_COMPATIBLE,
231235
IndexVersion.current()
232236
)
233237
)
@@ -250,4 +254,61 @@ public void testDiscoveryNodeToString() {
250254
assertThat(toString, containsString("{" + node.getBuildVersion() + "}"));
251255
assertThat(toString, containsString("{test-attr=val}"));// attributes
252256
}
257+
258+
public void testDiscoveryNodeMinReadOnlyVersionSerialization() throws Exception {
259+
var node = DiscoveryNodeUtils.create("_id", buildNewFakeTransportAddress(), VersionInformation.CURRENT);
260+
261+
{
262+
try (var out = new BytesStreamOutput()) {
263+
out.setTransportVersion(TransportVersion.current());
264+
node.writeTo(out);
265+
266+
try (var in = StreamInput.wrap(out.bytes().array())) {
267+
in.setTransportVersion(TransportVersion.current());
268+
269+
var deserialized = new DiscoveryNode(in);
270+
assertThat(deserialized.getId(), equalTo(node.getId()));
271+
assertThat(deserialized.getAddress(), equalTo(node.getAddress()));
272+
assertThat(deserialized.getMinIndexVersion(), equalTo(node.getMinIndexVersion()));
273+
assertThat(deserialized.getMaxIndexVersion(), equalTo(node.getMaxIndexVersion()));
274+
assertThat(deserialized.getMinReadOnlyIndexVersion(), equalTo(node.getMinReadOnlyIndexVersion()));
275+
assertThat(deserialized.getVersionInformation(), equalTo(node.getVersionInformation()));
276+
}
277+
}
278+
}
279+
280+
{
281+
var oldVersion = randomVersionBetween(
282+
random(),
283+
TransportVersions.MINIMUM_COMPATIBLE,
284+
getPreviousVersion(TransportVersions.NODE_VERSION_INFORMATION_WITH_MIN_READ_ONLY_INDEX_VERSION)
285+
);
286+
try (var out = new BytesStreamOutput()) {
287+
out.setTransportVersion(oldVersion);
288+
node.writeTo(out);
289+
290+
try (var in = StreamInput.wrap(out.bytes().array())) {
291+
in.setTransportVersion(oldVersion);
292+
293+
var deserialized = new DiscoveryNode(in);
294+
assertThat(deserialized.getId(), equalTo(node.getId()));
295+
assertThat(deserialized.getAddress(), equalTo(node.getAddress()));
296+
assertThat(deserialized.getMinIndexVersion(), equalTo(node.getMinIndexVersion()));
297+
assertThat(deserialized.getMaxIndexVersion(), equalTo(node.getMaxIndexVersion()));
298+
assertThat(deserialized.getMinReadOnlyIndexVersion(), equalTo(node.getMinIndexVersion()));
299+
assertThat(
300+
deserialized.getVersionInformation(),
301+
equalTo(
302+
new VersionInformation(
303+
node.getBuildVersion(),
304+
node.getMinIndexVersion(),
305+
node.getMinIndexVersion(),
306+
node.getMaxIndexVersion()
307+
)
308+
)
309+
);
310+
}
311+
}
312+
}
313+
}
253314
}

0 commit comments

Comments
 (0)