diff --git a/core/trino-main/src/main/java/io/trino/connector/CatalogConnector.java b/core/trino-main/src/main/java/io/trino/connector/CatalogConnector.java index d36726cff83b..81e6530b75a3 100644 --- a/core/trino-main/src/main/java/io/trino/connector/CatalogConnector.java +++ b/core/trino-main/src/main/java/io/trino/connector/CatalogConnector.java @@ -16,6 +16,8 @@ import io.trino.connector.CatalogHandle.CatalogHandleType; import io.trino.metadata.Catalog; +import java.util.Optional; + import static com.google.common.base.MoreObjects.toStringHelper; import static java.util.Objects.requireNonNull; @@ -26,6 +28,7 @@ public class CatalogConnector private final ConnectorServices catalogConnector; private final ConnectorServices informationSchemaConnector; private final ConnectorServices systemConnector; + private final Optional catalogProperties; private final Catalog catalog; public CatalogConnector( @@ -33,13 +36,15 @@ public CatalogConnector( String connectorName, ConnectorServices catalogConnector, ConnectorServices informationSchemaConnector, - ConnectorServices systemConnector) + ConnectorServices systemConnector, + Optional catalogProperties) { this.catalogHandle = requireNonNull(catalogHandle, "catalogHandle is null"); this.connectorName = requireNonNull(connectorName, "connectorName is null"); this.catalogConnector = requireNonNull(catalogConnector, "catalogConnector is null"); this.informationSchemaConnector = requireNonNull(informationSchemaConnector, "informationSchemaConnector is null"); this.systemConnector = requireNonNull(systemConnector, "systemConnector is null"); + this.catalogProperties = requireNonNull(catalogProperties, "catalogProperties is null"); this.catalog = new Catalog( catalogHandle.getCatalogName(), @@ -60,6 +65,11 @@ public String getConnectorName() return connectorName; } + public Optional getCatalogProperties() + { + return catalogProperties; + } + public Catalog getCatalog() { return catalog; diff --git a/core/trino-main/src/main/java/io/trino/connector/CatalogFactory.java b/core/trino-main/src/main/java/io/trino/connector/CatalogFactory.java index bde355b0eae0..037be7a7c50e 100644 --- a/core/trino-main/src/main/java/io/trino/connector/CatalogFactory.java +++ b/core/trino-main/src/main/java/io/trino/connector/CatalogFactory.java @@ -18,7 +18,6 @@ import javax.annotation.concurrent.ThreadSafe; -import java.util.Map; import java.util.function.Function; @ThreadSafe @@ -26,7 +25,7 @@ public interface CatalogFactory { void addConnectorFactory(ConnectorFactory connectorFactory, Function duplicatePluginClassLoaderFactory); - CatalogConnector createCatalog(String catalogName, String connectorName, Map properties); + CatalogConnector createCatalog(CatalogProperties catalogProperties); CatalogConnector createCatalog(CatalogHandle catalogHandle, String connectorName, Connector connector); } diff --git a/core/trino-main/src/main/java/io/trino/connector/CatalogManagerConfig.java b/core/trino-main/src/main/java/io/trino/connector/CatalogManagerConfig.java new file mode 100644 index 000000000000..be06b3249199 --- /dev/null +++ b/core/trino-main/src/main/java/io/trino/connector/CatalogManagerConfig.java @@ -0,0 +1,41 @@ +/* + * 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.connector; + +import io.airlift.configuration.Config; + +import javax.validation.constraints.NotNull; + +public class CatalogManagerConfig +{ + public enum CatalogMangerKind + { + STATIC, DYNAMIC + } + + private CatalogMangerKind catalogMangerKind = CatalogMangerKind.STATIC; + + @NotNull + public CatalogMangerKind getCatalogMangerKind() + { + return catalogMangerKind; + } + + @Config("catalog.management") + public CatalogManagerConfig setCatalogMangerKind(CatalogMangerKind catalogMangerKind) + { + this.catalogMangerKind = catalogMangerKind; + return this; + } +} diff --git a/core/trino-main/src/main/java/io/trino/connector/CatalogManagerModule.java b/core/trino-main/src/main/java/io/trino/connector/CatalogManagerModule.java index 6aa9cf3d6a11..e75233e9cefd 100644 --- a/core/trino-main/src/main/java/io/trino/connector/CatalogManagerModule.java +++ b/core/trino-main/src/main/java/io/trino/connector/CatalogManagerModule.java @@ -16,10 +16,6 @@ import com.google.inject.Binder; import com.google.inject.Scopes; import io.airlift.configuration.AbstractConfigurationAwareModule; -import io.trino.connector.system.GlobalSystemConnector; -import io.trino.metadata.CatalogManager; - -import javax.inject.Inject; public class CatalogManagerModule extends AbstractConfigurationAwareModule @@ -30,27 +26,13 @@ protected void setup(Binder binder) binder.bind(DefaultCatalogFactory.class).in(Scopes.SINGLETON); binder.bind(LazyCatalogFactory.class).in(Scopes.SINGLETON); binder.bind(CatalogFactory.class).to(LazyCatalogFactory.class).in(Scopes.SINGLETON); - binder.bind(LazyRegister.class).asEagerSingleton(); - - binder.bind(ConnectorManager.class).in(Scopes.SINGLETON); - binder.bind(ConnectorServicesProvider.class).to(ConnectorManager.class).in(Scopes.SINGLETON); - binder.bind(CatalogManager.class).in(Scopes.SINGLETON); + CatalogManagerConfig config = buildConfigObject(CatalogManagerConfig.class); + switch (config.getCatalogMangerKind()) { + case STATIC -> install(new StaticCatalogManagerModule()); + case DYNAMIC -> install(new DynamicCatalogManagerModule()); + } install(new CatalogServiceProviderModule()); } - - private static class LazyRegister - { - @Inject - public LazyRegister( - DefaultCatalogFactory defaultCatalogFactory, - LazyCatalogFactory lazyCatalogFactory, - ConnectorManager manager, - GlobalSystemConnector globalSystemConnector) - { - lazyCatalogFactory.setCatalogFactory(defaultCatalogFactory); - manager.createCatalog(GlobalSystemConnector.CATALOG_HANDLE, GlobalSystemConnector.NAME, globalSystemConnector); - } - } } diff --git a/core/trino-main/src/main/java/io/trino/connector/CatalogProperties.java b/core/trino-main/src/main/java/io/trino/connector/CatalogProperties.java new file mode 100644 index 000000000000..0df47374ad48 --- /dev/null +++ b/core/trino-main/src/main/java/io/trino/connector/CatalogProperties.java @@ -0,0 +1,68 @@ +/* + * 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.connector; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableMap; + +import java.util.Map; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static java.util.Objects.requireNonNull; + +public class CatalogProperties +{ + private final CatalogHandle catalogHandle; + private final String connectorName; + private final Map properties; + + @JsonCreator + public CatalogProperties( + @JsonProperty("catalogHandle") CatalogHandle catalogHandle, + @JsonProperty("connectorName") String connectorName, + @JsonProperty("properties") Map properties) + { + this.catalogHandle = requireNonNull(catalogHandle, "catalogHandle is null"); + this.connectorName = requireNonNull(connectorName, "connectorName is null"); + this.properties = ImmutableMap.copyOf(requireNonNull(properties, "properties is null")); + } + + @JsonProperty + public CatalogHandle getCatalogHandle() + { + return catalogHandle; + } + + @JsonProperty + public String getConnectorName() + { + return connectorName; + } + + @JsonProperty + public Map getProperties() + { + return properties; + } + + @Override + public String toString() + { + return toStringHelper(this) + .add("catalogHandle", catalogHandle) + .add("connectorName", connectorName) + .toString(); + } +} diff --git a/core/trino-main/src/main/java/io/trino/connector/CatalogStore.java b/core/trino-main/src/main/java/io/trino/connector/CatalogStore.java new file mode 100644 index 000000000000..766291f5c6d9 --- /dev/null +++ b/core/trino-main/src/main/java/io/trino/connector/CatalogStore.java @@ -0,0 +1,28 @@ +/* + * 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.connector; + +import com.google.common.collect.ImmutableList; + +import java.util.Collection; + +public interface CatalogStore +{ + CatalogStore NO_STORED_CATALOGS = ImmutableList::of; + + /** + * Get all catalogs + */ + Collection getCatalogs(); +} diff --git a/core/trino-main/src/main/java/io/trino/connector/CatalogStoreConfig.java b/core/trino-main/src/main/java/io/trino/connector/CatalogStoreConfig.java new file mode 100644 index 000000000000..e1feedfc14c2 --- /dev/null +++ b/core/trino-main/src/main/java/io/trino/connector/CatalogStoreConfig.java @@ -0,0 +1,41 @@ +/* + * 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.connector; + +import io.airlift.configuration.Config; + +import javax.validation.constraints.NotNull; + +public class CatalogStoreConfig +{ + public enum CatalogStoreKind + { + NONE, FILE + } + + private CatalogStoreKind catalogStoreKind = CatalogStoreKind.FILE; + + @NotNull + public CatalogStoreKind getCatalogStoreKind() + { + return catalogStoreKind; + } + + @Config("catalog.store") + public CatalogStoreConfig setCatalogStoreKind(CatalogStoreKind catalogStoreKind) + { + this.catalogStoreKind = catalogStoreKind; + return this; + } +} diff --git a/core/trino-main/src/main/java/io/trino/connector/ConnectorManager.java b/core/trino-main/src/main/java/io/trino/connector/ConnectorManager.java deleted file mode 100644 index 1ad9905831de..000000000000 --- a/core/trino-main/src/main/java/io/trino/connector/ConnectorManager.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.connector; - -import io.trino.metadata.CatalogManager; -import io.trino.spi.connector.Connector; - -import javax.annotation.PreDestroy; -import javax.annotation.concurrent.GuardedBy; -import javax.annotation.concurrent.ThreadSafe; -import javax.inject.Inject; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicBoolean; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; -import static java.util.Objects.requireNonNull; - -@ThreadSafe -public class ConnectorManager - implements ConnectorServicesProvider -{ - private final CatalogFactory catalogFactory; - private final CatalogManager catalogManager; - - @GuardedBy("this") - private final ConcurrentMap catalogs = new ConcurrentHashMap<>(); - - private final AtomicBoolean stopped = new AtomicBoolean(); - - @Inject - public ConnectorManager(CatalogFactory catalogFactory, CatalogManager catalogManager) - { - this.catalogFactory = requireNonNull(catalogFactory, "catalogFactory is null"); - this.catalogManager = requireNonNull(catalogManager, "catalogManager is null"); - } - - @PreDestroy - public synchronized void stop() - { - if (stopped.getAndSet(true)) { - return; - } - - for (CatalogConnector connector : catalogs.values()) { - connector.shutdown(); - } - catalogs.clear(); - } - - @Override - public synchronized ConnectorServices getConnectorServices(CatalogHandle catalogHandle) - { - CatalogConnector catalogConnector = catalogs.get(catalogHandle.getCatalogName()); - checkArgument(catalogConnector != null, "No catalog '%s'", catalogHandle.getCatalogName()); - return catalogConnector.getMaterializedConnector(catalogHandle.getType()); - } - - public synchronized CatalogHandle createCatalog(String catalogName, String connectorName, Map properties) - { - requireNonNull(catalogName, "catalogName is null"); - requireNonNull(connectorName, "connectorName is null"); - requireNonNull(properties, "properties is null"); - - checkState(!stopped.get(), "ConnectorManager is stopped"); - checkArgument(!catalogs.containsKey(catalogName), "Catalog '%s' already exists", catalogName); - checkArgument(catalogManager.getCatalog(catalogName).isEmpty(), "Catalog '%s' already exists", catalogName); - - CatalogConnector catalog = catalogFactory.createCatalog(catalogName, connectorName, properties); - catalogs.put(catalogName, catalog); - catalogManager.registerCatalog(catalog.getCatalog()); - return catalog.getCatalogHandle(); - } - - public synchronized void createCatalog(CatalogHandle catalogHandle, String connectorName, Connector connector) - { - requireNonNull(catalogHandle, "catalogHandle is null"); - requireNonNull(connectorName, "connectorName is null"); - requireNonNull(connector, "connector is null"); - - checkState(!stopped.get(), "ConnectorManager is stopped"); - String catalogName = catalogHandle.getCatalogName(); - checkArgument(!catalogs.containsKey(catalogName), "Catalog '%s' already exists", catalogName); - checkArgument(catalogManager.getCatalog(catalogName).isEmpty(), "Catalog '%s' already exists", catalogName); - - CatalogConnector catalog = catalogFactory.createCatalog(catalogHandle, connectorName, connector); - catalogs.put(catalogName, catalog); - catalogManager.registerCatalog(catalog.getCatalog()); - } -} diff --git a/core/trino-main/src/main/java/io/trino/connector/ConnectorServicesProvider.java b/core/trino-main/src/main/java/io/trino/connector/ConnectorServicesProvider.java index 2af91fa60211..74285fbfa8e5 100644 --- a/core/trino-main/src/main/java/io/trino/connector/ConnectorServicesProvider.java +++ b/core/trino-main/src/main/java/io/trino/connector/ConnectorServicesProvider.java @@ -13,7 +13,15 @@ */ package io.trino.connector; +import io.trino.Session; + +import java.util.List; + public interface ConnectorServicesProvider { + void loadInitialCatalogs(); + + void ensureCatalogsLoaded(Session session, List catalogs); + ConnectorServices getConnectorServices(CatalogHandle catalogHandle); } diff --git a/core/trino-main/src/main/java/io/trino/connector/CoordinatorDynamicCatalogManager.java b/core/trino-main/src/main/java/io/trino/connector/CoordinatorDynamicCatalogManager.java new file mode 100644 index 000000000000..0f34007d58d0 --- /dev/null +++ b/core/trino-main/src/main/java/io/trino/connector/CoordinatorDynamicCatalogManager.java @@ -0,0 +1,202 @@ +/* + * 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.connector; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import io.airlift.log.Logger; +import io.trino.Session; +import io.trino.connector.system.GlobalSystemConnector; +import io.trino.metadata.Catalog; +import io.trino.metadata.CatalogManager; +import io.trino.spi.TrinoException; + +import javax.annotation.PreDestroy; +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; +import javax.inject.Inject; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static io.trino.connector.CatalogHandle.createRootCatalogHandle; +import static io.trino.spi.StandardErrorCode.ALREADY_EXISTS; +import static io.trino.spi.StandardErrorCode.CATALOG_NOT_AVAILABLE; +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; + +@ThreadSafe +public class CoordinatorDynamicCatalogManager + implements CatalogManager, ConnectorServicesProvider +{ + private static final Logger log = Logger.get(CoordinatorDynamicCatalogManager.class); + + private enum State { CREATED, INITIALIZED, STOPPED } + + private final CatalogStore catalogStore; + private final CatalogFactory catalogFactory; + + private final Lock catalogsUpdateLock = new ReentrantLock(); + private final ConcurrentMap catalogs = new ConcurrentHashMap<>(); + + @GuardedBy("catalogsUpdateLock") + private State state = State.CREATED; + + @Inject + public CoordinatorDynamicCatalogManager(CatalogStore catalogStore, CatalogFactory catalogFactory) + { + this.catalogStore = requireNonNull(catalogStore, "catalogStore is null"); + this.catalogFactory = requireNonNull(catalogFactory, "catalogFactory is null"); + } + + @PreDestroy + public void stop() + { + List catalogs; + + catalogsUpdateLock.lock(); + try { + if (state == State.STOPPED) { + return; + } + state = State.STOPPED; + + catalogs = ImmutableList.copyOf(this.catalogs.values()); + this.catalogs.clear(); + } + finally { + catalogsUpdateLock.unlock(); + } + + for (CatalogConnector connector : catalogs) { + connector.shutdown(); + } + } + + @Override + public void loadInitialCatalogs() + { + catalogsUpdateLock.lock(); + try { + if (state == State.INITIALIZED) { + return; + } + checkState(state != State.STOPPED, "ConnectorManager is stopped"); + state = State.INITIALIZED; + + for (CatalogProperties catalog : catalogStore.getCatalogs()) { + log.info("-- Loading catalog %s --", catalog.getCatalogHandle().getCatalogName()); + CatalogConnector newCatalog = catalogFactory.createCatalog(catalog); + catalogs.put(catalog.getCatalogHandle().getCatalogName(), newCatalog); + log.info("-- Added catalog %s using connector %s --", catalog.getCatalogHandle().getCatalogName(), catalog.getConnectorName()); + } + } + finally { + catalogsUpdateLock.unlock(); + } + } + + @Override + public Set getCatalogNames() + { + return ImmutableSet.copyOf(catalogs.keySet()); + } + + @Override + public Optional getCatalog(String catalogName) + { + return Optional.ofNullable(catalogs.get(catalogName)) + .map(CatalogConnector::getCatalog); + } + + @Override + public void ensureCatalogsLoaded(Session session, List catalogs) + { + List missingCatalogs = catalogs.stream() + .filter(catalog -> !this.catalogs.containsKey(catalog.getCatalogHandle().getCatalogName())) + .collect(toImmutableList()); + + if (!missingCatalogs.isEmpty()) { + throw new TrinoException(CATALOG_NOT_AVAILABLE, "Missing catalogs: " + missingCatalogs); + } + } + + @Override + public Optional getCatalogProperties(CatalogHandle catalogHandle) + { + return Optional.ofNullable(catalogs.get(catalogHandle.getCatalogName())) + .flatMap(CatalogConnector::getCatalogProperties); + } + + @Override + public ConnectorServices getConnectorServices(CatalogHandle catalogHandle) + { + CatalogConnector catalogConnector = catalogs.get(catalogHandle.getCatalogName()); + checkArgument(catalogConnector != null, "No catalog '%s'", catalogHandle.getCatalogName()); + return catalogConnector.getMaterializedConnector(catalogHandle.getType()); + } + + @Override + public void createCatalog(String catalogName, String connectorName, Map properties) + { + requireNonNull(catalogName, "catalogName is null"); + requireNonNull(connectorName, "connectorName is null"); + requireNonNull(properties, "properties is null"); + + catalogsUpdateLock.lock(); + try { + checkState(state != State.STOPPED, "ConnectorManager is stopped"); + + if (catalogs.containsKey(catalogName)) { + throw new TrinoException(ALREADY_EXISTS, format("Catalog '%s' already exists", catalogName)); + } + + CatalogProperties catalogProperties = new CatalogProperties(createRootCatalogHandle(catalogName), connectorName, properties); + CatalogConnector catalog = catalogFactory.createCatalog(catalogProperties); + catalogs.put(catalogName, catalog); + } + finally { + catalogsUpdateLock.unlock(); + } + } + + public void registerGlobalSystemConnector(GlobalSystemConnector connector) + { + requireNonNull(connector, "connector is null"); + + catalogsUpdateLock.lock(); + try { + if (state == State.STOPPED) { + return; + } + + CatalogConnector catalog = catalogFactory.createCatalog(GlobalSystemConnector.CATALOG_HANDLE, GlobalSystemConnector.NAME, connector); + if (catalogs.putIfAbsent(GlobalSystemConnector.NAME, catalog) != null) { + throw new IllegalStateException("Global system catalog already registered"); + } + } + finally { + catalogsUpdateLock.unlock(); + } + } +} diff --git a/core/trino-main/src/main/java/io/trino/connector/DefaultCatalogFactory.java b/core/trino-main/src/main/java/io/trino/connector/DefaultCatalogFactory.java index 5833b0f5cc2b..c13b8e081a54 100644 --- a/core/trino-main/src/main/java/io/trino/connector/DefaultCatalogFactory.java +++ b/core/trino-main/src/main/java/io/trino/connector/DefaultCatalogFactory.java @@ -40,6 +40,7 @@ import javax.inject.Inject; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; @@ -48,7 +49,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static io.trino.connector.CatalogHandle.createInformationSchemaCatalogHandle; -import static io.trino.connector.CatalogHandle.createRootCatalogHandle; import static io.trino.connector.CatalogHandle.createSystemTablesCatalogHandle; import static java.util.Objects.requireNonNull; @@ -109,27 +109,38 @@ public synchronized void addConnectorFactory(ConnectorFactory connectorFactory, } @Override - public CatalogConnector createCatalog(String catalogName, String connectorName, Map properties) + public CatalogConnector createCatalog(CatalogProperties catalogProperties) { - requireNonNull(connectorName, "connectorName is null"); - requireNonNull(properties, "properties is null"); - - InternalConnectorFactory factory = connectorFactories.get(connectorName); - checkArgument(factory != null, "No factory for connector '%s'. Available factories: %s", connectorName, connectorFactories.keySet()); - - CatalogHandle catalogHandle = createRootCatalogHandle(catalogName); - CatalogClassLoaderSupplier duplicatePluginClassLoaderFactory = new CatalogClassLoaderSupplier(catalogHandle, factory.getDuplicatePluginClassLoaderFactory(), handleResolver); - Connector connector = createConnector(catalogName, catalogHandle, factory.getConnectorFactory(), duplicatePluginClassLoaderFactory, properties); - return createCatalog(catalogHandle, factory.getConnectorFactory().getName(), connector, duplicatePluginClassLoaderFactory::destroy); + requireNonNull(catalogProperties, "catalogProperties is null"); + + InternalConnectorFactory factory = connectorFactories.get(catalogProperties.getConnectorName()); + checkArgument(factory != null, "No factory for connector '%s'. Available factories: %s", catalogProperties.getConnectorName(), connectorFactories.keySet()); + + CatalogClassLoaderSupplier duplicatePluginClassLoaderFactory = new CatalogClassLoaderSupplier( + catalogProperties.getCatalogHandle(), + factory.getDuplicatePluginClassLoaderFactory(), + handleResolver); + Connector connector = createConnector( + catalogProperties.getCatalogHandle().getCatalogName(), + catalogProperties.getCatalogHandle(), + factory.getConnectorFactory(), + duplicatePluginClassLoaderFactory, + catalogProperties.getProperties()); + return createCatalog( + catalogProperties.getCatalogHandle(), + factory.getConnectorFactory().getName(), + connector, + duplicatePluginClassLoaderFactory::destroy, + Optional.of(catalogProperties)); } @Override public CatalogConnector createCatalog(CatalogHandle catalogHandle, String connectorName, Connector connector) { - return createCatalog(catalogHandle, connectorName, connector, () -> {}); + return createCatalog(catalogHandle, connectorName, connector, () -> {}, Optional.empty()); } - private CatalogConnector createCatalog(CatalogHandle catalogHandle, String connectorName, Connector connector, Runnable destroy) + private CatalogConnector createCatalog(CatalogHandle catalogHandle, String connectorName, Connector connector, Runnable destroy, Optional catalogProperties) { ConnectorServices catalogConnector = new ConnectorServices( catalogHandle, @@ -166,7 +177,8 @@ private CatalogConnector createCatalog(CatalogHandle catalogHandle, String conne connectorName, catalogConnector, informationSchemaConnector, - systemConnector); + systemConnector, + catalogProperties); } private Connector createConnector( diff --git a/core/trino-main/src/main/java/io/trino/connector/DynamicCatalogManagerModule.java b/core/trino-main/src/main/java/io/trino/connector/DynamicCatalogManagerModule.java new file mode 100644 index 000000000000..c19253fabb2f --- /dev/null +++ b/core/trino-main/src/main/java/io/trino/connector/DynamicCatalogManagerModule.java @@ -0,0 +1,83 @@ +/* + * 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.connector; + +import com.google.inject.Binder; +import com.google.inject.Scopes; +import io.airlift.configuration.AbstractConfigurationAwareModule; +import io.trino.connector.system.GlobalSystemConnector; +import io.trino.metadata.CatalogManager; +import io.trino.server.ServerConfig; + +import javax.inject.Inject; + +import static io.airlift.configuration.ConfigBinder.configBinder; +import static io.trino.connector.CatalogStore.NO_STORED_CATALOGS; + +public class DynamicCatalogManagerModule + extends AbstractConfigurationAwareModule +{ + @Override + protected void setup(Binder binder) + { + if (buildConfigObject(ServerConfig.class).isCoordinator()) { + binder.bind(CoordinatorDynamicCatalogManager.class).in(Scopes.SINGLETON); + CatalogStoreConfig config = buildConfigObject(CatalogStoreConfig.class); + switch (config.getCatalogStoreKind()) { + case NONE -> binder.bind(CatalogStore.class).toInstance(NO_STORED_CATALOGS); + case FILE -> { + configBinder(binder).bindConfig(StaticCatalogManagerConfig.class); + binder.bind(CatalogStore.class).to(FileCatalogStore.class).in(Scopes.SINGLETON); + } + } + binder.bind(ConnectorServicesProvider.class).to(CoordinatorDynamicCatalogManager.class).in(Scopes.SINGLETON); + binder.bind(CatalogManager.class).to(CoordinatorDynamicCatalogManager.class).in(Scopes.SINGLETON); + binder.bind(CoordinatorLazyRegister.class).asEagerSingleton(); + } + else { + binder.bind(WorkerDynamicCatalogManager.class).in(Scopes.SINGLETON); + binder.bind(ConnectorServicesProvider.class).to(WorkerDynamicCatalogManager.class).in(Scopes.SINGLETON); + // catalog manager is not registered on worker + binder.bind(WorkerLazyRegister.class).asEagerSingleton(); + } + } + + private static class CoordinatorLazyRegister + { + @Inject + public CoordinatorLazyRegister( + DefaultCatalogFactory defaultCatalogFactory, + LazyCatalogFactory lazyCatalogFactory, + CoordinatorDynamicCatalogManager catalogManager, + GlobalSystemConnector globalSystemConnector) + { + lazyCatalogFactory.setCatalogFactory(defaultCatalogFactory); + catalogManager.registerGlobalSystemConnector(globalSystemConnector); + } + } + + private static class WorkerLazyRegister + { + @Inject + public WorkerLazyRegister( + DefaultCatalogFactory defaultCatalogFactory, + LazyCatalogFactory lazyCatalogFactory, + WorkerDynamicCatalogManager catalogManager, + GlobalSystemConnector globalSystemConnector) + { + lazyCatalogFactory.setCatalogFactory(defaultCatalogFactory); + catalogManager.registerGlobalSystemConnector(globalSystemConnector); + } + } +} diff --git a/core/trino-main/src/main/java/io/trino/connector/FileCatalogStore.java b/core/trino-main/src/main/java/io/trino/connector/FileCatalogStore.java new file mode 100644 index 000000000000..f0a69836173a --- /dev/null +++ b/core/trino-main/src/main/java/io/trino/connector/FileCatalogStore.java @@ -0,0 +1,98 @@ +/* + * 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.connector; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.io.Files; +import io.airlift.log.Logger; +import io.trino.connector.system.GlobalSystemConnector; + +import javax.inject.Inject; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.google.common.base.MoreObjects.firstNonNull; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static io.airlift.configuration.ConfigurationLoader.loadPropertiesFrom; +import static io.trino.connector.CatalogHandle.createRootCatalogHandle; + +public class FileCatalogStore + implements CatalogStore +{ + private static final Logger log = Logger.get(FileCatalogStore.class); + + private final List catalogs; + + @Inject + public FileCatalogStore(StaticCatalogManagerConfig config) + { + List disabledCatalogs = firstNonNull(config.getDisabledCatalogs(), ImmutableList.of()); + + ImmutableList.Builder catalogProperties = ImmutableList.builder(); + for (File file : listCatalogFiles(config.getCatalogConfigurationDir())) { + String catalogName = Files.getNameWithoutExtension(file.getName()); + checkArgument(!catalogName.equals(GlobalSystemConnector.NAME), "Catalog name SYSTEM is reserved for internal usage"); + if (disabledCatalogs.contains(catalogName)) { + log.info("Skipping disabled catalog %s", catalogName); + continue; + } + + Map properties; + try { + properties = new HashMap<>(loadPropertiesFrom(file.getPath())); + } + catch (IOException e) { + throw new UncheckedIOException("Error reading catalog property file " + file, e); + } + + String connectorName = properties.remove("connector.name"); + checkState(connectorName != null, "Catalog configuration %s does not contain 'connector.name'", file.getAbsoluteFile()); + + catalogProperties.add(new CatalogProperties(createRootCatalogHandle(catalogName), connectorName, ImmutableMap.copyOf(properties))); + } + this.catalogs = catalogProperties.build(); + } + + @Override + public Collection getCatalogs() + { + return catalogs; + } + + private static List listCatalogFiles(File catalogsDirectory) + { + if (catalogsDirectory == null || !catalogsDirectory.isDirectory()) { + return ImmutableList.of(); + } + + File[] files = catalogsDirectory.listFiles(); + if (files == null) { + return ImmutableList.of(); + } + return Arrays.stream(files) + .filter(File::isFile) + .filter(file -> file.getName().endsWith(".properties")) + .collect(toImmutableList()); + } +} diff --git a/core/trino-main/src/main/java/io/trino/connector/LazyCatalogFactory.java b/core/trino-main/src/main/java/io/trino/connector/LazyCatalogFactory.java index a2a39e94724a..d5f416c651b1 100644 --- a/core/trino-main/src/main/java/io/trino/connector/LazyCatalogFactory.java +++ b/core/trino-main/src/main/java/io/trino/connector/LazyCatalogFactory.java @@ -16,7 +16,6 @@ import io.trino.spi.connector.Connector; import io.trino.spi.connector.ConnectorFactory; -import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; @@ -40,9 +39,9 @@ public void addConnectorFactory(ConnectorFactory connectorFactory, } @Override - public CatalogConnector createCatalog(String catalogName, String connectorName, Map properties) + public CatalogConnector createCatalog(CatalogProperties catalogProperties) { - return getDelegate().createCatalog(catalogName, connectorName, properties); + return getDelegate().createCatalog(catalogProperties); } @Override diff --git a/core/trino-main/src/main/java/io/trino/connector/StaticCatalogManager.java b/core/trino-main/src/main/java/io/trino/connector/StaticCatalogManager.java new file mode 100644 index 000000000000..c522a0b73c73 --- /dev/null +++ b/core/trino-main/src/main/java/io/trino/connector/StaticCatalogManager.java @@ -0,0 +1,200 @@ +/* + * 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.connector; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.io.Files; +import io.airlift.log.Logger; +import io.trino.Session; +import io.trino.connector.system.GlobalSystemConnector; +import io.trino.metadata.Catalog; +import io.trino.metadata.CatalogManager; +import io.trino.spi.TrinoException; + +import javax.annotation.PreDestroy; +import javax.annotation.concurrent.ThreadSafe; +import javax.inject.Inject; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicReference; + +import static com.google.common.base.MoreObjects.firstNonNull; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static io.airlift.configuration.ConfigurationLoader.loadPropertiesFrom; +import static io.trino.connector.CatalogHandle.createRootCatalogHandle; +import static io.trino.spi.StandardErrorCode.CATALOG_NOT_AVAILABLE; +import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED; +import static java.util.Objects.requireNonNull; + +@ThreadSafe +public class StaticCatalogManager + implements CatalogManager, ConnectorServicesProvider +{ + private static final Logger log = Logger.get(StaticCatalogManager.class); + + private enum State { CREATED, INITIALIZED, STOPPED } + + private final CatalogFactory catalogFactory; + private final List catalogProperties; + + private final ConcurrentMap catalogs = new ConcurrentHashMap<>(); + + private final AtomicReference state = new AtomicReference<>(State.CREATED); + + @Inject + public StaticCatalogManager(CatalogFactory catalogFactory, StaticCatalogManagerConfig config) + { + this.catalogFactory = requireNonNull(catalogFactory, "catalogFactory is null"); + List disabledCatalogs = firstNonNull(config.getDisabledCatalogs(), ImmutableList.of()); + + ImmutableList.Builder catalogProperties = ImmutableList.builder(); + for (File file : listCatalogFiles(config.getCatalogConfigurationDir())) { + String catalogName = Files.getNameWithoutExtension(file.getName()); + checkArgument(!catalogName.equals(GlobalSystemConnector.NAME), "Catalog name SYSTEM is reserved for internal usage"); + if (disabledCatalogs.contains(catalogName)) { + log.info("Skipping disabled catalog %s", catalogName); + continue; + } + + Map properties; + try { + properties = new HashMap<>(loadPropertiesFrom(file.getPath())); + } + catch (IOException e) { + throw new UncheckedIOException("Error reading catalog property file " + file, e); + } + + String connectorName = properties.remove("connector.name"); + checkState(connectorName != null, "Catalog configuration %s does not contain connector.name", file.getAbsoluteFile()); + + catalogProperties.add(new CatalogProperties(createRootCatalogHandle(catalogName), connectorName, ImmutableMap.copyOf(properties))); + } + this.catalogProperties = catalogProperties.build(); + } + + private static List listCatalogFiles(File catalogsDirectory) + { + if (catalogsDirectory == null || !catalogsDirectory.isDirectory()) { + return ImmutableList.of(); + } + + File[] files = catalogsDirectory.listFiles(); + if (files == null) { + return ImmutableList.of(); + } + return Arrays.stream(files) + .filter(File::isFile) + .filter(file -> file.getName().endsWith(".properties")) + .collect(toImmutableList()); + } + + @PreDestroy + public void stop() + { + if (state.getAndSet(State.STOPPED) == State.STOPPED) { + return; + } + + for (CatalogConnector connector : catalogs.values()) { + connector.shutdown(); + } + catalogs.clear(); + } + + @Override + public void loadInitialCatalogs() + { + if (!state.compareAndSet(State.CREATED, State.INITIALIZED)) { + return; + } + + for (CatalogProperties catalog : catalogProperties) { + String catalogName = catalog.getCatalogHandle().getCatalogName(); + log.info("-- Loading catalog %s --", catalogName); + CatalogConnector newCatalog = catalogFactory.createCatalog(catalog); + catalogs.put(catalogName, newCatalog); + log.info("-- Added catalog %s using connector %s --", catalogName, catalog.getConnectorName()); + } + } + + @Override + public Set getCatalogNames() + { + return ImmutableSet.copyOf(catalogs.keySet()); + } + + @Override + public Optional getCatalog(String catalogName) + { + return Optional.ofNullable(catalogs.get(catalogName)) + .map(CatalogConnector::getCatalog); + } + + @Override + public void ensureCatalogsLoaded(Session session, List catalogs) + { + List missingCatalogs = catalogs.stream() + .filter(catalog -> !this.catalogs.containsKey(catalog.getCatalogHandle().getCatalogName())) + .collect(toImmutableList()); + + if (!missingCatalogs.isEmpty()) { + throw new TrinoException(CATALOG_NOT_AVAILABLE, "Missing catalogs: " + missingCatalogs); + } + } + + @Override + public Optional getCatalogProperties(CatalogHandle catalogHandle) + { + // static catalog manager does not propagate catalogs between machines + return Optional.empty(); + } + + @Override + public ConnectorServices getConnectorServices(CatalogHandle catalogHandle) + { + CatalogConnector catalogConnector = catalogs.get(catalogHandle.getCatalogName()); + checkArgument(catalogConnector != null, "No catalog '%s'", catalogHandle.getCatalogName()); + return catalogConnector.getMaterializedConnector(catalogHandle.getType()); + } + + public void registerGlobalSystemConnector(GlobalSystemConnector connector) + { + requireNonNull(connector, "connector is null"); + + CatalogConnector catalog = catalogFactory.createCatalog(GlobalSystemConnector.CATALOG_HANDLE, GlobalSystemConnector.NAME, connector); + if (catalogs.putIfAbsent(GlobalSystemConnector.NAME, catalog) != null) { + throw new IllegalStateException("Global system catalog already registered"); + } + } + + @Override + public void createCatalog(String catalogName, String connectorName, Map properties) + { + throw new TrinoException(NOT_SUPPORTED, "Create catalog is not supported by the static catalog manager"); + } +} diff --git a/core/trino-main/src/main/java/io/trino/metadata/StaticCatalogStoreConfig.java b/core/trino-main/src/main/java/io/trino/connector/StaticCatalogManagerConfig.java similarity index 84% rename from core/trino-main/src/main/java/io/trino/metadata/StaticCatalogStoreConfig.java rename to core/trino-main/src/main/java/io/trino/connector/StaticCatalogManagerConfig.java index a3a2de0bc6cd..4969dff82e30 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/StaticCatalogStoreConfig.java +++ b/core/trino-main/src/main/java/io/trino/connector/StaticCatalogManagerConfig.java @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.trino.metadata; +package io.trino.connector; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; @@ -23,7 +23,7 @@ import java.io.File; import java.util.List; -public class StaticCatalogStoreConfig +public class StaticCatalogManagerConfig { private static final Splitter SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings(); @@ -38,7 +38,7 @@ public File getCatalogConfigurationDir() @LegacyConfig("plugin.config-dir") @Config("catalog.config-dir") - public StaticCatalogStoreConfig setCatalogConfigurationDir(File dir) + public StaticCatalogManagerConfig setCatalogConfigurationDir(File dir) { this.catalogConfigurationDir = dir; return this; @@ -50,13 +50,13 @@ public List getDisabledCatalogs() } @Config("catalog.disabled-catalogs") - public StaticCatalogStoreConfig setDisabledCatalogs(String catalogs) + public StaticCatalogManagerConfig setDisabledCatalogs(String catalogs) { this.disabledCatalogs = (catalogs == null) ? null : SPLITTER.splitToList(catalogs); return this; } - public StaticCatalogStoreConfig setDisabledCatalogs(List catalogs) + public StaticCatalogManagerConfig setDisabledCatalogs(List catalogs) { this.disabledCatalogs = (catalogs == null) ? null : ImmutableList.copyOf(catalogs); return this; diff --git a/core/trino-main/src/main/java/io/trino/connector/StaticCatalogManagerModule.java b/core/trino-main/src/main/java/io/trino/connector/StaticCatalogManagerModule.java new file mode 100644 index 000000000000..52755be568b3 --- /dev/null +++ b/core/trino-main/src/main/java/io/trino/connector/StaticCatalogManagerModule.java @@ -0,0 +1,53 @@ +/* + * 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.connector; + +import com.google.inject.Binder; +import com.google.inject.Module; +import com.google.inject.Scopes; +import io.trino.connector.system.GlobalSystemConnector; +import io.trino.metadata.CatalogManager; + +import javax.inject.Inject; + +import static io.airlift.configuration.ConfigBinder.configBinder; + +public class StaticCatalogManagerModule + implements Module +{ + @Override + public void configure(Binder binder) + { + configBinder(binder).bindConfig(StaticCatalogManagerConfig.class); + binder.bind(StaticCatalogManager.class).in(Scopes.SINGLETON); + binder.bind(ConnectorServicesProvider.class).to(StaticCatalogManager.class).in(Scopes.SINGLETON); + binder.bind(CatalogManager.class).to(StaticCatalogManager.class).in(Scopes.SINGLETON); + + binder.bind(LazyRegister.class).asEagerSingleton(); + } + + private static class LazyRegister + { + @Inject + public LazyRegister( + DefaultCatalogFactory defaultCatalogFactory, + LazyCatalogFactory lazyCatalogFactory, + StaticCatalogManager catalogManager, + GlobalSystemConnector globalSystemConnector) + { + lazyCatalogFactory.setCatalogFactory(defaultCatalogFactory); + catalogManager.registerGlobalSystemConnector(globalSystemConnector); + } + } +} diff --git a/core/trino-main/src/main/java/io/trino/connector/WorkerDynamicCatalogManager.java b/core/trino-main/src/main/java/io/trino/connector/WorkerDynamicCatalogManager.java new file mode 100644 index 000000000000..5cb22ad5b969 --- /dev/null +++ b/core/trino-main/src/main/java/io/trino/connector/WorkerDynamicCatalogManager.java @@ -0,0 +1,138 @@ +/* + * 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.connector; + +import com.google.common.collect.ImmutableList; +import io.trino.Session; +import io.trino.connector.system.GlobalSystemConnector; + +import javax.annotation.PreDestroy; +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; +import javax.inject.Inject; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static java.util.Objects.requireNonNull; + +@ThreadSafe +public class WorkerDynamicCatalogManager + implements ConnectorServicesProvider +{ + private final CatalogFactory catalogFactory; + + private final Lock catalogsUpdateLock = new ReentrantLock(); + private final ConcurrentMap catalogs = new ConcurrentHashMap<>(); + + @GuardedBy("catalogsUpdateLock") + private boolean stopped; + + @Inject + public WorkerDynamicCatalogManager(CatalogFactory catalogFactory) + { + this.catalogFactory = requireNonNull(catalogFactory, "catalogFactory is null"); + } + + @PreDestroy + public void stop() + { + List catalogs; + + catalogsUpdateLock.lock(); + try { + if (stopped) { + return; + } + stopped = true; + + catalogs = ImmutableList.copyOf(this.catalogs.values()); + this.catalogs.clear(); + } + finally { + catalogsUpdateLock.unlock(); + } + + for (CatalogConnector connector : catalogs) { + connector.shutdown(); + } + } + + @Override + public void loadInitialCatalogs() {} + + @Override + public void ensureCatalogsLoaded(Session session, List expectedCatalogs) + { + if (getMissingCatalogs(expectedCatalogs).isEmpty()) { + return; + } + + catalogsUpdateLock.lock(); + try { + if (stopped) { + return; + } + + for (CatalogProperties catalog : getMissingCatalogs(expectedCatalogs)) { + checkArgument(!catalog.getCatalogHandle().equals(GlobalSystemConnector.CATALOG_HANDLE), "Global system catalog not registered"); + CatalogConnector newCatalog = catalogFactory.createCatalog(catalog); + catalogs.put(catalog.getCatalogHandle(), newCatalog); + } + } + finally { + catalogsUpdateLock.unlock(); + } + } + + private List getMissingCatalogs(List expectedCatalogs) + { + return expectedCatalogs.stream() + .filter(catalog -> !catalogs.containsKey(catalog.getCatalogHandle())) + .collect(toImmutableList()); + } + + @Override + public ConnectorServices getConnectorServices(CatalogHandle catalogHandle) + { + CatalogConnector catalogConnector = catalogs.get(catalogHandle.getRootCatalogHandle()); + checkArgument(catalogConnector != null, "No catalog '%s'", catalogHandle.getCatalogName()); + return catalogConnector.getMaterializedConnector(catalogHandle.getType()); + } + + public void registerGlobalSystemConnector(GlobalSystemConnector connector) + { + requireNonNull(connector, "connector is null"); + + catalogsUpdateLock.lock(); + try { + if (stopped) { + return; + } + + CatalogConnector catalog = catalogFactory.createCatalog(GlobalSystemConnector.CATALOG_HANDLE, GlobalSystemConnector.NAME, connector); + if (catalogs.putIfAbsent(GlobalSystemConnector.CATALOG_HANDLE, catalog) != null) { + throw new IllegalStateException("Global system catalog already registered"); + } + } + finally { + catalogsUpdateLock.unlock(); + } + } +} diff --git a/core/trino-main/src/main/java/io/trino/execution/SqlTaskManager.java b/core/trino-main/src/main/java/io/trino/execution/SqlTaskManager.java index a38e465eb395..db5457dae6a1 100644 --- a/core/trino-main/src/main/java/io/trino/execution/SqlTaskManager.java +++ b/core/trino-main/src/main/java/io/trino/execution/SqlTaskManager.java @@ -28,6 +28,7 @@ import io.airlift.units.Duration; import io.trino.Session; import io.trino.collect.cache.NonEvictableLoadingCache; +import io.trino.connector.ConnectorServicesProvider; import io.trino.event.SplitMonitor; import io.trino.exchange.ExchangeManagerRegistry; import io.trino.execution.DynamicFiltersCollector.VersionedDynamicFilterDomains; @@ -108,6 +109,7 @@ public class SqlTaskManager elements -> elements.stream().anyMatch(stackTraceElement -> JONI_REGEXP_FUNCTION_CLASS_NAMES.contains(stackTraceElement.getClassName())); private final VersionEmbedder versionEmbedder; + private final ConnectorServicesProvider connectorServicesProvider; private final ExecutorService taskNotificationExecutor; private final ThreadPoolExecutorMBean taskNotificationExecutorMBean; @@ -131,6 +133,7 @@ public class SqlTaskManager @Inject public SqlTaskManager( VersionEmbedder versionEmbedder, + ConnectorServicesProvider connectorServicesProvider, LocalExecutionPlanner planner, LocationFactory locationFactory, TaskExecutor taskExecutor, @@ -146,6 +149,7 @@ public SqlTaskManager( ExchangeManagerRegistry exchangeManagerRegistry) { this(versionEmbedder, + connectorServicesProvider, planner, locationFactory, taskExecutor, @@ -165,6 +169,7 @@ public SqlTaskManager( @VisibleForTesting public SqlTaskManager( VersionEmbedder versionEmbedder, + ConnectorServicesProvider connectorServicesProvider, LocalExecutionPlanner planner, LocationFactory locationFactory, TaskExecutor taskExecutor, @@ -180,6 +185,8 @@ public SqlTaskManager( ExchangeManagerRegistry exchangeManagerRegistry, Predicate> stuckSplitStackTracePredicate) { + this.connectorServicesProvider = requireNonNull(connectorServicesProvider, "connectorServicesProvider is null"); + requireNonNull(nodeInfo, "nodeInfo is null"); requireNonNull(config, "config is null"); infoCacheTime = config.getInfoMaxAge(); @@ -486,6 +493,8 @@ private TaskInfo doUpdateTask( } } + fragment.ifPresent(planFragment -> connectorServicesProvider.ensureCatalogsLoaded(session, planFragment.getActiveCatalogs())); + sqlTask.recordHeartbeat(); return sqlTask.updateTask(session, fragment, splitAssignments, outputBuffers, dynamicFilterDomains); } diff --git a/core/trino-main/src/main/java/io/trino/metadata/CatalogManager.java b/core/trino-main/src/main/java/io/trino/metadata/CatalogManager.java index 370770162446..abce98ef67e8 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/CatalogManager.java +++ b/core/trino-main/src/main/java/io/trino/metadata/CatalogManager.java @@ -15,42 +15,46 @@ import com.google.common.collect.ImmutableSet; import io.trino.connector.CatalogHandle; +import io.trino.connector.CatalogProperties; -import javax.annotation.concurrent.ThreadSafe; - +import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import static com.google.common.base.Preconditions.checkState; -import static java.util.Objects.requireNonNull; -@ThreadSafe -public class CatalogManager +public interface CatalogManager { - private final ConcurrentMap catalogs = new ConcurrentHashMap<>(); - - public synchronized void registerCatalog(Catalog catalog) - { - requireNonNull(catalog, "catalog is null"); - - checkState(catalogs.put(catalog.getCatalogName(), catalog) == null, "Catalog '%s' is already registered", catalog.getCatalogName()); - } - - public Optional removeCatalog(String catalogName) - { - return Optional.ofNullable(catalogs.remove(catalogName)) - .map(Catalog::getCatalogHandle); - } - - public Set getCatalogNames() - { - return ImmutableSet.copyOf(catalogs.keySet()); - } - - public Optional getCatalog(String catalogName) + CatalogManager NO_CATALOGS = new CatalogManager() { - return Optional.ofNullable(catalogs.get(catalogName)); - } + @Override + public Set getCatalogNames() + { + return ImmutableSet.of(); + } + + @Override + public Optional getCatalog(String catalogName) + { + return Optional.empty(); + } + + @Override + public Optional getCatalogProperties(CatalogHandle catalogHandle) + { + return Optional.empty(); + } + + @Override + public void createCatalog(String catalogName, String connectorName, Map properties) + { + throw new UnsupportedOperationException(); + } + }; + + Set getCatalogNames(); + + Optional getCatalog(String catalogName); + + Optional getCatalogProperties(CatalogHandle catalogHandle); + + void createCatalog(String catalogName, String connectorName, Map properties); } diff --git a/core/trino-main/src/main/java/io/trino/metadata/DiscoveryNodeManager.java b/core/trino-main/src/main/java/io/trino/metadata/DiscoveryNodeManager.java index 2bc8985814f6..53ff4a9d2598 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/DiscoveryNodeManager.java +++ b/core/trino-main/src/main/java/io/trino/metadata/DiscoveryNodeManager.java @@ -28,6 +28,8 @@ import io.airlift.node.NodeInfo; import io.trino.client.NodeVersion; import io.trino.connector.CatalogHandle; +import io.trino.connector.CatalogManagerConfig; +import io.trino.connector.CatalogManagerConfig.CatalogMangerKind; import io.trino.failuredetector.FailureDetector; import io.trino.server.InternalCommunicationConfig; import org.weakref.jmx.Managed; @@ -80,9 +82,10 @@ public final class DiscoveryNodeManager private final ExecutorService nodeStateEventExecutor; private final boolean httpsRequired; private final InternalNode currentNode; + private final boolean allCatalogsOnAllNodes; @GuardedBy("this") - private SetMultimap activeNodesByCatalogHandle; + private Optional> activeNodesByCatalogHandle = Optional.empty(); @GuardedBy("this") private AllNodes allNodes; @@ -100,7 +103,8 @@ public DiscoveryNodeManager( FailureDetector failureDetector, NodeVersion expectedNodeVersion, @ForNodeManager HttpClient httpClient, - InternalCommunicationConfig internalCommunicationConfig) + InternalCommunicationConfig internalCommunicationConfig, + CatalogManagerConfig catalogManagerConfig) { this.serviceSelector = requireNonNull(serviceSelector, "serviceSelector is null"); this.failureDetector = requireNonNull(failureDetector, "failureDetector is null"); @@ -109,6 +113,7 @@ public DiscoveryNodeManager( this.nodeStateUpdateExecutor = newSingleThreadScheduledExecutor(daemonThreadsNamed("node-state-poller-%s")); this.nodeStateEventExecutor = newCachedThreadPool(daemonThreadsNamed("node-state-events-%s")); this.httpsRequired = internalCommunicationConfig.isHttpsRequired(); + this.allCatalogsOnAllNodes = catalogManagerConfig.getCatalogMangerKind() != CatalogMangerKind.STATIC; this.currentNode = findCurrentNode( serviceSelector.selectAllServices(), @@ -264,7 +269,9 @@ private synchronized void refreshNodesInternal() } // nodes by catalog handle changes anytime a node adds or removes a catalog (note: this is not part of the listener system) - activeNodesByCatalogHandle = byCatalogHandleBuilder.build(); + if (!allCatalogsOnAllNodes) { + activeNodesByCatalogHandle = Optional.of(byCatalogHandleBuilder.build()); + } AllNodes allNodes = new AllNodes(activeNodesBuilder.build(), inactiveNodesBuilder.build(), shuttingDownNodesBuilder.build(), coordinatorsBuilder.build()); // only update if all nodes actually changed (note: this does not include the connectors registered with the nodes) @@ -339,8 +346,10 @@ public Set getNodes(NodeState state) @Override public synchronized Set getActiveCatalogNodes(CatalogHandle catalogHandle) { - // activeNodesByCatalogHandle is immutable - return activeNodesByCatalogHandle.get(catalogHandle); + // activeNodesByCatalogName is immutable + return activeNodesByCatalogHandle + .map(map -> map.get(catalogHandle)) + .orElseGet(() -> allNodes.getActiveNodes()); } @Override diff --git a/core/trino-main/src/main/java/io/trino/metadata/InMemoryNodeManager.java b/core/trino-main/src/main/java/io/trino/metadata/InMemoryNodeManager.java index 21f5c7e3af2e..b7cc68c65d1d 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/InMemoryNodeManager.java +++ b/core/trino-main/src/main/java/io/trino/metadata/InMemoryNodeManager.java @@ -13,21 +13,14 @@ */ package io.trino.metadata; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Multimaps; -import com.google.common.collect.SetMultimap; import io.trino.client.NodeVersion; import io.trino.connector.CatalogHandle; -import javax.annotation.concurrent.GuardedBy; -import javax.inject.Inject; - import java.net.URI; -import java.util.ArrayList; -import java.util.List; +import java.util.Optional; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import static java.util.Objects.requireNonNull; @@ -35,55 +28,30 @@ public class InMemoryNodeManager implements InternalNodeManager { - private final InternalNode localNode; - private final SetMultimap remoteNodes = Multimaps.synchronizedSetMultimap(HashMultimap.create()); - - @GuardedBy("this") - private final List> listeners = new ArrayList<>(); - - @Inject - public InMemoryNodeManager() - { - this(URI.create("local://127.0.0.1:8080")); - } + private static final InternalNode CURRENT_NODE = new InternalNode("local", URI.create("local://127.0.0.1:8080"), NodeVersion.UNKNOWN, true); + private final Set allNodes = ConcurrentHashMap.newKeySet(); - public InMemoryNodeManager(URI localUri) + public InMemoryNodeManager(InternalNode... remoteNodes) { - localNode = new InternalNode("local", localUri, NodeVersion.UNKNOWN, true); + this(ImmutableSet.copyOf(remoteNodes)); } - public void addCurrentNodeCatalog(CatalogHandle catalogHandle) + public InMemoryNodeManager(Set remoteNodes) { - addNode(catalogHandle, localNode); + allNodes.add(CURRENT_NODE); + allNodes.addAll(remoteNodes); } - public void addNode(CatalogHandle catalogHandle, InternalNode... nodes) + public void addNodes(InternalNode... internalNodes) { - addNode(catalogHandle, ImmutableList.copyOf(nodes)); - } - - public void addNode(CatalogHandle catalogHandle, Iterable nodes) - { - remoteNodes.putAll(catalogHandle, nodes); - - List> listeners; - synchronized (this) { - listeners = ImmutableList.copyOf(this.listeners); + for (InternalNode internalNode : internalNodes) { + allNodes.add(requireNonNull(internalNode, "internalNode is null")); } - AllNodes allNodes = getAllNodes(); - listeners.forEach(listener -> listener.accept(allNodes)); } - public void removeNode(InternalNode node) + public void removeNode(InternalNode internalNode) { - for (CatalogHandle catalogHandle : ImmutableSet.copyOf(remoteNodes.keySet())) { - removeNode(catalogHandle, node); - } - } - - public void removeNode(CatalogHandle catalogHandle, InternalNode node) - { - remoteNodes.remove(catalogHandle, node); + allNodes.remove(internalNode); } @Override @@ -91,11 +59,10 @@ public Set getNodes(NodeState state) { switch (state) { case ACTIVE: - return getAllNodes().getActiveNodes(); + return allNodes; case INACTIVE: - return getAllNodes().getInactiveNodes(); case SHUTTING_DOWN: - return getAllNodes().getShuttingDownNodes(); + return ImmutableSet.of(); } throw new IllegalArgumentException("Unknown node state " + state); } @@ -103,53 +70,44 @@ public Set getNodes(NodeState state) @Override public Set getActiveCatalogNodes(CatalogHandle catalogHandle) { - return ImmutableSet.copyOf(remoteNodes.get(catalogHandle)); + return allNodes; } @Override public NodesSnapshot getActiveNodesSnapshot() { - Set allActiveNodes = ImmutableSet.builder() - .addAll(remoteNodes.values()) - .add(localNode) - .build(); - return new NodesSnapshot(allActiveNodes, remoteNodes); + return new NodesSnapshot(allNodes, Optional.empty()); } @Override public AllNodes getAllNodes() { - return new AllNodes(ImmutableSet.builder().add(localNode).addAll(remoteNodes.values()).build(), ImmutableSet.of(), ImmutableSet.of(), ImmutableSet.of(localNode)); + return new AllNodes( + allNodes, + ImmutableSet.of(), + ImmutableSet.of(), + ImmutableSet.of(CURRENT_NODE)); } @Override public InternalNode getCurrentNode() { - return localNode; + return CURRENT_NODE; } @Override public Set getCoordinators() { // always use localNode as coordinator - return ImmutableSet.of(localNode); + return ImmutableSet.of(CURRENT_NODE); } @Override - public void refreshNodes() - { - // no-op - } + public void refreshNodes() {} @Override - public synchronized void addNodeChangeListener(Consumer listener) - { - listeners.add(requireNonNull(listener, "listener is null")); - } + public void addNodeChangeListener(Consumer listener) {} @Override - public synchronized void removeNodeChangeListener(Consumer listener) - { - listeners.remove(requireNonNull(listener, "listener is null")); - } + public void removeNodeChangeListener(Consumer listener) {} } diff --git a/core/trino-main/src/main/java/io/trino/metadata/InternalNodeManager.java b/core/trino-main/src/main/java/io/trino/metadata/InternalNodeManager.java index b504c6e7c02b..b6499de3477a 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/InternalNodeManager.java +++ b/core/trino-main/src/main/java/io/trino/metadata/InternalNodeManager.java @@ -18,6 +18,7 @@ import com.google.common.collect.SetMultimap; import io.trino.connector.CatalogHandle; +import java.util.Optional; import java.util.Set; import java.util.function.Consumer; @@ -46,14 +47,14 @@ public interface InternalNodeManager class NodesSnapshot { private final Set allNodes; - private final SetMultimap connectorNodes; + private final Optional> connectorNodes; - public NodesSnapshot(Set allActiveNodes, SetMultimap activeNodesByCatalogName) + public NodesSnapshot(Set allActiveNodes, Optional> activeNodesByCatalogName) { requireNonNull(allActiveNodes, "allActiveNodes is null"); requireNonNull(activeNodesByCatalogName, "activeNodesByCatalogName is null"); this.allNodes = ImmutableSet.copyOf(allActiveNodes); - this.connectorNodes = ImmutableSetMultimap.copyOf(activeNodesByCatalogName); + this.connectorNodes = activeNodesByCatalogName.map(ImmutableSetMultimap::copyOf); } public Set getAllNodes() @@ -63,7 +64,9 @@ public Set getAllNodes() public Set getConnectorNodes(CatalogHandle catalogHandle) { - return connectorNodes.get(catalogHandle); + return connectorNodes + .map(map -> map.get(catalogHandle)) + .orElse(allNodes); } } } diff --git a/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java b/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java index 964342c46f22..d6aa5434fe7a 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java +++ b/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java @@ -2578,12 +2578,6 @@ public static class TestMetadataManagerBuilder private TestMetadataManagerBuilder() {} - public TestMetadataManagerBuilder withCatalogManager(CatalogManager catalogManager) - { - this.transactionManager = createTestTransactionManager(catalogManager); - return this; - } - public TestMetadataManagerBuilder withTransactionManager(TransactionManager transactionManager) { this.transactionManager = transactionManager; diff --git a/core/trino-main/src/main/java/io/trino/metadata/StaticCatalogStore.java b/core/trino-main/src/main/java/io/trino/metadata/StaticCatalogStore.java deleted file mode 100644 index 67aac3cb3161..000000000000 --- a/core/trino-main/src/main/java/io/trino/metadata/StaticCatalogStore.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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.metadata; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.io.Files; -import io.airlift.log.Logger; -import io.trino.connector.ConnectorManager; - -import javax.inject.Inject; - -import java.io.File; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; - -import static com.google.common.base.MoreObjects.firstNonNull; -import static com.google.common.base.Preconditions.checkState; -import static io.airlift.configuration.ConfigurationLoader.loadPropertiesFrom; - -public class StaticCatalogStore -{ - private static final Logger log = Logger.get(StaticCatalogStore.class); - private final ConnectorManager connectorManager; - private final File catalogConfigurationDir; - private final Set disabledCatalogs; - private final AtomicBoolean catalogsLoading = new AtomicBoolean(); - - @Inject - public StaticCatalogStore(ConnectorManager connectorManager, StaticCatalogStoreConfig config) - { - this(connectorManager, - config.getCatalogConfigurationDir(), - firstNonNull(config.getDisabledCatalogs(), ImmutableList.of())); - } - - public StaticCatalogStore(ConnectorManager connectorManager, File catalogConfigurationDir, List disabledCatalogs) - { - this.connectorManager = connectorManager; - this.catalogConfigurationDir = catalogConfigurationDir; - this.disabledCatalogs = ImmutableSet.copyOf(disabledCatalogs); - } - - public void loadCatalogs() - throws Exception - { - if (!catalogsLoading.compareAndSet(false, true)) { - return; - } - - for (File file : listFiles(catalogConfigurationDir)) { - if (file.isFile() && file.getName().endsWith(".properties")) { - loadCatalog(file); - } - } - } - - private void loadCatalog(File file) - throws Exception - { - String catalogName = Files.getNameWithoutExtension(file.getName()); - if (disabledCatalogs.contains(catalogName)) { - log.info("Skipping disabled catalog %s", catalogName); - return; - } - - log.info("-- Loading catalog %s --", file); - Map properties = new HashMap<>(loadPropertiesFrom(file.getPath())); - - String connectorName = properties.remove("connector.name"); - checkState(connectorName != null, "Catalog configuration %s does not contain connector.name", file.getAbsoluteFile()); - - connectorManager.createCatalog(catalogName, connectorName, ImmutableMap.copyOf(properties)); - log.info("-- Added catalog %s using connector %s --", catalogName, connectorName); - } - - private static List listFiles(File installedPluginsDir) - { - if (installedPluginsDir != null && installedPluginsDir.isDirectory()) { - File[] files = installedPluginsDir.listFiles(); - if (files != null) { - return ImmutableList.copyOf(files); - } - } - return ImmutableList.of(); - } -} diff --git a/core/trino-main/src/main/java/io/trino/security/AccessControlManager.java b/core/trino-main/src/main/java/io/trino/security/AccessControlManager.java index 65525564c2d9..9946337b0ae1 100644 --- a/core/trino-main/src/main/java/io/trino/security/AccessControlManager.java +++ b/core/trino-main/src/main/java/io/trino/security/AccessControlManager.java @@ -124,7 +124,7 @@ public final void addSystemAccessControlFactory(SystemAccessControlFactory acces } /** - * Lazy registry for connector access controls due to circular dependency between access control and connector creation in ConnectorManager. + * Lazy registry for connector access controls due to circular dependency between access control and connector creation in CatalogManager. */ public void setConnectorAccessControlProvider(CatalogServiceProvider> connectorAccessControlProvider) { diff --git a/core/trino-main/src/main/java/io/trino/server/Server.java b/core/trino-main/src/main/java/io/trino/server/Server.java index 1656afb7d7c8..be9c7e038ba3 100644 --- a/core/trino-main/src/main/java/io/trino/server/Server.java +++ b/core/trino-main/src/main/java/io/trino/server/Server.java @@ -39,6 +39,8 @@ import io.airlift.tracetoken.TraceTokenModule; import io.trino.client.NodeVersion; import io.trino.connector.CatalogHandle; +import io.trino.connector.CatalogManagerConfig; +import io.trino.connector.CatalogManagerConfig.CatalogMangerKind; import io.trino.connector.CatalogManagerModule; import io.trino.connector.ConnectorServices; import io.trino.connector.ConnectorServicesProvider; @@ -50,7 +52,6 @@ import io.trino.execution.warnings.WarningCollectorModule; import io.trino.metadata.Catalog; import io.trino.metadata.CatalogManager; -import io.trino.metadata.StaticCatalogStore; import io.trino.security.AccessControlManager; import io.trino.security.AccessControlModule; import io.trino.security.GroupProviderManager; @@ -134,17 +135,22 @@ private void doStart(String trinoVersion) injector.getInstance(PluginManager.class).loadPlugins(); - injector.getInstance(StaticCatalogStore.class).loadCatalogs(); + ConnectorServicesProvider connectorServicesProvider = injector.getInstance(ConnectorServicesProvider.class); + connectorServicesProvider.loadInitialCatalogs(); + // Only static catalog manager announces catalogs // Connector event listeners are only supported for statically loaded catalogs // TODO: remove connector event listeners or add support for dynamic loading from connector - addConnectorEventListeners( - injector.getInstance(CatalogManager.class), - injector.getInstance(ConnectorServicesProvider.class), - injector.getInstance(EventListenerManager.class)); + if (injector.getInstance(CatalogManagerConfig.class).getCatalogMangerKind() == CatalogMangerKind.STATIC) { + CatalogManager catalogManager = injector.getInstance(CatalogManager.class); + addConnectorEventListeners( + catalogManager, + injector.getInstance(ConnectorServicesProvider.class), + injector.getInstance(EventListenerManager.class)); - // TODO: remove this huge hack - updateConnectorIds(injector.getInstance(Announcer.class), injector.getInstance(CatalogManager.class)); + // TODO: remove this huge hack + updateConnectorIds(injector.getInstance(Announcer.class), catalogManager); + } injector.getInstance(SessionPropertyDefaults.class).loadConfigurationManager(); injector.getInstance(ResourceGroupManager.class).loadConfigurationManager(); diff --git a/core/trino-main/src/main/java/io/trino/server/ServerMainModule.java b/core/trino-main/src/main/java/io/trino/server/ServerMainModule.java index 89f34ae3f006..a3dc7a6f1512 100644 --- a/core/trino-main/src/main/java/io/trino/server/ServerMainModule.java +++ b/core/trino-main/src/main/java/io/trino/server/ServerMainModule.java @@ -75,8 +75,6 @@ import io.trino.metadata.Metadata; import io.trino.metadata.MetadataManager; import io.trino.metadata.ProcedureRegistry; -import io.trino.metadata.StaticCatalogStore; -import io.trino.metadata.StaticCatalogStoreConfig; import io.trino.metadata.SystemFunctionBundle; import io.trino.metadata.SystemSecurityMetadata; import io.trino.metadata.TableFunctionRegistry; @@ -349,8 +347,6 @@ protected void setup(Binder binder) binder.bind(PageSinkProvider.class).to(PageSinkManager.class).in(Scopes.SINGLETON); // metadata - binder.bind(StaticCatalogStore.class).in(Scopes.SINGLETON); - configBinder(binder).bindConfig(StaticCatalogStoreConfig.class); binder.bind(MetadataManager.class).in(Scopes.SINGLETON); binder.bind(Metadata.class).to(MetadataManager.class).in(Scopes.SINGLETON); newOptionalBinder(binder, SystemSecurityMetadata.class) diff --git a/core/trino-main/src/main/java/io/trino/server/testing/TestingTrinoServer.java b/core/trino-main/src/main/java/io/trino/server/testing/TestingTrinoServer.java index 24e4c6043487..30d40ee2c7d9 100644 --- a/core/trino-main/src/main/java/io/trino/server/testing/TestingTrinoServer.java +++ b/core/trino-main/src/main/java/io/trino/server/testing/TestingTrinoServer.java @@ -13,8 +13,6 @@ */ package io.trino.server.testing; -import com.google.common.base.Joiner; -import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.io.Closer; @@ -27,7 +25,6 @@ import io.airlift.bootstrap.LifeCycleManager; import io.airlift.discovery.client.Announcer; import io.airlift.discovery.client.DiscoveryModule; -import io.airlift.discovery.client.ServiceAnnouncement; import io.airlift.discovery.client.ServiceSelectorManager; import io.airlift.discovery.client.testing.TestingDiscoveryModule; import io.airlift.event.client.EventModule; @@ -38,9 +35,7 @@ import io.airlift.json.JsonModule; import io.airlift.node.testing.TestingNodeModule; import io.airlift.tracetoken.TraceTokenModule; -import io.trino.connector.CatalogHandle; import io.trino.connector.CatalogManagerModule; -import io.trino.connector.ConnectorManager; import io.trino.connector.ConnectorServicesProvider; import io.trino.cost.StatsCalculator; import io.trino.dispatcher.DispatchManager; @@ -62,7 +57,6 @@ import io.trino.metadata.FunctionBundle; import io.trino.metadata.FunctionManager; import io.trino.metadata.GlobalFunctionCatalog; -import io.trino.metadata.InternalNode; import io.trino.metadata.InternalNodeManager; import io.trino.metadata.Metadata; import io.trino.metadata.ProcedureRegistry; @@ -113,21 +107,16 @@ import java.time.Duration; import java.time.Instant; import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeoutException; import static com.google.common.base.Preconditions.checkState; -import static com.google.common.base.Strings.nullToEmpty; import static com.google.common.io.MoreFiles.deleteRecursively; import static com.google.common.io.RecursiveDeleteOption.ALLOW_INSECURE; import static com.google.inject.util.Modules.EMPTY_MODULE; -import static io.airlift.discovery.client.ServiceAnnouncement.serviceAnnouncement; import static java.lang.Integer.parseInt; import static java.nio.file.Files.createTempDirectory; import static java.nio.file.Files.isDirectory; @@ -152,7 +141,7 @@ public static Builder builder() private final boolean preserveData; private final LifeCycleManager lifeCycleManager; private final PluginManager pluginManager; - private final ConnectorManager connectorManager; + private final Optional catalogManager; private final TestingHttpServer server; private final TransactionManager transactionManager; private final Metadata metadata; @@ -175,7 +164,6 @@ public static Builder builder() private final LocalMemoryManager localMemoryManager; private final InternalNodeManager nodeManager; private final ServiceSelectorManager serviceSelectorManager; - private final Announcer announcer; private final DispatchManager dispatchManager; private final SqlQueryManager queryManager; private final SqlTaskManager taskManager; @@ -237,6 +225,7 @@ private TestingTrinoServer( ImmutableMap.Builder serverProperties = ImmutableMap.builder() .putAll(properties) .put("coordinator", String.valueOf(coordinator)) + .put("catalog.management", "dynamic") .put("task.concurrency", "4") .put("task.max-worker-threads", "4") .put("exchange.client-threads", "4") @@ -245,6 +234,7 @@ private TestingTrinoServer( if (coordinator) { // TODO: enable failure detector serverProperties.put("failure-detector.enabled", "false"); + serverProperties.put("catalog.store", "none"); } serverProperties.put("optimizer.ignore-stats-calculator-failures", "false"); @@ -309,7 +299,11 @@ private TestingTrinoServer( pluginManager = injector.getInstance(PluginManager.class); - connectorManager = injector.getInstance(ConnectorManager.class); + Optional catalogManager = Optional.empty(); + if (injector.getExistingBinding(Key.get(CatalogManager.class)) != null) { + catalogManager = Optional.of(injector.getInstance(CatalogManager.class)); + } + this.catalogManager = catalogManager; server = injector.getInstance(TestingHttpServer.class); transactionManager = injector.getInstance(TransactionManager.class); @@ -354,7 +348,6 @@ private TestingTrinoServer( taskManager = injector.getInstance(SqlTaskManager.class); shutdownAction = injector.getInstance(ShutdownAction.class); mBeanServer = injector.getInstance(MBeanServer.class); - announcer = injector.getInstance(Announcer.class); failureInjector = injector.getInstance(FailureInjector.class); exchangeManagerRegistry = injector.getInstance(ExchangeManagerRegistry.class); @@ -363,7 +356,7 @@ private TestingTrinoServer( EventListenerManager eventListenerManager = injector.getInstance(EventListenerManager.class); eventListeners.forEach(eventListenerManager::addEventListener); - announcer.forceAnnounce(); + injector.getInstance(Announcer.class).forceAnnounce(); refreshNodes(); } @@ -417,16 +410,18 @@ public void addFinalQueryInfoListener(QueryId queryId, StateChangeListener properties) + public void createCatalog(String catalogName, String connectorName, Map properties) { - CatalogHandle catalogHandle = connectorManager.createCatalog(catalogName, connectorName, properties); - updateConnectorIdAnnouncement(announcer, catalogHandle, nodeManager); - return catalogHandle; + if (catalogManager.isEmpty()) { + // this is a worker so catalogs are dynamically registered + return; + } + catalogManager.get().createCatalog(catalogName, connectorName, properties); } public void loadExchangeManager(String name, Map properties) @@ -620,11 +615,6 @@ public void waitForNodeRefresh(Duration timeout) } } - public Set getActiveNodesWithConnector(CatalogHandle catalogHandle) - { - return nodeManager.getActiveCatalogNodes(catalogHandle); - } - public T getInstance(Key key) { return injector.getInstance(key); @@ -647,40 +637,6 @@ public void injectTaskFailure( errorType); } - private static void updateConnectorIdAnnouncement(Announcer announcer, CatalogHandle catalogHandle, InternalNodeManager nodeManager) - { - // - // This code was copied from TrinoServer, and is a hack that should be removed when the connectorId property is removed - // - - // get existing announcement - ServiceAnnouncement announcement = getTrinoAnnouncement(announcer.getServiceAnnouncements()); - - // update catalogHandleIds property - Map properties = new LinkedHashMap<>(announcement.getProperties()); - String property = nullToEmpty(properties.get("catalogHandleIds")); - Set catalogHandleIds = new LinkedHashSet<>(Splitter.on(',').trimResults().omitEmptyStrings().splitToList(property)); - catalogHandleIds.add(catalogHandle.getId()); - properties.put("catalogHandleIds", Joiner.on(',').join(catalogHandleIds)); - - // update announcement - announcer.removeServiceAnnouncement(announcement.getId()); - announcer.addServiceAnnouncement(serviceAnnouncement(announcement.getType()).addProperties(properties).build()); - announcer.forceAnnounce(); - - nodeManager.refreshNodes(); - } - - private static ServiceAnnouncement getTrinoAnnouncement(Set announcements) - { - for (ServiceAnnouncement announcement : announcements) { - if (announcement.getType().equals("trino")) { - return announcement; - } - } - throw new RuntimeException("Trino announcement not found: " + announcements); - } - private static Path tempDirectory() { try { diff --git a/core/trino-main/src/main/java/io/trino/sql/planner/PlanFragment.java b/core/trino-main/src/main/java/io/trino/sql/planner/PlanFragment.java index 57990a12b5c0..474564f1dd43 100644 --- a/core/trino-main/src/main/java/io/trino/sql/planner/PlanFragment.java +++ b/core/trino-main/src/main/java/io/trino/sql/planner/PlanFragment.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import io.trino.connector.CatalogProperties; import io.trino.cost.StatsAndCosts; import io.trino.spi.type.Type; import io.trino.sql.planner.plan.PlanFragmentId; @@ -50,6 +51,7 @@ public class PlanFragment private final List remoteSourceNodes; private final PartitioningScheme partitioningScheme; private final StatsAndCosts statsAndCosts; + private final List activeCatalogs; private final Optional jsonRepresentation; // Only for creating instances without the JSON representation embedded @@ -64,7 +66,8 @@ private PlanFragment( Set partitionedSourceNodes, List remoteSourceNodes, PartitioningScheme partitioningScheme, - StatsAndCosts statsAndCosts) + StatsAndCosts statsAndCosts, + List activeCatalogs) { this.id = requireNonNull(id, "id is null"); this.root = requireNonNull(root, "root is null"); @@ -77,6 +80,7 @@ private PlanFragment( this.remoteSourceNodes = requireNonNull(remoteSourceNodes, "remoteSourceNodes is null"); this.partitioningScheme = requireNonNull(partitioningScheme, "partitioningScheme is null"); this.statsAndCosts = requireNonNull(statsAndCosts, "statsAndCosts is null"); + this.activeCatalogs = requireNonNull(activeCatalogs, "activeCatalogs is null"); this.jsonRepresentation = Optional.empty(); } @@ -89,6 +93,7 @@ public PlanFragment( @JsonProperty("partitionedSources") List partitionedSources, @JsonProperty("partitioningScheme") PartitioningScheme partitioningScheme, @JsonProperty("statsAndCosts") StatsAndCosts statsAndCosts, + @JsonProperty("activeCatalogs") List activeCatalogs, @JsonProperty("jsonRepresentation") Optional jsonRepresentation) { this.id = requireNonNull(id, "id is null"); @@ -98,6 +103,7 @@ public PlanFragment( this.partitionedSources = ImmutableList.copyOf(requireNonNull(partitionedSources, "partitionedSources is null")); this.partitionedSourcesSet = ImmutableSet.copyOf(partitionedSources); this.statsAndCosts = requireNonNull(statsAndCosts, "statsAndCosts is null"); + this.activeCatalogs = requireNonNull(activeCatalogs, "activeCatalogs is null"); this.jsonRepresentation = requireNonNull(jsonRepresentation, "jsonRepresentation is null"); checkArgument(partitionedSourcesSet.size() == partitionedSources.size(), "partitionedSources contains duplicates"); @@ -164,6 +170,12 @@ public StatsAndCosts getStatsAndCosts() return statsAndCosts; } + @JsonProperty + public List getActiveCatalogs() + { + return activeCatalogs; + } + @JsonProperty public Optional getJsonRepresentation() { @@ -188,7 +200,8 @@ public PlanFragment withoutEmbeddedJsonRepresentation() this.partitionedSourceNodes, this.remoteSourceNodes, this.partitioningScheme, - this.statsAndCosts); + this.statsAndCosts, + this.activeCatalogs); } public List getTypes() @@ -242,7 +255,7 @@ private static void findRemoteSourceNodes(PlanNode node, ImmutableList.Builder bucketToPartition) { - return new PlanFragment(id, root, symbols, partitioning, partitionedSources, partitioningScheme.withBucketToPartition(bucketToPartition), statsAndCosts, jsonRepresentation); + return new PlanFragment(id, root, symbols, partitioning, partitionedSources, partitioningScheme.withBucketToPartition(bucketToPartition), statsAndCosts, activeCatalogs, jsonRepresentation); } @Override diff --git a/core/trino-main/src/main/java/io/trino/sql/planner/PlanFragmenter.java b/core/trino-main/src/main/java/io/trino/sql/planner/PlanFragmenter.java index 38ddb77e1419..fa44a15dd43e 100644 --- a/core/trino-main/src/main/java/io/trino/sql/planner/PlanFragmenter.java +++ b/core/trino-main/src/main/java/io/trino/sql/planner/PlanFragmenter.java @@ -17,9 +17,12 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import io.trino.Session; +import io.trino.connector.CatalogProperties; import io.trino.cost.StatsAndCosts; import io.trino.execution.QueryManagerConfig; import io.trino.execution.warnings.WarningCollector; +import io.trino.metadata.CatalogInfo; +import io.trino.metadata.CatalogManager; import io.trino.metadata.FunctionManager; import io.trino.metadata.Metadata; import io.trino.metadata.TableHandle; @@ -47,6 +50,7 @@ import io.trino.sql.planner.plan.TableScanNode; import io.trino.sql.planner.plan.TableWriterNode; import io.trino.sql.planner.plan.ValuesNode; +import io.trino.transaction.TransactionManager; import javax.inject.Inject; @@ -86,22 +90,32 @@ public class PlanFragmenter private final Metadata metadata; private final FunctionManager functionManager; + private final TransactionManager transactionManager; + private final CatalogManager catalogManager; private final QueryManagerConfig config; @Inject public PlanFragmenter( Metadata metadata, FunctionManager functionManager, + TransactionManager transactionManager, + CatalogManager catalogManager, QueryManagerConfig queryManagerConfig) { this.metadata = requireNonNull(metadata, "metadata is null"); this.functionManager = requireNonNull(functionManager, "functionManager is null"); + this.transactionManager = requireNonNull(transactionManager, "transactionManager is null"); + this.catalogManager = requireNonNull(catalogManager, "catalogManager is null"); this.config = requireNonNull(queryManagerConfig, "queryManagerConfig is null"); } public SubPlan createSubPlans(Session session, Plan plan, boolean forceSingleNode, WarningCollector warningCollector) { - Fragmenter fragmenter = new Fragmenter(session, metadata, functionManager, plan.getTypes(), plan.getStatsAndCosts()); + List activeCatalogs = transactionManager.getActiveCatalogs(session.getTransactionId().orElseThrow()).stream() + .map(CatalogInfo::getCatalogHandle) + .flatMap(catalogHandle -> catalogManager.getCatalogProperties(catalogHandle).stream()) + .collect(toImmutableList()); + Fragmenter fragmenter = new Fragmenter(session, metadata, functionManager, plan.getTypes(), plan.getStatsAndCosts(), activeCatalogs); FragmentProperties properties = new FragmentProperties(new PartitioningScheme(Partitioning.create(SINGLE_DISTRIBUTION, ImmutableList.of()), plan.getRoot().getOutputSymbols())); if (forceSingleNode || isForceSingleNodeOutput(session)) { @@ -174,6 +188,7 @@ private SubPlan reassignPartitioningHandleIfNecessaryHelper(Session session, Sub outputPartitioningScheme.isReplicateNullsAndAny(), outputPartitioningScheme.getBucketToPartition()), fragment.getStatsAndCosts(), + fragment.getActiveCatalogs(), fragment.getJsonRepresentation()); ImmutableList.Builder childrenBuilder = ImmutableList.builder(); @@ -193,15 +208,17 @@ private static class Fragmenter private final FunctionManager functionManager; private final TypeProvider types; private final StatsAndCosts statsAndCosts; + private final List activeCatalogs; private int nextFragmentId = ROOT_FRAGMENT_ID + 1; - public Fragmenter(Session session, Metadata metadata, FunctionManager functionManager, TypeProvider types, StatsAndCosts statsAndCosts) + public Fragmenter(Session session, Metadata metadata, FunctionManager functionManager, TypeProvider types, StatsAndCosts statsAndCosts, List activeCatalogs) { this.session = requireNonNull(session, "session is null"); this.metadata = requireNonNull(metadata, "metadata is null"); this.functionManager = requireNonNull(functionManager, "functionManager is null"); this.types = requireNonNull(types, "types is null"); this.statsAndCosts = requireNonNull(statsAndCosts, "statsAndCosts is null"); + this.activeCatalogs = requireNonNull(activeCatalogs, "activeCatalogs is null"); } public SubPlan buildRootFragment(PlanNode root, FragmentProperties properties) @@ -232,6 +249,7 @@ private SubPlan buildFragment(PlanNode root, FragmentProperties properties, Plan schedulingOrder, properties.getPartitioningScheme(), statsAndCosts.getForSubplan(root), + activeCatalogs, Optional.of(jsonFragmentPlan(root, symbols, metadata, functionManager, session))); return new SubPlan(fragment, properties.getChildren()); diff --git a/core/trino-main/src/main/java/io/trino/sql/planner/planprinter/PlanPrinter.java b/core/trino-main/src/main/java/io/trino/sql/planner/planprinter/PlanPrinter.java index ec4152b80891..76e6b88796ba 100644 --- a/core/trino-main/src/main/java/io/trino/sql/planner/planprinter/PlanPrinter.java +++ b/core/trino-main/src/main/java/io/trino/sql/planner/planprinter/PlanPrinter.java @@ -444,6 +444,7 @@ public static String graphvizLogicalPlan(PlanNode plan, TypeProvider types) ImmutableList.of(plan.getId()), new PartitioningScheme(Partitioning.create(SINGLE_DISTRIBUTION, ImmutableList.of()), plan.getOutputSymbols()), StatsAndCosts.empty(), + ImmutableList.of(), Optional.empty()); return GraphvizPrinter.printLogical(ImmutableList.of(fragment)); } diff --git a/core/trino-main/src/main/java/io/trino/testing/LocalQueryRunner.java b/core/trino-main/src/main/java/io/trino/testing/LocalQueryRunner.java index d66484e7406c..49171de52b7f 100644 --- a/core/trino-main/src/main/java/io/trino/testing/LocalQueryRunner.java +++ b/core/trino-main/src/main/java/io/trino/testing/LocalQueryRunner.java @@ -24,11 +24,11 @@ import io.trino.SystemSessionProperties; import io.trino.SystemSessionPropertiesProvider; import io.trino.connector.CatalogFactory; -import io.trino.connector.CatalogHandle; import io.trino.connector.CatalogServiceProviderModule; -import io.trino.connector.ConnectorManager; import io.trino.connector.ConnectorServicesProvider; +import io.trino.connector.CoordinatorDynamicCatalogManager; import io.trino.connector.DefaultCatalogFactory; +import io.trino.connector.LazyCatalogFactory; import io.trino.connector.system.AnalyzePropertiesSystemTable; import io.trino.connector.system.CatalogSystemTable; import io.trino.connector.system.ColumnPropertiesSystemTable; @@ -85,6 +85,7 @@ import io.trino.metadata.InMemoryNodeManager; import io.trino.metadata.InternalBlockEncodingSerde; import io.trino.metadata.InternalFunctionBundle; +import io.trino.metadata.InternalNodeManager; import io.trino.metadata.LiteralFunction; import io.trino.metadata.MaterializedViewPropertyManager; import io.trino.metadata.Metadata; @@ -231,6 +232,7 @@ import static io.trino.connector.CatalogServiceProviderModule.createTableProceduresPropertyManager; import static io.trino.connector.CatalogServiceProviderModule.createTableProceduresProvider; import static io.trino.connector.CatalogServiceProviderModule.createTablePropertyManager; +import static io.trino.connector.CatalogStore.NO_STORED_CATALOGS; import static io.trino.spi.connector.Constraint.alwaysTrue; import static io.trino.spi.connector.DynamicFilter.EMPTY; import static io.trino.sql.ParameterUtils.parameterExtractor; @@ -256,7 +258,7 @@ public class LocalQueryRunner private final SqlParser sqlParser; private final PlanFragmenter planFragmenter; - private final InMemoryNodeManager nodeManager; + private final InternalNodeManager nodeManager; private final BlockTypeOperators blockTypeOperators; private final PlannerContext plannerContext; private final TypeRegistry typeRegistry; @@ -290,7 +292,7 @@ public class LocalQueryRunner private final JoinFilterFunctionCompiler joinFilterFunctionCompiler; private final JoinCompiler joinCompiler; private final CatalogFactory catalogFactory; - private final ConnectorManager connectorManager; + private final CoordinatorDynamicCatalogManager catalogManager; private final PluginManager pluginManager; private final ExchangeManagerRegistry exchangeManagerRegistry; @@ -348,7 +350,9 @@ private LocalQueryRunner( NodeSchedulerConfig nodeSchedulerConfig = new NodeSchedulerConfig().setIncludeCoordinator(true); requireNonNull(featuresConfig, "featuresConfig is null"); this.optimizerConfig = new OptimizerConfig(); - CatalogManager catalogManager = new CatalogManager(); + LazyCatalogFactory catalogFactory = new LazyCatalogFactory(); + this.catalogFactory = catalogFactory; + this.catalogManager = new CoordinatorDynamicCatalogManager(NO_STORED_CATALOGS, catalogFactory); this.transactionManager = InMemoryTransactionManager.create( new TransactionManagerConfig().setIdleTimeout(new Duration(1, TimeUnit.DAYS)), yieldExecutor, @@ -388,7 +392,7 @@ private LocalQueryRunner( HandleResolver handleResolver = new HandleResolver(); NodeInfo nodeInfo = new NodeInfo("test"); - this.catalogFactory = new DefaultCatalogFactory( + catalogFactory.setCatalogFactory(new DefaultCatalogFactory( metadata, accessControl, handleResolver, @@ -399,25 +403,24 @@ private LocalQueryRunner( testingVersionEmbedder(), transactionManager, typeManager, - nodeSchedulerConfig); - this.connectorManager = new ConnectorManager(catalogFactory, catalogManager); - this.splitManager = new SplitManager(createSplitManagerProvider(connectorManager), new QueryManagerConfig()); - this.pageSourceManager = new PageSourceManager(createPageSourceProvider(connectorManager)); - this.pageSinkManager = new PageSinkManager(createPageSinkProvider(connectorManager)); - this.indexManager = new IndexManager(createIndexProvider(connectorManager)); + nodeSchedulerConfig)); + this.splitManager = new SplitManager(createSplitManagerProvider(catalogManager), new QueryManagerConfig()); + this.pageSourceManager = new PageSourceManager(createPageSourceProvider(catalogManager)); + this.pageSinkManager = new PageSinkManager(createPageSinkProvider(catalogManager)); + this.indexManager = new IndexManager(createIndexProvider(catalogManager)); NodeScheduler nodeScheduler = new NodeScheduler(new UniformNodeSelectorFactory(nodeManager, nodeSchedulerConfig, new NodeTaskMap(finalizerService))); - this.sessionPropertyManager = createSessionPropertyManager(connectorManager, extraSessionProperties, taskManagerConfig, featuresConfig, optimizerConfig); - this.nodePartitioningManager = new NodePartitioningManager(nodeScheduler, blockTypeOperators, createNodePartitioningProvider(connectorManager)); - TableProceduresRegistry tableProceduresRegistry = new TableProceduresRegistry(createTableProceduresProvider(connectorManager)); - TableFunctionRegistry tableFunctionRegistry = new TableFunctionRegistry(createTableFunctionProvider(connectorManager)); - this.schemaPropertyManager = createSchemaPropertyManager(connectorManager); - this.columnPropertyManager = createColumnPropertyManager(connectorManager); - this.tablePropertyManager = createTablePropertyManager(connectorManager); - this.materializedViewPropertyManager = createMaterializedViewPropertyManager(connectorManager); - this.analyzePropertyManager = createAnalyzePropertyManager(connectorManager); - TableProceduresPropertyManager tableProceduresPropertyManager = createTableProceduresPropertyManager(connectorManager); - - accessControl.setConnectorAccessControlProvider(createAccessControlProvider(connectorManager)); + this.sessionPropertyManager = createSessionPropertyManager(catalogManager, extraSessionProperties, taskManagerConfig, featuresConfig, optimizerConfig); + this.nodePartitioningManager = new NodePartitioningManager(nodeScheduler, blockTypeOperators, createNodePartitioningProvider(catalogManager)); + TableProceduresRegistry tableProceduresRegistry = new TableProceduresRegistry(createTableProceduresProvider(catalogManager)); + TableFunctionRegistry tableFunctionRegistry = new TableFunctionRegistry(createTableFunctionProvider(catalogManager)); + this.schemaPropertyManager = createSchemaPropertyManager(catalogManager); + this.columnPropertyManager = createColumnPropertyManager(catalogManager); + this.tablePropertyManager = createTablePropertyManager(catalogManager); + this.materializedViewPropertyManager = createMaterializedViewPropertyManager(catalogManager); + this.analyzePropertyManager = createAnalyzePropertyManager(catalogManager); + TableProceduresPropertyManager tableProceduresPropertyManager = createTableProceduresPropertyManager(catalogManager); + + accessControl.setConnectorAccessControlProvider(createAccessControlProvider(catalogManager)); this.statementAnalyzerFactory = new StatementAnalyzerFactory( plannerContext, @@ -438,7 +441,7 @@ private LocalQueryRunner( this.costCalculator = new CostCalculatorUsingExchanges(taskCountEstimator); this.estimatedExchangesCostCalculator = new CostCalculatorWithEstimatedExchanges(costCalculator, taskCountEstimator); - this.planFragmenter = new PlanFragmenter(metadata, functionManager, new QueryManagerConfig()); + this.planFragmenter = new PlanFragmenter(metadata, functionManager, transactionManager, catalogManager, new QueryManagerConfig()); GlobalSystemConnector globalSystemConnector = new GlobalSystemConnector(ImmutableSet.of( new NodeSystemTable(nodeManager), @@ -471,7 +474,7 @@ private LocalQueryRunner( handleResolver, exchangeManagerRegistry); - connectorManager.createCatalog(GlobalSystemConnector.CATALOG_HANDLE, GlobalSystemConnector.NAME, globalSystemConnector); + catalogManager.registerGlobalSystemConnector(globalSystemConnector); // rewrite session to use managed SessionPropertyMetadata Optional transactionId = withInitialTransaction ? Optional.of(transactionManager.beginTransaction(true)) : defaultSession.getTransactionId(); @@ -542,7 +545,7 @@ public void close() { notificationExecutor.shutdownNow(); yieldExecutor.shutdownNow(); - connectorManager.stop(); + catalogManager.stop(); finalizerService.destroy(); singleStreamSpillerFactory.destroy(); } @@ -713,12 +716,10 @@ public ExpressionCompiler getExpressionCompiler() return expressionCompiler; } - public CatalogHandle createCatalog(String catalogName, ConnectorFactory connectorFactory, Map properties) + public void createCatalog(String catalogName, ConnectorFactory connectorFactory, Map properties) { catalogFactory.addConnectorFactory(connectorFactory, ignored -> connectorFactory.getClass().getClassLoader()); - CatalogHandle catalogHandle = connectorManager.createCatalog(catalogName, connectorFactory.getName(), properties); - nodeManager.addCurrentNodeCatalog(catalogHandle); - return catalogHandle; + catalogManager.createCatalog(catalogName, connectorFactory.getName(), properties); } @Override @@ -736,8 +737,12 @@ public void addFunctions(FunctionBundle functionBundle) @Override public void createCatalog(String catalogName, String connectorName, Map properties) { - CatalogHandle catalogHandle = connectorManager.createCatalog(catalogName, connectorName, properties); - nodeManager.addCurrentNodeCatalog(catalogHandle); + catalogManager.createCatalog(catalogName, connectorName, properties); + } + + public CatalogManager getCatalogManager() + { + return catalogManager; } public LocalQueryRunner printPlan() diff --git a/core/trino-main/src/main/java/io/trino/testing/TestingConnectorContext.java b/core/trino-main/src/main/java/io/trino/testing/TestingConnectorContext.java index 89c987f38653..5d6c093c2c85 100644 --- a/core/trino-main/src/main/java/io/trino/testing/TestingConnectorContext.java +++ b/core/trino-main/src/main/java/io/trino/testing/TestingConnectorContext.java @@ -46,9 +46,7 @@ public TestingConnectorContext() { TypeOperators typeOperators = new TypeOperators(); pageIndexerFactory = new GroupByHashPageIndexerFactory(new JoinCompiler(typeOperators), new BlockTypeOperators(typeOperators)); - InMemoryNodeManager inMemoryNodeManager = new InMemoryNodeManager(); - inMemoryNodeManager.addCurrentNodeCatalog(TEST_CATALOG_HANDLE); - nodeManager = new ConnectorAwareNodeManager(inMemoryNodeManager, "testenv", TEST_CATALOG_HANDLE, true); + nodeManager = new ConnectorAwareNodeManager(new InMemoryNodeManager(), "testenv", TEST_CATALOG_HANDLE, true); } @Override diff --git a/core/trino-main/src/main/java/io/trino/transaction/InMemoryTransactionManager.java b/core/trino-main/src/main/java/io/trino/transaction/InMemoryTransactionManager.java index a51e124ca842..8df986833457 100644 --- a/core/trino-main/src/main/java/io/trino/transaction/InMemoryTransactionManager.java +++ b/core/trino-main/src/main/java/io/trino/transaction/InMemoryTransactionManager.java @@ -54,6 +54,7 @@ import static com.google.common.util.concurrent.Futures.nonCancellationPropagating; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static io.airlift.concurrent.MoreFutures.addExceptionCallback; +import static io.trino.metadata.CatalogManager.NO_CATALOGS; import static io.trino.spi.StandardErrorCode.AUTOCOMMIT_WRITE_CONFLICT; import static io.trino.spi.StandardErrorCode.MULTI_CATALOG_WRITE_CONFLICT; import static io.trino.spi.StandardErrorCode.NOT_FOUND; @@ -101,14 +102,9 @@ public static TransactionManager create( } public static TransactionManager createTestTransactionManager() - { - return createTestTransactionManager(new CatalogManager()); - } - - public static TransactionManager createTestTransactionManager(CatalogManager catalogManager) { // No idle checks needed - return new InMemoryTransactionManager(new Duration(1, TimeUnit.DAYS), 1, catalogManager, directExecutor()); + return new InMemoryTransactionManager(new Duration(1, TimeUnit.DAYS), 1, NO_CATALOGS, directExecutor()); } private void scheduleIdleChecks(Duration idleCheckInterval, ScheduledExecutorService idleCheckExecutor) @@ -184,6 +180,12 @@ public List getCatalogs(TransactionId transactionId) return getTransactionMetadata(transactionId).listCatalogs(); } + @Override + public List getActiveCatalogs(TransactionId transactionId) + { + return getTransactionMetadata(transactionId).getActiveCatalogs(); + } + @Override public Optional getCatalogHandle(TransactionId transactionId, String catalogName) { @@ -379,6 +381,17 @@ public void checkOpenTransaction() } } + private synchronized List getActiveCatalogs() + { + return activeCatalogs.keySet().stream() + .map(CatalogHandle::getCatalogName) + .distinct() + .map(key -> registeredCatalogs.getOrDefault(key, Optional.empty())) + .flatMap(Optional::stream) + .map(catalog -> new CatalogInfo(catalog.getCatalogName(), catalog.getCatalogHandle(), catalog.getConnectorName())) + .collect(toImmutableList()); + } + private synchronized List listCatalogs() { // register all known catalogs diff --git a/core/trino-main/src/main/java/io/trino/transaction/NoOpTransactionManager.java b/core/trino-main/src/main/java/io/trino/transaction/NoOpTransactionManager.java index d101c8d5ef5f..b51e7c175aba 100644 --- a/core/trino-main/src/main/java/io/trino/transaction/NoOpTransactionManager.java +++ b/core/trino-main/src/main/java/io/trino/transaction/NoOpTransactionManager.java @@ -71,6 +71,12 @@ public List getCatalogs(TransactionId transactionId) throw new UnsupportedOperationException(); } + @Override + public List getActiveCatalogs(TransactionId transactionId) + { + throw new UnsupportedOperationException(); + } + @Override public Optional getCatalogHandle(TransactionId transactionId, String catalogName) { diff --git a/core/trino-main/src/main/java/io/trino/transaction/TransactionManager.java b/core/trino-main/src/main/java/io/trino/transaction/TransactionManager.java index d25159756b7e..d263f8ed9346 100644 --- a/core/trino-main/src/main/java/io/trino/transaction/TransactionManager.java +++ b/core/trino-main/src/main/java/io/trino/transaction/TransactionManager.java @@ -45,6 +45,8 @@ public interface TransactionManager List getCatalogs(TransactionId transactionId); + List getActiveCatalogs(TransactionId transactionId); + Optional getCatalogHandle(TransactionId transactionId, String catalogName); default CatalogMetadata getRequiredCatalogMetadata(TransactionId transactionId, String catalogName) diff --git a/core/trino-main/src/test/java/io/trino/connector/TestCatalogManagerConfig.java b/core/trino-main/src/test/java/io/trino/connector/TestCatalogManagerConfig.java new file mode 100644 index 000000000000..d72bfe10a7bd --- /dev/null +++ b/core/trino-main/src/test/java/io/trino/connector/TestCatalogManagerConfig.java @@ -0,0 +1,47 @@ +/* + * 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.connector; + +import com.google.common.collect.ImmutableMap; +import io.trino.connector.CatalogManagerConfig.CatalogMangerKind; +import org.testng.annotations.Test; + +import java.util.Map; + +import static io.airlift.configuration.testing.ConfigAssertions.assertFullMapping; +import static io.airlift.configuration.testing.ConfigAssertions.assertRecordedDefaults; +import static io.airlift.configuration.testing.ConfigAssertions.recordDefaults; + +public class TestCatalogManagerConfig +{ + @Test + public void testDefaults() + { + assertRecordedDefaults(recordDefaults(CatalogManagerConfig.class) + .setCatalogMangerKind(CatalogMangerKind.STATIC)); + } + + @Test + public void testExplicitPropertyMappings() + { + Map properties = ImmutableMap.builder() + .put("catalog.management", "dynamic") + .buildOrThrow(); + + CatalogManagerConfig expected = new CatalogManagerConfig() + .setCatalogMangerKind(CatalogMangerKind.DYNAMIC); + + assertFullMapping(properties, expected); + } +} diff --git a/core/trino-main/src/test/java/io/trino/connector/TestCatalogStoreConfig.java b/core/trino-main/src/test/java/io/trino/connector/TestCatalogStoreConfig.java new file mode 100644 index 000000000000..a8e96ddf0659 --- /dev/null +++ b/core/trino-main/src/test/java/io/trino/connector/TestCatalogStoreConfig.java @@ -0,0 +1,47 @@ +/* + * 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.connector; + +import com.google.common.collect.ImmutableMap; +import io.trino.connector.CatalogStoreConfig.CatalogStoreKind; +import org.testng.annotations.Test; + +import java.util.Map; + +import static io.airlift.configuration.testing.ConfigAssertions.assertFullMapping; +import static io.airlift.configuration.testing.ConfigAssertions.assertRecordedDefaults; +import static io.airlift.configuration.testing.ConfigAssertions.recordDefaults; + +public class TestCatalogStoreConfig +{ + @Test + public void testDefaults() + { + assertRecordedDefaults(recordDefaults(CatalogStoreConfig.class) + .setCatalogStoreKind(CatalogStoreKind.FILE)); + } + + @Test + public void testExplicitPropertyMappings() + { + Map properties = ImmutableMap.builder() + .put("catalog.store", "none") + .buildOrThrow(); + + CatalogStoreConfig expected = new CatalogStoreConfig() + .setCatalogStoreKind(CatalogStoreKind.NONE); + + assertFullMapping(properties, expected); + } +} diff --git a/core/trino-main/src/test/java/io/trino/metadata/TestStaticCatalogStoreConfig.java b/core/trino-main/src/test/java/io/trino/connector/TestStaticCatalogManagerConfig.java similarity index 87% rename from core/trino-main/src/test/java/io/trino/metadata/TestStaticCatalogStoreConfig.java rename to core/trino-main/src/test/java/io/trino/connector/TestStaticCatalogManagerConfig.java index d00d87b59c20..e99e5623c4ed 100644 --- a/core/trino-main/src/test/java/io/trino/metadata/TestStaticCatalogStoreConfig.java +++ b/core/trino-main/src/test/java/io/trino/connector/TestStaticCatalogManagerConfig.java @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.trino.metadata; +package io.trino.connector; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -24,12 +24,12 @@ import static io.airlift.configuration.testing.ConfigAssertions.assertRecordedDefaults; import static io.airlift.configuration.testing.ConfigAssertions.recordDefaults; -public class TestStaticCatalogStoreConfig +public class TestStaticCatalogManagerConfig { @Test public void testDefaults() { - assertRecordedDefaults(recordDefaults(StaticCatalogStoreConfig.class) + assertRecordedDefaults(recordDefaults(StaticCatalogManagerConfig.class) .setCatalogConfigurationDir(new File("etc/catalog")) .setDisabledCatalogs((String) null)); } @@ -42,7 +42,7 @@ public void testExplicitPropertyMappings() .put("catalog.disabled-catalogs", "abc,xyz") .buildOrThrow(); - StaticCatalogStoreConfig expected = new StaticCatalogStoreConfig() + StaticCatalogManagerConfig expected = new StaticCatalogManagerConfig() .setCatalogConfigurationDir(new File("/foo")) .setDisabledCatalogs(ImmutableList.of("abc", "xyz")); diff --git a/core/trino-main/src/test/java/io/trino/cost/TestCostCalculator.java b/core/trino-main/src/test/java/io/trino/cost/TestCostCalculator.java index 26cd19d24f87..9ab4749e7d1b 100644 --- a/core/trino-main/src/test/java/io/trino/cost/TestCostCalculator.java +++ b/core/trino-main/src/test/java/io/trino/cost/TestCostCalculator.java @@ -112,6 +112,8 @@ public void setUp() planFragmenter = new PlanFragmenter( localQueryRunner.getMetadata(), localQueryRunner.getFunctionManager(), + localQueryRunner.getTransactionManager(), + localQueryRunner.getCatalogManager(), new QueryManagerConfig()); } diff --git a/core/trino-main/src/test/java/io/trino/execution/BenchmarkNodeScheduler.java b/core/trino-main/src/test/java/io/trino/execution/BenchmarkNodeScheduler.java index f63ea8c1f4a9..92abf9609b21 100644 --- a/core/trino-main/src/test/java/io/trino/execution/BenchmarkNodeScheduler.java +++ b/core/trino-main/src/test/java/io/trino/execution/BenchmarkNodeScheduler.java @@ -33,6 +33,7 @@ import io.trino.jmh.Benchmarks; import io.trino.metadata.InMemoryNodeManager; import io.trino.metadata.InternalNode; +import io.trino.metadata.InternalNodeManager; import io.trino.metadata.Split; import io.trino.spi.HostAddress; import io.trino.spi.connector.ConnectorSplit; @@ -167,9 +168,7 @@ public void setup() splits.add(new Split(TEST_CATALOG_HANDLE, new TestSplitRemote(ThreadLocalRandom.current().nextInt(DATA_NODES)))); } - InMemoryNodeManager nodeManager = new InMemoryNodeManager(); - nodeManager.addNode(TEST_CATALOG_HANDLE, nodes); - NodeScheduler nodeScheduler = new NodeScheduler(getNodeSelectorFactory(nodeManager, nodeTaskMap)); + NodeScheduler nodeScheduler = new NodeScheduler(getNodeSelectorFactory(new InMemoryNodeManager(), nodeTaskMap)); Session session = TestingSession.testSessionBuilder() .setSystemProperty(MAX_UNACKNOWLEDGED_SPLITS_PER_TASK, Integer.toString(Integer.MAX_VALUE)) .build(); @@ -191,7 +190,7 @@ private NodeSchedulerConfig getNodeSchedulerConfig() .setMaxPendingSplitsPerTask(MAX_PENDING_SPLITS_PER_TASK_PER_NODE); } - private NodeSelectorFactory getNodeSelectorFactory(InMemoryNodeManager nodeManager, NodeTaskMap nodeTaskMap) + private NodeSelectorFactory getNodeSelectorFactory(InternalNodeManager nodeManager, NodeTaskMap nodeTaskMap) { NodeSchedulerConfig nodeSchedulerConfig = getNodeSchedulerConfig(); switch (policy) { diff --git a/core/trino-main/src/test/java/io/trino/execution/MockRemoteTaskFactory.java b/core/trino-main/src/test/java/io/trino/execution/MockRemoteTaskFactory.java index 8a8a6f35746a..0e5eacc2ecc8 100644 --- a/core/trino-main/src/test/java/io/trino/execution/MockRemoteTaskFactory.java +++ b/core/trino-main/src/test/java/io/trino/execution/MockRemoteTaskFactory.java @@ -121,6 +121,7 @@ public MockRemoteTask createTableScanTask(TaskId taskId, InternalNode newNode, L ImmutableList.of(sourceId), new PartitioningScheme(Partitioning.create(SINGLE_DISTRIBUTION, ImmutableList.of()), ImmutableList.of(symbol)), StatsAndCosts.empty(), + ImmutableList.of(), Optional.empty()); ImmutableMultimap.Builder initialSplits = ImmutableMultimap.builder(); diff --git a/core/trino-main/src/test/java/io/trino/execution/TaskTestUtils.java b/core/trino-main/src/test/java/io/trino/execution/TaskTestUtils.java index cf08a741d8a5..cc50e5fcb89a 100644 --- a/core/trino-main/src/test/java/io/trino/execution/TaskTestUtils.java +++ b/core/trino-main/src/test/java/io/trino/execution/TaskTestUtils.java @@ -100,6 +100,7 @@ private TaskTestUtils() {} new PartitioningScheme(Partitioning.create(SINGLE_DISTRIBUTION, ImmutableList.of()), ImmutableList.of(SYMBOL)) .withBucketToPartition(Optional.of(new int[1])), StatsAndCosts.empty(), + ImmutableList.of(), Optional.empty()); public static final DynamicFilterId DYNAMIC_FILTER_SOURCE_ID = new DynamicFilterId("filter"); @@ -122,6 +123,7 @@ private TaskTestUtils() {} new PartitioningScheme(Partitioning.create(SINGLE_DISTRIBUTION, ImmutableList.of()), ImmutableList.of(SYMBOL)) .withBucketToPartition(Optional.of(new int[1])), StatsAndCosts.empty(), + ImmutableList.of(), Optional.empty()); public static LocalExecutionPlanner createTestingPlanner() diff --git a/core/trino-main/src/test/java/io/trino/execution/TestNodeScheduler.java b/core/trino-main/src/test/java/io/trino/execution/TestNodeScheduler.java index 4d0692fead35..0c674b472050 100644 --- a/core/trino-main/src/test/java/io/trino/execution/TestNodeScheduler.java +++ b/core/trino-main/src/test/java/io/trino/execution/TestNodeScheduler.java @@ -39,6 +39,7 @@ import io.trino.execution.scheduler.UniformNodeSelectorFactory; import io.trino.metadata.InMemoryNodeManager; import io.trino.metadata.InternalNode; +import io.trino.metadata.InternalNodeManager; import io.trino.metadata.Split; import io.trino.spi.HostAddress; import io.trino.spi.SplitWeight; @@ -70,6 +71,8 @@ import java.util.concurrent.ThreadLocalRandom; import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.collect.Iterables.getOnlyElement; import static io.airlift.concurrent.Threads.daemonThreadsNamed; import static io.airlift.slice.SizeOf.estimatedSizeOf; @@ -125,12 +128,10 @@ public void setUp() private void setUpNodes() { - ImmutableList.Builder nodeBuilder = ImmutableList.builder(); - nodeBuilder.add(new InternalNode("other1", URI.create("http://10.0.0.1:11"), NodeVersion.UNKNOWN, false)); - nodeBuilder.add(new InternalNode("other2", URI.create("http://10.0.0.1:12"), NodeVersion.UNKNOWN, false)); - nodeBuilder.add(new InternalNode("other3", URI.create("http://10.0.0.1:13"), NodeVersion.UNKNOWN, false)); - ImmutableList nodes = nodeBuilder.build(); - nodeManager.addNode(TEST_CATALOG_HANDLE, nodes); + nodeManager.addNodes( + new InternalNode("other1", URI.create("http://10.0.0.1:11"), NodeVersion.UNKNOWN, false), + new InternalNode("other2", URI.create("http://10.0.0.1:12"), NodeVersion.UNKNOWN, false), + new InternalNode("other3", URI.create("http://10.0.0.1:13"), NodeVersion.UNKNOWN, false)); } @AfterMethod(alwaysRun = true) @@ -175,14 +176,10 @@ public void testScheduleLocal() public void testTopologyAwareScheduling() { NodeTaskMap nodeTaskMap = new NodeTaskMap(finalizerService); - InMemoryNodeManager nodeManager = new InMemoryNodeManager(); - - ImmutableList.Builder nodeBuilder = ImmutableList.builder(); - nodeBuilder.add(new InternalNode("node1", URI.create("http://host1.rack1:11"), NodeVersion.UNKNOWN, false)); - nodeBuilder.add(new InternalNode("node2", URI.create("http://host2.rack1:12"), NodeVersion.UNKNOWN, false)); - nodeBuilder.add(new InternalNode("node3", URI.create("http://host3.rack2:13"), NodeVersion.UNKNOWN, false)); - ImmutableList nodes = nodeBuilder.build(); - nodeManager.addNode(TEST_CATALOG_HANDLE, nodes); + InternalNodeManager nodeManager = new InMemoryNodeManager( + new InternalNode("node1", URI.create("http://host1.rack1:11"), NodeVersion.UNKNOWN, false), + new InternalNode("node2", URI.create("http://host2.rack1:12"), NodeVersion.UNKNOWN, false), + new InternalNode("node3", URI.create("http://host3.rack2:13"), NodeVersion.UNKNOWN, false)); // contents of taskMap indicate the node-task map for the current stage Map taskMap = new HashMap<>(); @@ -297,14 +294,18 @@ public void testScheduleRemote() public void testBasicAssignment() { setUpNodes(); + Set activeCatalogNodes = nodeManager.getActiveCatalogNodes(TEST_CATALOG_HANDLE).stream() + .filter(node -> !node.isCoordinator()) + .collect(toImmutableSet()); + // One split for each node Set splits = new HashSet<>(); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < activeCatalogNodes.size(); i++) { splits.add(new Split(TEST_CATALOG_HANDLE, new TestSplitRemote())); } Multimap assignments = nodeSelector.computeAssignments(splits, ImmutableList.copyOf(taskMap.values())).getAssignments(); - assertEquals(assignments.entries().size(), 3); - for (InternalNode node : nodeManager.getActiveCatalogNodes(TEST_CATALOG_HANDLE)) { + assertEquals(assignments.entries().size(), assignments.size()); + for (InternalNode node : activeCatalogNodes) { assertTrue(assignments.keySet().contains(node)); } } @@ -314,7 +315,7 @@ public void testMaxSplitsPerNode() { setUpNodes(); InternalNode newNode = new InternalNode("other4", URI.create("http://10.0.0.1:14"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, newNode); + nodeManager.addNodes(newNode); ImmutableList.Builder initialSplits = ImmutableList.builder(); for (int i = 0; i < 10; i++) { @@ -353,15 +354,17 @@ public void testBasicAssignmentMaxUnacknowledgedSplitsPerTask() nodeSelector = nodeScheduler.createNodeSelector(sessionWithMaxUnacknowledgedSplitsPerTask(1), Optional.of(TEST_CATALOG_HANDLE)); setUpNodes(); // One split for each node, and one extra split that can't be placed - int nodeCount = nodeManager.getActiveCatalogNodes(TEST_CATALOG_HANDLE).size(); - int splitCount = nodeCount + 1; + Set activeCatalogNodes = nodeManager.getActiveCatalogNodes(TEST_CATALOG_HANDLE).stream() + .filter(node -> !node.isCoordinator()) + .collect(toImmutableSet()); + int splitCount = activeCatalogNodes.size() + 1; Set splits = new HashSet<>(); for (int i = 0; i < splitCount; i++) { splits.add(new Split(TEST_CATALOG_HANDLE, new TestSplitRemote())); } Multimap assignments = nodeSelector.computeAssignments(splits, ImmutableList.copyOf(taskMap.values())).getAssignments(); - assertEquals(assignments.entries().size(), nodeCount); - for (InternalNode node : nodeManager.getActiveCatalogNodes(TEST_CATALOG_HANDLE)) { + assertEquals(assignments.entries().size(), activeCatalogNodes.size()); + for (InternalNode node : activeCatalogNodes) { assertTrue(assignments.keySet().contains(node)); } } @@ -371,7 +374,7 @@ public void testMaxSplitsPerNodePerTask() { setUpNodes(); InternalNode newNode = new InternalNode("other4", URI.create("http://10.0.0.1:14"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, newNode); + nodeManager.addNodes(newNode); ImmutableList.Builder initialSplits = ImmutableList.builder(); for (int i = 0; i < 20; i++) { @@ -471,7 +474,7 @@ public void testSplitCount() public void testPrioritizedAssignmentOfLocalSplit() { InternalNode node = new InternalNode("node1", URI.create("http://10.0.0.1:11"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, node); + nodeManager.addNodes(node); // Check for Split assignments till maxSplitsPerNode (20) Set splits = new LinkedHashSet<>(); @@ -510,7 +513,7 @@ public void testPrioritizedAssignmentOfLocalSplit() public void testAssignmentWhenMixedSplits() { InternalNode node = new InternalNode("node1", URI.create("http://10.0.0.1:11"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, node); + nodeManager.addNodes(node); // Check for Split assignments till maxSplitsPerNode (20) Set splits = new LinkedHashSet<>(); @@ -553,9 +556,9 @@ public void testAssignmentWhenMixedSplits() public void testOptimizedLocalScheduling() { InternalNode node1 = new InternalNode("node1", URI.create("http://10.0.0.1:11"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, node1); + nodeManager.addNodes(node1); InternalNode node2 = new InternalNode("node2", URI.create("http://10.0.0.1:12"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, node2); + nodeManager.addNodes(node2); Set splits = new LinkedHashSet<>(); // 20 splits with node1 as local node to be assigned in the first iteration of computeAssignments @@ -625,13 +628,13 @@ public void testOptimizedLocalScheduling() public void testEquateDistribution() { InternalNode node1 = new InternalNode("node1", URI.create("http://10.0.0.1:11"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, node1); + nodeManager.addNodes(node1); InternalNode node2 = new InternalNode("node2", URI.create("http://10.0.0.1:12"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, node2); + nodeManager.addNodes(node2); InternalNode node3 = new InternalNode("node3", URI.create("http://10.0.0.1:13"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, node3); + nodeManager.addNodes(node3); InternalNode node4 = new InternalNode("node4", URI.create("http://10.0.0.1:14"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, node4); + nodeManager.addNodes(node4); Set splits = new LinkedHashSet<>(); // 20 splits with node1 as local node to be assigned in the first iteration of computeAssignments @@ -673,7 +676,7 @@ public void testEquateDistributionConsistentHashing(int numberOfNodes, int numbe for (int i = 0; i < numberOfNodes; ++i) { InternalNode node = new InternalNode("node" + i, URI.create("http://10.0.0.1:" + (i + 10)), NodeVersion.UNKNOWN, false); nodesBuilder.add(node); - nodeManager.addNode(TEST_CATALOG_HANDLE, node); + nodeManager.addNodes(node); } List nodes = nodesBuilder.build(); @@ -706,9 +709,9 @@ public void testEquateDistributionConsistentHashing(int numberOfNodes, int numbe public void testRedistributeSplit() { InternalNode node1 = new InternalNode("node1", URI.create("http://10.0.0.1:11"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, node1); + nodeManager.addNodes(node1); InternalNode node2 = new InternalNode("node2", URI.create("http://10.0.0.1:12"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, node2); + nodeManager.addNodes(node2); Multimap assignment = HashMultimap.create(); @@ -760,9 +763,9 @@ public void testRedistributeSplit() public void testEmptyAssignmentWithFullNodes() { InternalNode node1 = new InternalNode("node1", URI.create("http://10.0.0.1:11"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, node1); + nodeManager.addNodes(node1); InternalNode node2 = new InternalNode("node2", URI.create("http://10.0.0.1:12"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(TEST_CATALOG_HANDLE, node2); + nodeManager.addNodes(node2); Set splits = new LinkedHashSet<>(); // 20 splits with node1 as local node to be assigned in the first iteration of computeAssignments @@ -813,11 +816,13 @@ public void testMaxUnacknowledgedSplitsPerTask() initialSplits.add(new Split(TEST_CATALOG_HANDLE, new TestSplitRemote())); } - List nodes = new ArrayList<>(); + List nodes = nodeManager.getActiveCatalogNodes(TEST_CATALOG_HANDLE).stream() + .filter(node -> !node.isCoordinator()) + .collect(toImmutableList()); List tasks = new ArrayList<>(); MockRemoteTaskFactory remoteTaskFactory = new MockRemoteTaskFactory(remoteTaskExecutor, remoteTaskScheduledExecutor); int counter = 1; - for (InternalNode node : nodeManager.getActiveCatalogNodes(TEST_CATALOG_HANDLE)) { + for (InternalNode node : nodes) { // Max out number of unacknowledged splits on each task TaskId taskId = new TaskId(new StageId("test", 1), counter, 0); counter++; @@ -825,7 +830,6 @@ public void testMaxUnacknowledgedSplitsPerTask() nodeTaskMap.addTask(node, remoteTask); remoteTask.setMaxUnacknowledgedSplits(maxUnacknowledgedSplitsPerTask); remoteTask.setUnacknowledgedSplits(maxUnacknowledgedSplitsPerTask); - nodes.add(node); tasks.add(remoteTask); } diff --git a/core/trino-main/src/test/java/io/trino/execution/TestSetPathTask.java b/core/trino-main/src/test/java/io/trino/execution/TestSetPathTask.java index 04a91decbc48..4a0c99b75c45 100644 --- a/core/trino-main/src/test/java/io/trino/execution/TestSetPathTask.java +++ b/core/trino-main/src/test/java/io/trino/execution/TestSetPathTask.java @@ -15,7 +15,6 @@ import com.google.common.collect.ImmutableList; import io.trino.execution.warnings.WarningCollector; -import io.trino.metadata.CatalogManager; import io.trino.metadata.Metadata; import io.trino.security.AccessControl; import io.trino.security.AllowAllAccessControl; @@ -53,8 +52,7 @@ public class TestSetPathTask public TestSetPathTask() { - CatalogManager catalogManager = new CatalogManager(); - transactionManager = createTestTransactionManager(catalogManager); + transactionManager = createTestTransactionManager(); accessControl = new AllowAllAccessControl(); metadata = testMetadataManagerBuilder() diff --git a/core/trino-main/src/test/java/io/trino/execution/TestSqlStage.java b/core/trino-main/src/test/java/io/trino/execution/TestSqlStage.java index 51b001d6dbfe..6ddcbf7e08d5 100644 --- a/core/trino-main/src/test/java/io/trino/execution/TestSqlStage.java +++ b/core/trino-main/src/test/java/io/trino/execution/TestSqlStage.java @@ -183,6 +183,7 @@ private static PlanFragment createExchangePlanFragment() ImmutableList.of(planNode.getId()), new PartitioningScheme(Partitioning.create(SINGLE_DISTRIBUTION, ImmutableList.of()), planNode.getOutputSymbols()), StatsAndCosts.empty(), + ImmutableList.of(), Optional.empty()); } } diff --git a/core/trino-main/src/test/java/io/trino/execution/TestSqlTaskManager.java b/core/trino-main/src/test/java/io/trino/execution/TestSqlTaskManager.java index e122340a9ce1..21579b5fa388 100644 --- a/core/trino-main/src/test/java/io/trino/execution/TestSqlTaskManager.java +++ b/core/trino-main/src/test/java/io/trino/execution/TestSqlTaskManager.java @@ -25,6 +25,11 @@ import io.airlift.units.DataSize; import io.airlift.units.DataSize.Unit; import io.airlift.units.Duration; +import io.trino.Session; +import io.trino.connector.CatalogHandle; +import io.trino.connector.CatalogProperties; +import io.trino.connector.ConnectorServices; +import io.trino.connector.ConnectorServicesProvider; import io.trino.exchange.ExchangeManagerRegistry; import io.trino.execution.buffer.BufferResult; import io.trino.execution.buffer.BufferState; @@ -337,6 +342,7 @@ private SqlTaskManager createSqlTaskManager(TaskManagerConfig taskManagerConfig, { return new SqlTaskManager( new EmbedVersion("testversion"), + new NoConnectorServicesProvider(), createTestingPlanner(), new MockLocationFactory(), taskExecutor, @@ -360,6 +366,7 @@ private SqlTaskManager createSqlTaskManager( { return new SqlTaskManager( new EmbedVersion("testversion"), + new NoConnectorServicesProvider(), createTestingPlanner(), new MockLocationFactory(), taskExecutor, @@ -478,4 +485,20 @@ public void close() { } } + + private static class NoConnectorServicesProvider + implements ConnectorServicesProvider + { + @Override + public void loadInitialCatalogs() {} + + @Override + public void ensureCatalogsLoaded(Session session, List catalogs) {} + + @Override + public ConnectorServices getConnectorServices(CatalogHandle catalogHandle) + { + throw new UnsupportedOperationException(); + } + } } diff --git a/core/trino-main/src/test/java/io/trino/execution/TestStageStateMachine.java b/core/trino-main/src/test/java/io/trino/execution/TestStageStateMachine.java index 3d52a5241eb8..451da665020a 100644 --- a/core/trino-main/src/test/java/io/trino/execution/TestStageStateMachine.java +++ b/core/trino-main/src/test/java/io/trino/execution/TestStageStateMachine.java @@ -253,6 +253,7 @@ private static PlanFragment createValuesPlan() ImmutableList.of(valuesNodeId), new PartitioningScheme(Partitioning.create(SINGLE_DISTRIBUTION, ImmutableList.of()), ImmutableList.of(symbol)), StatsAndCosts.empty(), + ImmutableList.of(), Optional.empty()); return planFragment; diff --git a/core/trino-main/src/test/java/io/trino/execution/TestStartTransactionTask.java b/core/trino-main/src/test/java/io/trino/execution/TestStartTransactionTask.java index ddd8865fcddc..83835af3372f 100644 --- a/core/trino-main/src/test/java/io/trino/execution/TestStartTransactionTask.java +++ b/core/trino-main/src/test/java/io/trino/execution/TestStartTransactionTask.java @@ -18,7 +18,6 @@ import io.trino.Session; import io.trino.Session.SessionBuilder; import io.trino.execution.warnings.WarningCollector; -import io.trino.metadata.CatalogManager; import io.trino.metadata.Metadata; import io.trino.plugin.base.security.DefaultSystemAccessControl; import io.trino.security.AccessControlConfig; @@ -44,6 +43,7 @@ import static io.airlift.concurrent.MoreFutures.getFutureValue; import static io.airlift.concurrent.Threads.daemonThreadsNamed; +import static io.trino.metadata.CatalogManager.NO_CATALOGS; import static io.trino.metadata.MetadataManager.createTestMetadataManager; import static io.trino.plugin.tpch.TpchMetadata.TINY_SCHEMA_NAME; import static io.trino.spi.StandardErrorCode.INCOMPATIBLE_CLIENT; @@ -218,7 +218,7 @@ public void testStartTransactionIdleExpiration() .setIdleTimeout(new Duration(1, TimeUnit.MICROSECONDS)) // Fast idle timeout .setIdleCheckInterval(new Duration(10, TimeUnit.MILLISECONDS)), scheduledExecutor, - new CatalogManager(), + NO_CATALOGS, executor); QueryStateMachine stateMachine = createQueryStateMachine("START TRANSACTION", session, transactionManager); assertFalse(stateMachine.getSession().getTransactionId().isPresent()); diff --git a/core/trino-main/src/test/java/io/trino/execution/scheduler/TestBinPackingNodeAllocator.java b/core/trino-main/src/test/java/io/trino/execution/scheduler/TestBinPackingNodeAllocator.java index 0df1469de6c7..d8fa6ba90e15 100644 --- a/core/trino-main/src/test/java/io/trino/execution/scheduler/TestBinPackingNodeAllocator.java +++ b/core/trino-main/src/test/java/io/trino/execution/scheduler/TestBinPackingNodeAllocator.java @@ -13,7 +13,6 @@ */ package io.trino.execution.scheduler; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.Futures; import io.airlift.testing.TestingTicker; @@ -34,15 +33,12 @@ import java.net.URI; import java.time.Duration; -import java.util.Arrays; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.ImmutableMap.toImmutableMap; import static io.airlift.concurrent.MoreFutures.getFutureValue; import static io.airlift.units.DataSize.Unit.GIGABYTE; @@ -71,8 +67,6 @@ public class TestBinPackingNodeAllocator private static final InternalNode NODE_4 = new InternalNode("node-4", URI.create("local://" + NODE_4_ADDRESS), NodeVersion.UNKNOWN, false); private static final CatalogHandle CATALOG_1 = createTestCatalogHandle("catalog1"); - private static final CatalogHandle CATALOG_2 = createTestCatalogHandle("catalog2"); - private static final List ALL_CATALOGS = ImmutableList.of(CATALOG_1, CATALOG_2); private static final NodeRequirements REQ_32 = new NodeRequirements(Optional.empty(), Set.of(), DataSize.of(32, GIGABYTE)); private static final NodeRequirements REQ_20 = new NodeRequirements(Optional.empty(), Set.of(), DataSize.of(16, GIGABYTE)); @@ -151,7 +145,7 @@ public void shutdownNodeAllocatorService() public void testAllocateSimple() throws Exception { - InMemoryNodeManager nodeManager = testingNodeManager(basicNodesMap(NODE_1, NODE_2)); + InMemoryNodeManager nodeManager = new InMemoryNodeManager(NODE_1, NODE_2); setupNodeAllocatorService(nodeManager); try (NodeAllocator nodeAllocator = nodeAllocatorService.getNodeAllocator(SESSION)) { @@ -184,7 +178,7 @@ public void testAllocateSimple() assertNotAcquired(acquire6); // add new node - addNode(nodeManager, NODE_3); + nodeManager.addNodes(NODE_3); // TODO: make BinPackingNodeAllocatorService react on new node added automatically nodeAllocatorService.processPendingAcquires(); @@ -200,7 +194,7 @@ public void testAllocateSimple() public void testAllocateDifferentSizes() throws Exception { - InMemoryNodeManager nodeManager = testingNodeManager(basicNodesMap(NODE_1, NODE_2)); + InMemoryNodeManager nodeManager = new InMemoryNodeManager(NODE_1, NODE_2); setupNodeAllocatorService(nodeManager); try (NodeAllocator nodeAllocator = nodeAllocatorService.getNodeAllocator(SESSION)) { @@ -246,7 +240,7 @@ public void testAllocateDifferentSizes() @Test(timeOut = TEST_TIMEOUT) public void testAllocateDifferentSizesOpportunisticAcquisition() { - InMemoryNodeManager nodeManager = testingNodeManager(basicNodesMap(NODE_1, NODE_2)); + InMemoryNodeManager nodeManager = new InMemoryNodeManager(NODE_1, NODE_2); setupNodeAllocatorService(nodeManager); try (NodeAllocator nodeAllocator = nodeAllocatorService.getNodeAllocator(SESSION)) { @@ -286,7 +280,7 @@ public void testAllocateDifferentSizesOpportunisticAcquisition() @Test(timeOut = TEST_TIMEOUT) public void testAllocateReleaseBeforeAcquired() { - InMemoryNodeManager nodeManager = testingNodeManager(basicNodesMap(NODE_1)); + InMemoryNodeManager nodeManager = new InMemoryNodeManager(NODE_1); setupNodeAllocatorService(nodeManager); try (NodeAllocator nodeAllocator = nodeAllocatorService.getNodeAllocator(SESSION)) { @@ -315,9 +309,7 @@ public void testAllocateReleaseBeforeAcquired() @Test(timeOut = TEST_TIMEOUT) public void testNoMatchingNodeAvailable() { - InMemoryNodeManager nodeManager = testingNodeManager(nodesMapBuilder() - .put(NODE_1, ImmutableList.of(CATALOG_2)) - .buildOrThrow()); + InMemoryNodeManager nodeManager = new InMemoryNodeManager(); setupNodeAllocatorService(nodeManager); try (NodeAllocator nodeAllocator = nodeAllocatorService.getNodeAllocator(SESSION)) { @@ -333,7 +325,7 @@ public void testNoMatchingNodeAvailable() .hasMessageContaining("No nodes available to run query"); // add node with specific catalog - addNode(nodeManager, NODE_2, CATALOG_1); + nodeManager.addNodes(NODE_2); // we should be able to acquire the node now NodeAllocator.NodeLease acquire1 = nodeAllocator.acquire(REQ_CATALOG_1_32.withMemory(DataSize.of(64, GIGABYTE))); @@ -363,7 +355,7 @@ public void testNoMatchingNodeAvailable() @Test(timeOut = TEST_TIMEOUT) public void testRemoveAcquiredNode() { - InMemoryNodeManager nodeManager = testingNodeManager(basicNodesMap(NODE_1)); + InMemoryNodeManager nodeManager = new InMemoryNodeManager(NODE_1); setupNodeAllocatorService(nodeManager); try (NodeAllocator nodeAllocator = nodeAllocatorService.getNodeAllocator(SESSION)) { @@ -381,7 +373,7 @@ public void testRemoveAcquiredNode() @Test(timeOut = TEST_TIMEOUT) public void testAllocateNodeWithAddressRequirements() { - InMemoryNodeManager nodeManager = testingNodeManager(basicNodesMap(NODE_1, NODE_2)); + InMemoryNodeManager nodeManager = new InMemoryNodeManager(NODE_1, NODE_2); setupNodeAllocatorService(nodeManager); @@ -409,7 +401,7 @@ public void testAllocateNodeWithAddressRequirements() @Test(timeOut = TEST_TIMEOUT) public void testAllocateNotEnoughRuntimeMemory() { - InMemoryNodeManager nodeManager = testingNodeManager(basicNodesMap(NODE_1, NODE_2)); + InMemoryNodeManager nodeManager = new InMemoryNodeManager(NODE_1, NODE_2); setupNodeAllocatorService(nodeManager); try (NodeAllocator nodeAllocator = nodeAllocatorService.getNodeAllocator(SESSION)) { @@ -465,7 +457,7 @@ public void testAllocateNotEnoughRuntimeMemory() @Test(timeOut = TEST_TIMEOUT) public void testAllocateRuntimeMemoryDiscrepancies() { - InMemoryNodeManager nodeManager = testingNodeManager(basicNodesMap(NODE_1)); + InMemoryNodeManager nodeManager = new InMemoryNodeManager(NODE_1); setupNodeAllocatorService(nodeManager); // test when global memory usage on node is greater than per task usage @@ -526,7 +518,7 @@ public void testAllocateRuntimeMemoryDiscrepancies() @Test(timeOut = TEST_TIMEOUT) public void testSpaceReservedOnPrimaryNodeIfNoNodeWithEnoughRuntimeMemoryAvailable() { - InMemoryNodeManager nodeManager = testingNodeManager(basicNodesMap(NODE_1, NODE_2)); + InMemoryNodeManager nodeManager = new InMemoryNodeManager(NODE_1, NODE_2); setupNodeAllocatorService(nodeManager); // test when global memory usage on node is greater than per task usage @@ -564,7 +556,7 @@ public void testSpaceReservedOnPrimaryNodeIfNoNodeWithEnoughRuntimeMemoryAvailab @Test(timeOut = TEST_TIMEOUT) public void testAllocateWithRuntimeMemoryEstimateOverhead() { - InMemoryNodeManager nodeManager = testingNodeManager(basicNodesMap(NODE_1)); + InMemoryNodeManager nodeManager = new InMemoryNodeManager(NODE_1); setupNodeAllocatorService(nodeManager, DataSize.of(4, GIGABYTE)); // test when global memory usage on node is greater than per task usage @@ -600,7 +592,7 @@ public void testAllocateWithRuntimeMemoryEstimateOverhead() @Test public void testStressAcquireRelease() { - InMemoryNodeManager nodeManager = testingNodeManager(basicNodesMap(NODE_1)); + InMemoryNodeManager nodeManager = new InMemoryNodeManager(NODE_1); setupNodeAllocatorService(nodeManager, DataSize.of(4, GIGABYTE)); try (NodeAllocator nodeAllocator = nodeAllocatorService.getNodeAllocator(SESSION)) { @@ -616,50 +608,6 @@ private TaskId taskId(int partition) return new TaskId(new StageId("test_query", 0), partition, 0); } - private InMemoryNodeManager testingNodeManager(Map> nodeMap) - { - InMemoryNodeManager nodeManager = new InMemoryNodeManager(); - for (Map.Entry> entry : nodeMap.entrySet()) { - InternalNode node = entry.getKey(); - List catalogs = entry.getValue(); - for (CatalogHandle catalog : catalogs) { - nodeManager.addNode(catalog, node); - } - } - return nodeManager; - } - - private Map> basicNodesMap(InternalNode... nodes) - { - return Arrays.stream(nodes) - .collect(toImmutableMap( - node -> node, - node -> ALL_CATALOGS)); - } - - private ImmutableMap.Builder> nodesMapBuilder() - { - return ImmutableMap.builder(); - } - - private void addNode(InMemoryNodeManager nodeManager, InternalNode node) - { - addNode(nodeManager, node, ALL_CATALOGS); - } - - private void addNode(InMemoryNodeManager nodeManager, InternalNode node, CatalogHandle... catalogs) - { - addNode(nodeManager, node, ImmutableList.copyOf(Arrays.asList(catalogs))); - } - - private void addNode(InMemoryNodeManager nodeManager, InternalNode node, List catalogs) - { - checkArgument(!catalogs.isEmpty(), "no catalogs specified"); - for (CatalogHandle catalog : catalogs) { - nodeManager.addNode(catalog, node); - } - } - private void assertAcquired(NodeAllocator.NodeLease lease, InternalNode node) { assertAcquired(lease, Optional.of(node)); diff --git a/core/trino-main/src/test/java/io/trino/execution/scheduler/TestExponentialGrowthPartitionMemoryEstimator.java b/core/trino-main/src/test/java/io/trino/execution/scheduler/TestExponentialGrowthPartitionMemoryEstimator.java index 10722eccef72..f84a94ededeb 100644 --- a/core/trino-main/src/test/java/io/trino/execution/scheduler/TestExponentialGrowthPartitionMemoryEstimator.java +++ b/core/trino-main/src/test/java/io/trino/execution/scheduler/TestExponentialGrowthPartitionMemoryEstimator.java @@ -22,6 +22,7 @@ import io.trino.memory.MemoryInfo; import io.trino.metadata.InMemoryNodeManager; import io.trino.metadata.InternalNode; +import io.trino.metadata.InternalNodeManager; import io.trino.spi.StandardErrorCode; import io.trino.spi.memory.MemoryPoolInfo; import io.trino.testing.TestingSession; @@ -36,7 +37,6 @@ import static io.trino.spi.StandardErrorCode.ADMINISTRATIVELY_PREEMPTED; import static io.trino.spi.StandardErrorCode.CLUSTER_OUT_OF_MEMORY; import static io.trino.spi.StandardErrorCode.EXCEEDED_LOCAL_MEMORY_LIMIT; -import static io.trino.testing.TestingHandles.TEST_CATALOG_HANDLE; import static java.time.temporal.ChronoUnit.MINUTES; import static org.assertj.core.api.Assertions.assertThat; @@ -46,8 +46,7 @@ public class TestExponentialGrowthPartitionMemoryEstimator public void testEstimator() throws Exception { - InMemoryNodeManager nodeManager = new InMemoryNodeManager(); - nodeManager.addNode(TEST_CATALOG_HANDLE, new InternalNode("a-node", URI.create("local://blah"), NodeVersion.UNKNOWN, false)); + InternalNodeManager nodeManager = new InMemoryNodeManager(new InternalNode("a-node", URI.create("local://blah"), NodeVersion.UNKNOWN, false)); BinPackingNodeAllocatorService nodeAllocatorService = new BinPackingNodeAllocatorService( nodeManager, () -> ImmutableMap.of(new InternalNode("a-node", URI.create("local://blah"), NodeVersion.UNKNOWN, false).getNodeIdentifier(), Optional.of(buildWorkerMemoryInfo(DataSize.ofBytes(0)))), diff --git a/core/trino-main/src/test/java/io/trino/execution/scheduler/TestFaultTolerantStageScheduler.java b/core/trino-main/src/test/java/io/trino/execution/scheduler/TestFaultTolerantStageScheduler.java index 2259254b3f26..2ec487724342 100644 --- a/core/trino-main/src/test/java/io/trino/execution/scheduler/TestFaultTolerantStageScheduler.java +++ b/core/trino-main/src/test/java/io/trino/execution/scheduler/TestFaultTolerantStageScheduler.java @@ -1046,6 +1046,7 @@ private PlanFragment createPlanFragment() ImmutableList.of(TABLE_SCAN_NODE_ID), new PartitioningScheme(Partitioning.create(SINGLE_DISTRIBUTION, ImmutableList.of()), ImmutableList.of(probeColumnSymbol, buildColumnSymbol)), StatsAndCosts.empty(), + ImmutableList.of(), Optional.empty()); } diff --git a/core/trino-main/src/test/java/io/trino/execution/scheduler/TestSourcePartitionedScheduler.java b/core/trino-main/src/test/java/io/trino/execution/scheduler/TestSourcePartitionedScheduler.java index c2e8d7616eff..2399a2ca78f8 100644 --- a/core/trino-main/src/test/java/io/trino/execution/scheduler/TestSourcePartitionedScheduler.java +++ b/core/trino-main/src/test/java/io/trino/execution/scheduler/TestSourcePartitionedScheduler.java @@ -19,7 +19,6 @@ import io.airlift.units.Duration; import io.trino.Session; import io.trino.client.NodeVersion; -import io.trino.connector.CatalogHandle; import io.trino.cost.StatsAndCosts; import io.trino.execution.DynamicFilterConfig; import io.trino.execution.MockRemoteTaskFactory; @@ -100,6 +99,7 @@ import static io.trino.sql.planner.SystemPartitioningHandle.SOURCE_DISTRIBUTION; import static io.trino.sql.planner.plan.ExchangeNode.Type.REPLICATE; import static io.trino.sql.planner.plan.JoinNode.Type.INNER; +import static io.trino.testing.TestingHandles.TEST_CATALOG_HANDLE; import static io.trino.testing.TestingHandles.TEST_TABLE_HANDLE; import static io.trino.testing.assertions.TrinoExceptionAssert.assertTrinoExceptionThrownBy; import static java.lang.Integer.min; @@ -114,7 +114,6 @@ public class TestSourcePartitionedScheduler { private static final PlanNodeId TABLE_SCAN_NODE_ID = new PlanNodeId("plan_id"); - private static final CatalogHandle CATALOG_HANDLE = TEST_TABLE_HANDLE.getCatalogHandle(); private static final QueryId QUERY_ID = new QueryId("query"); private static final DynamicFilterId DYNAMIC_FILTER_ID = new DynamicFilterId("filter1"); @@ -129,8 +128,7 @@ public class TestSourcePartitionedScheduler public TestSourcePartitionedScheduler() { - nodeManager.addNode( - CATALOG_HANDLE, + nodeManager.addNodes( new InternalNode("other1", URI.create("http://127.0.0.1:11"), NodeVersion.UNKNOWN, false), new InternalNode("other2", URI.create("http://127.0.0.1:12"), NodeVersion.UNKNOWN, false), new InternalNode("other3", URI.create("http://127.0.0.1:13"), NodeVersion.UNKNOWN, false)); @@ -344,8 +342,8 @@ public void testNoNodes() StageScheduler scheduler = newSourcePartitionedSchedulerAsStageScheduler( stage, TABLE_SCAN_NODE_ID, - new ConnectorAwareSplitSource(CATALOG_HANDLE, createFixedSplitSource(20, TestingSplit::createRemoteSplit)), - new DynamicSplitPlacementPolicy(nodeScheduler.createNodeSelector(session, Optional.of(CATALOG_HANDLE)), stage::getAllTasks), + new ConnectorAwareSplitSource(TEST_CATALOG_HANDLE, createFixedSplitSource(20, TestingSplit::createRemoteSplit)), + new DynamicSplitPlacementPolicy(nodeScheduler.createNodeSelector(session, Optional.of(TEST_CATALOG_HANDLE)), stage::getAllTasks), 2, new DynamicFilterService(metadata, functionManager, typeOperators, new DynamicFilterConfig()), new TableExecuteContextManager(), @@ -358,9 +356,7 @@ public void testNoNodes() public void testWorkerBalancedSplitAssignment() { // use private node manager so we can add a node later - InMemoryNodeManager nodeManager = new InMemoryNodeManager(); - nodeManager.addNode( - CATALOG_HANDLE, + InMemoryNodeManager nodeManager = new InMemoryNodeManager( new InternalNode("other1", URI.create("http://127.0.0.1:11"), NodeVersion.UNKNOWN, false), new InternalNode("other2", URI.create("http://127.0.0.1:12"), NodeVersion.UNKNOWN, false), new InternalNode("other3", URI.create("http://127.0.0.1:13"), NodeVersion.UNKNOWN, false)); @@ -383,7 +379,7 @@ public void testWorkerBalancedSplitAssignment() // Add new node InternalNode additionalNode = new InternalNode("other4", URI.create("http://127.0.0.1:14"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(CATALOG_HANDLE, additionalNode); + nodeManager.addNodes(additionalNode); // Schedule 5 splits in another query. Since the new node does not have any splits, all 5 splits are assigned to the new node PlanFragment secondPlan = createFragment(); @@ -406,9 +402,7 @@ public void testWorkerBalancedSplitAssignment() public void testStageBalancedSplitAssignment() { // use private node manager so we can add a node later - InMemoryNodeManager nodeManager = new InMemoryNodeManager(); - nodeManager.addNode( - CATALOG_HANDLE, + InMemoryNodeManager nodeManager = new InMemoryNodeManager( new InternalNode("other1", URI.create("http://127.0.0.1:11"), NodeVersion.UNKNOWN, false), new InternalNode("other2", URI.create("http://127.0.0.1:12"), NodeVersion.UNKNOWN, false), new InternalNode("other3", URI.create("http://127.0.0.1:13"), NodeVersion.UNKNOWN, false)); @@ -432,7 +426,7 @@ public void testStageBalancedSplitAssignment() // Add new node InternalNode additionalNode = new InternalNode("other4", URI.create("http://127.0.0.1:14"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(CATALOG_HANDLE, additionalNode); + nodeManager.addNodes(additionalNode); // Schedule 5 splits in first query. Since the new node does not have any splits, all 5 splits are assigned to the new node firstSplitSource.addSplits(5); @@ -449,7 +443,7 @@ public void testStageBalancedSplitAssignment() // Add new node InternalNode anotherAdditionalNode = new InternalNode("other5", URI.create("http://127.0.0.1:15"), NodeVersion.UNKNOWN, false); - nodeManager.addNode(CATALOG_HANDLE, anotherAdditionalNode); + nodeManager.addNodes(anotherAdditionalNode); // Schedule 5 splits in another query. New query should be balanced across all nodes PlanFragment secondPlan = createFragment(); @@ -473,9 +467,7 @@ public void testNewTaskScheduledWhenChildStageBufferIsUnderutilized() { NodeTaskMap nodeTaskMap = new NodeTaskMap(finalizerService); // use private node manager so we can add a node later - InMemoryNodeManager nodeManager = new InMemoryNodeManager(); - nodeManager.addNode( - CATALOG_HANDLE, + InMemoryNodeManager nodeManager = new InMemoryNodeManager( new InternalNode("other1", URI.create("http://127.0.0.1:11"), NodeVersion.UNKNOWN, false), new InternalNode("other2", URI.create("http://127.0.0.1:12"), NodeVersion.UNKNOWN, false), new InternalNode("other3", URI.create("http://127.0.0.1:13"), NodeVersion.UNKNOWN, false)); @@ -488,8 +480,8 @@ public void testNewTaskScheduledWhenChildStageBufferIsUnderutilized() StageScheduler scheduler = newSourcePartitionedSchedulerAsStageScheduler( stage, TABLE_SCAN_NODE_ID, - new ConnectorAwareSplitSource(CATALOG_HANDLE, createFixedSplitSource(500, TestingSplit::createRemoteSplit)), - new DynamicSplitPlacementPolicy(nodeScheduler.createNodeSelector(session, Optional.of(CATALOG_HANDLE)), stage::getAllTasks), + new ConnectorAwareSplitSource(TEST_CATALOG_HANDLE, createFixedSplitSource(500, TestingSplit::createRemoteSplit)), + new DynamicSplitPlacementPolicy(nodeScheduler.createNodeSelector(session, Optional.of(TEST_CATALOG_HANDLE)), stage::getAllTasks), 500, new DynamicFilterService(metadata, functionManager, typeOperators, new DynamicFilterConfig()), new TableExecuteContextManager(), @@ -506,7 +498,7 @@ public void testNewTaskScheduledWhenChildStageBufferIsUnderutilized() } // new node added - the pending splits should go to it since the child tasks are not blocked - nodeManager.addNode(CATALOG_HANDLE, new InternalNode("other4", URI.create("http://127.0.0.4:14"), NodeVersion.UNKNOWN, false)); + nodeManager.addNodes(new InternalNode("other4", URI.create("http://127.0.0.4:14"), NodeVersion.UNKNOWN, false)); scheduleResult = scheduler.schedule(); assertEquals(scheduleResult.getBlockedReason().get(), SPLIT_QUEUES_FULL); // split queue is full but still the source task creation isn't blocked assertEquals(scheduleResult.getNewTasks().size(), 1); @@ -518,9 +510,7 @@ public void testNoNewTaskScheduledWhenChildStageBufferIsOverutilized() { NodeTaskMap nodeTaskMap = new NodeTaskMap(finalizerService); // use private node manager so we can add a node later - InMemoryNodeManager nodeManager = new InMemoryNodeManager(); - nodeManager.addNode( - CATALOG_HANDLE, + InMemoryNodeManager nodeManager = new InMemoryNodeManager( new InternalNode("other1", URI.create("http://127.0.0.1:11"), NodeVersion.UNKNOWN, false), new InternalNode("other2", URI.create("http://127.0.0.1:12"), NodeVersion.UNKNOWN, false), new InternalNode("other3", URI.create("http://127.0.0.1:13"), NodeVersion.UNKNOWN, false)); @@ -533,8 +523,8 @@ public void testNoNewTaskScheduledWhenChildStageBufferIsOverutilized() StageScheduler scheduler = newSourcePartitionedSchedulerAsStageScheduler( stage, TABLE_SCAN_NODE_ID, - new ConnectorAwareSplitSource(CATALOG_HANDLE, createFixedSplitSource(400, TestingSplit::createRemoteSplit)), - new DynamicSplitPlacementPolicy(nodeScheduler.createNodeSelector(session, Optional.of(CATALOG_HANDLE)), stage::getAllTasks), + new ConnectorAwareSplitSource(TEST_CATALOG_HANDLE, createFixedSplitSource(400, TestingSplit::createRemoteSplit)), + new DynamicSplitPlacementPolicy(nodeScheduler.createNodeSelector(session, Optional.of(TEST_CATALOG_HANDLE)), stage::getAllTasks), 400, new DynamicFilterService(metadata, functionManager, typeOperators, new DynamicFilterConfig()), new TableExecuteContextManager(), @@ -551,7 +541,7 @@ public void testNoNewTaskScheduledWhenChildStageBufferIsOverutilized() } // new node added but 1 child's output buffer is overutilized - so lockdown the tasks - nodeManager.addNode(CATALOG_HANDLE, new InternalNode("other4", URI.create("http://127.0.0.4:14"), NodeVersion.UNKNOWN, false)); + nodeManager.addNodes(new InternalNode("other4", URI.create("http://127.0.0.4:14"), NodeVersion.UNKNOWN, false)); scheduleResult = scheduler.schedule(); assertEquals(scheduleResult.getBlockedReason().get(), SPLIT_QUEUES_FULL); assertEquals(scheduleResult.getNewTasks().size(), 0); @@ -575,8 +565,8 @@ public void testDynamicFiltersUnblockedOnBlockedBuildSource() StageScheduler scheduler = newSourcePartitionedSchedulerAsStageScheduler( stage, TABLE_SCAN_NODE_ID, - new ConnectorAwareSplitSource(CATALOG_HANDLE, createBlockedSplitSource()), - new DynamicSplitPlacementPolicy(nodeScheduler.createNodeSelector(session, Optional.of(CATALOG_HANDLE)), stage::getAllTasks), + new ConnectorAwareSplitSource(TEST_CATALOG_HANDLE, createBlockedSplitSource()), + new DynamicSplitPlacementPolicy(nodeScheduler.createNodeSelector(session, Optional.of(TEST_CATALOG_HANDLE)), stage::getAllTasks), 2, dynamicFilterService, new TableExecuteContextManager(), @@ -642,11 +632,11 @@ private StageScheduler getSourcePartitionedScheduler( .setSplitsBalancingPolicy(splitsBalancingPolicy); NodeScheduler nodeScheduler = new NodeScheduler(new UniformNodeSelectorFactory(nodeManager, nodeSchedulerConfig, nodeTaskMap, new Duration(0, SECONDS))); - SplitPlacementPolicy placementPolicy = new DynamicSplitPlacementPolicy(nodeScheduler.createNodeSelector(session, Optional.of(CATALOG_HANDLE)), stage::getAllTasks); + SplitPlacementPolicy placementPolicy = new DynamicSplitPlacementPolicy(nodeScheduler.createNodeSelector(session, Optional.of(TEST_CATALOG_HANDLE)), stage::getAllTasks); return newSourcePartitionedSchedulerAsStageScheduler( stage, TABLE_SCAN_NODE_ID, - new ConnectorAwareSplitSource(CATALOG_HANDLE, splitSource), + new ConnectorAwareSplitSource(TEST_CATALOG_HANDLE, splitSource), placementPolicy, splitBatchSize, new DynamicFilterService(metadata, functionManager, typeOperators, new DynamicFilterConfig()), @@ -695,6 +685,7 @@ private static PlanFragment createFragment() ImmutableList.of(TABLE_SCAN_NODE_ID), new PartitioningScheme(Partitioning.create(SINGLE_DISTRIBUTION, ImmutableList.of()), ImmutableList.of(symbol)), StatsAndCosts.empty(), + ImmutableList.of(), Optional.empty()); } diff --git a/core/trino-main/src/test/java/io/trino/execution/scheduler/policy/PlanUtils.java b/core/trino-main/src/test/java/io/trino/execution/scheduler/policy/PlanUtils.java index 5b9069567a98..69bb8bac21f8 100644 --- a/core/trino-main/src/test/java/io/trino/execution/scheduler/policy/PlanUtils.java +++ b/core/trino-main/src/test/java/io/trino/execution/scheduler/policy/PlanUtils.java @@ -230,6 +230,7 @@ private static PlanFragment createFragment(PlanNode planNode) ImmutableList.of(planNode.getId()), new PartitioningScheme(Partitioning.create(SINGLE_DISTRIBUTION, ImmutableList.of()), planNode.getOutputSymbols()), StatsAndCosts.empty(), + ImmutableList.of(), Optional.empty()); } } diff --git a/core/trino-main/src/test/java/io/trino/metadata/TestDiscoveryNodeManager.java b/core/trino-main/src/test/java/io/trino/metadata/TestDiscoveryNodeManager.java index 009a5425061d..d161620bfabd 100644 --- a/core/trino-main/src/test/java/io/trino/metadata/TestDiscoveryNodeManager.java +++ b/core/trino-main/src/test/java/io/trino/metadata/TestDiscoveryNodeManager.java @@ -26,6 +26,7 @@ import io.airlift.node.NodeConfig; import io.airlift.node.NodeInfo; import io.trino.client.NodeVersion; +import io.trino.connector.CatalogManagerConfig; import io.trino.connector.system.GlobalSystemConnector; import io.trino.failuredetector.NoOpFailureDetector; import io.trino.server.InternalCommunicationConfig; @@ -89,7 +90,14 @@ public void setup() @Test public void testGetAllNodes() { - DiscoveryNodeManager manager = new DiscoveryNodeManager(selector, nodeInfo, new NoOpFailureDetector(), expectedVersion, testHttpClient, internalCommunicationConfig); + DiscoveryNodeManager manager = new DiscoveryNodeManager( + selector, + nodeInfo, + new NoOpFailureDetector(), + expectedVersion, + testHttpClient, + internalCommunicationConfig, + new CatalogManagerConfig()); try { AllNodes allNodes = manager.getAllNodes(); @@ -131,7 +139,14 @@ public void testGetCurrentNode() .setEnvironment("test") .setNodeId(currentNode.getNodeIdentifier())); - DiscoveryNodeManager manager = new DiscoveryNodeManager(selector, nodeInfo, new NoOpFailureDetector(), expectedVersion, testHttpClient, internalCommunicationConfig); + DiscoveryNodeManager manager = new DiscoveryNodeManager( + selector, + nodeInfo, + new NoOpFailureDetector(), + expectedVersion, + testHttpClient, + internalCommunicationConfig, + new CatalogManagerConfig()); try { assertEquals(manager.getCurrentNode(), currentNode); } @@ -143,7 +158,14 @@ public void testGetCurrentNode() @Test public void testGetCoordinators() { - DiscoveryNodeManager manager = new DiscoveryNodeManager(selector, nodeInfo, new NoOpFailureDetector(), expectedVersion, testHttpClient, internalCommunicationConfig); + DiscoveryNodeManager manager = new DiscoveryNodeManager( + selector, + nodeInfo, + new NoOpFailureDetector(), + expectedVersion, + testHttpClient, + internalCommunicationConfig, + new CatalogManagerConfig()); try { assertEquals(manager.getCoordinators(), ImmutableSet.of(coordinator)); } @@ -156,14 +178,28 @@ public void testGetCoordinators() @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = ".* current node not returned .*") public void testGetCurrentNodeRequired() { - new DiscoveryNodeManager(selector, new NodeInfo("test"), new NoOpFailureDetector(), expectedVersion, testHttpClient, internalCommunicationConfig); + new DiscoveryNodeManager( + selector, + new NodeInfo("test"), + new NoOpFailureDetector(), + expectedVersion, + testHttpClient, + internalCommunicationConfig, + new CatalogManagerConfig()); } @Test(timeOut = 60000) public void testNodeChangeListener() throws Exception { - DiscoveryNodeManager manager = new DiscoveryNodeManager(selector, nodeInfo, new NoOpFailureDetector(), expectedVersion, testHttpClient, internalCommunicationConfig); + DiscoveryNodeManager manager = new DiscoveryNodeManager( + selector, + nodeInfo, + new NoOpFailureDetector(), + expectedVersion, + testHttpClient, + internalCommunicationConfig, + new CatalogManagerConfig()); try { manager.startPollingNodeStates(); diff --git a/core/trino-main/src/test/java/io/trino/security/TestAccessControlManager.java b/core/trino-main/src/test/java/io/trino/security/TestAccessControlManager.java index d7516f763f46..ab692a765fa7 100644 --- a/core/trino-main/src/test/java/io/trino/security/TestAccessControlManager.java +++ b/core/trino-main/src/test/java/io/trino/security/TestAccessControlManager.java @@ -19,7 +19,6 @@ import io.trino.connector.CatalogServiceProvider; import io.trino.connector.MockConnectorFactory; import io.trino.eventlistener.EventListenerManager; -import io.trino.metadata.CatalogManager; import io.trino.metadata.QualifiedObjectName; import io.trino.plugin.base.security.AllowAllAccessControl; import io.trino.plugin.base.security.AllowAllSystemAccessControl; @@ -285,8 +284,7 @@ public void testDenySystemAccessControl() @Test public void testDenyExecuteProcedureBySystem() { - CatalogManager catalogManager = new CatalogManager(); - TransactionManager transactionManager = createTestTransactionManager(catalogManager); + TransactionManager transactionManager = createTestTransactionManager(); AccessControlManager accessControlManager = createAccessControlManager(transactionManager); TestSystemAccessControlFactory accessControlFactory = new TestSystemAccessControlFactory("deny-all"); @@ -419,8 +417,7 @@ private void assertDenyExecuteProcedure(TransactionManager transactionManager, A @Test public void testDenyExecuteFunctionBySystemAccessControl() { - CatalogManager catalogManager = new CatalogManager(); - TransactionManager transactionManager = createTestTransactionManager(catalogManager); + TransactionManager transactionManager = createTestTransactionManager(); AccessControlManager accessControlManager = createAccessControlManager(transactionManager); TestSystemAccessControlFactory accessControlFactory = new TestSystemAccessControlFactory("deny-all"); @@ -441,8 +438,7 @@ public void testDenyExecuteFunctionBySystemAccessControl() @Test public void testAllowExecuteFunction() { - CatalogManager catalogManager = new CatalogManager(); - TransactionManager transactionManager = createTestTransactionManager(catalogManager); + TransactionManager transactionManager = createTestTransactionManager(); AccessControlManager accessControlManager = createAccessControlManager(transactionManager); accessControlManager.loadSystemAccessControl("allow-all", ImmutableMap.of()); diff --git a/core/trino-main/src/test/java/io/trino/server/TestDynamicFilterService.java b/core/trino-main/src/test/java/io/trino/server/TestDynamicFilterService.java index 963c2616b0f7..14a3d4a234e0 100644 --- a/core/trino-main/src/test/java/io/trino/server/TestDynamicFilterService.java +++ b/core/trino-main/src/test/java/io/trino/server/TestDynamicFilterService.java @@ -1087,6 +1087,7 @@ private static PlanFragment createPlan( ImmutableList.of(tableScanNodeId), new PartitioningScheme(Partitioning.create(SINGLE_DISTRIBUTION, ImmutableList.of()), ImmutableList.of(symbol)), StatsAndCosts.empty(), + ImmutableList.of(), Optional.empty()); } } diff --git a/core/trino-main/src/test/java/io/trino/transaction/TestTransactionManager.java b/core/trino-main/src/test/java/io/trino/transaction/TestTransactionManager.java index 12ff4436d596..c518d2e93308 100644 --- a/core/trino-main/src/test/java/io/trino/transaction/TestTransactionManager.java +++ b/core/trino-main/src/test/java/io/trino/transaction/TestTransactionManager.java @@ -16,7 +16,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import io.airlift.units.Duration; -import io.trino.metadata.CatalogManager; import io.trino.plugin.tpch.TpchConnectorFactory; import io.trino.spi.connector.ConnectorMetadata; import io.trino.testing.LocalQueryRunner; @@ -31,6 +30,7 @@ import static io.airlift.concurrent.MoreFutures.getFutureValue; import static io.airlift.concurrent.Threads.daemonThreadsNamed; import static io.trino.SessionTestUtils.TEST_SESSION; +import static io.trino.metadata.CatalogManager.NO_CATALOGS; import static io.trino.spi.StandardErrorCode.TRANSACTION_ALREADY_ABORTED; import static io.trino.testing.TestingHandles.TEST_CATALOG_HANDLE; import static io.trino.testing.TestingHandles.TEST_CATALOG_NAME; @@ -154,7 +154,7 @@ public void testExpiration() .setIdleTimeout(new Duration(1, TimeUnit.MILLISECONDS)) .setIdleCheckInterval(new Duration(5, TimeUnit.MILLISECONDS)), executor.getExecutor(), - new CatalogManager(), + NO_CATALOGS, finishingExecutor); TransactionId transactionId = transactionManager.beginTransaction(false); diff --git a/core/trino-main/src/test/java/io/trino/transaction/TestingTransactionManager.java b/core/trino-main/src/test/java/io/trino/transaction/TestingTransactionManager.java index 45451c2f5ee4..d22a92afb610 100644 --- a/core/trino-main/src/test/java/io/trino/transaction/TestingTransactionManager.java +++ b/core/trino-main/src/test/java/io/trino/transaction/TestingTransactionManager.java @@ -97,6 +97,12 @@ public List getCatalogs(TransactionId transactionId) return ImmutableList.of(); } + @Override + public List getActiveCatalogs(TransactionId transactionId) + { + return ImmutableList.of(); + } + @Override public Optional getCatalogHandle(TransactionId transactionId, String catalogName) { diff --git a/core/trino-spi/src/main/java/io/trino/spi/StandardErrorCode.java b/core/trino-spi/src/main/java/io/trino/spi/StandardErrorCode.java index b98424d0b2d9..040471bca038 100644 --- a/core/trino-spi/src/main/java/io/trino/spi/StandardErrorCode.java +++ b/core/trino-spi/src/main/java/io/trino/spi/StandardErrorCode.java @@ -171,6 +171,7 @@ public enum StandardErrorCode SERIALIZATION_ERROR(65562, INTERNAL_ERROR), REMOTE_TASK_FAILED(65563, INTERNAL_ERROR), EXCHANGE_MANAGER_NOT_CONFIGURED(65564, INTERNAL_ERROR), + CATALOG_NOT_AVAILABLE(65565, INTERNAL_ERROR), GENERIC_INSUFFICIENT_RESOURCES(131072, INSUFFICIENT_RESOURCES), EXCEEDED_GLOBAL_MEMORY_LIMIT(131073, INSUFFICIENT_RESOURCES), diff --git a/testing/trino-testing/src/main/java/io/trino/testing/DistributedQueryRunner.java b/testing/trino-testing/src/main/java/io/trino/testing/DistributedQueryRunner.java index a9566b3f56b6..8fa490bb7563 100644 --- a/testing/trino-testing/src/main/java/io/trino/testing/DistributedQueryRunner.java +++ b/testing/trino-testing/src/main/java/io/trino/testing/DistributedQueryRunner.java @@ -24,7 +24,6 @@ import io.airlift.units.Duration; import io.trino.Session; import io.trino.Session.SessionBuilder; -import io.trino.connector.CatalogHandle; import io.trino.cost.StatsCalculator; import io.trino.execution.FailureInjector.InjectedFailureType; import io.trino.execution.QueryManager; @@ -32,7 +31,6 @@ import io.trino.metadata.AllNodes; import io.trino.metadata.FunctionBundle; import io.trino.metadata.FunctionManager; -import io.trino.metadata.InternalNode; import io.trino.metadata.Metadata; import io.trino.metadata.QualifiedObjectName; import io.trino.metadata.SessionPropertyManager; @@ -58,11 +56,10 @@ import java.net.URI; import java.nio.file.Path; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -71,7 +68,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Throwables.throwIfUnchecked; -import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.inject.util.Modules.EMPTY_MODULE; import static io.airlift.log.Level.DEBUG; import static io.airlift.log.Level.ERROR; @@ -91,7 +87,10 @@ public class DistributedQueryRunner private final TestingDiscoveryServer discoveryServer; private final TestingTrinoServer coordinator; private final Optional backupCoordinator; - private List servers; + private final Runnable registerNewWorker; + private final List servers = new CopyOnWriteArrayList<>(); + private final List functionBundles = new CopyOnWriteArrayList<>(ImmutableList.of(AbstractTestQueries.CUSTOM_FUNCTIONS)); + private final List plugins = new CopyOnWriteArrayList<>(); private final Closer closer = Closer.create(); @@ -131,19 +130,10 @@ private DistributedQueryRunner( closer.register(() -> closeUnchecked(discoveryServer)); log.info("Created TestingDiscoveryServer in %s", nanosSince(start).convertToMostSuccinctTimeUnit()); - ImmutableList.Builder servers = ImmutableList.builder(); + registerNewWorker = () -> createServer(false, extraProperties, environment, additionalModule, baseDataDir, ImmutableList.of(), ImmutableList.of()); for (int i = backupCoordinatorProperties.isEmpty() ? 1 : 2; i < nodeCount; i++) { - TestingTrinoServer worker = closer.register(createTestingTrinoServer( - discoveryServer.getBaseUrl(), - false, - extraProperties, - environment, - additionalModule, - baseDataDir, - ImmutableList.of(), - ImmutableList.of())); - servers.add(worker); + registerNewWorker.run(); } Map extraCoordinatorProperties = new HashMap<>(); @@ -157,36 +147,23 @@ private DistributedQueryRunner( extraCoordinatorProperties.put("web-ui.user", "admin"); } - coordinator = closer.register(createTestingTrinoServer( - discoveryServer.getBaseUrl(), - true, - extraCoordinatorProperties, - environment, - additionalModule, - baseDataDir, - systemAccessControls, - eventListeners)); - servers.add(coordinator); + coordinator = createServer(true, extraCoordinatorProperties, environment, additionalModule, baseDataDir, systemAccessControls, eventListeners); if (backupCoordinatorProperties.isPresent()) { Map extraBackupCoordinatorProperties = new HashMap<>(); extraBackupCoordinatorProperties.putAll(extraProperties); extraBackupCoordinatorProperties.putAll(backupCoordinatorProperties.get()); - backupCoordinator = Optional.of(closer.register(createTestingTrinoServer( - discoveryServer.getBaseUrl(), + backupCoordinator = Optional.of(createServer( true, extraBackupCoordinatorProperties, environment, additionalModule, baseDataDir, systemAccessControls, - eventListeners))); - servers.add(backupCoordinator.get()); + eventListeners)); } else { backupCoordinator = Optional.empty(); } - - this.servers = servers.build(); } catch (Exception e) { try { @@ -202,12 +179,30 @@ private DistributedQueryRunner( this.trinoClient = closer.register(new TestingTrinoClient(coordinator, defaultSession)); waitForAllNodesGloballyVisible(); + } - long start = System.nanoTime(); - for (TestingTrinoServer server : servers) { - server.addFunctions(AbstractTestQueries.CUSTOM_FUNCTIONS); - } - log.info("Added functions in %s", nanosSince(start).convertToMostSuccinctTimeUnit()); + private TestingTrinoServer createServer( + boolean coordinator, + Map extraCoordinatorProperties, + String environment, + Module additionalModule, + Optional baseDataDir, + List systemAccessControls, + List eventListeners) + { + TestingTrinoServer server = closer.register(createTestingTrinoServer( + discoveryServer.getBaseUrl(), + coordinator, + extraCoordinatorProperties, + environment, + additionalModule, + baseDataDir, + systemAccessControls, + eventListeners)); + servers.add(server); + functionBundles.forEach(server::addFunctions); + plugins.forEach(server::installPlugin); + return server; } private static void setupLogging() @@ -273,23 +268,9 @@ private static TestingTrinoServer createTestingTrinoServer( public void addServers(int nodeCount) throws Exception { - ImmutableList.Builder serverBuilder = ImmutableList.builder() - .addAll(servers); for (int i = 0; i < nodeCount; i++) { - TestingTrinoServer server = closer.register(createTestingTrinoServer( - discoveryServer.getBaseUrl(), - false, - ImmutableMap.of(), - ENVIRONMENT, - EMPTY_MODULE, - Optional.empty(), - ImmutableList.of(), - ImmutableList.of())); - serverBuilder.add(server); - // add functions - server.addFunctions(AbstractTestQueries.CUSTOM_FUNCTIONS); - } - servers = serverBuilder.build(); + registerNewWorker.run(); + } waitForAllNodesGloballyVisible(); } @@ -428,16 +409,16 @@ public List getServers() @Override public void installPlugin(Plugin plugin) { + plugins.add(plugin); long start = System.nanoTime(); - for (TestingTrinoServer server : servers) { - server.installPlugin(plugin); - } + servers.forEach(server -> server.installPlugin(plugin)); log.info("Installed plugin %s in %s", plugin.getClass().getSimpleName(), nanosSince(start).convertToMostSuccinctTimeUnit()); } @Override public void addFunctions(FunctionBundle functionBundle) { + functionBundles.add(functionBundle); servers.forEach(server -> server.addFunctions(functionBundle)); } @@ -450,38 +431,8 @@ public void createCatalog(String catalogName, String connectorName) public void createCatalog(String catalogName, String connectorName, Map properties) { long start = System.nanoTime(); - Set catalogHandles = new HashSet<>(); - for (TestingTrinoServer server : servers) { - catalogHandles.add(server.createCatalog(catalogName, connectorName, properties)); - } - CatalogHandle catalog = getOnlyElement(catalogHandles); - log.info("Created catalog %s (%s) in %s", catalogName, catalog, nanosSince(start)); - - // wait for all nodes to announce the new catalog - start = System.nanoTime(); - while (!isConnectionVisibleToAllNodes(catalog)) { - Assertions.assertLessThan(nanosSince(start), new Duration(100, SECONDS), "waiting for catalog " + catalogName + " to be initialized in every node"); - try { - MILLISECONDS.sleep(10); - } - catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException(e); - } - } - log.info("Announced catalog %s (%s) in %s", catalogName, catalog, nanosSince(start)); - } - - private boolean isConnectionVisibleToAllNodes(CatalogHandle catalogHandle) - { - for (TestingTrinoServer server : servers) { - server.refreshNodes(); - Set activeNodesWithConnector = server.getActiveNodesWithConnector(catalogHandle); - if (activeNodesWithConnector.size() != servers.size()) { - return false; - } - } - return true; + coordinator.createCatalog(catalogName, connectorName, properties); + log.info("Created catalog %s in %s", catalogName, nanosSince(start)); } @Override diff --git a/testing/trino-testing/src/main/java/io/trino/testing/StandaloneQueryRunner.java b/testing/trino-testing/src/main/java/io/trino/testing/StandaloneQueryRunner.java index 9ca82010a79c..28c6c8714fb3 100644 --- a/testing/trino-testing/src/main/java/io/trino/testing/StandaloneQueryRunner.java +++ b/testing/trino-testing/src/main/java/io/trino/testing/StandaloneQueryRunner.java @@ -15,13 +15,10 @@ import com.google.common.collect.ImmutableMap; import io.trino.Session; -import io.trino.connector.CatalogHandle; import io.trino.cost.StatsCalculator; import io.trino.execution.FailureInjector.InjectedFailureType; -import io.trino.metadata.AllNodes; import io.trino.metadata.FunctionBundle; import io.trino.metadata.FunctionManager; -import io.trino.metadata.InternalNode; import io.trino.metadata.Metadata; import io.trino.metadata.QualifiedObjectName; import io.trino.metadata.SessionPropertyManager; @@ -40,14 +37,12 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import static io.airlift.testing.Closeables.closeAll; import static java.util.Objects.requireNonNull; -import static java.util.concurrent.TimeUnit.MILLISECONDS; public final class StandaloneQueryRunner implements QueryRunner @@ -65,8 +60,6 @@ public StandaloneQueryRunner(Session defaultSession) this.server = createTestingTrinoServer(); this.trinoClient = new TestingTrinoClient(server, defaultSession); - refreshNodes(); - server.addFunctions(AbstractTestQueries.CUSTOM_FUNCTIONS); } @@ -194,40 +187,6 @@ public TestingTrinoServer getServer() return server; } - public void refreshNodes() - { - AllNodes allNodes; - - do { - try { - MILLISECONDS.sleep(10); - } - catch (InterruptedException e) { - Thread.currentThread().interrupt(); - break; - } - allNodes = server.refreshNodes(); - } - while (allNodes.getActiveNodes().isEmpty()); - } - - private void refreshNodes(CatalogHandle catalogHandle) - { - Set activeNodesWithConnector; - - do { - try { - MILLISECONDS.sleep(10); - } - catch (InterruptedException e) { - Thread.currentThread().interrupt(); - break; - } - activeNodesWithConnector = server.getActiveNodesWithConnector(catalogHandle); - } - while (activeNodesWithConnector.isEmpty()); - } - @Override public void installPlugin(Plugin plugin) { @@ -248,9 +207,7 @@ public void createCatalog(String catalogName, String connectorName) @Override public void createCatalog(String catalogName, String connectorName, Map properties) { - CatalogHandle catalog = server.createCatalog(catalogName, connectorName, properties); - - refreshNodes(catalog); + server.createCatalog(catalogName, connectorName, properties); } @Override