This is an automated email from the ASF dual-hosted git repository. maedhroz pushed a commit to branch cep-7-sai in repository https://gitbox.apache.org/repos/asf/cassandra.git
commit c24ee2da3418d8b3ab94f618b2094883f34f7887 Author: Caleb Rackliffe <calebrackli...@gmail.com> AuthorDate: Wed Jun 21 17:29:05 2023 -0500 Add support for index implementation selection via USING for CREATE INDEX patch by Caleb Rackliffe; reviewed by Maxwell Guo and Andres de la Peña for CASSANDRA-18615 --- conf/cassandra.yaml | 9 ++ doc/cql3/CQL.textile | 12 +- .../examples/BNF/create_index_statement.bnf | 3 +- .../cassandra/examples/CQL/create_index.cql | 3 +- .../pages/developing/cql/cql_singlefile.adoc | 27 +++-- .../cassandra/pages/developing/cql/indexes.adoc | 29 +++-- src/java/org/apache/cassandra/config/Config.java | 7 +- .../cassandra/config/DatabaseDescriptor.java | 20 ++++ .../statements/schema/CreateIndexStatement.java | 23 ++++ .../cassandra/index/internal/CassandraIndex.java | 2 + src/java/org/apache/cassandra/index/sai/README.md | 4 +- .../cassandra/index/sai/StorageAttachedIndex.java | 2 + .../org/apache/cassandra/schema/IndexMetadata.java | 5 +- .../validation/entities/SecondaryIndexTest.java | 46 ++++++++ .../org/apache/cassandra/index/sai/SAITester.java | 2 +- .../index/sai/cql/CollectionIndexingTest.java | 53 +++++---- .../sai/cql/CompositePartitionKeyIndexTest.java | 12 +- .../index/sai/cql/MultipleColumnIndexTest.java | 20 ++-- .../index/sai/cql/StorageAttachedIndexDDLTest.java | 124 ++++++++++++++------- .../index/sai/cql/types/IndexingTypeSupport.java | 6 +- .../index/sai/functional/GroupComponentsTest.java | 6 +- .../index/sai/virtual/SSTablesSystemViewTest.java | 4 +- 22 files changed, 305 insertions(+), 114 deletions(-) diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml index 9e79d3525b..a9d0ddadbc 100644 --- a/conf/cassandra.yaml +++ b/conf/cassandra.yaml @@ -1975,6 +1975,15 @@ drop_compact_storage_enabled: false # if zero_ttl_on_twcs_enabled is set to false, this property is irrelevant as such statements will fail. #zero_ttl_on_twcs_warned: true +# The default secondary index implementation when CREATE INDEX does not specify one via USING. +# ex. "legacy_local_table" - (default) legacy secondary index, implemented as a hidden table +# ex. "sai" - "storage-attched" index, implemented via optimized SSTable/Memtable-attached indexes +#default_secondary_index: legacy_local_table + +# Whether a default secondary index implementation is allowed. If this is "false", CREATE INDEX must +# specify an index implementation via USING. +#default_secondary_index_enabled: true + # Startup Checks are executed as part of Cassandra startup process, not all of them # are configurable (so you can disable them) but these which are enumerated bellow. # Uncomment the startup checks and configure them appropriately to cover your needs. diff --git a/doc/cql3/CQL.textile b/doc/cql3/CQL.textile index 0073ff7ed3..4f6a4d7338 100644 --- a/doc/cql3/CQL.textile +++ b/doc/cql3/CQL.textile @@ -513,7 +513,8 @@ __Sample:__ bc(sample). CREATE INDEX userIndex ON NerdMovies (user); CREATE INDEX ON Mutants (abilityId); -CREATE INDEX ON users (keys(favs)); +CREATE INDEX ON users (KEYS(favs)); +CREATE INDEX ON users (age) USING 'sai'; CREATE CUSTOM INDEX ON users (email) USING 'path.to.the.IndexClass'; CREATE CUSTOM INDEX ON users (email) USING 'path.to.the.IndexClass' WITH OPTIONS = {'storage': '/mnt/ssd/indexes/'}; @@ -521,6 +522,15 @@ The @CREATE INDEX@ statement is used to create a new (automatic) secondary index Attempting to create an already existing index will return an error unless the @IF NOT EXISTS@ option is used. If it is used, the statement will be a no-op if the index already exists. +h4(#usingIndex). Index Types + +The @USING@ keyword optionally specifies an index type. There are two built-in types: + +* legacy_local_table - (default) legacy secondary index, implemented as a hidden local table +* sai - "storage-attched" index, implemented via optimized SSTable/Memtable-attached indexes + +To create a custom index, a fully qualified class name must be specified. + h4(#keysIndex). Indexes on Map Keys When creating an index on a "map column":#map, you may index either the keys or the values. If the column identifier is placed within the @keys()@ function, the index will be on the map keys, allowing you to use @CONTAINS KEY@ in @WHERE@ clauses. Otherwise, the index will be on the map values. diff --git a/doc/modules/cassandra/examples/BNF/create_index_statement.bnf b/doc/modules/cassandra/examples/BNF/create_index_statement.bnf index 6e76947243..322799de1c 100644 --- a/doc/modules/cassandra/examples/BNF/create_index_statement.bnf +++ b/doc/modules/cassandra/examples/BNF/create_index_statement.bnf @@ -1,5 +1,6 @@ create_index_statement::= CREATE [ CUSTOM ] INDEX [ IF NOT EXISTS ] [ index_name ] ON table_name '(' index_identifier ')' - [ USING string [ WITH OPTIONS = map_literal ] ] + [ USING index_type [ WITH OPTIONS = map_literal ] ] index_identifier::= column_name | ( KEYS | VALUES | ENTRIES | FULL ) '(' column_name ')' +index_type::= 'sai' | 'legacy_local_table' | fully_qualified_class_name \ No newline at end of file diff --git a/doc/modules/cassandra/examples/CQL/create_index.cql b/doc/modules/cassandra/examples/CQL/create_index.cql index f84452aa1d..38bdfdff02 100644 --- a/doc/modules/cassandra/examples/CQL/create_index.cql +++ b/doc/modules/cassandra/examples/CQL/create_index.cql @@ -1,6 +1,7 @@ CREATE INDEX userIndex ON NerdMovies (user); CREATE INDEX ON Mutants (abilityId); -CREATE INDEX ON users (keys(favs)); +CREATE INDEX ON users (KEYS(favs)); +CREATE INDEX ON users (age) USING 'sai'; CREATE CUSTOM INDEX ON users (email) USING 'path.to.the.IndexClass'; CREATE CUSTOM INDEX ON users (email) diff --git a/doc/modules/cassandra/pages/developing/cql/cql_singlefile.adoc b/doc/modules/cassandra/pages/developing/cql/cql_singlefile.adoc index b6a0966cbf..64e71b051c 100644 --- a/doc/modules/cassandra/pages/developing/cql/cql_singlefile.adoc +++ b/doc/modules/cassandra/pages/developing/cql/cql_singlefile.adoc @@ -853,6 +853,11 @@ The `TRUNCATE` statement permanently removes all data from a table. [[createIndexStmt]] ==== CREATE INDEX +The `CREATE INDEX` statement is used to create a new +secondary index for a given (existing) column in a given table. A name +for the index itself can be specified before the `ON` keyword, if +desired. + _Syntax:_ bc(syntax).. + @@ -869,20 +874,26 @@ bc(sample). + CREATE INDEX userIndex ON NerdMovies (user); + CREATE INDEX ON Mutants (abilityId); + CREATE INDEX ON users (keys(favs)); + +CREATE INDEX ON users (age) USING 'sai'; + CREATE CUSTOM INDEX ON users (email) USING `path.to.the.IndexClass'; + CREATE CUSTOM INDEX ON users (email) USING `path.to.the.IndexClass' WITH OPTIONS = \{’storage’: `/mnt/ssd/indexes/'}; -The `CREATE INDEX` statement is used to create a new (automatic) -secondary index for a given (existing) column in a given table. A name -for the index itself can be specified before the `ON` keyword, if -desired. If data already exists for the column, it will be indexed +If data already exists for the column, it will be indexed asynchronously. After the index is created, new data for the column is -indexed automatically at insertion time. +indexed automatically at insertion time. Attempting to create an already +existing index will return an error unless the `IF NOT EXISTS` option is used. +If it is used, the statement will be a no-op if the index already exists. -Attempting to create an already existing index will return an error -unless the `IF NOT EXISTS` option is used. If it is used, the statement -will be a no-op if the index already exists. +[[indexTypes]] +===== Index Types + +The `USING` keyword optionally specifies an index type. There are two built-in types: + +- legacy_local_table - (default) legacy secondary index, implemented as a hidden local table +- sai - "storage-attched" index, implemented via optimized SSTable/Memtable-attached indexes + +To create a custom index, a fully qualified class name must be specified. [[keysIndex]] ===== Indexes on Map Keys diff --git a/doc/modules/cassandra/pages/developing/cql/indexes.adoc b/doc/modules/cassandra/pages/developing/cql/indexes.adoc index 32b45b59f5..20daf072f8 100644 --- a/doc/modules/cassandra/pages/developing/cql/indexes.adoc +++ b/doc/modules/cassandra/pages/developing/cql/indexes.adoc @@ -12,30 +12,37 @@ include::example$BNF/index_name.bnf[] [[create-index-statement]] == CREATE INDEX -Creating a secondary index on a table uses the `CREATE INDEX` statement: +The `CREATE INDEX` statement is used to create a new +secondary index for a given (existing) column in a given table. A name +for the index itself can be specified before the `ON` keyword, if +desired. [source,bnf] ---- include::example$BNF/create_index_statement.bnf[] ---- -For instance: +If data already exists for the column, it will be indexed +asynchronously. After the index is created, new data for the column is +indexed automatically at insertion time. Attempting to create an already +existing index will return an error unless the `IF NOT EXISTS` option is used. +If it is used, the statement will be a no-op if the index already exists. + +*Examples*: [source,cql] ---- include::example$CQL/create_index.cql[] ---- -The `CREATE INDEX` statement is used to create a new (automatic) -secondary index for a given (existing) column in a given table. A name -for the index itself can be specified before the `ON` keyword, if -desired. If data already exists for the column, it will be indexed -asynchronously. After the index is created, new data for the column is -indexed automatically at insertion time. +=== Index Types + +The `USING` keyword optionally specifies an index type. There are two built-in types: + +- legacy_local_table - (default) legacy secondary index, implemented as a hidden local table +- sai - "storage-attched" index, implemented via optimized SSTable/Memtable-attached indexes -Attempting to create an already existing index will return an error -unless the `IF NOT EXISTS` option is used. If it is used, the statement -will be a no-op if the index already exists. +To create a custom index, a fully qualified class name must be specified. === Indexes on Map Keys diff --git a/src/java/org/apache/cassandra/config/Config.java b/src/java/org/apache/cassandra/config/Config.java index 47b197cf9b..5b3bc81887 100644 --- a/src/java/org/apache/cassandra/config/Config.java +++ b/src/java/org/apache/cassandra/config/Config.java @@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory; import org.apache.cassandra.audit.AuditLogOptions; import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.fql.FullQueryLoggerOptions; +import org.apache.cassandra.index.internal.CassandraIndex; import org.apache.cassandra.io.sstable.format.big.BigFormat; import org.apache.cassandra.service.StartupChecks.StartupCheckType; import org.apache.cassandra.utils.StorageCompatibilityMode; @@ -49,7 +50,7 @@ import static org.apache.cassandra.config.CassandraRelevantProperties.SKIP_PAXOS /** * A class that contains configuration properties for the cassandra node it runs within. - * + * <p> * Properties declared as volatile can be mutated via JMX. */ public class Config @@ -864,6 +865,10 @@ public class Config public volatile boolean drop_truncate_table_enabled = true; public volatile boolean drop_keyspace_enabled = true; public volatile boolean secondary_indexes_enabled = true; + + public volatile String default_secondary_index = CassandraIndex.NAME; + public volatile boolean default_secondary_index_enabled = true; + public volatile boolean uncompressed_tables_enabled = true; public volatile boolean compact_tables_enabled = true; public volatile boolean read_before_write_list_operations_enabled = true; diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java index 043cb9b5bc..f288baefbf 100644 --- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java +++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java @@ -3765,6 +3765,26 @@ public class DatabaseDescriptor conf.sasi_indexes_enabled = enableSASIIndexes; } + public static String getDefaultSecondaryIndex() + { + return conf.default_secondary_index; + } + + public static void setDefaultSecondaryIndex(String name) + { + conf.default_secondary_index = name; + } + + public static boolean getDefaultSecondaryIndexEnabled() + { + return conf.default_secondary_index_enabled; + } + + public static void setDefaultSecondaryIndexEnabled(boolean enabled) + { + conf.default_secondary_index_enabled = enabled; + } + public static boolean isTransientReplicationEnabled() { return conf.transient_replication_enabled; diff --git a/src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java b/src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java index 73b66b738d..b53e066f90 100644 --- a/src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java @@ -35,6 +35,7 @@ import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.db.guardrails.Guardrails; import org.apache.cassandra.db.marshal.MapType; import org.apache.cassandra.exceptions.InvalidRequestException; +import org.apache.cassandra.index.internal.CassandraIndex; import org.apache.cassandra.index.sasi.SASIIndex; import org.apache.cassandra.schema.*; import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff; @@ -77,6 +78,7 @@ public final class CreateIndexStatement extends AlterSchemaStatement public static final String INDEX_DUPLICATE_OF_EXISTING = "Index %s is a duplicate of existing index %s"; public static final String KEYSPACE_DOES_NOT_MATCH_TABLE = "Keyspace name '%s' doesn't match table name '%s'"; public static final String KEYSPACE_DOES_NOT_MATCH_INDEX = "Keyspace name '%s' doesn't match index name '%s'"; + public static final String MUST_SPECIFY_INDEX_IMPLEMENTATION = "Must specify index implementation via USING"; private final String indexName; private final String tableName; @@ -316,6 +318,27 @@ public final class CreateIndexStatement extends AlterSchemaStatement if (indexName.hasKeyspace() && !keyspaceName.equals(indexName.getKeyspace())) throw ire(KEYSPACE_DOES_NOT_MATCH_INDEX, keyspaceName, tableName); + + // Set the configured default 2i implementation if one isn't specified with USING: + if (attrs.customClass == null) + { + if (DatabaseDescriptor.getDefaultSecondaryIndexEnabled()) + attrs.customClass = DatabaseDescriptor.getDefaultSecondaryIndex(); + else + // However, operators may require an implementation be specified + throw ire(MUST_SPECIFY_INDEX_IMPLEMENTATION); + } + + // If we explicitly specify the index type "legacy_local_table", we can just clear the custom class, and the + // non-custom 2i creation process will begin. Otherwise, if an index type has been specified with + // USING, make sure the appropriate custom index is created. + if (attrs.customClass != null) + { + if (!attrs.isCustom && attrs.customClass.equalsIgnoreCase(CassandraIndex.NAME)) + attrs.customClass = null; + else + attrs.isCustom = true; + } return new CreateIndexStatement(keyspaceName, tableName.getName(), indexName.getName(), rawIndexTargets, attrs, ifNotExists); } diff --git a/src/java/org/apache/cassandra/index/internal/CassandraIndex.java b/src/java/org/apache/cassandra/index/internal/CassandraIndex.java index 5d3e45089a..2979e41581 100644 --- a/src/java/org/apache/cassandra/index/internal/CassandraIndex.java +++ b/src/java/org/apache/cassandra/index/internal/CassandraIndex.java @@ -69,6 +69,8 @@ import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse */ public abstract class CassandraIndex implements Index { + public static final String NAME = "legacy_local_table"; + private static final Logger logger = LoggerFactory.getLogger(CassandraIndex.class); public final ColumnFamilyStore baseCfs; diff --git a/src/java/org/apache/cassandra/index/sai/README.md b/src/java/org/apache/cassandra/index/sai/README.md index 6be0fa981a..1b434dba3c 100644 --- a/src/java/org/apache/cassandra/index/sai/README.md +++ b/src/java/org/apache/cassandra/index/sai/README.md @@ -61,9 +61,9 @@ Follow the instructions to build and start Cassandra in README.asc in root folde `CREATE TABLE person (id int, name text, age int, PRIMARY KEY (id));` -`CREATE CUSTOM INDEX ON person (name) USING 'StorageAttachedIndex' WITH OPTIONS = {'case_sensitive': false};` +`CREATE INDEX ON person (name) USING 'sai' WITH OPTIONS = {'case_sensitive': false};` -`CREATE CUSTOM INDEX ON person (age) USING 'StorageAttachedIndex';` +`CREATE INDEX ON person (age) USING 'sai';` 2.) Add some data. diff --git a/src/java/org/apache/cassandra/index/sai/StorageAttachedIndex.java b/src/java/org/apache/cassandra/index/sai/StorageAttachedIndex.java index 264abdd71a..5a8f7b6a58 100644 --- a/src/java/org/apache/cassandra/index/sai/StorageAttachedIndex.java +++ b/src/java/org/apache/cassandra/index/sai/StorageAttachedIndex.java @@ -95,6 +95,8 @@ import org.apache.cassandra.utils.concurrent.OpOrder; public class StorageAttachedIndex implements Index { + public static final String NAME = "sai"; + private static final Logger logger = LoggerFactory.getLogger(StorageAttachedIndex.class); private static class StorageAttachedIndexBuildingSupport implements IndexBuildingSupport diff --git a/src/java/org/apache/cassandra/schema/IndexMetadata.java b/src/java/org/apache/cassandra/schema/IndexMetadata.java index 577c12b4ba..795abad984 100644 --- a/src/java/org/apache/cassandra/schema/IndexMetadata.java +++ b/src/java/org/apache/cassandra/schema/IndexMetadata.java @@ -67,7 +67,8 @@ public final class IndexMetadata static { - indexNameAliases.put(StorageAttachedIndex.class.getSimpleName(), StorageAttachedIndex.class.getCanonicalName()); + indexNameAliases.put(StorageAttachedIndex.NAME, StorageAttachedIndex.class.getCanonicalName()); + indexNameAliases.put(StorageAttachedIndex.class.getSimpleName().toLowerCase(), StorageAttachedIndex.class.getCanonicalName()); indexNameAliases.put(SASIIndex.class.getSimpleName(), SASIIndex.class.getCanonicalName()); } @@ -154,7 +155,7 @@ public final class IndexMetadata if (isCustom()) { String className = options.get(IndexTarget.CUSTOM_INDEX_OPTION_NAME); - return indexNameAliases.getOrDefault(className, className); + return indexNameAliases.getOrDefault(className.toLowerCase(), className); } return CassandraIndex.class.getName(); } diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java index d87855a8bd..38f724968e 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java @@ -25,9 +25,12 @@ import java.util.concurrent.CountDownLatch; import com.google.common.collect.ImmutableSet; import org.apache.commons.lang3.StringUtils; +import org.junit.BeforeClass; import org.junit.Test; import org.apache.cassandra.exceptions.ConfigurationException; +import org.apache.cassandra.index.internal.CassandraIndex; +import org.apache.cassandra.index.sai.StorageAttachedIndex; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.config.DatabaseDescriptor; @@ -70,6 +73,12 @@ import static org.junit.Assert.fail; public class SecondaryIndexTest extends CQLTester { public static final int TOO_BIG = 1024 * 65; + + @BeforeClass + public static void setDefaultSecondaryIndex() + { + DatabaseDescriptor.setDefaultSecondaryIndex(CassandraIndex.NAME); + } @Test public void testCreateAndDropIndex() throws Throwable @@ -161,6 +170,43 @@ public class SecondaryIndexTest extends CQLTester return StringUtils.remove(indexName, '\"'); } + @Test + public void shouldCreateCassandraIndexExplicitly() throws Throwable + { + createTable("CREATE TABLE %s (userid uuid PRIMARY KEY, firstname text, lastname text, age int)"); + createIndex("CREATE INDEX byAge ON %s(age) USING 'legacy_local_table'"); + + SecondaryIndexManager indexManager = getCurrentColumnFamilyStore().indexManager; + assertTrue(indexManager.getIndexByName("byage") instanceof CassandraIndex); + + UUID id1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); + execute("INSERT INTO %s (userid, firstname, lastname, age) VALUES (?, 'Frodo', 'Baggins', 32)", id1); + assertEmpty(execute("SELECT firstname FROM %s WHERE userid = ? AND age = 33", id1)); + } + + @Test + public void shouldCreateCassandraIndexWhenNotDefault() throws Throwable + { + DatabaseDescriptor.setDefaultSecondaryIndex(StorageAttachedIndex.NAME); + + try + { + createTable("CREATE TABLE %s (userid uuid PRIMARY KEY, firstname text, lastname text, age int)"); + createIndex("CREATE INDEX byAge ON %s(age) USING 'legacy_local_table'"); + + SecondaryIndexManager indexManager = getCurrentColumnFamilyStore().indexManager; + assertTrue(indexManager.getIndexByName("byage") instanceof CassandraIndex); + + UUID id1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000"); + execute("INSERT INTO %s (userid, firstname, lastname, age) VALUES (?, 'Frodo', 'Baggins', 32)", id1); + assertEmpty(execute("SELECT firstname FROM %s WHERE userid = ? AND age = 33", id1)); + } + finally + { + DatabaseDescriptor.setDefaultSecondaryIndex(CassandraIndex.NAME); + } + } + /** * Check that you can query for an indexed column even with a key EQ clause, * migrated from cql_tests.py:TestCQL.static_cf_test() diff --git a/test/unit/org/apache/cassandra/index/sai/SAITester.java b/test/unit/org/apache/cassandra/index/sai/SAITester.java index d1616f49f9..4f147dc4b8 100644 --- a/test/unit/org/apache/cassandra/index/sai/SAITester.java +++ b/test/unit/org/apache/cassandra/index/sai/SAITester.java @@ -115,7 +115,7 @@ public abstract class SAITester extends CQLTester protected static final String CREATE_TABLE_TEMPLATE = "CREATE TABLE %s (id1 TEXT PRIMARY KEY, v1 INT, v2 TEXT) WITH compaction = " + "{'class' : 'SizeTieredCompactionStrategy', 'enabled' : false }"; - protected static final String CREATE_INDEX_TEMPLATE = "CREATE CUSTOM INDEX IF NOT EXISTS ON %%s(%s) USING 'StorageAttachedIndex'"; + protected static final String CREATE_INDEX_TEMPLATE = "CREATE INDEX IF NOT EXISTS ON %%s(%s) USING 'sai'"; protected static final ColumnIdentifier V1_COLUMN_IDENTIFIER = ColumnIdentifier.getInterned("v1", true); protected static final ColumnIdentifier V2_COLUMN_IDENTIFIER = ColumnIdentifier.getInterned("v2", true); diff --git a/test/unit/org/apache/cassandra/index/sai/cql/CollectionIndexingTest.java b/test/unit/org/apache/cassandra/index/sai/cql/CollectionIndexingTest.java index 8bc9efb1ca..a82f539842 100644 --- a/test/unit/org/apache/cassandra/index/sai/cql/CollectionIndexingTest.java +++ b/test/unit/org/apache/cassandra/index/sai/cql/CollectionIndexingTest.java @@ -28,9 +28,11 @@ import org.apache.cassandra.index.sai.SAITester; import static org.junit.Assert.assertEquals; -// This test is primarily handling edge conditions, error conditions -// and basic functionality. Comprehensive type testing of collections -// is in the cql/types/collections package +/** + * This test is primarily handling edge conditions, error conditions + * and basic functionality. Comprehensive type testing of collections + * is in the cql/types/collections package + */ public class CollectionIndexingTest extends SAITester { @Before @@ -42,28 +44,28 @@ public class CollectionIndexingTest extends SAITester @Test public void indexMap() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(value) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("value")); assertEquals(2, execute("SELECT * FROM %s WHERE value CONTAINS 'v1'").size()); } @Test public void indexMapKeys() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(KEYS(value)) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("KEYS(value)")); assertEquals(2, execute("SELECT * FROM %s WHERE value CONTAINS KEY 1").size()); } @Test public void indexMapValues() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(VALUES(value)) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("VALUES(value)")); assertEquals(2, execute("SELECT * FROM %s WHERE value CONTAINS 'v1'").size()); } @Test public void indexMapEntries() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(ENTRIES(value)) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("ENTRIES(value)")); assertEquals(2, execute("SELECT * FROM %s WHERE value[1] = 'v1'").size()); assertEquals(1, execute("SELECT * FROM %s WHERE value[1] = 'v1' AND value[2] = 'v2'").size()); } @@ -71,14 +73,14 @@ public class CollectionIndexingTest extends SAITester @Test public void indexFrozenList() throws Throwable { - createPopulatedFrozenList("CREATE CUSTOM INDEX ON %s(FULL(value)) USING 'StorageAttachedIndex'"); + createPopulatedFrozenList(createIndexDDL("FULL(value)")); assertEquals(2, execute("SELECT * FROM %s WHERE value = ?", Arrays.asList(1, 2, 3)).size()); } @Test public void indexFrozenMap() throws Throwable { - createPopulatedFrozenMap("CREATE CUSTOM INDEX ON %s(FULL(value)) USING 'StorageAttachedIndex'"); + createPopulatedFrozenMap(createIndexDDL("FULL(value)")); assertEquals(1, execute("SELECT * FROM %s WHERE value = ?", new HashMap<Integer, String>() {{ put(1, "v1"); put(2, "v2"); @@ -89,21 +91,21 @@ public class CollectionIndexingTest extends SAITester @Test public void indexFrozenMapQueryKeys() throws Throwable { - createPopulatedFrozenMap("CREATE CUSTOM INDEX ON %s(FULL(value)) USING 'StorageAttachedIndex'"); + createPopulatedFrozenMap(createIndexDDL("FULL(value)")); assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains key 1"); } @Test public void indexFrozenMapQueryValues() throws Throwable { - createPopulatedFrozenMap("CREATE CUSTOM INDEX ON %s(FULL(value)) USING 'StorageAttachedIndex'"); + createPopulatedFrozenMap(createIndexDDL("FULL(value)")); assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains 'v1'"); } @Test public void indexFrozenMapQueryEntries() throws Throwable { - createPopulatedFrozenMap("CREATE CUSTOM INDEX ON %s(FULL(value)) USING 'StorageAttachedIndex'"); + createPopulatedFrozenMap(createIndexDDL("FULL(value)")); assertInvalidMessage("Map-entry equality predicates on frozen map column value are not supported", "SELECT * FROM %s WHERE value[1] = 'v1'"); } @@ -111,7 +113,7 @@ public class CollectionIndexingTest extends SAITester @Test public void indexMapEntriesQueryEq() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(ENTRIES(value)) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("ENTRIES(value)")); assertInvalidMessage("Collection column 'value' (map<int, text>) cannot be restricted by a '=' relation", "SELECT * FROM %s WHERE value = ?", Arrays.asList(1, 2)); } @@ -119,21 +121,21 @@ public class CollectionIndexingTest extends SAITester @Test public void indexMapEntriesQueryKeys() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(ENTRIES(value)) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("ENTRIES(value)")); assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains key 1"); } @Test public void indexMapEntriesQueryValues() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(ENTRIES(value)) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("ENTRIES(value)")); assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains 'v1'"); } @Test public void indexMapKeysQueryEq() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(KEYS(value)) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("KEYS(value)")); assertInvalidMessage("Collection column 'value' (map<int, text>) cannot be restricted by a '=' relation", "SELECT * FROM %s WHERE value = ?", Arrays.asList(1, 2)); } @@ -141,21 +143,21 @@ public class CollectionIndexingTest extends SAITester @Test public void indexMapKeysQueryValues() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(KEYS(value)) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("KEYS(value)")); assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains 'v1'"); } @Test public void indexMapKeysQueryEntries() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(KEYS(value)) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("KEYS(value)")); assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value[1] = 'v1'"); } @Test public void indexMapValuesQueryEq() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(VALUES(value)) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("VALUES(value)")); assertInvalidMessage("Collection column 'value' (map<int, text>) cannot be restricted by a '=' relation", "SELECT * FROM %s WHERE value = ?", Arrays.asList(1, 2)); } @@ -163,18 +165,18 @@ public class CollectionIndexingTest extends SAITester @Test public void indexMapValuesQueryKeys() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(VALUES(value)) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("VALUES(value)")); assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains key 1"); } @Test public void indexMapValuesQueryEntries() throws Throwable { - createPopulatedMap("CREATE CUSTOM INDEX ON %s(VALUES(value)) USING 'StorageAttachedIndex'"); + createPopulatedMap(createIndexDDL("VALUES(value)")); assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value[1] = 'v1'"); } - private void createPopulatedMap(String createIndex) throws Throwable + private void createPopulatedMap(String createIndex) { createTable("CREATE TABLE %s (pk int primary key, value map<int, text>)"); createIndex(createIndex); @@ -204,7 +206,7 @@ public class CollectionIndexingTest extends SAITester } @SuppressWarnings("SameParameterValue") - private void createPopulatedFrozenList(String createIndex) throws Throwable + private void createPopulatedFrozenList(String createIndex) { createTable("CREATE TABLE %s (pk int primary key, value frozen<list<int>>)"); createIndex(createIndex); @@ -220,4 +222,9 @@ public class CollectionIndexingTest extends SAITester assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, query, values); assertEquals(expectedSize, execute(query + " ALLOW FILTERING").size()); } + + private static String createIndexDDL(String target) + { + return "CREATE INDEX ON %s(" + target + ") USING 'sai'"; + } } diff --git a/test/unit/org/apache/cassandra/index/sai/cql/CompositePartitionKeyIndexTest.java b/test/unit/org/apache/cassandra/index/sai/cql/CompositePartitionKeyIndexTest.java index bfaabf5b9a..0e488b2507 100644 --- a/test/unit/org/apache/cassandra/index/sai/cql/CompositePartitionKeyIndexTest.java +++ b/test/unit/org/apache/cassandra/index/sai/cql/CompositePartitionKeyIndexTest.java @@ -30,20 +30,20 @@ public class CompositePartitionKeyIndexTest extends SAITester public void createTableAndIndex() { createTable("CREATE TABLE %s (pk1 int, pk2 text, val int, PRIMARY KEY((pk1, pk2)))"); - createIndex("CREATE CUSTOM INDEX ON %s(pk1) USING 'StorageAttachedIndex'"); - createIndex("CREATE CUSTOM INDEX ON %s(pk2) USING 'StorageAttachedIndex'"); + createIndex("CREATE INDEX ON %s(pk1) USING 'sai'"); + createIndex("CREATE INDEX ON %s(pk2) USING 'sai'"); disableCompaction(); } - private void insertData1() throws Throwable + private void insertData1() { execute("INSERT INTO %s (pk1, pk2, val) VALUES (1, '1', 1)"); execute("INSERT INTO %s (pk1, pk2, val) VALUES (2, '2', 2)"); execute("INSERT INTO %s (pk1, pk2, val) VALUES (3, '3', 3)"); } - private void insertData2() throws Throwable + private void insertData2() { execute("INSERT INTO %s (pk1, pk2, val) VALUES (4, '4', 4)"); execute("INSERT INTO %s (pk1, pk2, val) VALUES (5, '5', 5)"); @@ -51,7 +51,7 @@ public class CompositePartitionKeyIndexTest extends SAITester } @Test - public void queryFromMemtable() throws Throwable + public void queryFromMemtable() { insertData1(); insertData2(); @@ -62,7 +62,7 @@ public class CompositePartitionKeyIndexTest extends SAITester return row(index, Integer.toString(index), index); } - private void runQueries() throws Throwable + private void runQueries() { assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE pk1 = 2"), expectedRow(2)); diff --git a/test/unit/org/apache/cassandra/index/sai/cql/MultipleColumnIndexTest.java b/test/unit/org/apache/cassandra/index/sai/cql/MultipleColumnIndexTest.java index 97f93e29aa..459d608dc5 100644 --- a/test/unit/org/apache/cassandra/index/sai/cql/MultipleColumnIndexTest.java +++ b/test/unit/org/apache/cassandra/index/sai/cql/MultipleColumnIndexTest.java @@ -25,26 +25,26 @@ import static org.junit.Assert.assertEquals; public class MultipleColumnIndexTest extends SAITester { - // Note: Full testing of multiple map index types is done in the - // types/collections/maps/MultiMap*Test tests - // This is just testing that the indexes can be created @Test public void canCreateMultipleMapIndexesOnSameColumn() { + // Note: Full testing of multiple map index types is done in the + // types/collections/maps/MultiMap*Test tests + // This is just testing that the indexes can be created createTable("CREATE TABLE %s (pk int, ck int, value map<int,int>, PRIMARY KEY(pk, ck))"); - createIndex("CREATE CUSTOM INDEX ON %s(KEYS(value)) USING 'StorageAttachedIndex'"); - createIndex("CREATE CUSTOM INDEX ON %s(VALUES(value)) USING 'StorageAttachedIndex'"); - createIndex("CREATE CUSTOM INDEX ON %s(ENTRIES(value)) USING 'StorageAttachedIndex'"); + createIndex("CREATE INDEX ON %s(KEYS(value)) USING 'sai'"); + createIndex("CREATE INDEX ON %s(VALUES(value)) USING 'sai'"); + createIndex("CREATE INDEX ON %s(ENTRIES(value)) USING 'sai'"); } @Test - public void indexNamedAsColumnWillCoExistWithGeneratedIndexNames() throws Throwable + public void indexNamedAsColumnWillCoExistWithGeneratedIndexNames() { createTable("CREATE TABLE %s(id int PRIMARY KEY, text_map map<text, text>)"); - createIndex("CREATE CUSTOM INDEX text_map ON %s(keys(text_map)) USING 'StorageAttachedIndex'"); - createIndex("CREATE CUSTOM INDEX ON %s(values(text_map)) USING 'StorageAttachedIndex'"); - createIndex("CREATE CUSTOM INDEX ON %s(entries(text_map)) USING 'StorageAttachedIndex'"); + createIndex("CREATE INDEX text_map ON %s(keys(text_map)) USING 'sai'"); + createIndex("CREATE INDEX ON %s(values(text_map)) USING 'sai'"); + createIndex("CREATE INDEX ON %s(entries(text_map)) USING 'sai'"); execute("INSERT INTO %s(id, text_map) values (1, {'k1':'v1', 'k2':'v2'})"); execute("INSERT INTO %s(id, text_map) values (2, {'k1':'v1', 'k3':'v3'})"); diff --git a/test/unit/org/apache/cassandra/index/sai/cql/StorageAttachedIndexDDLTest.java b/test/unit/org/apache/cassandra/index/sai/cql/StorageAttachedIndexDDLTest.java index 2b621fcfe7..43635c2e7a 100644 --- a/test/unit/org/apache/cassandra/index/sai/cql/StorageAttachedIndexDDLTest.java +++ b/test/unit/org/apache/cassandra/index/sai/cql/StorageAttachedIndexDDLTest.java @@ -37,6 +37,7 @@ import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.exceptions.InvalidConfigurationInQueryException; import com.datastax.driver.core.exceptions.InvalidQueryException; import com.datastax.driver.core.exceptions.ReadFailureException; +import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.cql3.CQL3Type; import org.apache.cassandra.cql3.ColumnIdentifier; import org.apache.cassandra.cql3.restrictions.IndexRestrictions; @@ -50,6 +51,7 @@ import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.Int32Type; import org.apache.cassandra.db.marshal.ReversedType; import org.apache.cassandra.db.marshal.UTF8Type; +import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.index.Index; import org.apache.cassandra.index.SecondaryIndexManager; import org.apache.cassandra.index.sai.IndexContext; @@ -145,7 +147,7 @@ public class StorageAttachedIndexDDLTest extends SAITester try { - executeNet(String.format("CREATE CUSTOM INDEX ON %%s(%s) USING 'StorageAttachedIndex'", cql3Type)); + executeNet(String.format("CREATE INDEX ON %%s(%s) USING 'sai'", cql3Type)); assertTrue("Index creation on unsupported type " + cql3Type + " should have failed.", supported); } catch (RuntimeException e) @@ -161,7 +163,7 @@ public class StorageAttachedIndexDDLTest extends SAITester public void shouldFailCreationOnPartitionKey() { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(id) USING 'StorageAttachedIndex'")) + assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(id) USING 'sai'")) .isInstanceOf(InvalidQueryException.class) .hasMessageContaining(String.format(CreateIndexStatement.ONLY_PARTITION_KEY, "id")); } @@ -171,8 +173,8 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val) USING " + - "'StorageAttachedIndex' WITH OPTIONS = { 'mode' : 'CONTAINS' }")).isInstanceOf(InvalidConfigurationInQueryException.class); + assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val) USING 'sai' " + + "WITH OPTIONS = { 'mode' : 'CONTAINS' }")).isInstanceOf(InvalidConfigurationInQueryException.class); } @Test @@ -180,8 +182,8 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val) " + - "USING 'StorageAttachedIndex' " + + assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val) " + + "USING 'sai' " + "WITH OPTIONS = { 'analyzer_class' : 'org.apache.cassandra.index.sai.analyzer.NonTokenizingAnalyzer' }")) .isInstanceOf(InvalidConfigurationInQueryException.class); } @@ -191,8 +193,8 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val) " + - "USING 'StorageAttachedIndex' " + + assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val) " + + "USING 'sai' " + "WITH OPTIONS = { 'case-sensitive' : true }")).isInstanceOf(InvalidConfigurationInQueryException.class); } @@ -201,8 +203,8 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val int)"); - assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val) " + - "USING 'StorageAttachedIndex' " + + assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val) " + + "USING 'sai' " + "WITH OPTIONS = { 'case_sensitive' : true }")).isInstanceOf(InvalidQueryException.class); } @@ -211,8 +213,8 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val int)"); - assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val) " + - "USING 'StorageAttachedIndex' " + + assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val) " + + "USING 'sai' " + "WITH OPTIONS = { 'normalize' : true }")).isInstanceOf(InvalidQueryException.class); } @@ -222,8 +224,8 @@ public class StorageAttachedIndexDDLTest extends SAITester String typeName = createType("CREATE TYPE %s (a text, b int, c double)"); createTable("CREATE TABLE %s (id text PRIMARY KEY, val " + typeName + ')'); - assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val) " + - "USING 'StorageAttachedIndex'")).isInstanceOf(InvalidQueryException.class); + assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val) " + + "USING 'sai'")).isInstanceOf(InvalidQueryException.class); } @Test @@ -231,7 +233,7 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val tuple<text, int, double>)"); - executeNet("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex'"); + executeNet("CREATE INDEX ON %s(val) USING 'sai'"); TableMetadata metadata = currentTableMetadata(); AbstractType<?> tuple = metadata.getColumn(ColumnIdentifier.getInterned("val", false)).type; @@ -246,8 +248,8 @@ public class StorageAttachedIndexDDLTest extends SAITester String invalidColumn = "/invalid"; createTable(String.format("CREATE TABLE %%s (id text PRIMARY KEY, \"%s\" text)", invalidColumn)); - assertThatThrownBy(() -> executeNet(String.format("CREATE CUSTOM INDEX ON %%s(\"%s\")" + - " USING 'StorageAttachedIndex'", invalidColumn))) + assertThatThrownBy(() -> executeNet(String.format("CREATE INDEX ON %%s(\"%s\")" + + " USING 'sai'", invalidColumn))) .isInstanceOf(InvalidQueryException.class) .hasMessage(String.format(CreateIndexStatement.INVALID_CUSTOM_INDEX_TARGET, invalidColumn, SchemaConstants.NAME_LENGTH)); } @@ -256,20 +258,65 @@ public class StorageAttachedIndexDDLTest extends SAITester public void shouldCreateIndexIfExists() { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); + createIndex("CREATE INDEX IF NOT EXISTS ON %s(val) USING 'sai' "); + createIndexAsync("CREATE INDEX IF NOT EXISTS ON %s(val) USING 'sai' "); - createIndex("CREATE CUSTOM INDEX IF NOT EXISTS ON %s(val) USING 'StorageAttachedIndex' "); + assertEquals(1, saiCreationCounter.get()); + } + + @Test + public void shouldCreateIndexCaseInsensitive() + { + createTable("CREATE TABLE %s (id text PRIMARY KEY, val1 text, val2 text)"); + createIndex("CREATE INDEX mixed_case_val ON %s(val1) USING 'Sai' "); + createIndex("CREATE INDEX upper_case_val ON %s(val2) USING 'SAI' "); + + assertEquals(2, saiCreationCounter.get()); + } - createIndexAsync("CREATE CUSTOM INDEX IF NOT EXISTS ON %s(val) USING 'StorageAttachedIndex' "); + @Test + public void shouldCreateIndexWithClassName() + { + createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); + createIndex("CREATE INDEX ON %s(val) USING 'StorageAttachedIndex' "); + assertEquals(1, saiCreationCounter.get()); + } + @Test + public void shouldCreateIndexWithDefault() + { + DatabaseDescriptor.setDefaultSecondaryIndex(StorageAttachedIndex.NAME); + createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); + createIndex("CREATE INDEX ON %s(val)"); assertEquals(1, saiCreationCounter.get()); } + @Test + public void shouldFailWithDefaultIndexDisabled() + { + DatabaseDescriptor.setDefaultSecondaryIndex(StorageAttachedIndex.NAME); + boolean original = DatabaseDescriptor.getDefaultSecondaryIndexEnabled(); + + try + { + DatabaseDescriptor.setDefaultSecondaryIndexEnabled(false); + createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); + assertThatThrownBy(() -> createIndex("CREATE INDEX ON %s(val)")).hasRootCauseInstanceOf(InvalidRequestException.class) + .hasRootCauseMessage(CreateIndexStatement.MUST_SPECIFY_INDEX_IMPLEMENTATION); + assertEquals(0, saiCreationCounter.get()); + } + finally + { + DatabaseDescriptor.setDefaultSecondaryIndexEnabled(original); + } + } + @Test public void shouldBeCaseSensitiveByDefault() { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex'"); + createIndex("CREATE INDEX ON %s(val) USING 'sai'"); execute("INSERT INTO %s (id, val) VALUES ('1', 'Camel')"); @@ -283,7 +330,7 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex' WITH OPTIONS = { 'case_sensitive' : true }"); + createIndex("CREATE INDEX ON %s(val) USING 'sai' WITH OPTIONS = { 'case_sensitive' : true }"); execute("INSERT INTO %s (id, val) VALUES ('1', 'Camel')"); @@ -297,7 +344,7 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex' WITH OPTIONS = { 'case_sensitive' : false }"); + createIndex("CREATE INDEX ON %s(val) USING 'sai' WITH OPTIONS = { 'case_sensitive' : false }"); execute("INSERT INTO %s (id, val) VALUES ('1', 'Camel')"); @@ -309,7 +356,7 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex'"); + createIndex("CREATE INDEX ON %s(val) USING 'sai'"); execute("INSERT INTO %s (id, val) VALUES ('1', 'Cam\u00E1l')"); @@ -324,7 +371,7 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex' WITH OPTIONS = { 'normalize' : false }"); + createIndex("CREATE INDEX ON %s(val) USING 'sai' WITH OPTIONS = { 'normalize' : false }"); execute("INSERT INTO %s (id, val) VALUES ('1', 'Cam\u00E1l')"); @@ -339,7 +386,7 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex' WITH OPTIONS = { 'normalize' : true }"); + createIndex("CREATE INDEX ON %s(val) USING 'sai' WITH OPTIONS = { 'normalize' : true }"); execute("INSERT INTO %s (id, val) VALUES ('1', 'Cam\u00E1l')"); @@ -351,7 +398,7 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex' WITH OPTIONS = { 'normalize' : true, 'case_sensitive' : false}"); + createIndex("CREATE INDEX ON %s(val) USING 'sai' WITH OPTIONS = { 'normalize' : true, 'case_sensitive' : false}"); execute("INSERT INTO %s (id, val) VALUES ('1', 'Cam\u00E1l')"); @@ -363,7 +410,7 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex' WITH OPTIONS = { 'ascii' : true, 'case_sensitive' : false}"); + createIndex("CREATE INDEX ON %s(val) USING 'sai' WITH OPTIONS = { 'ascii' : true, 'case_sensitive' : false}"); execute("INSERT INTO %s (id, val) VALUES ('1', 'Éppinger')"); @@ -371,11 +418,11 @@ public class StorageAttachedIndexDDLTest extends SAITester } @Test - public void shouldCreateIndexOnReversedType() throws Throwable + public void shouldCreateIndexOnReversedType() { createTable("CREATE TABLE %s (id text, ck1 text, val text, PRIMARY KEY (id,ck1)) WITH CLUSTERING ORDER BY (ck1 desc)"); - String indexNameCk1 = createIndex("CREATE CUSTOM INDEX ON %s(ck1) USING 'StorageAttachedIndex'"); + String indexNameCk1 = createIndex("CREATE INDEX ON %s(ck1) USING 'sai'"); execute("insert into %s(id, ck1, val) values('1', '2', '3')"); execute("insert into %s(id, ck1, val) values('1', '3', '4')"); @@ -392,11 +439,10 @@ public class StorageAttachedIndexDDLTest extends SAITester } @Test - public void shouldCreateIndexWithAlias() + public void shouldCreateIndexWithFullClassName() { createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)"); - - createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex'"); + createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'org.apache.cassandra.index.sai.StorageAttachedIndex'"); assertEquals(1, saiCreationCounter.get()); } @@ -406,7 +452,7 @@ public class StorageAttachedIndexDDLTest extends SAITester * Not putting in {@link MixedIndexImplementationsTest} because it uses CQLTester which doesn't load SAI dependency. */ @Test - public void shouldCreateSASI() throws Throwable + public void shouldCreateSASI() { createTable(CREATE_TABLE_TEMPLATE); @@ -433,7 +479,7 @@ public class StorageAttachedIndexDDLTest extends SAITester { createTable("CREATE TABLE %s (id text PRIMARY KEY, val1 text, val2 text)"); - assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val1, val2) USING 'StorageAttachedIndex'")) + assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val1, val2) USING 'sai'")) .isInstanceOf(InvalidQueryException.class) .hasMessageContaining("storage-attached index cannot be created over multiple columns"); } @@ -445,21 +491,21 @@ public class StorageAttachedIndexDDLTest extends SAITester execute("INSERT INTO %s (id, v1) VALUES(1, '1')"); flush(); - executeNet("CREATE CUSTOM INDEX index_1 ON %s(v1) USING 'StorageAttachedIndex'"); + executeNet("CREATE INDEX index_1 ON %s(v1) USING 'sai'"); waitForTableIndexesQueryable(); // same name - assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX index_1 ON %s(v1) USING 'StorageAttachedIndex'")) + assertThatThrownBy(() -> executeNet("CREATE INDEX index_1 ON %s(v1) USING 'sai'")) .isInstanceOf(InvalidQueryException.class) .hasMessageContaining(String.format(CreateIndexStatement.INDEX_ALREADY_EXISTS, "index_1")); // different name, same option - assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX index_2 ON %s(v1) USING 'StorageAttachedIndex'")) + assertThatThrownBy(() -> executeNet("CREATE INDEX index_2 ON %s(v1) USING 'sai'")) .isInstanceOf(InvalidQueryException.class) .hasMessageContaining(String.format(CreateIndexStatement.INDEX_DUPLICATE_OF_EXISTING, "index_2", "index_1")); // different name, different option, same target. - assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(v1) USING 'StorageAttachedIndex' WITH OPTIONS = { 'case_sensitive' : true }")) + assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(v1) USING 'sai' WITH OPTIONS = { 'case_sensitive' : true }")) .isInstanceOf(InvalidQueryException.class) .hasMessageContaining("Cannot create more than one storage-attached index on the same column: v1" ); @@ -496,7 +542,7 @@ public class StorageAttachedIndexDDLTest extends SAITester // Create the index, but do not allow the initial index build to begin: Injections.inject(delayInitializationTask); - createIndexAsync("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex'"); + createIndexAsync("CREATE INDEX ON %s(val) USING 'sai'"); // Flush the Memtable's contents, which will feed data to the index as the SSTable is written: flush(); diff --git a/test/unit/org/apache/cassandra/index/sai/cql/types/IndexingTypeSupport.java b/test/unit/org/apache/cassandra/index/sai/cql/types/IndexingTypeSupport.java index b1d54085df..a9320ea173 100644 --- a/test/unit/org/apache/cassandra/index/sai/cql/types/IndexingTypeSupport.java +++ b/test/unit/org/apache/cassandra/index/sai/cql/types/IndexingTypeSupport.java @@ -87,7 +87,7 @@ public abstract class IndexingTypeSupport extends SAITester if (scenario != Scenario.POST_BUILD_QUERY) { for (String index : dataset.decorateIndexColumn("value")) - createIndex(String.format("CREATE CUSTOM INDEX ON %%s(%s) USING 'StorageAttachedIndex'", index)); + createIndex(String.format("CREATE INDEX ON %%s(%s) USING 'sai'", index)); } insertData(this, allRows, scenario); @@ -104,14 +104,14 @@ public abstract class IndexingTypeSupport extends SAITester case POST_BUILD_QUERY: flush(); for (String index : dataset.decorateIndexColumn("value")) - createIndex(String.format("CREATE CUSTOM INDEX ON %%s(%s) USING 'StorageAttachedIndex'", index)); + createIndex(String.format("CREATE INDEX ON %%s(%s) USING 'sai'", index)); break; } dataset.querySet().runQueries(this, allRows); } - public static void insertData(SAITester tester, Object[][] allRows, Scenario scenario) throws Throwable + public static void insertData(SAITester tester, Object[][] allRows, Scenario scenario) { int sstableCounter = 0; int sstableIncrement = NUMBER_OF_VALUES / 8; diff --git a/test/unit/org/apache/cassandra/index/sai/functional/GroupComponentsTest.java b/test/unit/org/apache/cassandra/index/sai/functional/GroupComponentsTest.java index 9e348dcd6c..45fd55bcd9 100644 --- a/test/unit/org/apache/cassandra/index/sai/functional/GroupComponentsTest.java +++ b/test/unit/org/apache/cassandra/index/sai/functional/GroupComponentsTest.java @@ -45,7 +45,7 @@ public class GroupComponentsTest extends SAITester public void testInvalidateWithoutObsolete() { createTable("CREATE TABLE %s (pk int primary key, value text)"); - createIndex("CREATE CUSTOM INDEX ON %s(value) USING 'StorageAttachedIndex'"); + createIndex("CREATE INDEX ON %s(value) USING 'sai'"); execute("INSERT INTO %s (pk) VALUES (1)"); flush(); @@ -70,7 +70,7 @@ public class GroupComponentsTest extends SAITester public void getLiveComponentsForEmptyIndex() { createTable("CREATE TABLE %s (pk int primary key, value text)"); - createIndex("CREATE CUSTOM INDEX ON %s(value) USING 'StorageAttachedIndex'"); + createIndex("CREATE INDEX ON %s(value) USING 'sai'"); execute("INSERT INTO %s (pk) VALUES (1)"); flush(); @@ -91,7 +91,7 @@ public class GroupComponentsTest extends SAITester public void getLiveComponentsForPopulatedIndex() { createTable("CREATE TABLE %s (pk int primary key, value text)"); - IndexContext indexContext = createIndexContext(createIndex("CREATE CUSTOM INDEX ON %s(value) USING 'StorageAttachedIndex'"), UTF8Type.instance); + IndexContext indexContext = createIndexContext(createIndex("CREATE INDEX ON %s(value) USING 'sai'"), UTF8Type.instance); execute("INSERT INTO %s (pk, value) VALUES (1, '1')"); flush(); diff --git a/test/unit/org/apache/cassandra/index/sai/virtual/SSTablesSystemViewTest.java b/test/unit/org/apache/cassandra/index/sai/virtual/SSTablesSystemViewTest.java index eebcdf6561..580d2694d5 100644 --- a/test/unit/org/apache/cassandra/index/sai/virtual/SSTablesSystemViewTest.java +++ b/test/unit/org/apache/cassandra/index/sai/virtual/SSTablesSystemViewTest.java @@ -73,7 +73,7 @@ public class SSTablesSystemViewTest extends SAITester public void testVirtualTableThroughIndexLifeCycle() throws Throwable { createTable("CREATE TABLE %s (k text, c text, v1 text, v2 text, PRIMARY KEY (k, c))"); - String v1IndexName = createIndex("CREATE CUSTOM INDEX ON %s(v1) USING 'StorageAttachedIndex'"); + String v1IndexName = createIndex("CREATE INDEX ON %s(v1) USING 'sai'"); String insert = "INSERT INTO %s(k, c, v1, v2) VALUES (?, ?, ?, ?)"; @@ -99,7 +99,7 @@ public class SSTablesSystemViewTest extends SAITester assertRowsIgnoringOrder(execute(SELECT), row1, row2); // create a second index, this should create a new additional entry in the table for each sstable - String v2IndexName = createIndex("CREATE CUSTOM INDEX ON %s(v2) USING 'StorageAttachedIndex'"); + String v2IndexName = createIndex("CREATE INDEX ON %s(v2) USING 'sai'"); Object[] row3 = readRow(v2IndexName, id1, "v2", 1L, 0L, 0L); Object[] row4 = readRow(v2IndexName, id2, "v2", 2L, 0L, 1L); assertRowsIgnoringOrder(execute(SELECT), row1, row2, row3, row4); --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org