From 52c5923358c0d3042524e841e685ae45bf117d0a Mon Sep 17 00:00:00 2001 From: Patryk Owczarek Date: Mon, 22 Jul 2024 09:31:00 +0200 Subject: [PATCH] Inject execution interceptors using multibinder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GlueMetastoreModule is not truly following the inversion of control paradigm. Many things are created directly in the methods without using injection. Using set multibinder for execution interceptors allows to independently define execution interceptors and use Guice injection. Co-authored-by: Grzegorz KokosiƄski --- .../metastore/glue/ForGlueHiveMetastore.java | 29 +++++++++++++ .../glue/GlueHiveExecutionInterceptor.java | 6 ++- .../metastore/glue/GlueMetastoreModule.java | 41 ++++++++++++++++--- .../hive/TestHiveGlueMetadataListing.java | 4 +- ...veConcurrentModificationGlueMetastore.java | 4 +- .../glue/TestingGlueHiveMetastore.java | 4 +- 6 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/ForGlueHiveMetastore.java diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/ForGlueHiveMetastore.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/ForGlueHiveMetastore.java new file mode 100644 index 00000000000..bb718759adf --- /dev/null +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/ForGlueHiveMetastore.java @@ -0,0 +1,29 @@ +/* + * 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 io.trino.plugin.hive.metastore.glue; + +import com.google.inject.BindingAnnotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Retention(RUNTIME) +@Target({FIELD, PARAMETER, METHOD}) +@BindingAnnotation +public @interface ForGlueHiveMetastore {} diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/GlueHiveExecutionInterceptor.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/GlueHiveExecutionInterceptor.java index 5dd7417dfd8..28ce1eb3a10 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/GlueHiveExecutionInterceptor.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/GlueHiveExecutionInterceptor.java @@ -13,6 +13,7 @@ */ package io.trino.plugin.hive.metastore.glue; +import jakarta.inject.Inject; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; @@ -24,9 +25,10 @@ public class GlueHiveExecutionInterceptor { private final boolean skipArchive; - GlueHiveExecutionInterceptor(boolean isSkipArchive) + @Inject + GlueHiveExecutionInterceptor(GlueHiveMetastoreConfig config) { - this.skipArchive = isSkipArchive; + this.skipArchive = config.isSkipArchive(); } @Override diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/GlueMetastoreModule.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/GlueMetastoreModule.java index 8c04a29ff7b..584ad46efe9 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/GlueMetastoreModule.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/glue/GlueMetastoreModule.java @@ -13,11 +13,15 @@ */ package io.trino.plugin.hive.metastore.glue; +import com.google.common.collect.ImmutableList; import com.google.inject.Binder; +import com.google.inject.Inject; import com.google.inject.Key; +import com.google.inject.Provider; import com.google.inject.Provides; import com.google.inject.Scopes; import com.google.inject.Singleton; +import com.google.inject.multibindings.Multibinder; import com.google.inject.multibindings.ProvidesIntoOptional; import io.airlift.configuration.AbstractConfigurationAwareModule; import io.airlift.units.Duration; @@ -32,6 +36,7 @@ import io.trino.spi.catalog.CatalogName; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.http.apache.ApacheHttpClient; import software.amazon.awssdk.http.apache.ProxyConfiguration; import software.amazon.awssdk.regions.Region; @@ -52,10 +57,12 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; +import static com.google.inject.multibindings.Multibinder.newSetBinder; import static com.google.inject.multibindings.OptionalBinder.newOptionalBinder; import static com.google.inject.multibindings.ProvidesIntoOptional.Type.DEFAULT; import static io.airlift.configuration.ConfigBinder.configBinder; import static io.trino.plugin.base.ClosingBinder.closingBinder; +import static java.util.Objects.requireNonNull; import static org.weakref.jmx.guice.ExportBinder.newExporter; public class GlueMetastoreModule @@ -76,6 +83,10 @@ protected void setup(Binder binder) .in(Scopes.SINGLETON); binder.bind(Key.get(boolean.class, AllowHiveTableRename.class)).toInstance(false); + Multibinder executionInterceptorMultibinder = newSetBinder(binder, ExecutionInterceptor.class, ForGlueHiveMetastore.class); + executionInterceptorMultibinder.addBinding().toProvider(TelemetryExecutionInterceptorProvider.class).in(Scopes.SINGLETON); + executionInterceptorMultibinder.addBinding().to(GlueHiveExecutionInterceptor.class).in(Scopes.SINGLETON); + closingBinder(binder).registerCloseable(GlueClient.class); } @@ -121,16 +132,12 @@ public static GlueCache createGlueCache(CachingHiveMetastoreConfig config, Catal @Provides @Singleton - public static GlueClient createGlueClient(GlueHiveMetastoreConfig config, OpenTelemetry openTelemetry) + public static GlueClient createGlueClient(GlueHiveMetastoreConfig config, @ForGlueHiveMetastore Set executionInterceptors) { GlueClientBuilder glue = GlueClient.builder(); glue.overrideConfiguration(builder -> builder - .addExecutionInterceptor(AwsSdkTelemetry.builder(openTelemetry) - .setCaptureExperimentalSpanAttributes(true) - .setRecordIndividualHttpError(true) - .build().newExecutionInterceptor()) - .addExecutionInterceptor(new GlueHiveExecutionInterceptor(config.isSkipArchive())) + .executionInterceptors(ImmutableList.copyOf(executionInterceptors)) .retryStrategy(retryBuilder -> retryBuilder .retryOnException(throwable -> throwable instanceof ConcurrentModificationException) .backoffStrategy(BackoffStrategy.exponentialDelay( @@ -209,4 +216,26 @@ else if (config.getPinGlueClientToCurrentRegion()) { return sts.build(); } + + private static class TelemetryExecutionInterceptorProvider + implements Provider + { + private final OpenTelemetry openTelemetry; + + @Inject + public TelemetryExecutionInterceptorProvider(OpenTelemetry openTelemetry) + { + this.openTelemetry = requireNonNull(openTelemetry, "openTelemetry is null"); + } + + @Override + public ExecutionInterceptor get() + { + return AwsSdkTelemetry.builder(openTelemetry) + .setCaptureExperimentalSpanAttributes(true) + .setRecordIndividualHttpError(true) + .build() + .newExecutionInterceptor(); + } + } } diff --git a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/TestHiveGlueMetadataListing.java b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/TestHiveGlueMetadataListing.java index 9b886f4fbf6..42fc5ff5f07 100644 --- a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/TestHiveGlueMetadataListing.java +++ b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/TestHiveGlueMetadataListing.java @@ -16,7 +16,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import io.airlift.log.Logger; -import io.opentelemetry.api.OpenTelemetry; import io.trino.Session; import io.trino.plugin.hive.metastore.glue.GlueHiveMetastore; import io.trino.plugin.hive.metastore.glue.GlueHiveMetastoreConfig; @@ -27,6 +26,7 @@ import io.trino.tpch.TpchTable; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Test; +import org.testcontainers.shaded.com.google.common.collect.ImmutableSet; import software.amazon.awssdk.services.glue.GlueClient; import software.amazon.awssdk.services.glue.model.CreateTableRequest; import software.amazon.awssdk.services.glue.model.TableInput; @@ -124,7 +124,7 @@ private void createBrokenTable(Path dataDirectory) { GlueHiveMetastoreConfig glueConfig = new GlueHiveMetastoreConfig() .setDefaultWarehouseDir(dataDirectory.toString()); - try (GlueClient glueClient = createGlueClient(glueConfig, OpenTelemetry.noop())) { + try (GlueClient glueClient = createGlueClient(glueConfig, ImmutableSet.of())) { TableInput tableInput = TableInput.builder() .name(FAILING_TABLE_WITH_NULL_STORAGE_DESCRIPTOR_NAME) .tableType("HIVE") diff --git a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestHiveConcurrentModificationGlueMetastore.java b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestHiveConcurrentModificationGlueMetastore.java index 82a915e109f..9a86ebb1057 100644 --- a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestHiveConcurrentModificationGlueMetastore.java +++ b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestHiveConcurrentModificationGlueMetastore.java @@ -13,9 +13,9 @@ */ package io.trino.plugin.hive.metastore.glue; -import io.opentelemetry.api.OpenTelemetry; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; +import org.testcontainers.shaded.com.google.common.collect.ImmutableSet; import software.amazon.awssdk.awscore.exception.AwsErrorDetails; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.retries.api.RefreshRetryTokenRequest; @@ -36,7 +36,7 @@ public class TestHiveConcurrentModificationGlueMetastore @Test public void testGlueClientShouldRetryConcurrentModificationException() { - try (GlueClient glueClient = createGlueClient(new GlueHiveMetastoreConfig(), OpenTelemetry.noop())) { + try (GlueClient glueClient = createGlueClient(new GlueHiveMetastoreConfig(), ImmutableSet.of())) { ClientOverrideConfiguration clientOverrideConfiguration = glueClient.serviceClientConfiguration().overrideConfiguration(); RetryStrategy retryStrategy = clientOverrideConfiguration.retryStrategy().orElseThrow(); diff --git a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestingGlueHiveMetastore.java b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestingGlueHiveMetastore.java index 40eeb96b089..6c490989f11 100644 --- a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestingGlueHiveMetastore.java +++ b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/metastore/glue/TestingGlueHiveMetastore.java @@ -13,7 +13,7 @@ */ package io.trino.plugin.hive.metastore.glue; -import io.opentelemetry.api.OpenTelemetry; +import com.google.common.collect.ImmutableSet; import io.trino.plugin.hive.metastore.glue.GlueHiveMetastore.TableKind; import software.amazon.awssdk.services.glue.GlueClient; @@ -52,7 +52,7 @@ public static GlueHiveMetastore createTestingGlueHiveMetastore(URI warehouseUri, { GlueHiveMetastoreConfig glueConfig = new GlueHiveMetastoreConfig() .setDefaultWarehouseDir(warehouseUri.toString()); - GlueClient glueClient = createGlueClient(glueConfig, OpenTelemetry.noop()); + GlueClient glueClient = createGlueClient(glueConfig, ImmutableSet.of()); registerResource.accept(glueClient); return new GlueHiveMetastore( glueClient,