Skip to content

Commit

Permalink
Remove more uses of Version#minimumCompatibilityVersion (elastic#99988)
Browse files Browse the repository at this point in the history
* Remove more uses of Version#minimumCompatibilityVersion
* Avoid mixing use of wire compat and index compat versions
  • Loading branch information
williamrandolph authored Oct 4, 2023
1 parent 061c3e7 commit 60daef3
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void testToXContent() throws IOException {
build.date(),
build.isSnapshot(),
indexVersion.luceneVersion().toString(),
version.minimumCompatibilityVersion().toString(),
build.minWireCompatVersion(),
Build.minimumCompatString(IndexVersion.MINIMUM_COMPATIBLE)
)
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

package org.elasticsearch.indices;

import org.elasticsearch.Build;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.common.Strings;
Expand Down Expand Up @@ -51,7 +52,7 @@ public class TestSystemIndexDescriptor extends SystemIndexDescriptor {
0,
"version",
"stack",
Version.CURRENT.minimumCompatibilityVersion(),
Version.fromString(Build.current().minWireCompatVersion()),
Type.INTERNAL_MANAGED,
List.of(),
List.of(),
Expand All @@ -72,7 +73,7 @@ public class TestSystemIndexDescriptor extends SystemIndexDescriptor {
0,
"version",
"stack",
Version.CURRENT.minimumCompatibilityVersion(),
Version.fromString(Build.current().minWireCompatVersion()),
Type.INTERNAL_MANAGED,
List.of(),
List.of(),
Expand Down
36 changes: 34 additions & 2 deletions server/src/main/java/org/elasticsearch/env/NodeEnvironment.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand Down Expand Up @@ -525,19 +527,21 @@ static void checkForIndexCompatibility(Logger logger, DataPath... dataPaths) thr
logger.info("oldest index version recorded in NodeMetadata {}", metadata.oldestIndexVersion());

if (metadata.oldestIndexVersion().isLegacyIndexVersion()) {

String bestDowngradeVersion = getBestDowngradeVersion(metadata.previousNodeVersion().toString());
throw new IllegalStateException(
"Cannot start this node because it holds metadata for indices with version ["
+ metadata.oldestIndexVersion()
+ "] with which this node of version ["
+ Build.current().version()
+ "] is incompatible. Revert this node to version ["
+ Version.max(Version.CURRENT.minimumCompatibilityVersion(), metadata.previousNodeVersion())
+ bestDowngradeVersion
+ "] and delete any indices with versions earlier than ["
+ IndexVersion.MINIMUM_COMPATIBLE
+ "] before upgrading to version ["
+ Build.current().version()
+ "]. If all such indices have already been deleted, revert this node to version ["
+ Version.max(Version.CURRENT.minimumCompatibilityVersion(), metadata.previousNodeVersion())
+ bestDowngradeVersion
+ "] and wait for it to join the cluster to clean up any older indices from its metadata."
);
}
Expand Down Expand Up @@ -1505,4 +1509,32 @@ private static void tryWriteTempFile(Path path) throws IOException {
}
}
}

/**
* Get a useful version string to direct a user's downgrade operation
*
* <p>If a user is trying to install 8.0 but has incompatible indices, the user should
* downgrade to 7.17.x. We return 7.17.0, unless the user is trying to upgrade from
* a 7.17.x release, in which case we return the last installed version.
* @return Version to downgrade to
*/
// visible for testing
static String getBestDowngradeVersion(String previousNodeVersion) {
// this method should only be called in the context of an upgrade to 8.x
assert Build.current().version().startsWith("9.") == false;
Pattern pattern = Pattern.compile("^7\\.(\\d+)\\.\\d+$");
Matcher matcher = pattern.matcher(previousNodeVersion);
if (matcher.matches()) {
try {
int minorVersion = Integer.parseInt(matcher.group(1));
if (minorVersion >= 17) {
return previousNodeVersion;
}
} catch (NumberFormatException e) {
// continue and return default
}
}
return "7.17.0";
}

}
19 changes: 18 additions & 1 deletion server/src/main/java/org/elasticsearch/env/NodeMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public void verifyUpgradeToCurrentVersion() {
assert (nodeVersion.equals(Version.V_EMPTY) == false) || (Version.CURRENT.major <= Version.V_7_0_0.major + 1)
: "version is required in the node metadata from v9 onwards";

if (nodeVersion.before(Version.CURRENT.minimumCompatibilityVersion())) {
if (NodeMetadata.isNodeVersionWireCompatible(nodeVersion.toString()) == false) {
throw new IllegalStateException(
"cannot upgrade a node from version ["
+ nodeVersion
Expand Down Expand Up @@ -220,4 +220,21 @@ public NodeMetadata fromXContent(XContentParser parser) throws IOException {
}

public static final MetadataStateFormat<NodeMetadata> FORMAT = new NodeMetadataStateFormat(false);

/**
* Check whether a node version is compatible with the current minimum transport version.
* @param version A version identifier as a string
* @throws IllegalArgumentException if version is not a valid transport version identifier
* @return true if the version is compatible, false otherwise
*/
// visible for testing
static boolean isNodeVersionWireCompatible(String version) {
try {
Version esVersion = Version.fromString(version);
return esVersion.onOrAfter(Version.CURRENT.minimumCompatibilityVersion());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Cannot parse [" + version + "] as a transport version identifier", e);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.elasticsearch.test.MockLogAppender;
import org.elasticsearch.test.NodeRoles;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.hamcrest.Matchers;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -636,6 +637,20 @@ public void testSymlinkDataDirectory() throws Exception {
env.close();
}

public void testGetBestDowngradeVersion() {
assertThat(NodeEnvironment.getBestDowngradeVersion("7.17.0"), Matchers.equalTo("7.17.0"));
assertThat(NodeEnvironment.getBestDowngradeVersion("7.17.5"), Matchers.equalTo("7.17.5"));
assertThat(NodeEnvironment.getBestDowngradeVersion("7.17.1234"), Matchers.equalTo("7.17.1234"));
assertThat(NodeEnvironment.getBestDowngradeVersion("7.18.0"), Matchers.equalTo("7.18.0"));
assertThat(NodeEnvironment.getBestDowngradeVersion("7.17.x"), Matchers.equalTo("7.17.0"));
assertThat(NodeEnvironment.getBestDowngradeVersion("7.17.5-SNAPSHOT"), Matchers.equalTo("7.17.0"));
assertThat(NodeEnvironment.getBestDowngradeVersion("7.17.6b"), Matchers.equalTo("7.17.0"));
assertThat(NodeEnvironment.getBestDowngradeVersion("7.16.0"), Matchers.equalTo("7.17.0"));
// when we get to version 7.2147483648.0 we will have to rethink our approach, but for now we return 7.17.0 with an integer overflow
assertThat(NodeEnvironment.getBestDowngradeVersion("7." + Integer.MAX_VALUE + "0.0"), Matchers.equalTo("7.17.0"));
assertThat(NodeEnvironment.getBestDowngradeVersion("foo"), Matchers.equalTo("7.17.0"));
}

private void verifyFailsOnShardData(Settings settings, Path indexPath, String shardDataDirName) {
IllegalStateException ex = expectThrows(
IllegalStateException.class,
Expand Down
18 changes: 18 additions & 0 deletions server/src/test/java/org/elasticsearch/env/NodeMetadataTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.elasticsearch.index.IndexVersion;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.EqualsHashCodeTestUtils;
import org.elasticsearch.test.TransportVersionUtils;
import org.elasticsearch.test.VersionUtils;
import org.elasticsearch.test.index.IndexVersionUtils;

Expand Down Expand Up @@ -158,6 +159,23 @@ public void testUpgradeMarksPreviousVersion() {
assertThat(nodeMetadata.previousNodeVersion(), equalTo(version));
}

public void testIsNodeVersionWireCompatible() {
String nodeVersion = VersionUtils.randomCompatibleVersion(random(), Version.CURRENT).toString();
assertTrue(NodeMetadata.isNodeVersionWireCompatible(nodeVersion));
nodeVersion = VersionUtils.getPreviousVersion(Version.CURRENT.minimumCompatibilityVersion()).toString();
assertFalse(NodeMetadata.isNodeVersionWireCompatible(nodeVersion));

String transportVersion = TransportVersionUtils.randomCompatibleVersion(random()).toString();
IllegalArgumentException e1 = expectThrows(
IllegalArgumentException.class,
() -> NodeMetadata.isNodeVersionWireCompatible(transportVersion)
);
assertThat(e1.getMessage(), equalTo("Cannot parse [" + transportVersion + "] as a transport version identifier"));

IllegalArgumentException e2 = expectThrows(IllegalArgumentException.class, () -> NodeMetadata.isNodeVersionWireCompatible("x.y.z"));
assertThat(e2.getMessage(), equalTo("Cannot parse [x.y.z] as a transport version identifier"));
}

public static Version tooNewVersion() {
return Version.fromId(between(Version.CURRENT.id + 1, 99999999));
}
Expand Down

0 comments on commit 60daef3

Please sign in to comment.