This is an automated email from the ASF dual-hosted git repository. amashenkov pushed a commit to branch ignite-26156 in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit 3cd3f995358e006a91ab02af72d53c4e128fef6e Author: amashenkov <[email protected]> AuthorDate: Mon Sep 1 11:56:58 2025 +0300 wip --- .../sql/planner/ItSqlPlannerCommandTest.java} | 34 ++++++------ .../cli/call/sql/InvalidateCacheCallInput.java | 64 ++++++++++++++++++++++ .../cli/call/sql/InvalidatePlannerCacheCall.java | 61 +++++++++++++++++++++ .../internal/cli/commands/sql/SqlCommand.java | 8 ++- .../sql/planner/InvalidateCacheCommand.java | 52 ++++++++++++++++++ .../cli/commands/sql/planner/PlanCommand.java} | 27 ++++----- .../ignite/internal/sql/api/IgniteSqlImpl.java | 7 ++- .../ignite/internal/sql/api/IgniteSqlInternal.java | 10 ++++ .../ignite/internal/sql/engine/QueryProcessor.java | 4 ++ .../internal/sql/engine/SqlQueryProcessor.java | 5 ++ .../sql/engine/prepare/PrepareService.java | 2 + .../sql/engine/prepare/PrepareServiceImpl.java | 6 ++ 12 files changed, 245 insertions(+), 35 deletions(-) diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareService.java b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/sql/planner/ItSqlPlannerCommandTest.java similarity index 50% copy from modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareService.java copy to modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/sql/planner/ItSqlPlannerCommandTest.java index 0cd83ea8e90..0f51473f34a 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareService.java +++ b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/sql/planner/ItSqlPlannerCommandTest.java @@ -15,25 +15,27 @@ * limitations under the License. */ -package org.apache.ignite.internal.sql.engine.prepare; +package org.apache.ignite.internal.cli.commands.sql.planner; -import java.util.concurrent.CompletableFuture; -import org.apache.ignite.internal.sql.engine.SqlOperationContext; -import org.apache.ignite.internal.sql.engine.exec.LifecycleAware; -import org.apache.ignite.internal.sql.engine.sql.ParsedResult; +import static org.apache.ignite.internal.cli.commands.Options.Constants.CLUSTER_URL_OPTION; +import static org.junit.jupiter.api.Assertions.assertAll; + +import org.apache.ignite.internal.cli.commands.sql.CliSqlCommandTestBase; +import org.apache.ignite.internal.cli.commands.sql.SqlCommand; +import org.junit.jupiter.api.Test; /** - * Preparation service that accepts an AST of the query and returns a prepared query plan. + * Tests for {@link SqlCommand}. */ -public interface PrepareService extends LifecycleAware { +class ItSqlPlannerCommandTest extends CliSqlCommandTestBase { + @Test + void clearCache() { + execute("sql", "plan", "clear-cache", CLUSTER_URL_OPTION, NODE_URL); - /** - * Prepare query plan. - * - * @param parsedResult Represent of parsed query as AST, which need to be planned. - * @param ctx Query context. - * - * @return Future that contains prepared query plan when completes. - */ - CompletableFuture<QueryPlan> prepareAsync(ParsedResult parsedResult, SqlOperationContext ctx); + assertAll( + () -> assertExitCodeIs(1), + this::assertOutputIsEmpty, + this::assertErrOutputIsEmpty + ); + } } diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/sql/InvalidateCacheCallInput.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/sql/InvalidateCacheCallInput.java new file mode 100644 index 00000000000..0c7acefec57 --- /dev/null +++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/sql/InvalidateCacheCallInput.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.cli.call.sql; + +import java.util.List; +import org.apache.ignite.internal.cli.core.call.CallInput; +import org.jetbrains.annotations.Nullable; + +/** + * Input for {@link InvalidatePlannerCacheCall}. + */ +public class InvalidateCacheCallInput implements CallInput { + /** + * Cluster url. + */ + private final String clusterUrl; + + /** + * Tables filter. + */ + @Nullable + private final List<String> tables; + + @Nullable + private final List<String> targetNodes; + + public InvalidateCacheCallInput(String clusterUrl, @Nullable List<String> tables, @Nullable List<String> targetNodes) { + this.clusterUrl = clusterUrl; + this.tables = tables; + this.targetNodes = targetNodes; + } + + /** Cluster url. */ + public String clusterUrl() { + return clusterUrl; + } + + /** Returns names specifying nodes to restart partitions. Empty/null means "all nodes". */ + @Nullable + public List<String> targetNodes() { + return targetNodes; + } + + /** Return tables that SQL plans contains any of these tables should be invalidated. */ + @Nullable + public List<String> getTables() { + return tables; + } +} diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/sql/InvalidatePlannerCacheCall.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/sql/InvalidatePlannerCacheCall.java new file mode 100644 index 00000000000..19ee55db064 --- /dev/null +++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/sql/InvalidatePlannerCacheCall.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.cli.call.sql; + +import jakarta.inject.Singleton; +import org.apache.ignite.internal.cli.call.configuration.JsonString; +import org.apache.ignite.internal.cli.core.call.Call; +import org.apache.ignite.internal.cli.core.call.CallOutput; +import org.apache.ignite.internal.cli.core.call.DefaultCallOutput; +import org.apache.ignite.internal.cli.core.exception.IgniteCliApiException; +import org.apache.ignite.internal.cli.core.rest.ApiClientFactory; +import org.apache.ignite.rest.client.api.SqlApi; +import org.apache.ignite.rest.client.invoker.ApiException; + +/** + * Shows node configuration from ignite cluster. + */ +@Singleton +public class InvalidatePlannerCacheCall implements Call<InvalidateCacheCallInput, JsonString> { + private final ApiClientFactory clientFactory; + + public InvalidatePlannerCacheCall(ApiClientFactory clientFactory) { + this.clientFactory = clientFactory; + } + + /** {@inheritDoc} */ + @Override + public CallOutput<JsonString> execute(InvalidateCacheCallInput input) { + SqlApi client = createApiClient(input); + + try { + return DefaultCallOutput.success(invalidateSqlPlannerCache(client, input)); + } catch (ApiException | IllegalArgumentException e) { + return DefaultCallOutput.failure(new IgniteCliApiException(e, input.clusterUrl())); + } + } + + private JsonString invalidateSqlPlannerCache(SqlApi api, InvalidateCacheCallInput input) throws ApiException { + // TODO: IGNITE-25872 serialize table names and implement api call. + return JsonString.fromString(""); + } + + private SqlApi createApiClient(InvalidateCacheCallInput input) { + return new SqlApi(clientFactory.getClient(input.clusterUrl())); + } +} diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlCommand.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlCommand.java index 0c23597b4db..3cb6f3d1b6f 100644 --- a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlCommand.java +++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlCommand.java @@ -33,6 +33,7 @@ import java.sql.SQLException; import java.util.concurrent.Callable; import org.apache.ignite.internal.cli.call.sql.SqlQueryCall; import org.apache.ignite.internal.cli.commands.BaseCommand; +import org.apache.ignite.internal.cli.commands.sql.planner.PlanCommand; import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline; import org.apache.ignite.internal.cli.core.call.StringCallInput; import org.apache.ignite.internal.cli.core.exception.ExceptionWriter; @@ -48,7 +49,12 @@ import picocli.CommandLine.Parameters; /** * Command for sql execution. */ -@Command(name = "sql", description = "Executes SQL query") +@Command(name = "sql", + subcommands = { + PlanCommand.class + }, + description = "Executes SQL query" +) public class SqlCommand extends BaseCommand implements Callable<Integer> { @Option(names = JDBC_URL_OPTION, required = true, descriptionKey = JDBC_URL_KEY, description = JDBC_URL_OPTION_DESC) private String jdbc; diff --git a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/planner/InvalidateCacheCommand.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/planner/InvalidateCacheCommand.java new file mode 100644 index 00000000000..731ad0e3c52 --- /dev/null +++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/planner/InvalidateCacheCommand.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.cli.commands.sql.planner; + +import jakarta.inject.Inject; +import java.util.List; +import java.util.concurrent.Callable; +import org.apache.ignite.internal.cli.call.sql.InvalidateCacheCallInput; +import org.apache.ignite.internal.cli.call.sql.InvalidatePlannerCacheCall; +import org.apache.ignite.internal.cli.commands.BaseCommand; +import org.apache.ignite.internal.cli.commands.cluster.ClusterUrlProfileMixin; +import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline; +import org.apache.ignite.internal.cli.core.exception.handler.ClusterNotInitializedExceptionHandler; +import picocli.CommandLine.Command; +import picocli.CommandLine.Mixin; + +/** + * Sql planner cache invalidation command. + */ +@Command(name = "clear-cache", description = "Invalidates SQL planner cache") +public class InvalidateCacheCommand extends BaseCommand implements Callable<Integer> { + /** Cluster endpoint URL option. */ + @Mixin + private ClusterUrlProfileMixin clusterUrl; + + @Inject + private InvalidatePlannerCacheCall call; + + /** {@inheritDoc} */ + @Override + public Integer call() { + return runPipeline(CallExecutionPipeline.builder(call) + .inputProvider(() -> new InvalidateCacheCallInput(clusterUrl.getClusterUrl(), List.of(), List.of())) + .exceptionHandler(ClusterNotInitializedExceptionHandler.createHandler("Failed to invalidate SQL planner cache")) + ); + } +} diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareService.java b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/planner/PlanCommand.java similarity index 50% copy from modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareService.java copy to modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/planner/PlanCommand.java index 0cd83ea8e90..fe3a237885d 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareService.java +++ b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/planner/PlanCommand.java @@ -15,25 +15,18 @@ * limitations under the License. */ -package org.apache.ignite.internal.sql.engine.prepare; +package org.apache.ignite.internal.cli.commands.sql.planner; -import java.util.concurrent.CompletableFuture; -import org.apache.ignite.internal.sql.engine.SqlOperationContext; -import org.apache.ignite.internal.sql.engine.exec.LifecycleAware; -import org.apache.ignite.internal.sql.engine.sql.ParsedResult; +import org.apache.ignite.internal.cli.commands.BaseCommand; +import picocli.CommandLine.Command; /** - * Preparation service that accepts an AST of the query and returns a prepared query plan. + * Sql planner command. */ -public interface PrepareService extends LifecycleAware { - - /** - * Prepare query plan. - * - * @param parsedResult Represent of parsed query as AST, which need to be planned. - * @param ctx Query context. - * - * @return Future that contains prepared query plan when completes. - */ - CompletableFuture<QueryPlan> prepareAsync(ParsedResult parsedResult, SqlOperationContext ctx); +@Command(name = "plan", + subcommands = { + InvalidateCacheCommand.class + }, + description = "SQL planner operations") +public class PlanCommand extends BaseCommand { } diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/IgniteSqlImpl.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/IgniteSqlImpl.java index bb2705e43b3..2e4abcb7aa8 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/IgniteSqlImpl.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/IgniteSqlImpl.java @@ -83,7 +83,7 @@ import org.jetbrains.annotations.TestOnly; * Embedded implementation of the Ignite SQL query facade. */ @SuppressWarnings("rawtypes") -public class IgniteSqlImpl implements IgniteSql, IgniteComponent { +public class IgniteSqlImpl implements IgniteSqlInternal, IgniteComponent { private static final IgniteLogger LOG = Loggers.forClass(IgniteSqlImpl.class); private static final int AWAIT_CURSOR_CLOSE_ON_STOP_IN_SECONDS = 10; @@ -649,6 +649,11 @@ public class IgniteSqlImpl implements IgniteSql, IgniteComponent { }); } + @Override + public void invalidatePlannerCache() { + queryProcessor.invalidatePlannerCache(); + } + private static void validateDmlResult(AsyncCursor.BatchedResult<InternalSqlRow> page) { if (page == null || page.items() == null diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/IgniteSqlInternal.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/IgniteSqlInternal.java new file mode 100644 index 00000000000..a560c28728a --- /dev/null +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/api/IgniteSqlInternal.java @@ -0,0 +1,10 @@ +package org.apache.ignite.internal.sql.api; + +import org.apache.ignite.sql.IgniteSql; + +/** + * Internal SQL facade. + */ +public interface IgniteSqlInternal extends IgniteSql { + void invalidatePlannerCache(); +} diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryProcessor.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryProcessor.java index 29e497a3dfa..4d0fc33d5b1 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryProcessor.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/QueryProcessor.java @@ -70,4 +70,8 @@ public interface QueryProcessor extends IgniteComponent { String qry, Object... params ); + + default void invalidatePlannerCache() { + + } } diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java index f2e11594072..cd2f7eaa992 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java @@ -604,6 +604,11 @@ public class SqlQueryProcessor implements QueryProcessor, SystemViewProvider { return List.of(queriesViewProvider.get()); } + @Override + public void invalidatePlannerCache() { + prepareSvc.invalidateCache(); + } + /** Completes the provided future when the callback is called. */ public static class PrefetchCallback implements QueryPrefetchCallback { private final CompletableFuture<Void> prefetchFuture = new CompletableFuture<>(); diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareService.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareService.java index 0cd83ea8e90..172da6c2a9f 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareService.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareService.java @@ -36,4 +36,6 @@ public interface PrepareService extends LifecycleAware { * @return Future that contains prepared query plan when completes. */ CompletableFuture<QueryPlan> prepareAsync(ParsedResult parsedResult, SqlOperationContext ctx); + + default void invalidateCache() {}; } diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareServiceImpl.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareServiceImpl.java index 16a7cfcce28..964524581ba 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareServiceImpl.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PrepareServiceImpl.java @@ -305,6 +305,12 @@ public class PrepareServiceImpl implements PrepareService { ); } + /** Invalidates planner cache. */ + @Override + public void invalidateCache() { + cache.clear(); + } + private CompletableFuture<QueryPlan> prepareAsync0( ParsedResult parsedResult, PlanningContext planningContext
