diff --git a/presto-common/src/main/java/com/facebook/presto/common/PrestoVersion.java b/presto-common/src/main/java/com/facebook/presto/common/PrestoVersion.java new file mode 100644 index 0000000000000..53d7087a8d1b1 --- /dev/null +++ b/presto-common/src/main/java/com/facebook/presto/common/PrestoVersion.java @@ -0,0 +1,121 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.common; + +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.util.Objects.requireNonNull; + +public class PrestoVersion + implements Comparable +{ + private static final Pattern VERSION_REGEX = Pattern.compile("^(?0|[1-9]\\d*)\\.(?0|[1-9]\\d*)(\\.(?0|[1-9]\\d*))?(?:-(?(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+(?[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"); + + private int majorVersion; + private int minorVersion; + private int patchVersion; + private String prereleaseVersion = ""; + private String version; + + public PrestoVersion(String version) + { + this.version = requireNonNull(version, "version string is null"); + Matcher matcher = VERSION_REGEX.matcher(version); + if (matcher.find()) { + this.majorVersion = Integer.parseInt(Optional.ofNullable(matcher.group("major")).orElse("0")); + this.minorVersion = Integer.parseInt(Optional.ofNullable(matcher.group("minor")).orElse("0")); + this.patchVersion = Integer.parseInt(Optional.ofNullable(matcher.group("patch")).orElse("0")); + this.prereleaseVersion = Optional.ofNullable(matcher.group("prerelease")).orElse(""); + } + } + + public String getVersion() + { + return version; + } + + @Override + public int hashCode() + { + return Objects.hash(this.majorVersion, this.minorVersion, this.patchVersion, this.prereleaseVersion); + } + + @Override + public boolean equals(Object version) + { + if (this == version) { + return true; + } + if (version == null || !(version instanceof PrestoVersion)) { + return false; + } + PrestoVersion prestoVersion = (PrestoVersion) version; + return (Objects.equals(this.majorVersion, prestoVersion.majorVersion) + && Objects.equals(this.minorVersion, prestoVersion.minorVersion) + && Objects.equals(this.patchVersion, prestoVersion.patchVersion) + && Objects.equals(this.prereleaseVersion, prestoVersion.prereleaseVersion)); + } + + @Override + public int compareTo(PrestoVersion prestoVersion) + { + if (this.majorVersion != prestoVersion.majorVersion) { + return Integer.compare(this.majorVersion, prestoVersion.majorVersion); + } + if (this.minorVersion != prestoVersion.minorVersion) { + return Integer.compare(this.minorVersion, prestoVersion.minorVersion); + } + if (this.patchVersion != prestoVersion.patchVersion) { + return Integer.compare(this.patchVersion, prestoVersion.patchVersion); + } + if (!(this.prereleaseVersion.equals(prestoVersion.prereleaseVersion))) { + if (prestoVersion.prereleaseVersion.isEmpty()) { + return -1; + } + if (this.prereleaseVersion.isEmpty()) { + return 1; + } + return this.prereleaseVersion.compareTo(prestoVersion.prereleaseVersion); + } + return 0; + } + + public boolean equalTo(PrestoVersion prestoVersion) + { + return this.compareTo(prestoVersion) == 0; + } + + public boolean greaterThan(PrestoVersion prestoVersion) + { + return this.compareTo(prestoVersion) > 0; + } + + public boolean lessThan(PrestoVersion prestoVersion) + { + return this.compareTo(prestoVersion) < 0; + } + + public boolean greaterThanOrEqualTo(PrestoVersion prestoVersion) + { + return this.compareTo(prestoVersion) >= 0; + } + + public boolean lessThanOrEqualTo(PrestoVersion prestoVersion) + { + return this.compareTo(prestoVersion) <= 0; + } +} diff --git a/presto-common/src/test/java/com/facebook/presto/common/TestPrestoVersion.java b/presto-common/src/test/java/com/facebook/presto/common/TestPrestoVersion.java new file mode 100644 index 0000000000000..48601cd6bf376 --- /dev/null +++ b/presto-common/src/test/java/com/facebook/presto/common/TestPrestoVersion.java @@ -0,0 +1,122 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.facebook.presto.common; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +public class TestPrestoVersion +{ + private static final PrestoVersion VERSION_274_20220517_171619_22 = new PrestoVersion("0.274-20220517.171619-22"); + private static final PrestoVersion VERSION_274_20220518_025123_29 = new PrestoVersion("0.274-20220518.025123-29"); + private static final PrestoVersion VERSION_274_SNAPSHOT_5d0ba93 = new PrestoVersion("0.274-SNAPSHOT-5d0ba93"); + private static final PrestoVersion VERSION_273 = new PrestoVersion("0.273"); + private static final PrestoVersion VERSION_274 = new PrestoVersion("0.274"); + private static final PrestoVersion VERSION_274_1 = new PrestoVersion("0.274.1"); + private static final PrestoVersion VERSION_274_2 = new PrestoVersion("0.274.2"); + + @Test + public void testPrestoEquals() + { + assertTrue(VERSION_274_20220517_171619_22.equals(VERSION_274_20220517_171619_22)); + assertTrue(VERSION_274_1.equals(new PrestoVersion("0.274.1"))); + assertFalse(VERSION_274_1.equals(VERSION_274)); + assertFalse(VERSION_274_20220517_171619_22.equals(null)); + } + + @Test + public void testLessThan() + { + //Comparing major versions + assertFalse(VERSION_274_1.lessThan(VERSION_273)); + + // Comparing Snapshot and non-Snapshot versions + assertTrue(VERSION_274_20220517_171619_22.lessThan(VERSION_274)); + assertTrue(VERSION_274_SNAPSHOT_5d0ba93.lessThan(VERSION_274)); + assertTrue(VERSION_274_SNAPSHOT_5d0ba93.lessThan(VERSION_274_1)); + + //Comparing snapshot versions + assertFalse(VERSION_274_20220518_025123_29.lessThan(VERSION_274_20220517_171619_22)); + + // Comparing equal versions + assertFalse(VERSION_274_SNAPSHOT_5d0ba93.lessThan(VERSION_274_SNAPSHOT_5d0ba93)); + + // Comparing major and minor versions + assertTrue(VERSION_274.lessThan(VERSION_274_1)); + assertFalse(VERSION_274_1.lessThan(VERSION_274)); + + //comparing minor versions + assertFalse(VERSION_274_2.lessThan(VERSION_274_1)); + } + + @Test + public void testLessThanOrEqualTo() + { + assertTrue(VERSION_274_20220517_171619_22.lessThanOrEqualTo(VERSION_274)); + assertTrue(VERSION_274_SNAPSHOT_5d0ba93.lessThanOrEqualTo(VERSION_274)); + assertTrue(VERSION_274.lessThanOrEqualTo(VERSION_274_1)); + assertTrue(VERSION_274_SNAPSHOT_5d0ba93.lessThanOrEqualTo(VERSION_274_1)); + + //The following values should be equal + assertTrue(VERSION_274_SNAPSHOT_5d0ba93.lessThanOrEqualTo(VERSION_274_SNAPSHOT_5d0ba93)); + assertTrue(VERSION_274.lessThanOrEqualTo(VERSION_274)); + } + + @Test + public void testGreaterThanOrEqualTo() + { + assertTrue(VERSION_274.greaterThanOrEqualTo(VERSION_274_20220517_171619_22)); + assertTrue(VERSION_274.greaterThanOrEqualTo(VERSION_274_SNAPSHOT_5d0ba93)); + assertTrue(VERSION_274_1.greaterThanOrEqualTo(VERSION_274)); + assertTrue(VERSION_274_1.greaterThanOrEqualTo(VERSION_274_SNAPSHOT_5d0ba93)); + + //The following values should be equal + assertTrue(VERSION_274_SNAPSHOT_5d0ba93.greaterThanOrEqualTo(VERSION_274_SNAPSHOT_5d0ba93)); + assertTrue(VERSION_274.greaterThanOrEqualTo(VERSION_274)); + } + + @Test + public void testGreaterThan() + { + //Comparing major versions + assertTrue(VERSION_274_1.greaterThan(VERSION_273)); + + // Comparing Snapshot and non-Snapshot versions + assertTrue(VERSION_274.greaterThan(VERSION_274_20220517_171619_22)); + assertFalse(VERSION_274_20220517_171619_22.greaterThan(VERSION_274)); + assertFalse(VERSION_274_SNAPSHOT_5d0ba93.greaterThan(VERSION_274)); + assertFalse(VERSION_274_SNAPSHOT_5d0ba93.greaterThan(VERSION_274_1)); + + //Comparing snapshot versions + assertFalse(VERSION_274_20220517_171619_22.greaterThan(VERSION_274_20220518_025123_29)); + assertTrue(VERSION_274_20220518_025123_29.greaterThan(VERSION_274_20220517_171619_22)); + + // Comparing equal versions + assertFalse(VERSION_274_SNAPSHOT_5d0ba93.greaterThan(VERSION_274_SNAPSHOT_5d0ba93)); + + // Comparing major and minor versions + assertFalse(VERSION_274.greaterThan(VERSION_274_1)); + assertTrue(VERSION_274_1.greaterThan(VERSION_274)); + } + + @Test + public void testVersionValidity() + { + PrestoVersion minVersion = new PrestoVersion("0.282"); + PrestoVersion maxVersion = new PrestoVersion("0.292"); + assertFalse(minVersion.lessThanOrEqualTo(VERSION_274_20220517_171619_22) && maxVersion.greaterThanOrEqualTo(VERSION_274_20220517_171619_22)); + } +} diff --git a/presto-session-property-managers/pom.xml b/presto-session-property-managers/pom.xml index a69fbf39fba3d..1b19527e243b5 100644 --- a/presto-session-property-managers/pom.xml +++ b/presto-session-property-managers/pom.xml @@ -75,18 +75,41 @@ provided + + com.facebook.presto + presto-client + + + + com.facebook.drift + drift-api + provided + + io.airlift units provided + + io.airlift + slice + provided + + com.fasterxml.jackson.core jackson-annotations provided + + org.openjdk.jol + jol-core + provided + + com.facebook.presto @@ -105,5 +128,9 @@ testing test + + com.facebook.presto + presto-main + diff --git a/presto-session-property-managers/src/main/java/com/facebook/presto/session/FileSessionPropertyManager.java b/presto-session-property-managers/src/main/java/com/facebook/presto/session/FileSessionPropertyManager.java index d6402324050bf..079efc1cf0bf8 100644 --- a/presto-session-property-managers/src/main/java/com/facebook/presto/session/FileSessionPropertyManager.java +++ b/presto-session-property-managers/src/main/java/com/facebook/presto/session/FileSessionPropertyManager.java @@ -16,6 +16,8 @@ import com.facebook.airlift.json.JsonCodec; import com.facebook.airlift.json.JsonCodecFactory; import com.facebook.airlift.json.JsonObjectMapperProvider; +import com.facebook.presto.client.NodeVersion; +import com.facebook.presto.common.PrestoVersion; import com.facebook.presto.spi.session.SessionConfigurationContext; import com.facebook.presto.spi.session.SessionPropertyConfigurationManager; import com.fasterxml.jackson.databind.JsonMappingException; @@ -46,11 +48,13 @@ public class FileSessionPropertyManager .listJsonCodec(SessionMatchSpec.class); private final List sessionMatchSpecs; + private final PrestoVersion prestoVersion; @Inject - public FileSessionPropertyManager(FileSessionPropertyManagerConfig config) + public FileSessionPropertyManager(FileSessionPropertyManagerConfig config, NodeVersion nodeVersion) { requireNonNull(config, "config is null"); + this.prestoVersion = new PrestoVersion(nodeVersion.getVersion()); Path configurationFile = config.getConfigFile().toPath(); try { @@ -87,7 +91,7 @@ public SystemSessionPropertyConfiguration getSystemSessionProperties(SessionConf Map defaultProperties = new HashMap<>(); Set overridePropertyNames = new HashSet<>(); for (SessionMatchSpec sessionMatchSpec : sessionMatchSpecs) { - Map newProperties = sessionMatchSpec.match(context); + Map newProperties = sessionMatchSpec.match(context, this.prestoVersion); defaultProperties.putAll(newProperties); if (sessionMatchSpec.getOverrideSessionProperties().orElse(false)) { overridePropertyNames.addAll(newProperties.keySet()); diff --git a/presto-session-property-managers/src/main/java/com/facebook/presto/session/FileSessionPropertyManagerModule.java b/presto-session-property-managers/src/main/java/com/facebook/presto/session/FileSessionPropertyManagerModule.java index 03fee8d5207dc..ec02d69b0154a 100644 --- a/presto-session-property-managers/src/main/java/com/facebook/presto/session/FileSessionPropertyManagerModule.java +++ b/presto-session-property-managers/src/main/java/com/facebook/presto/session/FileSessionPropertyManagerModule.java @@ -13,19 +13,25 @@ */ package com.facebook.presto.session; +import com.facebook.airlift.configuration.AbstractConfigurationAwareModule; +import com.facebook.presto.client.NodeVersion; +import com.facebook.presto.server.ServerConfig; import com.google.inject.Binder; -import com.google.inject.Module; import com.google.inject.Scopes; import static com.facebook.airlift.configuration.ConfigBinder.configBinder; public class FileSessionPropertyManagerModule - implements Module + extends AbstractConfigurationAwareModule { @Override - public void configure(Binder binder) + public void setup(Binder binder) { configBinder(binder).bindConfig(FileSessionPropertyManagerConfig.class); binder.bind(FileSessionPropertyManager.class).in(Scopes.SINGLETON); + + ServerConfig serverConfig = buildConfigObject(ServerConfig.class); + NodeVersion nodeVersion = new NodeVersion(serverConfig.getPrestoVersion()); + binder.bind(NodeVersion.class).toInstance(nodeVersion); } } diff --git a/presto-session-property-managers/src/main/java/com/facebook/presto/session/SessionMatchSpec.java b/presto-session-property-managers/src/main/java/com/facebook/presto/session/SessionMatchSpec.java index 18f34a80adf9d..94d53c9b26311 100644 --- a/presto-session-property-managers/src/main/java/com/facebook/presto/session/SessionMatchSpec.java +++ b/presto-session-property-managers/src/main/java/com/facebook/presto/session/SessionMatchSpec.java @@ -13,6 +13,7 @@ */ package com.facebook.presto.session; +import com.facebook.presto.common.PrestoVersion; import com.facebook.presto.spi.resourceGroups.ResourceGroupId; import com.facebook.presto.spi.session.SessionConfigurationContext; import com.fasterxml.jackson.annotation.JsonCreator; @@ -39,6 +40,8 @@ public class SessionMatchSpec private final Optional resourceGroupRegex; private final Optional overrideSessionProperties; private final Map sessionProperties; + private final Optional minVersion; + private final Optional maxVersion; @JsonCreator public SessionMatchSpec( @@ -49,10 +52,16 @@ public SessionMatchSpec( @JsonProperty("group") Optional resourceGroupRegex, @JsonProperty("clientInfo") Optional clientInfoRegex, @JsonProperty("overrideSessionProperties") Optional overrideSessionProperties, - @JsonProperty("sessionProperties") Map sessionProperties) + @JsonProperty("sessionProperties") Map sessionProperties, + @JsonProperty("minVersion") Optional minVersion, + @JsonProperty("maxVersion") Optional maxVersion) { this.userRegex = requireNonNull(userRegex, "userRegex is null"); this.sourceRegex = requireNonNull(sourceRegex, "sourceRegex is null"); + requireNonNull(minVersion, "Min version is null"); + requireNonNull(maxVersion, "Max version is null"); + this.minVersion = minVersion.map(PrestoVersion::new); + this.maxVersion = maxVersion.map(PrestoVersion::new); requireNonNull(clientTags, "clientTags is null"); this.clientTags = ImmutableSet.copyOf(clientTags.orElse(ImmutableList.of())); this.queryType = requireNonNull(queryType, "queryType is null"); @@ -63,7 +72,7 @@ public SessionMatchSpec( this.sessionProperties = ImmutableMap.copyOf(sessionProperties); } - public Map match(SessionConfigurationContext context) + public Map match(SessionConfigurationContext context, PrestoVersion coordinatorVersion) { if (userRegex.isPresent() && !userRegex.get().matcher(context.getUser()).matches()) { return ImmutableMap.of(); @@ -99,6 +108,18 @@ public Map match(SessionConfigurationContext context) } } + if (maxVersion.isPresent() || minVersion.isPresent()) { + boolean validVersion = true; + if (maxVersion.isPresent()) { + validVersion = coordinatorVersion.lessThanOrEqualTo(maxVersion.get()); + } + if (minVersion.isPresent()) { + validVersion = validVersion && coordinatorVersion.greaterThanOrEqualTo(minVersion.get()); + } + if (!validVersion) { + return ImmutableMap.of(); + } + } return sessionProperties; } diff --git a/presto-session-property-managers/src/test/java/com/facebook/presto/session/TestFileSessionPropertyManager.java b/presto-session-property-managers/src/test/java/com/facebook/presto/session/TestFileSessionPropertyManager.java index 70312096bcca1..329ee5b0a1b78 100644 --- a/presto-session-property-managers/src/test/java/com/facebook/presto/session/TestFileSessionPropertyManager.java +++ b/presto-session-property-managers/src/test/java/com/facebook/presto/session/TestFileSessionPropertyManager.java @@ -15,6 +15,7 @@ package com.facebook.presto.session; import com.facebook.airlift.testing.TempFile; +import com.facebook.presto.client.NodeVersion; import com.facebook.presto.spi.resourceGroups.QueryType; import com.facebook.presto.spi.resourceGroups.ResourceGroupId; import com.facebook.presto.spi.session.SessionConfigurationContext; @@ -59,7 +60,9 @@ public void testResourceGroupMatch() Optional.of(Pattern.compile("global.pipeline.user_.*")), Optional.empty(), Optional.empty(), - properties); + properties, + Optional.empty(), + Optional.empty()); assertProperties(properties, spec); } @@ -77,7 +80,9 @@ public void testClientTagMatch() Optional.empty(), Optional.empty(), Optional.empty(), - properties); + properties, + Optional.empty(), + Optional.empty()); assertProperties(properties, spec); } @@ -94,7 +99,9 @@ public void testMultipleMatch() Optional.empty(), Optional.empty(), Optional.empty(), - ImmutableMap.of("PROPERTY1", "VALUE1")); + ImmutableMap.of("PROPERTY1", "VALUE1"), + Optional.of("0.271"), + Optional.empty()); SessionMatchSpec spec2 = new SessionMatchSpec( Optional.empty(), Optional.empty(), @@ -103,7 +110,9 @@ public void testMultipleMatch() Optional.empty(), Optional.empty(), Optional.empty(), - ImmutableMap.of("PROPERTY1", "VALUE1", "PROPERTY2", "VALUE2")); + ImmutableMap.of("PROPERTY1", "VALUE1", "PROPERTY2", "VALUE2"), + Optional.of("0.221"), + Optional.of("0.281")); assertProperties(ImmutableMap.of("PROPERTY1", "VALUE1", "PROPERTY2", "VALUE2"), spec1, spec2); } @@ -120,7 +129,9 @@ public void testNoMatch() Optional.of(Pattern.compile("global.interactive.user_.*")), Optional.empty(), Optional.empty(), - ImmutableMap.of("PROPERTY", "VALUE")); + ImmutableMap.of("PROPERTY", "VALUE"), + Optional.empty(), + Optional.empty()); assertProperties(ImmutableMap.of(), spec); } @@ -138,7 +149,9 @@ public void testClientInfoMatch() Optional.empty(), Optional.of(Pattern.compile("bar")), Optional.empty(), - properties); + properties, + Optional.empty(), + Optional.empty()); assertProperties(properties, spec); } @@ -158,7 +171,9 @@ public void testOverride() Optional.empty(), Optional.of(Pattern.compile("bar")), Optional.of(true), - overrideProperties); + overrideProperties, + Optional.of("0.272"), + Optional.empty()); SessionMatchSpec specDefault = new SessionMatchSpec( Optional.empty(), @@ -168,7 +183,9 @@ public void testOverride() Optional.empty(), Optional.of(Pattern.compile("bar")), Optional.empty(), - defaultProperties); + defaultProperties, + Optional.empty(), + Optional.empty()); // PROPERTY1 should be an override property with the value from the default (non-override, higher precedence) // spec. @@ -188,7 +205,7 @@ private static void assertProperties(Map defaultProperties, Map< try (TempFile tempFile = new TempFile()) { Path configurationFile = tempFile.path(); Files.write(configurationFile, CODEC.toJsonBytes(Arrays.asList(spec))); - SessionPropertyConfigurationManager manager = new FileSessionPropertyManager(new FileSessionPropertyManagerConfig().setConfigFile(configurationFile.toFile())); + SessionPropertyConfigurationManager manager = new FileSessionPropertyManager(new FileSessionPropertyManagerConfig().setConfigFile(configurationFile.toFile()), new NodeVersion("0.271")); SystemSessionPropertyConfiguration propertyConfiguration = manager.getSystemSessionProperties(CONTEXT); assertEquals(propertyConfiguration.systemPropertyDefaults, defaultProperties); assertEquals(propertyConfiguration.systemPropertyOverrides, overrideProperties);