/* * 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 * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * 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.cassandra; import java.io.File; import java.io.IOException; import java.util.*; import org.apache.cassandra.cql3.statements.CreateTableStatement; import org.apache.cassandra.dht.Murmur3Partitioner; import org.apache.cassandra.index.sasi.SASIIndex; import org.apache.cassandra.index.sasi.disk.OnDiskIndexBuilder; import org.junit.After; import org.junit.BeforeClass; import org.apache.cassandra.config.*; import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.cql3.ColumnIdentifier; import org.apache.cassandra.cql3.statements.IndexTarget; import org.apache.cassandra.db.RowUpdateBuilder; import org.apache.cassandra.db.commitlog.CommitLog; import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.gms.Gossiper; import org.apache.cassandra.index.StubIndex; import org.apache.cassandra.io.util.FileUtils; import org.apache.cassandra.schema.*; import org.apache.cassandra.schema.MigrationManager; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.FBUtilities; public class SchemaLoader { @BeforeClass public static void loadSchema() throws ConfigurationException { prepareServer(); // Migrations aren't happy if gossiper is not started. Even if we don't use migrations though, // some tests now expect us to start gossip for them. startGossiper(); } @After public void leakDetect() throws InterruptedException { System.gc(); System.gc(); System.gc(); Thread.sleep(10); } public static void prepareServer() { CQLTester.prepareServer(); } public static void startGossiper() { // skip shadow round and endpoint collision check in tests System.setProperty("cassandra.allow_unsafe_join", "true"); if (!Gossiper.instance.isEnabled()) Gossiper.instance.start((int) (System.currentTimeMillis() / 1000)); } public static void schemaDefinition(String testName) throws ConfigurationException { List<KeyspaceMetadata> schema = new ArrayList<KeyspaceMetadata>(); // A whole bucket of shorthand String ks1 = testName + "Keyspace1"; String ks2 = testName + "Keyspace2"; String ks3 = testName + "Keyspace3"; String ks4 = testName + "Keyspace4"; String ks5 = testName + "Keyspace5"; String ks6 = testName + "Keyspace6"; String ks7 = testName + "Keyspace7"; String ks_kcs = testName + "KeyCacheSpace"; String ks_rcs = testName + "RowCacheSpace"; String ks_ccs = testName + "CounterCacheSpace"; String ks_nocommit = testName + "NoCommitlogSpace"; String ks_prsi = testName + "PerRowSecondaryIndex"; String ks_cql = testName + "cql_keyspace"; AbstractType bytes = BytesType.instance; AbstractType<?> composite = CompositeType.getInstance(Arrays.asList(new AbstractType<?>[]{BytesType.instance, TimeUUIDType.instance, IntegerType.instance})); AbstractType<?> compositeMaxMin = CompositeType.getInstance(Arrays.asList(new AbstractType<?>[]{BytesType.instance, IntegerType.instance})); Map<Byte, AbstractType<?>> aliases = new HashMap<Byte, AbstractType<?>>(); aliases.put((byte)'b', BytesType.instance); aliases.put((byte)'t', TimeUUIDType.instance); aliases.put((byte)'B', ReversedType.getInstance(BytesType.instance)); aliases.put((byte)'T', ReversedType.getInstance(TimeUUIDType.instance)); AbstractType<?> dynamicComposite = DynamicCompositeType.getInstance(aliases); // Make it easy to test compaction Map<String, String> compactionOptions = new HashMap<String, String>(); compactionOptions.put("tombstone_compaction_interval", "1"); Map<String, String> leveledOptions = new HashMap<String, String>(); leveledOptions.put("sstable_size_in_mb", "1"); leveledOptions.put("fanout_size", "5"); // Keyspace 1 schema.add(KeyspaceMetadata.create(ks1, KeyspaceParams.simple(1), Tables.of( // Column Families standardCFMD(ks1, "Standard1").compaction(CompactionParams.scts(compactionOptions)).build(), standardCFMD(ks1, "Standard2").build(), standardCFMD(ks1, "Standard3").build(), standardCFMD(ks1, "Standard4").build(), standardCFMD(ks1, "StandardGCGS0").gcGraceSeconds(0).build(), standardCFMD(ks1, "StandardLong1").build(), standardCFMD(ks1, "StandardLong2").build(), superCFMD(ks1, "Super1", LongType.instance).build(), superCFMD(ks1, "Super2", LongType.instance).build(), superCFMD(ks1, "Super3", LongType.instance).build(), superCFMD(ks1, "Super4", UTF8Type.instance).build(), superCFMD(ks1, "Super5", bytes).build(), superCFMD(ks1, "Super6", LexicalUUIDType.instance, UTF8Type.instance).build(), keysIndexCFMD(ks1, "Indexed1", true).build(), keysIndexCFMD(ks1, "Indexed2", false).build(), superCFMD(ks1, "SuperDirectGC", BytesType.instance).gcGraceSeconds(0).build(), jdbcCFMD(ks1, "JdbcUtf8", UTF8Type.instance).addColumn(utf8Column(ks1, "JdbcUtf8")).build(), jdbcCFMD(ks1, "JdbcLong", LongType.instance).build(), jdbcCFMD(ks1, "JdbcBytes", bytes).build(), jdbcCFMD(ks1, "JdbcAscii", AsciiType.instance).build(), standardCFMD(ks1, "StandardLeveled").compaction(CompactionParams.lcs(leveledOptions)).build(), standardCFMD(ks1, "legacyleveled").compaction(CompactionParams.lcs(leveledOptions)).build(), standardCFMD(ks1, "StandardLowIndexInterval").minIndexInterval(8) .maxIndexInterval(256) .caching(CachingParams.CACHE_NOTHING).build() ))); // Keyspace 2 schema.add(KeyspaceMetadata.create(ks2, KeyspaceParams.simple(1), Tables.of( // Column Families standardCFMD(ks2, "Standard1").build(), standardCFMD(ks2, "Standard3").build(), superCFMD(ks2, "Super3", bytes).build(), superCFMD(ks2, "Super4", TimeUUIDType.instance).build(), keysIndexCFMD(ks2, "Indexed1", true).build(), compositeIndexCFMD(ks2, "Indexed2", true).build(), compositeIndexCFMD(ks2, "Indexed3", true).gcGraceSeconds(0).build()))); // Keyspace 3 schema.add(KeyspaceMetadata.create(ks3, KeyspaceParams.simple(5), Tables.of( standardCFMD(ks3, "Standard1").build(), keysIndexCFMD(ks3, "Indexed1", true).build()))); // Keyspace 4 schema.add(KeyspaceMetadata.create(ks4, KeyspaceParams.simple(3), Tables.of( standardCFMD(ks4, "Standard1").build(), standardCFMD(ks4, "Standard3").build(), superCFMD(ks4, "Super3", bytes).build(), superCFMD(ks4, "Super4", TimeUUIDType.instance).build(), superCFMD(ks4, "Super5", TimeUUIDType.instance, BytesType.instance).build()))); // Keyspace 5 schema.add(KeyspaceMetadata.create(ks5, KeyspaceParams.simple(2), Tables.of(standardCFMD(ks5, "Standard1").build()))); // Keyspace 6 schema.add(KeyspaceMetadata.create(ks6, KeyspaceParams.simple(1), Tables.of(keysIndexCFMD(ks6, "Indexed1", true).build()))); // Keyspace 7 schema.add(KeyspaceMetadata.create(ks7, KeyspaceParams.simple(1), Tables.of(customIndexCFMD(ks7, "Indexed1").build()))); // KeyCacheSpace schema.add(KeyspaceMetadata.create(ks_kcs, KeyspaceParams.simple(1), Tables.of( standardCFMD(ks_kcs, "Standard1").build(), standardCFMD(ks_kcs, "Standard2").build(), standardCFMD(ks_kcs, "Standard3").build()))); // RowCacheSpace schema.add(KeyspaceMetadata.create(ks_rcs, KeyspaceParams.simple(1), Tables.of( standardCFMD(ks_rcs, "CFWithoutCache").caching(CachingParams.CACHE_NOTHING).build(), standardCFMD(ks_rcs, "CachedCF").caching(CachingParams.CACHE_EVERYTHING).build(), standardCFMD(ks_rcs, "CachedNoClustering", 1, IntegerType.instance, IntegerType.instance, null).caching(CachingParams.CACHE_EVERYTHING).build(), standardCFMD(ks_rcs, "CachedIntCF").caching(new CachingParams(true, 100)).build()))); schema.add(KeyspaceMetadata.create(ks_nocommit, KeyspaceParams.simpleTransient(1), Tables.of( standardCFMD(ks_nocommit, "Standard1").build()))); // CQLKeyspace schema.add(KeyspaceMetadata.create(ks_cql, KeyspaceParams.simple(1), Tables.of( // Column Families CreateTableStatement.parse("CREATE TABLE table1 (" + "k int PRIMARY KEY," + "v1 text," + "v2 int" + ")", ks_cql) .build(), CreateTableStatement.parse("CREATE TABLE table2 (" + "k text," + "c text," + "v text," + "PRIMARY KEY (k, c))", ks_cql) .build(), CreateTableStatement.parse("CREATE TABLE foo (" + "bar text, " + "baz text, " + "qux text, " + "PRIMARY KEY(bar, baz) ) " + "WITH COMPACT STORAGE", ks_cql) .build(), CreateTableStatement.parse("CREATE TABLE foofoo (" + "bar text, " + "baz text, " + "qux text, " + "quz text, " + "foo text, " + "PRIMARY KEY((bar, baz), qux, quz) ) " + "WITH COMPACT STORAGE", ks_cql) .build() ))); if (DatabaseDescriptor.getPartitioner() instanceof Murmur3Partitioner) { schema.add(KeyspaceMetadata.create("sasi", KeyspaceParams.simpleTransient(1), Tables.of(sasiCFMD("sasi", "test_cf").build(), clusteringSASICFMD("sasi", "clustering_test_cf").build()))); } // if you're messing with low-level sstable stuff, it can be useful to inject the schema directly // Schema.instance.load(schemaDefinition()); for (KeyspaceMetadata ksm : schema) MigrationManager.announceNewKeyspace(ksm, false); if (Boolean.parseBoolean(System.getProperty("cassandra.test.compression", "false"))) useCompression(schema); } public static void createKeyspace(String name, KeyspaceParams params) { MigrationManager.announceNewKeyspace(KeyspaceMetadata.create(name, params, Tables.of()), true); } public static void createKeyspace(String name, KeyspaceParams params, TableMetadata.Builder... builders) { Tables.Builder tables = Tables.builder(); for (TableMetadata.Builder builder : builders) tables.add(builder.build()); MigrationManager.announceNewKeyspace(KeyspaceMetadata.create(name, params, tables.build()), true); } public static void createKeyspace(String name, KeyspaceParams params, TableMetadata... tables) { MigrationManager.announceNewKeyspace(KeyspaceMetadata.create(name, params, Tables.of(tables)), true); } public static void createKeyspace(String name, KeyspaceParams params, Tables tables, Types types) { MigrationManager.announceNewKeyspace(KeyspaceMetadata.create(name, params, tables, Views.none(), types, Functions.none()), true); } public static ColumnMetadata integerColumn(String ksName, String cfName) { return new ColumnMetadata(ksName, cfName, ColumnIdentifier.getInterned(IntegerType.instance.fromString("42"), IntegerType.instance), UTF8Type.instance, ColumnMetadata.NO_POSITION, ColumnMetadata.Kind.REGULAR); } public static ColumnMetadata utf8Column(String ksName, String cfName) { return new ColumnMetadata(ksName, cfName, ColumnIdentifier.getInterned("fortytwo", true), UTF8Type.instance, ColumnMetadata.NO_POSITION, ColumnMetadata.Kind.REGULAR); } public static TableMetadata perRowIndexedCFMD(String ksName, String cfName) { ColumnMetadata indexedColumn = ColumnMetadata.regularColumn(ksName, cfName, "indexed", AsciiType.instance); TableMetadata.Builder builder = TableMetadata.builder(ksName, cfName) .addPartitionKeyColumn("key", AsciiType.instance) .addColumn(indexedColumn); final Map<String, String> indexOptions = Collections.singletonMap(IndexTarget.CUSTOM_INDEX_OPTION_NAME, StubIndex.class.getName()); builder.indexes(Indexes.of(IndexMetadata.fromIndexTargets( Collections.singletonList(new IndexTarget(indexedColumn.name, IndexTarget.Type.VALUES)), "indexe1", IndexMetadata.Kind.CUSTOM, indexOptions))); return builder.build(); } private static void useCompression(List<KeyspaceMetadata> schema) { for (KeyspaceMetadata ksm : schema) for (TableMetadata cfm : ksm.tablesAndViews()) MigrationManager.announceTableUpdate(cfm.unbuild().compression(CompressionParams.snappy()).build(), true); } public static TableMetadata.Builder counterCFMD(String ksName, String cfName) { return TableMetadata.builder(ksName, cfName) .isCounter(true) .addPartitionKeyColumn("key", AsciiType.instance) .addClusteringColumn("name", AsciiType.instance) .addRegularColumn("val", CounterColumnType.instance) .addRegularColumn("val2", CounterColumnType.instance) .compression(getCompressionParameters()); } public static TableMetadata.Builder standardCFMD(String ksName, String cfName) { return standardCFMD(ksName, cfName, 1, AsciiType.instance); } public static TableMetadata.Builder standardCFMD(String ksName, String cfName, int columnCount, AbstractType<?> keyType) { return standardCFMD(ksName, cfName, columnCount, keyType, AsciiType.instance); } public static TableMetadata.Builder standardCFMD(String ksName, String cfName, int columnCount, AbstractType<?> keyType, AbstractType<?> valType) { return standardCFMD(ksName, cfName, columnCount, keyType, valType, AsciiType.instance); } public static TableMetadata.Builder standardCFMD(String ksName, String cfName, int columnCount, AbstractType<?> keyType, AbstractType<?> valType, AbstractType<?> clusteringType) { TableMetadata.Builder builder = TableMetadata.builder(ksName, cfName) .addPartitionKeyColumn("key", keyType) .addRegularColumn("val", valType) .compression(getCompressionParameters()); if (clusteringType != null) builder.addClusteringColumn("name", clusteringType); for (int i = 0; i < columnCount; i++) builder.addRegularColumn("val" + i, AsciiType.instance); return builder; } public static TableMetadata.Builder denseCFMD(String ksName, String cfName) { return denseCFMD(ksName, cfName, AsciiType.instance); } public static TableMetadata.Builder denseCFMD(String ksName, String cfName, AbstractType cc) { return denseCFMD(ksName, cfName, cc, null); } public static TableMetadata.Builder denseCFMD(String ksName, String cfName, AbstractType cc, AbstractType subcc) { AbstractType comp = cc; if (subcc != null) comp = CompositeType.getInstance(Arrays.asList(new AbstractType<?>[]{cc, subcc})); return TableMetadata.builder(ksName, cfName) .isDense(true) .isCompound(subcc != null) .addPartitionKeyColumn("key", AsciiType.instance) .addClusteringColumn("cols", comp) .addRegularColumn("val", AsciiType.instance) .compression(getCompressionParameters()); } // TODO: Fix superCFMD failing on legacy table creation. Seems to be applying composite comparator to partition key public static TableMetadata.Builder superCFMD(String ksName, String cfName, AbstractType subcc) { return superCFMD(ksName, cfName, BytesType.instance, subcc); } public static TableMetadata.Builder superCFMD(String ksName, String cfName, AbstractType cc, AbstractType subcc) { return superCFMD(ksName, cfName, "cols", cc, subcc); } public static TableMetadata.Builder superCFMD(String ksName, String cfName, String ccName, AbstractType cc, AbstractType subcc) { return standardCFMD(ksName, cfName); } public static TableMetadata.Builder compositeIndexCFMD(String ksName, String cfName, boolean withRegularIndex) throws ConfigurationException { return compositeIndexCFMD(ksName, cfName, withRegularIndex, false); } public static TableMetadata.Builder compositeIndexCFMD(String ksName, String cfName, boolean withRegularIndex, boolean withStaticIndex) throws ConfigurationException { // the withIndex flag exists to allow tests index creation // on existing columns TableMetadata.Builder builder = TableMetadata.builder(ksName, cfName) .addPartitionKeyColumn("key", AsciiType.instance) .addClusteringColumn("c1", AsciiType.instance) .addRegularColumn("birthdate", LongType.instance) .addRegularColumn("notbirthdate", LongType.instance) .addStaticColumn("static", LongType.instance) .compression(getCompressionParameters()); Indexes.Builder indexes = Indexes.builder(); if (withRegularIndex) { indexes.add(IndexMetadata.fromIndexTargets( Collections.singletonList( new IndexTarget(new ColumnIdentifier("birthdate", true), IndexTarget.Type.VALUES)), cfName + "_birthdate_key_index", IndexMetadata.Kind.COMPOSITES, Collections.EMPTY_MAP)); } if (withStaticIndex) { indexes.add(IndexMetadata.fromIndexTargets( Collections.singletonList( new IndexTarget(new ColumnIdentifier("static", true), IndexTarget.Type.VALUES)), cfName + "_static_index", IndexMetadata.Kind.COMPOSITES, Collections.EMPTY_MAP)); } return builder.indexes(indexes.build()); } public static TableMetadata.Builder keysIndexCFMD(String ksName, String cfName, boolean withIndex) { TableMetadata.Builder builder = TableMetadata.builder(ksName, cfName) .isCompound(false) .isDense(true) .addPartitionKeyColumn("key", AsciiType.instance) .addClusteringColumn("c1", AsciiType.instance) .addStaticColumn("birthdate", LongType.instance) .addStaticColumn("notbirthdate", LongType.instance) .addRegularColumn("value", LongType.instance) .compression(getCompressionParameters()); if (withIndex) { IndexMetadata index = IndexMetadata.fromIndexTargets( Collections.singletonList(new IndexTarget(new ColumnIdentifier("birthdate", true), IndexTarget.Type.VALUES)), cfName + "_birthdate_composite_index", IndexMetadata.Kind.KEYS, Collections.EMPTY_MAP); builder.indexes(Indexes.builder().add(index).build()); } return builder; } public static TableMetadata.Builder customIndexCFMD(String ksName, String cfName) { TableMetadata.Builder builder = TableMetadata.builder(ksName, cfName) .isCompound(false) .isDense(true) .addPartitionKeyColumn("key", AsciiType.instance) .addClusteringColumn("c1", AsciiType.instance) .addRegularColumn("value", LongType.instance) .compression(getCompressionParameters()); IndexMetadata index = IndexMetadata.fromIndexTargets( Collections.singletonList(new IndexTarget(new ColumnIdentifier("value", true), IndexTarget.Type.VALUES)), cfName + "_value_index", IndexMetadata.Kind.CUSTOM, Collections.singletonMap(IndexTarget.CUSTOM_INDEX_OPTION_NAME, StubIndex.class.getName())); builder.indexes(Indexes.of(index)); return builder; } public static TableMetadata.Builder jdbcCFMD(String ksName, String cfName, AbstractType comp) { return TableMetadata.builder(ksName, cfName) .addPartitionKeyColumn("key", BytesType.instance) .compression(getCompressionParameters()); } public static TableMetadata.Builder sasiCFMD(String ksName, String cfName) { TableMetadata.Builder builder = TableMetadata.builder(ksName, cfName) .addPartitionKeyColumn("id", UTF8Type.instance) .addRegularColumn("first_name", UTF8Type.instance) .addRegularColumn("last_name", UTF8Type.instance) .addRegularColumn("age", Int32Type.instance) .addRegularColumn("height", Int32Type.instance) .addRegularColumn("timestamp", LongType.instance) .addRegularColumn("address", UTF8Type.instance) .addRegularColumn("score", DoubleType.instance) .addRegularColumn("comment", UTF8Type.instance) .addRegularColumn("comment_suffix_split", UTF8Type.instance) .addRegularColumn("/output/full-name/", UTF8Type.instance) .addRegularColumn("/data/output/id", UTF8Type.instance) .addRegularColumn("first_name_prefix", UTF8Type.instance); Indexes.Builder indexes = Indexes.builder(); indexes.add(IndexMetadata.fromSchemaMetadata(cfName + "_first_name", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "first_name"); put("mode", OnDiskIndexBuilder.Mode.CONTAINS.toString()); }})) .add(IndexMetadata.fromSchemaMetadata(cfName + "_last_name", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "last_name"); put("mode", OnDiskIndexBuilder.Mode.CONTAINS.toString()); }})) .add(IndexMetadata.fromSchemaMetadata(cfName + "_age", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "age"); }})) .add(IndexMetadata.fromSchemaMetadata(cfName + "_timestamp", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "timestamp"); put("mode", OnDiskIndexBuilder.Mode.SPARSE.toString()); }})) .add(IndexMetadata.fromSchemaMetadata(cfName + "_address", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put("analyzer_class", "org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer"); put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "address"); put("mode", OnDiskIndexBuilder.Mode.PREFIX.toString()); put("case_sensitive", "false"); }})) .add(IndexMetadata.fromSchemaMetadata(cfName + "_score", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "score"); }})) .add(IndexMetadata.fromSchemaMetadata(cfName + "_comment", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "comment"); put("mode", OnDiskIndexBuilder.Mode.CONTAINS.toString()); put("analyzed", "true"); }})) .add(IndexMetadata.fromSchemaMetadata(cfName + "_comment_suffix_split", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "comment_suffix_split"); put("mode", OnDiskIndexBuilder.Mode.CONTAINS.toString()); put("analyzed", "false"); }})) .add(IndexMetadata.fromSchemaMetadata(cfName + "_output_full_name", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "/output/full-name/"); put("analyzed", "true"); put("analyzer_class", "org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer"); put("case_sensitive", "false"); }})) .add(IndexMetadata.fromSchemaMetadata(cfName + "_data_output_id", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "/data/output/id"); put("mode", OnDiskIndexBuilder.Mode.CONTAINS.toString()); }})) .add(IndexMetadata.fromSchemaMetadata(cfName + "_first_name_prefix", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "first_name_prefix"); put("analyzed", "true"); put("tokenization_normalize_lowercase", "true"); }})); return builder.indexes(indexes.build()); } public static TableMetadata.Builder clusteringSASICFMD(String ksName, String cfName) { return clusteringSASICFMD(ksName, cfName, "location", "age", "height", "score"); } public static TableMetadata.Builder clusteringSASICFMD(String ksName, String cfName, String...indexedColumns) { Indexes.Builder indexes = Indexes.builder(); for (String indexedColumn : indexedColumns) { indexes.add(IndexMetadata.fromSchemaMetadata(cfName + "_" + indexedColumn, IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, indexedColumn); put("mode", OnDiskIndexBuilder.Mode.PREFIX.toString()); }})); } return TableMetadata.builder(ksName, cfName) .addPartitionKeyColumn("name", UTF8Type.instance) .addClusteringColumn("location", UTF8Type.instance) .addClusteringColumn("age", Int32Type.instance) .addRegularColumn("height", Int32Type.instance) .addRegularColumn("score", DoubleType.instance) .addStaticColumn("nickname", UTF8Type.instance) .indexes(indexes.build()); } public static TableMetadata.Builder staticSASICFMD(String ksName, String cfName) { TableMetadata.Builder builder = TableMetadata.builder(ksName, cfName) .addPartitionKeyColumn("sensor_id", Int32Type.instance) .addStaticColumn("sensor_type", UTF8Type.instance) .addClusteringColumn("date", LongType.instance) .addRegularColumn("value", DoubleType.instance) .addRegularColumn("variance", Int32Type.instance); Indexes.Builder indexes = Indexes.builder(); indexes.add(IndexMetadata.fromSchemaMetadata(cfName + "_sensor_type", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "sensor_type"); put("mode", OnDiskIndexBuilder.Mode.PREFIX.toString()); put("analyzer_class", "org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer"); put("case_sensitive", "false"); }})); indexes.add(IndexMetadata.fromSchemaMetadata(cfName + "_value", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "value"); put("mode", OnDiskIndexBuilder.Mode.PREFIX.toString()); }})); indexes.add(IndexMetadata.fromSchemaMetadata(cfName + "_variance", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "variance"); put("mode", OnDiskIndexBuilder.Mode.PREFIX.toString()); }})); return builder.indexes(indexes.build()); } public static TableMetadata.Builder fullTextSearchSASICFMD(String ksName, String cfName) { TableMetadata.Builder builder = TableMetadata.builder(ksName, cfName) .addPartitionKeyColumn("song_id", UUIDType.instance) .addRegularColumn("title", UTF8Type.instance) .addRegularColumn("artist", UTF8Type.instance); Indexes.Builder indexes = Indexes.builder(); indexes.add(IndexMetadata.fromSchemaMetadata(cfName + "_title", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "title"); put("mode", OnDiskIndexBuilder.Mode.CONTAINS.toString()); put("analyzer_class", "org.apache.cassandra.index.sasi.analyzer.StandardAnalyzer"); put("tokenization_enable_stemming", "true"); put("tokenization_locale", "en"); put("tokenization_skip_stop_words", "true"); put("tokenization_normalize_lowercase", "true"); }})); indexes.add(IndexMetadata.fromSchemaMetadata(cfName + "_artist", IndexMetadata.Kind.CUSTOM, new HashMap<String, String>() {{ put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, SASIIndex.class.getName()); put(IndexTarget.TARGET_OPTION_NAME, "artist"); put("mode", OnDiskIndexBuilder.Mode.CONTAINS.toString()); put("analyzer_class", "org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer"); put("case_sensitive", "false"); }})); return builder.indexes(indexes.build()); } public static CompressionParams getCompressionParameters() { return getCompressionParameters(null); } public static CompressionParams getCompressionParameters(Integer chunkSize) { if (Boolean.parseBoolean(System.getProperty("cassandra.test.compression", "false"))) return chunkSize != null ? CompressionParams.snappy(chunkSize) : CompressionParams.snappy(); return CompressionParams.noCompression(); } public static void cleanupAndLeaveDirs() throws IOException { // We need to stop and unmap all CLS instances prior to cleanup() or we'll get failures on Windows. CommitLog.instance.stopUnsafe(true); mkdirs(); cleanup(); mkdirs(); CommitLog.instance.restartUnsafe(); } public static void cleanup() { // clean up commitlog String[] directoryNames = { DatabaseDescriptor.getCommitLogLocation(), }; for (String dirName : directoryNames) { File dir = new File(dirName); if (!dir.exists()) throw new RuntimeException("No such directory: " + dir.getAbsolutePath()); // Leave the folder around as Windows will complain about directory deletion w/handles open to children files String[] children = dir.list(); for (String child : children) FileUtils.deleteRecursive(new File(dir, child)); } cleanupSavedCaches(); // clean up data directory which are stored as data directory/keyspace/data files for (String dirName : DatabaseDescriptor.getAllDataFileLocations()) { File dir = new File(dirName); if (!dir.exists()) throw new RuntimeException("No such directory: " + dir.getAbsolutePath()); String[] children = dir.list(); for (String child : children) FileUtils.deleteRecursive(new File(dir, child)); } } public static void mkdirs() { DatabaseDescriptor.createAllDirectories(); } public static void insertData(String keyspace, String columnFamily, int offset, int numberOfRows) { TableMetadata cfm = Schema.instance.getTableMetadata(keyspace, columnFamily); for (int i = offset; i < offset + numberOfRows; i++) { RowUpdateBuilder builder = new RowUpdateBuilder(cfm, FBUtilities.timestampMicros(), ByteBufferUtil.bytes("key"+i)); if (cfm.clusteringColumns() != null && !cfm.clusteringColumns().isEmpty()) builder.clustering(ByteBufferUtil.bytes("col"+ i)).add("val", ByteBufferUtil.bytes("val" + i)); else builder.add("val", ByteBufferUtil.bytes("val"+i)); builder.build().apply(); } } public static void cleanupSavedCaches() { File cachesDir = new File(DatabaseDescriptor.getSavedCachesLocation()); if (!cachesDir.exists() || !cachesDir.isDirectory()) return; FileUtils.delete(cachesDir.listFiles()); } }