This is an automated email from the ASF dual-hosted git repository. korlov pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push: new a5662cc26 IGNITE-14937 Introduce index management (#980) a5662cc26 is described below commit a5662cc269dfb85c5dd01ef8f0e4ef754f6f0d4d Author: korlov42 <kor...@gridgain.com> AuthorDate: Tue Aug 9 10:00:42 2022 +0300 IGNITE-14937 Introduce index management (#980) --- .../table/HashIndexConfigurationSchema.java | 2 +- .../table/PartialIndexConfigurationSchema.java | 38 --- .../table/TableIndexConfigurationSchema.java | 13 +- .../builder/PartialIndexDefinitionBuilder.java | 72 ---- .../java/org/apache/ignite/lang/ErrorGroups.java | 9 + modules/index/pom.xml | 95 ++++++ .../org/apache/ignite/internal/index/Index.java} | 31 +- .../apache/ignite/internal/index/IndexManager.java | 261 +++++++++++++++ .../ignite/internal/index/IndexManagerTest.java | 363 +++++++++++++++++++++ modules/runner/pom.xml | 5 + .../org/apache/ignite/internal/app/IgniteImpl.java | 13 + .../CoreDistributedConfigurationModule.java | 2 - .../CoreDistributedConfigurationModuleTest.java | 6 - .../SchemaConfigurationConverter.java | 33 +- .../builder/PartialIndexDefinitionBuilderImpl.java | 121 ------- .../index/PartialIndexDefinitionImpl.java | 61 ---- .../org/apache/ignite/schema/SchemaBuilders.java | 12 - .../internal/schema/SchemaConfigurationTest.java | 9 - .../builder/PartialIndexDefinitionBuilderTest.java | 46 --- .../SchemaConfigurationConverterTest.java | 27 -- .../configuration/TableValidatorImplTest.java | 4 +- .../internal/sql/engine/session/Session.java | 2 +- .../sql/engine/exec/MockedStructuresTest.java | 2 - .../internal/table/distributed/TableManager.java | 2 +- .../table/distributed/TableManagerTest.java | 2 - parent/pom.xml | 6 + pom.xml | 1 + 27 files changed, 782 insertions(+), 456 deletions(-) diff --git a/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/HashIndexConfigurationSchema.java b/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/HashIndexConfigurationSchema.java index 7fa3564e4..ce1a1e5c2 100644 --- a/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/HashIndexConfigurationSchema.java +++ b/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/HashIndexConfigurationSchema.java @@ -29,5 +29,5 @@ import org.apache.ignite.configuration.annotation.Value; public class HashIndexConfigurationSchema extends TableIndexConfigurationSchema { /** Columns names for hash indexes. */ @Value - public String[] colNames; + public String[] columnNames; } diff --git a/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/PartialIndexConfigurationSchema.java b/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/PartialIndexConfigurationSchema.java deleted file mode 100644 index 952bb4347..000000000 --- a/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/PartialIndexConfigurationSchema.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.configuration.schemas.table; - -import static org.apache.ignite.configuration.schemas.table.TableIndexConfigurationSchema.PARTIAL_INDEX_TYPE; - -import org.apache.ignite.configuration.annotation.NamedConfigValue; -import org.apache.ignite.configuration.annotation.PolymorphicConfigInstance; -import org.apache.ignite.configuration.annotation.Value; - -/** - * Schema for the Partial Index configuration. - */ -@PolymorphicConfigInstance(PARTIAL_INDEX_TYPE) -public class PartialIndexConfigurationSchema extends TableIndexConfigurationSchema { - /** Expression for PartialIndex: PARTIAL indexes. */ - @Value - public String expr; - - /** Columns configuration for sorted indexes. */ - @NamedConfigValue - public IndexColumnConfigurationSchema columns; -} diff --git a/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/TableIndexConfigurationSchema.java b/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/TableIndexConfigurationSchema.java index 23c2be22a..ae9043f06 100644 --- a/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/TableIndexConfigurationSchema.java +++ b/modules/api/src/main/java/org/apache/ignite/configuration/schemas/table/TableIndexConfigurationSchema.java @@ -17,7 +17,9 @@ package org.apache.ignite.configuration.schemas.table; +import java.util.UUID; import org.apache.ignite.configuration.annotation.InjectedName; +import org.apache.ignite.configuration.annotation.InternalId; import org.apache.ignite.configuration.annotation.PolymorphicConfig; import org.apache.ignite.configuration.annotation.PolymorphicId; import org.apache.ignite.configuration.annotation.Value; @@ -33,13 +35,14 @@ public class TableIndexConfigurationSchema { /** Sorted index type. */ public static final String SORTED_INDEX_TYPE = "SORTED"; - /** Partial index type. */ - public static final String PARTIAL_INDEX_TYPE = "PARTIAL"; - /** Index type name. */ @PolymorphicId public String type; + /** Index identifier. */ + @InternalId + public UUID id; + /** Index name. */ @InjectedName public String name; @@ -47,8 +50,4 @@ public class TableIndexConfigurationSchema { /** Has default value flag. */ @Value(hasDefault = true) public boolean uniq = false; - - /** Affinity column names for PrimaryKey. */ - @Value(hasDefault = true) - public String[] affinityColumns = new String[0]; } diff --git a/modules/api/src/main/java/org/apache/ignite/schema/definition/builder/PartialIndexDefinitionBuilder.java b/modules/api/src/main/java/org/apache/ignite/schema/definition/builder/PartialIndexDefinitionBuilder.java deleted file mode 100644 index 2dd10ecdd..000000000 --- a/modules/api/src/main/java/org/apache/ignite/schema/definition/builder/PartialIndexDefinitionBuilder.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.schema.definition.builder; - -import java.util.Map; -import org.apache.ignite.schema.definition.index.PartialIndexDefinition; - -/** - * Partial index descriptor builder. - */ -public interface PartialIndexDefinitionBuilder extends SortedIndexDefinitionBuilder { - /** - * Sets partial index expression. - * - * @param expr Partial index expression. - * @return {@code this} for chaining. - */ - PartialIndexDefinitionBuilder withExpression(String expr); - - /** {@inheritDoc} */ - @Override - PartialIndexColumnBuilder addIndexColumn(String name); - - /** {@inheritDoc} */ - @Override - PartialIndexDefinitionBuilder withHints(Map<String, String> hints); - - /** - * Builds partial index. - * - * @return Partial index. - */ - @Override - PartialIndexDefinition build(); - - /** - * Index column builder. - */ - @SuppressWarnings("PublicInnerClass") - interface PartialIndexColumnBuilder extends SortedIndexColumnBuilder { - /** {@inheritDoc} */ - @Override - PartialIndexColumnBuilder desc(); - - /** {@inheritDoc} */ - @Override - PartialIndexColumnBuilder asc(); - - /** {@inheritDoc} */ - @Override - PartialIndexColumnBuilder withName(String name); - - /** {@inheritDoc} */ - @Override - PartialIndexDefinitionBuilder done(); - } -} diff --git a/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java index 3afd77c9e..fee265564 100755 --- a/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java +++ b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java @@ -154,4 +154,13 @@ public class ErrorGroups { /** Failed to close a cursor. */ public static final int CURSOR_CLOSING_ERR = META_STORAGE_ERR_GROUP.registerErrorCode(11); } + + /** Index error group. */ + public static class Index { + /** Index error group. */ + public static final ErrorGroup INDEX_ERR_GROUP = ErrorGroup.newGroup("IDX", 6); + + /** Invalid index definition. */ + public static final int INVALID_INDEX_DEFINITION_ERR = INDEX_ERR_GROUP.registerErrorCode(1); + } } diff --git a/modules/index/pom.xml b/modules/index/pom.xml new file mode 100644 index 000000000..d3e066b0c --- /dev/null +++ b/modules/index/pom.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + 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. +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.ignite</groupId> + <artifactId>ignite-parent</artifactId> + <version>1</version> + <relativePath>../../parent/pom.xml</relativePath> + </parent> + + <artifactId>ignite-index</artifactId> + <version>3.0.0-SNAPSHOT</version> + + <dependencies> + <dependency> + <groupId>org.apache.ignite</groupId> + <artifactId>ignite-api</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.ignite</groupId> + <artifactId>ignite-core</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.ignite</groupId> + <artifactId>ignite-table</artifactId> + </dependency> + + <!-- Test dependencies --> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-params</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-inline</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-junit-jupiter</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <scope>test</scope> + </dependency> + + <!-- Logging in tests --> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-jdk14</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/modules/api/src/main/java/org/apache/ignite/schema/definition/index/PartialIndexDefinition.java b/modules/index/src/main/java/org/apache/ignite/internal/index/Index.java similarity index 57% rename from modules/api/src/main/java/org/apache/ignite/schema/definition/index/PartialIndexDefinition.java rename to modules/index/src/main/java/org/apache/ignite/internal/index/Index.java index aff8e3b35..9c4b79388 100644 --- a/modules/api/src/main/java/org/apache/ignite/schema/definition/index/PartialIndexDefinition.java +++ b/modules/index/src/main/java/org/apache/ignite/internal/index/Index.java @@ -15,22 +15,25 @@ * limitations under the License. */ -package org.apache.ignite.schema.definition.index; +package org.apache.ignite.internal.index; + +import java.util.BitSet; +import java.util.UUID; +import org.apache.ignite.internal.schema.BinaryTuple; +import org.apache.ignite.internal.util.Cursor; /** - * Partial index descriptor. + * An object describing an abstract index. + * + * <p>Provides access to the indexed data as well as all information about index itself. */ -public interface PartialIndexDefinition extends SortedIndexDefinition { - /** - * Partial index expression. - * - * @return Expression. - */ - String expr(); +public interface Index { + /** Returns identifier of the index. */ + UUID id(); + + /** Returns name of the index. */ + String name(); - /** {@inheritDoc} */ - @Override - default String type() { - return "PARTIAL"; - } + /** Returns cursor for the values corresponding to the given key. */ + Cursor<BinaryTuple> scan(BinaryTuple key, BitSet columns); } diff --git a/modules/index/src/main/java/org/apache/ignite/internal/index/IndexManager.java b/modules/index/src/main/java/org/apache/ignite/internal/index/IndexManager.java new file mode 100644 index 000000000..099da43a0 --- /dev/null +++ b/modules/index/src/main/java/org/apache/ignite/internal/index/IndexManager.java @@ -0,0 +1,261 @@ +/* + * 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.index; + +import static org.apache.ignite.internal.schema.definition.TableDefinitionImpl.canonicalName; + +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import org.apache.ignite.configuration.schemas.table.HashIndexView; +import org.apache.ignite.configuration.schemas.table.SortedIndexView; +import org.apache.ignite.configuration.schemas.table.TableIndexChange; +import org.apache.ignite.configuration.schemas.table.TableIndexView; +import org.apache.ignite.internal.logger.IgniteLogger; +import org.apache.ignite.internal.logger.Loggers; +import org.apache.ignite.internal.manager.IgniteComponent; +import org.apache.ignite.internal.table.distributed.TableManager; +import org.apache.ignite.internal.util.CollectionUtils; +import org.apache.ignite.internal.util.IgniteSpinBusyLock; +import org.apache.ignite.internal.util.StringUtils; +import org.apache.ignite.lang.ErrorGroups; +import org.apache.ignite.lang.ErrorGroups.Common; +import org.apache.ignite.lang.ErrorGroups.Table; +import org.apache.ignite.lang.IgniteInternalException; +import org.apache.ignite.lang.IndexAlreadyExistsException; +import org.apache.ignite.lang.NodeStoppingException; +import org.apache.ignite.lang.TableNotFoundException; + +/** + * An Ignite component that is responsible for handling index-related commands like CREATE or DROP + * as well as managing indexes lifecycle. + */ +public class IndexManager implements IgniteComponent { + private static final IgniteLogger LOG = Loggers.forClass(IndexManager.class); + + private final TableManager tableManager; + + private final Map<UUID, Index> indices = new ConcurrentHashMap<>(); + + /** Busy lock to stop synchronously. */ + private final IgniteSpinBusyLock busyLock = new IgniteSpinBusyLock(); + + /** Prevents double stopping of the component. */ + private final AtomicBoolean stopGuard = new AtomicBoolean(); + + /** + * Constructor. + * + * @param tableManager Table manager. + */ + public IndexManager( + TableManager tableManager + ) { + this.tableManager = Objects.requireNonNull(tableManager, "tableManager"); + } + + /** {@inheritDoc} */ + @Override + public void start() { + LOG.info("Index manager started"); + } + + /** {@inheritDoc} */ + @Override + public void stop() throws Exception { + LOG.debug("Index manager is about to stop"); + + if (!stopGuard.compareAndSet(false, true)) { + LOG.debug("Index manager already stopped"); + + return; + } + + busyLock.block(); + + LOG.info("Index manager stopped"); + } + + /** + * Creates index from provided configuration changer. + * + * @param schemaName A name of the schema to create index in. + * @param indexName A name of the index to create. + * @param tableName A name of the table to create index for. + * @param indexChange A consumer that suppose to change the configuration in order to provide description of an index. + * @return A future represented the result of creation. + */ + // TODO: https://issues.apache.org/jira/browse/IGNITE-17474 + // Validation of the index name uniqueness is not implemented, because with given + // configuration hierarchy this is a bit tricky exercise. Given that this hierarchy + // is subject to change in the future, seems to be more rational just to omit this + // part for now + public CompletableFuture<Index> createIndexAsync( + String schemaName, + String indexName, + String tableName, + Consumer<TableIndexChange> indexChange + ) { + if (!busyLock.enterBusy()) { + return CompletableFuture.failedFuture(new NodeStoppingException()); + } + + LOG.debug("Going to create index [schema={}, schema={}, index={}]", schemaName, tableName, indexName); + + try { + validateName(indexName); + + CompletableFuture<Index> future = new CompletableFuture<>(); + + var canonicalName = canonicalName(schemaName, tableName); + + tableManager.tableAsyncInternal(canonicalName).thenAccept((table) -> { + if (table == null) { + var exception = new TableNotFoundException(canonicalName); + + LOG.info("Unable to create index [schema={}, schema={}, index={}]", + exception, schemaName, tableName, indexName); + + future.completeExceptionally(exception); + + return; + } + + tableManager.alterTableAsync(table.name(), tableChange -> tableChange.changeIndices(indexListChange -> { + if (indexListChange.get(indexName) != null) { + var exception = new IndexAlreadyExistsException(indexName); + + LOG.info("Unable to create index [schema={}, schema={}, index={}]", + exception, schemaName, tableName, indexName); + + future.completeExceptionally(exception); + + return; + } + + indexListChange.create(indexName, indexChange); + + TableIndexView indexView = indexListChange.get(indexName); + + Set<String> columnNames = Set.copyOf(tableChange.columns().namedListKeys()); + + validateColumns(indexView, columnNames); + })).whenComplete((index, th) -> { + if (th != null) { + LOG.info("Unable to create index [schema={}, schema={}, index={}]", + th, schemaName, tableName, indexName); + + future.completeExceptionally(th); + } else if (!future.isDone()) { + // don't pay too much attention to this part because it should be reworked + // within refactoring of schema objects: when both tables and indexes will be derived + // from common parent and become entity of the same level in the configuration, + // then there sill be no need to look up indices in such way + + var createdIndex = indices.values().stream() + .filter(idx -> indexName.equals(idx.name())) + .findFirst() + .orElse(null); + + if (createdIndex != null) { + LOG.info("Index created [schema={}, schema={}, index={}, indexId={}]", + schemaName, tableName, indexName, createdIndex.id()); + + future.complete(createdIndex); + } else { + var exception = new IgniteInternalException( + Common.UNEXPECTED_ERR, "Looks like the index was concurrently deleted"); + + LOG.info("Unable to create index [schema={}, schema={}, index={}]", + exception, schemaName, tableName, indexName); + + future.completeExceptionally(exception); + } + } + }); + }); + + return future; + } catch (Exception ex) { + return CompletableFuture.failedFuture(ex); + } finally { + busyLock.leaveBusy(); + } + } + + /** + * Drops the index with a given name. + * + * @param schemaName A name of the schema the index belong to. + * @param indexName A name of the index to drop. + * @return A future representing the result of the operation. + */ + // TODO: https://issues.apache.org/jira/browse/IGNITE-17474 + // For now it is impossible to locate the index neither by id nor name. + public CompletableFuture<Void> dropIndexAsync( + String schemaName, + String indexName + ) { + return CompletableFuture.failedFuture(new UnsupportedOperationException()); + } + + private void validateName(String indexName) { + if (StringUtils.nullOrEmpty(indexName)) { + throw new IgniteInternalException( + ErrorGroups.Index.INVALID_INDEX_DEFINITION_ERR, + "Index name should be at least 1 character long" + ); + } + } + + private void validateColumns(TableIndexView indexView, Set<String> tableColumns) { + if (indexView instanceof SortedIndexView) { + var sortedIndexView = (SortedIndexView) indexView; + + validateColumns(sortedIndexView.columns().namedListKeys(), tableColumns); + } else if (indexView instanceof HashIndexView) { + validateColumns(Arrays.asList(((HashIndexView) indexView).columnNames()), tableColumns); + } else { + throw new AssertionError("Unknown index type [type=" + (indexView != null ? indexView.getClass() : null) + ']'); + } + } + + private void validateColumns(Iterable<String> indexedColumns, Set<String> tableColumns) { + if (CollectionUtils.nullOrEmpty(indexedColumns)) { + throw new IgniteInternalException( + ErrorGroups.Index.INVALID_INDEX_DEFINITION_ERR, + "At least one column should be specified by index definition" + ); + } + + for (var columnName : indexedColumns) { + if (!tableColumns.contains(columnName)) { + throw new IgniteInternalException( + Table.COLUMN_NOT_FOUND_ERR, + "Column not found [name=" + columnName + ']' + ); + } + } + } +} diff --git a/modules/index/src/test/java/org/apache/ignite/internal/index/IndexManagerTest.java b/modules/index/src/test/java/org/apache/ignite/internal/index/IndexManagerTest.java new file mode 100644 index 000000000..433ddf8a5 --- /dev/null +++ b/modules/index/src/test/java/org/apache/ignite/internal/index/IndexManagerTest.java @@ -0,0 +1,363 @@ +/* + * 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.index; + +import static org.apache.ignite.lang.IgniteStringFormatter.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.function.Consumer; +import org.apache.ignite.configuration.schemas.store.DataStorageConfigurationSchema; +import org.apache.ignite.configuration.schemas.store.UnknownDataStorageConfigurationSchema; +import org.apache.ignite.configuration.schemas.table.ColumnDefaultConfigurationSchema; +import org.apache.ignite.configuration.schemas.table.ConstantValueDefaultConfigurationSchema; +import org.apache.ignite.configuration.schemas.table.FunctionCallDefaultConfigurationSchema; +import org.apache.ignite.configuration.schemas.table.HashIndexChange; +import org.apache.ignite.configuration.schemas.table.HashIndexConfigurationSchema; +import org.apache.ignite.configuration.schemas.table.NullValueDefaultConfigurationSchema; +import org.apache.ignite.configuration.schemas.table.SortedIndexChange; +import org.apache.ignite.configuration.schemas.table.SortedIndexConfigurationSchema; +import org.apache.ignite.configuration.schemas.table.TableChange; +import org.apache.ignite.configuration.schemas.table.TableConfigurationSchema; +import org.apache.ignite.configuration.schemas.table.TableIndexConfigurationSchema; +import org.apache.ignite.configuration.schemas.table.TablesConfiguration; +import org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator; +import org.apache.ignite.internal.configuration.tree.ConverterToMapVisitor; +import org.apache.ignite.internal.configuration.tree.TraversableTreeNode; +import org.apache.ignite.internal.table.TableImpl; +import org.apache.ignite.internal.table.distributed.TableManager; +import org.apache.ignite.lang.ErrorGroups; +import org.apache.ignite.lang.ErrorGroups.Table; +import org.apache.ignite.lang.IgniteInternalException; +import org.apache.ignite.lang.TableNotFoundException; +import org.junit.jupiter.api.Test; + +/** + * Test class to verify {@link IndexManager}. + */ +public class IndexManagerTest { + @Test + void configurationChangedWhenCreateIsInvoked() { + var tableManagerMock = mock(TableManager.class); + var canonicalName = "sName.tName"; + + TableChange tableChange = createNode(TableConfigurationSchema.class); + + tableChange.changeColumns(columnListChange -> { + columnListChange.create("c1", columnChange -> {}); + columnListChange.create("c2", columnChange -> {}); + }); + + var successfulCompletion = new RuntimeException("This is expected"); + + when(tableManagerMock.tableAsyncInternal(eq(canonicalName))).thenReturn(CompletableFuture.completedFuture(mock(TableImpl.class))); + when(tableManagerMock.alterTableAsync(any(), any())).thenAnswer(answer -> { + Consumer<TableChange> changeConsumer = answer.getArgument(1); + + try { + changeConsumer.accept(tableChange); + } catch (Throwable th) { + return CompletableFuture.failedFuture(th); + } + + // return failed future here to prevent index manager to further process the + // create request, because after returned future is competed, index manager expects + // to all configuration listeners to be executed, but no one have configured them + // for this test + return CompletableFuture.failedFuture(successfulCompletion); + }); + + var indexManager = new IndexManager(tableManagerMock); + + try { + indexManager.createIndexAsync("sName", "idx", "tName", indexChange -> { + var sortedIndexChange = indexChange.convert(SortedIndexChange.class); + + sortedIndexChange.changeColumns(columns -> { + columns.create("c1", columnChange -> columnChange.changeAsc(true)); + columns.create("c2", columnChange -> columnChange.changeAsc(false)); + }); + }).join(); + } catch (CompletionException ex) { + if (ex.getCause() != successfulCompletion) { + throw ex; + } + } + + var expected = List.of( + Map.of( + "columns", List.of( + Map.of( + "asc", true, + "name", "c1" + ), + Map.of( + "asc", false, + "name", "c2" + ) + ), + "name", "idx", + "type", "SORTED", + "uniq", false + ) + ); + + assertSameObjects(expected, toMap(tableChange.indices())); + } + + @Test + public void createIndexForNonExistingTable() { + var tableManagerMock = mock(TableManager.class); + var canonicalName = "sName.tName"; + + when(tableManagerMock.tableAsyncInternal(eq(canonicalName))).thenReturn(CompletableFuture.completedFuture(null)); + + var indexManager = new IndexManager(tableManagerMock); + + CompletionException completionException = assertThrows( + CompletionException.class, + () -> indexManager.createIndexAsync("sName", "idx", "tName", indexChange -> {/* doesn't matter */}).join() + ); + + assertThat(completionException.getCause(), instanceOf(TableNotFoundException.class)); + assertThat(completionException.getCause().getMessage(), containsString(canonicalName)); + } + + @Test + public void createIndexWithEmptyName() { + var tableManagerMock = mock(TableManager.class); + + var indexManager = new IndexManager(tableManagerMock); + + CompletionException completionException = assertThrows( + CompletionException.class, + () -> indexManager.createIndexAsync("sName", "", "tName", indexChange -> {/* doesn't matter */}).join() + ); + + assertThat(completionException.getCause(), instanceOf(IgniteInternalException.class)); + assertThat( + ((IgniteInternalException) completionException.getCause()).code(), + equalTo(ErrorGroups.Index.INVALID_INDEX_DEFINITION_ERR) + ); + } + + @Test + public void createIndexWithEmptyColumnList() { + var tableManagerMock = mock(TableManager.class); + var tableMock = mock(TableImpl.class); + TableChange tableChange = createNode(TableConfigurationSchema.class); + + when(tableManagerMock.tableAsyncInternal(any())).thenReturn(CompletableFuture.completedFuture(tableMock)); + when(tableManagerMock.alterTableAsync(any(), any())).thenAnswer(answer -> { + Consumer<TableChange> changeConsumer = answer.getArgument(1); + + Throwable exception = null; + try { + changeConsumer.accept(tableChange); + } catch (Exception ex) { + exception = ex; + } + + if (exception == null) { + // consumer expected to fail on validation + exception = new AssertionError(); + } + + return CompletableFuture.failedFuture(exception); + }); + + var indexManager = new IndexManager(tableManagerMock); + + CompletionException completionException = assertThrows( + CompletionException.class, + () -> indexManager.createIndexAsync("sName", "idx", "tName", + indexChange -> indexChange.convert(HashIndexChange.class).changeColumnNames()).join() + ); + + assertThat(completionException.getCause(), instanceOf(IgniteInternalException.class)); + assertThat( + ((IgniteInternalException) completionException.getCause()).code(), + equalTo(ErrorGroups.Index.INVALID_INDEX_DEFINITION_ERR) + ); + } + + @Test + public void createIndexForNonExistingColumn() { + var tableManagerMock = mock(TableManager.class); + var canonicalName = "sName.tName"; + var tableMock = mock(TableImpl.class); + TableChange tableChange = createNode(TableConfigurationSchema.class); + + when(tableManagerMock.tableAsyncInternal(eq(canonicalName))).thenReturn(CompletableFuture.completedFuture(tableMock)); + when(tableManagerMock.alterTableAsync(any(), any())).thenAnswer(answer -> { + Consumer<TableChange> changeConsumer = answer.getArgument(1); + + Throwable exception = null; + try { + changeConsumer.accept(tableChange); + } catch (Exception ex) { + exception = ex; + } + + if (exception == null) { + // consumer expected to fail on validation + exception = new AssertionError(); + } + + return CompletableFuture.failedFuture(exception); + }); + + var indexManager = new IndexManager(tableManagerMock); + + CompletionException completionException = assertThrows( + CompletionException.class, + () -> indexManager.createIndexAsync("sName", "idx", "tName", + indexChange -> indexChange.convert(HashIndexChange.class).changeColumnNames("nonExistingColumn")).join() + ); + + assertThat(completionException.getCause(), instanceOf(IgniteInternalException.class)); + assertThat( + ((IgniteInternalException) completionException.getCause()).code(), + equalTo(Table.COLUMN_NOT_FOUND_ERR) + ); + } + + /** Creates configuration node for given *SchemaConfiguration class. */ + @SuppressWarnings("unchecked") + private <T> T createNode(Class<?> cls) { + var cgen = new ConfigurationAsmGenerator(); + + Map<Class<?>, Set<Class<?>>> polymorphicExtensions = Map.of( + DataStorageConfigurationSchema.class, + Set.of( + UnknownDataStorageConfigurationSchema.class + ), + TableIndexConfigurationSchema.class, + Set.of( + HashIndexConfigurationSchema.class, + SortedIndexConfigurationSchema.class + ), + ColumnDefaultConfigurationSchema.class, + Set.of( + ConstantValueDefaultConfigurationSchema.class, + NullValueDefaultConfigurationSchema.class, + FunctionCallDefaultConfigurationSchema.class + ) + ); + + cgen.compileRootSchema(TablesConfiguration.KEY.schemaClass(), Map.of(), polymorphicExtensions); + + return (T) cgen.instantiateNode(cls); + } + + private static Object toMap(Object obj) { + assert obj instanceof TraversableTreeNode; + + return ((TraversableTreeNode) obj).accept(null, new ConverterToMapVisitor(false)); + } + + private static void assertSameObjects(Object expected, Object actual) { + try { + contentEquals(expected, actual); + } catch (ObjectsNotEqualException ex) { + fail( + format( + "Objects are not equal at position {}:\n\texpected={}\n\tactual={}", + String.join(".", ex.path), ex.o1, ex.o2) + ); + } + } + + private static void contentEquals(Object o1, Object o2) { + if (o1 instanceof Map && o2 instanceof Map) { + var m1 = (Map<?, ?>) o1; + var m2 = (Map<?, ?>) o2; + + if (m1.size() != m2.size()) { + throw new ObjectsNotEqualException(m1, m2); + } + + for (Map.Entry<?, ?> entry : m1.entrySet()) { + var v1 = entry.getValue(); + var v2 = m2.get(entry.getKey()); + + try { + contentEquals(v1, v2); + } catch (ObjectsNotEqualException ex) { + ex.path.add(0, entry.getKey().toString()); + + throw ex; + } + } + } else if (o1 instanceof List && o2 instanceof List) { + var l1 = (List<?>) o1; + var l2 = (List<?>) o2; + + if (l1.size() != l2.size()) { + throw new ObjectsNotEqualException(l1, l2); + } + + var it1 = l1.iterator(); + var it2 = l2.iterator(); + + int idx = 0; + while (it1.hasNext()) { + var v1 = it1.next(); + var v2 = it2.next(); + + try { + contentEquals(v1, v2); + } catch (ObjectsNotEqualException ex) { + ex.path.add(0, "[" + idx + ']'); + + throw ex; + } + } + } else if (!Objects.equals(o1, o2)) { + throw new ObjectsNotEqualException(o1, o2); + } + } + + static class ObjectsNotEqualException extends RuntimeException { + private final Object o1; + private final Object o2; + + private final List<String> path = new ArrayList<>(); + + public ObjectsNotEqualException(Object o1, Object o2) { + super(null, null, false, false); + this.o1 = o1; + this.o2 = o2; + } + } +} \ No newline at end of file diff --git a/modules/runner/pom.xml b/modules/runner/pom.xml index 0565870ae..5cbc1e7c2 100644 --- a/modules/runner/pom.xml +++ b/modules/runner/pom.xml @@ -83,6 +83,11 @@ <artifactId>ignite-table</artifactId> </dependency> + <dependency> + <groupId>org.apache.ignite</groupId> + <artifactId>ignite-index</artifactId> + </dependency> + <dependency> <groupId>org.apache.ignite</groupId> <artifactId>ignite-sql-engine</artifactId> diff --git a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java index d81662cf4..3ddf746c1 100644 --- a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java +++ b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java @@ -54,6 +54,7 @@ import org.apache.ignite.internal.configuration.ServiceLoaderModulesProvider; import org.apache.ignite.internal.configuration.storage.ConfigurationStorage; import org.apache.ignite.internal.configuration.storage.DistributedConfigurationStorage; import org.apache.ignite.internal.configuration.storage.LocalConfigurationStorage; +import org.apache.ignite.internal.index.IndexManager; import org.apache.ignite.internal.logger.IgniteLogger; import org.apache.ignite.internal.logger.Loggers; import org.apache.ignite.internal.metastorage.MetaStorageManager; @@ -172,6 +173,8 @@ public class IgniteImpl implements Ignite { /** Distributed table manager. */ private final TableManager distributedTblMgr; + private final IndexManager indexManager; + /** Rest module. */ private final RestComponent restComponent; @@ -326,6 +329,10 @@ public class IgniteImpl implements Ignite { schemaManager ); + indexManager = new IndexManager( + distributedTblMgr + ); + qryEngine = new SqlQueryProcessor( registry, clusterSvc, @@ -440,6 +447,7 @@ public class IgniteImpl implements Ignite { dataStorageMgr, schemaManager, distributedTblMgr, + indexManager, qryEngine, clientHandlerModule ); @@ -521,6 +529,11 @@ public class IgniteImpl implements Ignite { return qryEngine; } + @TestOnly + public IndexManager indexManager() { + return indexManager; + } + /** {@inheritDoc} */ @Override public IgniteTransactions transactions() { diff --git a/modules/runner/src/main/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModule.java b/modules/runner/src/main/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModule.java index 89d8cc9ef..e264bf3eb 100644 --- a/modules/runner/src/main/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModule.java +++ b/modules/runner/src/main/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModule.java @@ -27,7 +27,6 @@ import org.apache.ignite.configuration.annotation.ConfigurationType; import org.apache.ignite.configuration.schemas.store.KnownDataStorage; import org.apache.ignite.configuration.schemas.store.UnknownDataStorageConfigurationSchema; import org.apache.ignite.configuration.schemas.table.HashIndexConfigurationSchema; -import org.apache.ignite.configuration.schemas.table.PartialIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.SortedIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.TablesConfiguration; import org.apache.ignite.configuration.validation.Validator; @@ -55,7 +54,6 @@ public class CoreDistributedConfigurationModule implements ConfigurationModule { return List.of( HashIndexConfigurationSchema.class, SortedIndexConfigurationSchema.class, - PartialIndexConfigurationSchema.class, UnknownDataStorageConfigurationSchema.class ); } diff --git a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModuleTest.java b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModuleTest.java index 8f3624875..b95533c97 100644 --- a/modules/runner/src/test/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModuleTest.java +++ b/modules/runner/src/test/java/org/apache/ignite/internal/configuration/CoreDistributedConfigurationModuleTest.java @@ -30,7 +30,6 @@ import java.util.Optional; import java.util.ServiceLoader; import java.util.ServiceLoader.Provider; import org.apache.ignite.configuration.schemas.table.HashIndexConfigurationSchema; -import org.apache.ignite.configuration.schemas.table.PartialIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.SortedIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.TablesConfiguration; import org.junit.jupiter.api.Test; @@ -71,11 +70,6 @@ class CoreDistributedConfigurationModuleTest { assertThat(module.polymorphicSchemaExtensions(), hasItem(SortedIndexConfigurationSchema.class)); } - @Test - void providesPartialIndexConfigurationSchemaAsPolymorphicExtension() { - assertThat(module.polymorphicSchemaExtensions(), hasItem(PartialIndexConfigurationSchema.class)); - } - @Test void isLoadedByServiceLoader() { Optional<ConfigurationModule> maybeModule = ServiceLoader.load(ConfigurationModule.class).stream() diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/configuration/SchemaConfigurationConverter.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/configuration/SchemaConfigurationConverter.java index ec7b8ef59..a69072bde 100644 --- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/configuration/SchemaConfigurationConverter.java +++ b/modules/schema/src/main/java/org/apache/ignite/internal/schema/configuration/SchemaConfigurationConverter.java @@ -20,7 +20,6 @@ package org.apache.ignite.internal.schema.configuration; import static java.math.RoundingMode.HALF_UP; import static java.util.Arrays.asList; import static org.apache.ignite.configuration.schemas.table.TableIndexConfigurationSchema.HASH_INDEX_TYPE; -import static org.apache.ignite.configuration.schemas.table.TableIndexConfigurationSchema.PARTIAL_INDEX_TYPE; import static org.apache.ignite.configuration.schemas.table.TableIndexConfigurationSchema.SORTED_INDEX_TYPE; import static org.apache.ignite.internal.util.IgniteUtils.capacity; @@ -52,8 +51,6 @@ import org.apache.ignite.configuration.schemas.table.HashIndexView; import org.apache.ignite.configuration.schemas.table.IndexColumnChange; import org.apache.ignite.configuration.schemas.table.IndexColumnView; import org.apache.ignite.configuration.schemas.table.NullValueDefaultView; -import org.apache.ignite.configuration.schemas.table.PartialIndexChange; -import org.apache.ignite.configuration.schemas.table.PartialIndexView; import org.apache.ignite.configuration.schemas.table.PrimaryKeyView; import org.apache.ignite.configuration.schemas.table.SortedIndexChange; import org.apache.ignite.configuration.schemas.table.SortedIndexView; @@ -66,7 +63,6 @@ import org.apache.ignite.configuration.schemas.table.TablesChange; import org.apache.ignite.internal.schema.definition.ColumnDefinitionImpl; import org.apache.ignite.internal.schema.definition.TableDefinitionImpl; import org.apache.ignite.internal.schema.definition.index.HashIndexDefinitionImpl; -import org.apache.ignite.internal.schema.definition.index.PartialIndexDefinitionImpl; import org.apache.ignite.internal.schema.definition.index.PrimaryKeyDefinitionImpl; import org.apache.ignite.internal.schema.definition.index.SortedIndexColumnDefinitionImpl; import org.apache.ignite.internal.schema.definition.index.SortedIndexDefinitionImpl; @@ -82,7 +78,6 @@ import org.apache.ignite.schema.definition.TableDefinition; import org.apache.ignite.schema.definition.index.HashIndexDefinition; import org.apache.ignite.schema.definition.index.IndexColumnDefinition; import org.apache.ignite.schema.definition.index.IndexDefinition; -import org.apache.ignite.schema.definition.index.PartialIndexDefinition; import org.apache.ignite.schema.definition.index.SortOrder; import org.apache.ignite.schema.definition.index.SortedIndexColumnDefinition; import org.apache.ignite.schema.definition.index.SortedIndexDefinition; @@ -155,19 +150,7 @@ public class SchemaConfigurationConverter { String[] colNames = hashIdx.columns().stream().map(IndexColumnDefinition::name).toArray(String[]::new); - return idxChg.convert(HashIndexChange.class).changeColNames(colNames); - - case PARTIAL_INDEX_TYPE: - PartialIndexDefinition partIdx = (PartialIndexDefinition) idx; - - return idxChg.changeUniq(partIdx.unique()) - .convert(PartialIndexChange.class) - .changeExpr(partIdx.expr()) - .changeColumns(colsChg -> { - for (SortedIndexColumnDefinition col : partIdx.columns()) { - colsChg.create(col.name(), colInit -> convert(col, colInit)); - } - }); + return idxChg.convert(HashIndexChange.class).changeColumnNames(colNames); case SORTED_INDEX_TYPE: SortedIndexDefinition sortIdx = (SortedIndexDefinition) idx; @@ -197,7 +180,7 @@ public class SchemaConfigurationConverter { switch (type.toUpperCase()) { case HASH_INDEX_TYPE: - String[] hashCols = ((HashIndexView) idxView).colNames(); + String[] hashCols = ((HashIndexView) idxView).columnNames(); return new HashIndexDefinitionImpl(name, asList(hashCols)); @@ -211,18 +194,6 @@ public class SchemaConfigurationConverter { return new SortedIndexDefinitionImpl(name, sortedIndexColumnDefinitions, idxView.uniq()); - case PARTIAL_INDEX_TYPE: - String expr = ((PartialIndexView) idxView).expr(); - - NamedListView<? extends IndexColumnView> partialIndexColumns = ((PartialIndexView) idxView).columns(); - - List<SortedIndexColumnDefinition> partialIndexColumnDefinitions = partialIndexColumns.namedListKeys().stream() - .map(partialIndexColumns::get) - .map(SchemaConfigurationConverter::convert) - .collect(Collectors.toList()); - - return new PartialIndexDefinitionImpl(name, partialIndexColumnDefinitions, expr, idxView.uniq()); - default: throw new IllegalArgumentException("Unknown type " + type); } diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/definition/builder/PartialIndexDefinitionBuilderImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/definition/builder/PartialIndexDefinitionBuilderImpl.java deleted file mode 100644 index f3d03bea6..000000000 --- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/definition/builder/PartialIndexDefinitionBuilderImpl.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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.schema.definition.builder; - -import java.util.Map; -import java.util.stream.Collectors; -import org.apache.ignite.internal.schema.definition.index.PartialIndexDefinitionImpl; -import org.apache.ignite.internal.schema.definition.index.SortedIndexColumnDefinitionImpl; -import org.apache.ignite.schema.definition.builder.PartialIndexDefinitionBuilder; -import org.apache.ignite.schema.definition.index.PartialIndexDefinition; - -/** - * Partial index builder. - */ -public class PartialIndexDefinitionBuilderImpl extends SortedIndexDefinitionBuilderImpl implements PartialIndexDefinitionBuilder { - /** Partial index expression. */ - private String expr; - - /** - * Constructor. - * - * @param idxName Index name. - */ - public PartialIndexDefinitionBuilderImpl(String idxName) { - super(idxName); - } - - /** {@inheritDoc} */ - @Override - public PartialIndexDefinitionBuilderImpl withHints(Map<String, String> hints) { - super.withHints(hints); - - return this; - } - - /** {@inheritDoc} */ - @Override - public PartialIndexDefinition build() { - assert expr != null && !expr.trim().isEmpty(); - - return new PartialIndexDefinitionImpl( - name, - cols.values().stream().map(c -> new SortedIndexColumnDefinitionImpl(c.name, c.asc)).collect(Collectors.toList()), - expr, - unique() - ); - } - - /** {@inheritDoc} */ - @Override - public PartialIndexDefinitionBuilder withExpression(String expr) { - this.expr = expr; - - return this; - } - - /** {@inheritDoc} */ - @Override - public PartialIndexColumnBuilderImpl addIndexColumn(String name) { - return new PartialIndexColumnBuilderImpl(this).withName(name); - } - - /** - * Index column builder. - */ - private static class PartialIndexColumnBuilderImpl extends SortedIndexColumnBuilderImpl implements PartialIndexColumnBuilder { - /** - * Constructor. - * - * @param idxBuilder Index builder. - */ - PartialIndexColumnBuilderImpl(PartialIndexDefinitionBuilderImpl idxBuilder) { - super(idxBuilder); - } - - /** {@inheritDoc} */ - @Override - public PartialIndexColumnBuilderImpl desc() { - super.desc(); - - return this; - } - - /** {@inheritDoc} */ - @Override - public PartialIndexColumnBuilderImpl asc() { - super.asc(); - - return this; - } - - /** {@inheritDoc} */ - @Override - public PartialIndexColumnBuilderImpl withName(String name) { - super.withName(name); - - return this; - } - - /** {@inheritDoc} */ - @Override - public PartialIndexDefinitionBuilderImpl done() { - return (PartialIndexDefinitionBuilderImpl) super.done(); - } - } -} diff --git a/modules/schema/src/main/java/org/apache/ignite/internal/schema/definition/index/PartialIndexDefinitionImpl.java b/modules/schema/src/main/java/org/apache/ignite/internal/schema/definition/index/PartialIndexDefinitionImpl.java deleted file mode 100644 index 521bc5378..000000000 --- a/modules/schema/src/main/java/org/apache/ignite/internal/schema/definition/index/PartialIndexDefinitionImpl.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.schema.definition.index; - -import java.util.List; -import org.apache.ignite.internal.tostring.S; -import org.apache.ignite.schema.definition.index.PartialIndexDefinition; -import org.apache.ignite.schema.definition.index.SortedIndexColumnDefinition; - -/** - * Partial table index. - */ -public class PartialIndexDefinitionImpl extends SortedIndexDefinitionImpl implements PartialIndexDefinition { - /** Expression. */ - private final String expr; - - /** - * Constructor. - * - * @param name Index name. - * @param columns Index columns. - * @param expr Partial index expression. - * @param unique Unique flag. - */ - public PartialIndexDefinitionImpl(String name, List<SortedIndexColumnDefinition> columns, String expr, boolean unique) { - super(name, columns, unique); - - this.expr = expr; - } - - /** {@inheritDoc} */ - @Override - public String expr() { - return expr; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return S.toString(PartialIndexDefinition.class, this, - "type", type(), - "name", name(), - "uniq", unique(), - "cols", columns()); - } -} diff --git a/modules/schema/src/main/java/org/apache/ignite/schema/SchemaBuilders.java b/modules/schema/src/main/java/org/apache/ignite/schema/SchemaBuilders.java index 5b143fd9d..570460e19 100644 --- a/modules/schema/src/main/java/org/apache/ignite/schema/SchemaBuilders.java +++ b/modules/schema/src/main/java/org/apache/ignite/schema/SchemaBuilders.java @@ -19,7 +19,6 @@ package org.apache.ignite.schema; import org.apache.ignite.internal.schema.definition.builder.ColumnDefinitionBuilderImpl; import org.apache.ignite.internal.schema.definition.builder.HashIndexDefinitionBuilderImpl; -import org.apache.ignite.internal.schema.definition.builder.PartialIndexDefinitionBuilderImpl; import org.apache.ignite.internal.schema.definition.builder.PrimaryKeyDefinitionBuilderImpl; import org.apache.ignite.internal.schema.definition.builder.SortedIndexDefinitionBuilderImpl; import org.apache.ignite.internal.schema.definition.builder.TableDefinitionBuilderImpl; @@ -27,7 +26,6 @@ import org.apache.ignite.schema.definition.ColumnType; import org.apache.ignite.schema.definition.TableDefinition; import org.apache.ignite.schema.definition.builder.ColumnDefinitionBuilder; import org.apache.ignite.schema.definition.builder.HashIndexDefinitionBuilder; -import org.apache.ignite.schema.definition.builder.PartialIndexDefinitionBuilder; import org.apache.ignite.schema.definition.builder.PrimaryKeyDefinitionBuilder; import org.apache.ignite.schema.definition.builder.SortedIndexDefinitionBuilder; import org.apache.ignite.schema.definition.builder.TableDefinitionBuilder; @@ -92,16 +90,6 @@ public final class SchemaBuilders { return new SortedIndexDefinitionBuilderImpl(name); } - /** - * Creates partial index builder. - * - * @param name Index name. - * @return Partial index builder. - */ - public static PartialIndexDefinitionBuilder partialIndex(String name) { - return new PartialIndexDefinitionBuilderImpl(name); - } - /** * Creates hash index builder. * diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/SchemaConfigurationTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/SchemaConfigurationTest.java index 671399749..2337f53ec 100644 --- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/SchemaConfigurationTest.java +++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/SchemaConfigurationTest.java @@ -70,15 +70,6 @@ public class SchemaConfigurationTest { .build() ) - .withIndex( - SchemaBuilders.partialIndex("idx_2_partial") - .addIndexColumn("id").desc().done() - .addIndexColumn("name").asc().done() - .withExpression("id > 0") - .withHints(Map.of("INLINE_COLUMNS", "id")) - .build() - ) - .withIndex( SchemaBuilders.hashIndex("idx_3_hash") .withColumns("id", "affId") diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/builder/PartialIndexDefinitionBuilderTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/builder/PartialIndexDefinitionBuilderTest.java deleted file mode 100644 index ec8530f67..000000000 --- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/builder/PartialIndexDefinitionBuilderTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.schema.builder; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.apache.ignite.schema.SchemaBuilders; -import org.apache.ignite.schema.definition.builder.PartialIndexDefinitionBuilder; -import org.apache.ignite.schema.definition.index.PartialIndexDefinition; -import org.junit.jupiter.api.Test; - -/** - * Tests for partial index builder. - */ -public class PartialIndexDefinitionBuilderTest { - /** - * Test partial index parameters. - */ - @Test - public void testPartialIndexCreate() { - PartialIndexDefinitionBuilder builder = SchemaBuilders.partialIndex("TEST"); - - builder.addIndexColumn("A").done(); - builder.withExpression("WHERE A > 0"); - - PartialIndexDefinition idx = builder.build(); - - assertEquals(1, idx.columns().size()); - assertEquals("WHERE A > 0", idx.expr()); - } -} diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/configuration/SchemaConfigurationConverterTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/configuration/SchemaConfigurationConverterTest.java index 0c7de6172..b62ebcf46 100644 --- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/configuration/SchemaConfigurationConverterTest.java +++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/configuration/SchemaConfigurationConverterTest.java @@ -39,7 +39,6 @@ import org.apache.ignite.configuration.schemas.table.ConstantValueDefaultConfigu import org.apache.ignite.configuration.schemas.table.FunctionCallDefaultConfigurationSchema; import org.apache.ignite.configuration.schemas.table.HashIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.NullValueDefaultConfigurationSchema; -import org.apache.ignite.configuration.schemas.table.PartialIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.SortedIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.TableConfiguration; import org.apache.ignite.configuration.schemas.table.TableValidator; @@ -55,13 +54,11 @@ import org.apache.ignite.schema.definition.DefaultValueDefinition.FunctionCall; import org.apache.ignite.schema.definition.DefaultValueGenerators; import org.apache.ignite.schema.definition.TableDefinition; import org.apache.ignite.schema.definition.builder.HashIndexDefinitionBuilder; -import org.apache.ignite.schema.definition.builder.PartialIndexDefinitionBuilder; import org.apache.ignite.schema.definition.builder.SortedIndexDefinitionBuilder; import org.apache.ignite.schema.definition.builder.TableDefinitionBuilder; import org.apache.ignite.schema.definition.index.HashIndexDefinition; import org.apache.ignite.schema.definition.index.IndexColumnDefinition; import org.apache.ignite.schema.definition.index.IndexDefinition; -import org.apache.ignite.schema.definition.index.PartialIndexDefinition; import org.apache.ignite.schema.definition.index.SortOrder; import org.apache.ignite.schema.definition.index.SortedIndexDefinition; import org.junit.jupiter.api.AfterEach; @@ -98,7 +95,6 @@ public class SchemaConfigurationConverterTest extends AbstractSchemaConverterTes List.of( HashIndexConfigurationSchema.class, SortedIndexConfigurationSchema.class, - PartialIndexConfigurationSchema.class, UnknownDataStorageConfigurationSchema.class, ConstantValueDefaultConfigurationSchema.class, FunctionCallDefaultConfigurationSchema.class, @@ -234,29 +230,6 @@ public class SchemaConfigurationConverterTest extends AbstractSchemaConverterTes assertEquals(SortOrder.DESC, idx2.columns().get(1).sortOrder()); } - /** - * Add/remove PartialIndex into configuration and read it back. - */ - @Test - public void testPartialIndex() throws Exception { - PartialIndexDefinitionBuilder builder = SchemaBuilders.partialIndex("TEST"); - - builder.addIndexColumn("A").done(); - builder.withExpression("WHERE A > 0"); - - PartialIndexDefinition idx = builder.build(); - - getTbl().change(ch -> SchemaConfigurationConverter.addIndex(idx, ch)).get(); - - TableDefinition tbl = SchemaConfigurationConverter.convert(getTbl().value()); - - PartialIndexDefinition idx2 = (PartialIndexDefinition) getIdx(idx.name(), tbl.indices()); - - assertNotNull(idx2); - assertEquals("PARTIAL", idx2.type()); - assertEquals(idx.columns().size(), idx2.columns().size()); - } - /** * Add/remove table and read it back. */ diff --git a/modules/schema/src/test/java/org/apache/ignite/internal/schema/configuration/TableValidatorImplTest.java b/modules/schema/src/test/java/org/apache/ignite/internal/schema/configuration/TableValidatorImplTest.java index 7c7ce2ea3..d84694eaf 100644 --- a/modules/schema/src/test/java/org/apache/ignite/internal/schema/configuration/TableValidatorImplTest.java +++ b/modules/schema/src/test/java/org/apache/ignite/internal/schema/configuration/TableValidatorImplTest.java @@ -27,7 +27,6 @@ import org.apache.ignite.configuration.schemas.table.ConstantValueDefaultConfigu import org.apache.ignite.configuration.schemas.table.FunctionCallDefaultConfigurationSchema; import org.apache.ignite.configuration.schemas.table.HashIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.NullValueDefaultConfigurationSchema; -import org.apache.ignite.configuration.schemas.table.PartialIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.SortedIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.TableValidator; import org.apache.ignite.configuration.schemas.table.TableView; @@ -51,12 +50,11 @@ public class TableValidatorImplTest { + " name = schema.table,\n" + " columns.id {type.type = STRING, nullable = true},\n" + " primaryKey {columns = [id], colocationColumns = [id]},\n" - + " indices.foo {type = HASH, colNames = [id]}\n" + + " indices.foo {type = HASH, columnNames = [id]}\n" + "}]", polymorphicExtensions = { HashIndexConfigurationSchema.class, SortedIndexConfigurationSchema.class, - PartialIndexConfigurationSchema.class, UnknownDataStorageConfigurationSchema.class, TestDataStorageConfigurationSchema.class, ConstantValueDefaultConfigurationSchema.class, diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/session/Session.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/session/Session.java index aa860b47e..9a444a298 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/session/Session.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/session/Session.java @@ -38,7 +38,7 @@ import org.apache.ignite.internal.sql.engine.property.PropertiesHolder; * with all properties set during session's creation. */ public class Session implements AsyncCloseable { - /** Marker used to mark a session which has been experid. */ + /** Marker used to mark a session which has been expired. */ private static final long EXPIRED = 0L; private final Set<AsyncCloseable> resources = Collections.synchronizedSet( diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java index 1b07f2d0c..23d715f4c 100644 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java +++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/MockedStructuresTest.java @@ -52,7 +52,6 @@ import org.apache.ignite.configuration.schemas.table.ConstantValueDefaultConfigu import org.apache.ignite.configuration.schemas.table.FunctionCallDefaultConfigurationSchema; import org.apache.ignite.configuration.schemas.table.HashIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.NullValueDefaultConfigurationSchema; -import org.apache.ignite.configuration.schemas.table.PartialIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.SortedIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.TableView; import org.apache.ignite.configuration.schemas.table.TablesConfiguration; @@ -165,7 +164,6 @@ public class MockedStructuresTest extends IgniteAbstractTest { polymorphicExtensions = { HashIndexConfigurationSchema.class, SortedIndexConfigurationSchema.class, - PartialIndexConfigurationSchema.class, UnknownDataStorageConfigurationSchema.class, RocksDbDataStorageConfigurationSchema.class, TestConcurrentHashMapDataStorageConfigurationSchema.class, diff --git a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/TableManager.java b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/TableManager.java index 1d8cb9b2a..ec94395e9 100644 --- a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/TableManager.java +++ b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/TableManager.java @@ -1183,7 +1183,7 @@ public class TableManager extends Producer<TableEvent, TableEventParameters> imp * @param name Table name. * @return Future representing pending completion of the {@code TableManager#tableAsyncInternal} operation. * */ - private CompletableFuture<TableImpl> tableAsyncInternal(String name) { + public CompletableFuture<TableImpl> tableAsyncInternal(String name) { if (!busyLock.enterBusy()) { throw new IgniteException(new NodeStoppingException()); } diff --git a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TableManagerTest.java b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TableManagerTest.java index f7054994f..1063bd1e5 100644 --- a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TableManagerTest.java +++ b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/TableManagerTest.java @@ -67,7 +67,6 @@ import org.apache.ignite.configuration.schemas.table.ConstantValueDefaultConfigu import org.apache.ignite.configuration.schemas.table.FunctionCallDefaultConfigurationSchema; import org.apache.ignite.configuration.schemas.table.HashIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.NullValueDefaultConfigurationSchema; -import org.apache.ignite.configuration.schemas.table.PartialIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.SortedIndexConfigurationSchema; import org.apache.ignite.configuration.schemas.table.TableChange; import org.apache.ignite.configuration.schemas.table.TableView; @@ -212,7 +211,6 @@ public class TableManagerTest extends IgniteAbstractTest { polymorphicExtensions = { HashIndexConfigurationSchema.class, SortedIndexConfigurationSchema.class, - PartialIndexConfigurationSchema.class, UnknownDataStorageConfigurationSchema.class, RocksDbDataStorageConfigurationSchema.class, ConstantValueDefaultConfigurationSchema.class, diff --git a/parent/pom.xml b/parent/pom.xml index ce0a518bd..33233a4a4 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -403,6 +403,12 @@ <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.apache.ignite</groupId> + <artifactId>ignite-index</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> <groupId>org.apache.ignite</groupId> <artifactId>ignite-vault</artifactId> diff --git a/pom.xml b/pom.xml index 38936285e..d514df6d1 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,7 @@ <module>modules/core</module> <module>modules/extended-api</module> <module>modules/file-io</module> + <module>modules/index</module> <module>modules/jacoco-report</module> <module>modules/marshaller-common</module> <module>modules/metastorage</module>