Add flag to disable SASI indexes, and warning on creation

patch by Andres de la Peña; reviewed by Robert Stupp for CASSANDRA-14866
This commit is contained in:
Andrés de la Peña 2018-11-06 19:01:47 +00:00
parent b9b2e8e574
commit e6a61be8c8
11 changed files with 164 additions and 19 deletions

View File

@ -1,10 +1,11 @@
3.11.5
* Add flag to disable SASI indexes, and warnings on creation (CASSANDRA-14866)
Merged from 3.0:
* Improve `nodetool status -r` speed (CASSANDRA-14847)
* Improve merkle tree size and time on heap (CASSANDRA-14096)
* Add missing commands to nodetool_completion (CASSANDRA-14916)
* Anti-compaction temporarily corrupts sstable state for readers (CASSANDRA-15004)
Merged from 2.2:
Merged from 2.2:
* Multi-version in-JVM dtests (CASSANDRA-14937)
@ -43,7 +44,7 @@ Merged from 3.0:
* Fix static column order for SELECT * wildcard queries (CASSANDRA-14638)
* sstableloader should use discovered broadcast address to connect intra-cluster (CASSANDRA-14522)
* Fix reading columns with non-UTF names from schema (CASSANDRA-14468)
Merged from 2.2:
Merged from 2.2:
* CircleCI docker image should bake in more dependencies (CASSANDRA-14985)
* Don't enable client transports when bootstrap is pending (CASSANDRA-14525)
* MigrationManager attempts to pull schema from different major version nodes (CASSANDRA-14928)

View File

@ -50,6 +50,14 @@ Upgrading
- repair_session_max_tree_depth setting has been added to cassandra.yaml to allow operators to reduce
merkle tree size if repair is creating too much heap pressure. See CASSANDRA-14096 for details.
Experimental features
---------------------
- An 'enable_sasi_indexes' flag, true by default, has been added to cassandra.yaml to allow operators to prevent
the creation of new SASI indexes, which are considered experimental and are not recommended for production use.
(See https://www.mail-archive.com/dev@cassandra.apache.org/msg13582.html)
- The flags 'enable_sasi_indexes' and 'enable_materialized_views' have been grouped under an experimental features
section in cassandra.yaml.
3.11.4
======

View File

@ -1112,10 +1112,6 @@ enable_user_defined_functions: false
# This option has no effect, if enable_user_defined_functions is false.
enable_scripted_user_defined_functions: false
# Enables materialized view creation on this node.
# Materialized views are considered experimental and are not recommended for production use.
enable_materialized_views: true
# The default Windows kernel timer and scheduling resolution is 15.6ms for power conservation.
# Lowering this value on Windows can provide much tighter latency and better throughput, however
# some virtualized environments may see a negative performance impact from changing this setting
@ -1247,4 +1243,17 @@ back_pressure_strategy:
# time and queue contention while iterating the backlog of messages.
# An interval of 0 disables any wait time, which is the behavior of former Cassandra versions.
#
# otc_backlog_expiration_interval_ms: 200
# otc_backlog_expiration_interval_ms: 200
#########################
# EXPERIMENTAL FEATURES #
#########################
# Enables materialized view creation on this node.
# Materialized views are considered experimental and are not recommended for production use.
enable_materialized_views: true
# Enables SASI index creation on this node.
# SASI indexes are considered experimental and are not recommended for production use.
enable_sasi_indexes: true

View File

@ -348,6 +348,8 @@ public class Config
public boolean enable_materialized_views = true;
public boolean enable_sasi_indexes = true;
/**
* Optionally disable asynchronous UDF execution.
* Disabling asynchronous UDF execution also implicitly disables the security-manager!

View File

@ -2407,11 +2407,26 @@ public class DatabaseDescriptor
conf.user_defined_function_warn_timeout = userDefinedFunctionWarnTimeout;
}
public static boolean enableMaterializedViews()
public static boolean getEnableMaterializedViews()
{
return conf.enable_materialized_views;
}
public static void setEnableMaterializedViews(boolean enableMaterializedViews)
{
conf.enable_materialized_views = enableMaterializedViews;
}
public static boolean getEnableSASIIndexes()
{
return conf.enable_sasi_indexes;
}
public static void setEnableSASIIndexes(boolean enableSASIIndexes)
{
conf.enable_sasi_indexes = enableSASIIndexes;
}
public static long getUserDefinedFunctionFailTimeout()
{
return conf.user_defined_function_fail_timeout;

View File

@ -29,18 +29,20 @@ import org.slf4j.LoggerFactory;
import org.apache.cassandra.auth.Permission;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.config.Schema;
import org.apache.cassandra.cql3.CFName;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.IndexName;
import org.apache.cassandra.db.marshal.DurationType;
import org.apache.cassandra.db.marshal.MapType;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.exceptions.RequestValidationException;
import org.apache.cassandra.exceptions.UnauthorizedException;
import org.apache.cassandra.index.sasi.SASIIndex;
import org.apache.cassandra.schema.IndexMetadata;
import org.apache.cassandra.schema.Indexes;
import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.service.ClientWarn;
import org.apache.cassandra.service.MigrationManager;
import org.apache.cassandra.service.QueryState;
import org.apache.cassandra.thrift.ThriftValidation;
@ -229,6 +231,17 @@ public class CreateIndexStatement extends SchemaAlteringStatement
{
kind = IndexMetadata.Kind.CUSTOM;
indexOptions = properties.getOptions();
if (properties.customClass.equals(SASIIndex.class.getName()))
{
if (!DatabaseDescriptor.getEnableSASIIndexes())
throw new InvalidRequestException("SASI indexes are disabled. Enable in cassandra.yaml to use.");
logger.warn("Creating SASI index {} for {}.{}. {}",
acceptedName, cfm.ksName, cfm.cfName, SASIIndex.USAGE_WARNING);
ClientWarn.instance.warn(SASIIndex.USAGE_WARNING);
}
}
else
{

View File

@ -123,7 +123,7 @@ public class CreateViewStatement extends SchemaAlteringStatement
public Event.SchemaChange announceMigration(QueryState queryState, boolean isLocalOnly) throws RequestValidationException
{
if (!DatabaseDescriptor.enableMaterializedViews())
if (!DatabaseDescriptor.getEnableMaterializedViews())
{
throw new InvalidRequestException("Materialized views are disabled. Enable in cassandra.yaml to use.");
}
@ -327,13 +327,12 @@ public class CreateViewStatement extends SchemaAlteringStatement
whereClauseText,
viewCfm);
logger.warn("Creating materialized view {} for {}.{}. " +
"Materialized views are experimental and are not recommended for production use.",
definition.viewName, cfm.ksName, cfm.cfName);
logger.warn("Creating materialized view {} for {}.{}. {}",
definition.viewName, cfm.ksName, cfm.cfName, View.USAGE_WARNING);
try
{
ClientWarn.instance.warn("Materialized views are experimental and are not recommended for production use.");
ClientWarn.instance.warn(View.USAGE_WARNING);
MigrationManager.announceNewView(definition, isLocalOnly);
return new Event.SchemaChange(Event.SchemaChange.Change.CREATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
}

View File

@ -33,7 +33,6 @@ import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.config.Schema;
import org.apache.cassandra.config.ViewDefinition;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.MultiColumnRelation;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.Relation;
@ -57,6 +56,8 @@ import org.apache.cassandra.utils.FBUtilities;
*/
public class View
{
public final static String USAGE_WARNING = "Materialized views are experimental and are not recommended for production use.";
private static final Logger logger = LoggerFactory.getLogger(View.class);
public final String name;

View File

@ -59,6 +59,8 @@ import org.apache.cassandra.utils.concurrent.OpOrder;
public class SASIIndex implements Index, INotificationConsumer
{
public final static String USAGE_WARNING = "SASI indexes are experimental and are not recommended for production use.";
private static class SASIIndexBuildingSupport implements IndexBuildingSupport
{
public SecondaryIndexBuilder getIndexBuildTask(ColumnFamilyStore cfs,

View File

@ -18,12 +18,9 @@
package org.apache.cassandra.cql3;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import com.google.common.util.concurrent.Uninterruptibles;
@ -43,14 +40,16 @@ import org.apache.cassandra.concurrent.Stage;
import org.apache.cassandra.concurrent.StageManager;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.db.ColumnFamilyStore;
import org.apache.cassandra.db.Keyspace;
import org.apache.cassandra.db.SystemKeyspace;
import org.apache.cassandra.db.compaction.CompactionManager;
import org.apache.cassandra.db.marshal.AsciiType;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.db.view.View;
import org.apache.cassandra.exceptions.SyntaxException;
import org.apache.cassandra.schema.KeyspaceParams;
import org.apache.cassandra.service.ClientWarn;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.FBUtilities;
@ -1421,4 +1420,52 @@ public class ViewTest extends CQLTester
{
execute("CREATE MATERIALIZED VIEW myview AS SELECT a, b FROM \"\" WHERE b IS NOT NULL PRIMARY KEY (b, a)");
}
/**
* Tests that a client warning is issued on materialized view creation.
*/
@Test
public void testClientWarningOnCreate() throws Throwable
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, v int)");
ClientWarn.instance.captureWarnings();
String viewName = keyspace() + ".warning_view";
execute("CREATE MATERIALIZED VIEW " + viewName +
" AS SELECT v FROM %s WHERE k IS NOT NULL AND v IS NOT NULL PRIMARY KEY (v, k)");
views.add(viewName);
List<String> warnings = ClientWarn.instance.getWarnings();
Assert.assertNotNull(warnings);
Assert.assertEquals(1, warnings.size());
Assert.assertEquals(View.USAGE_WARNING, warnings.get(0));
}
/**
* Tests the configuration flag to disable materialized views.
*/
@Test
public void testDisableMaterializedViews() throws Throwable
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, v int)");
executeNet(protocolVersion, "USE " + keyspace());
boolean enableMaterializedViews = DatabaseDescriptor.getEnableMaterializedViews();
try
{
DatabaseDescriptor.setEnableMaterializedViews(false);
createView("view1", "CREATE MATERIALIZED VIEW %s AS SELECT v FROM %%s WHERE k IS NOT NULL AND v IS NOT NULL PRIMARY KEY (v, k)");
Assert.fail("Should not be able to create a materialized view if they are disabled");
}
catch (Throwable e)
{
Assert.assertTrue(e instanceof InvalidQueryException);
Assert.assertTrue(e.getMessage().contains("Materialized views are disabled"));
}
finally
{
DatabaseDescriptor.setEnableMaterializedViews(enableMaterializedViews);
}
}
}

View File

@ -28,7 +28,10 @@ import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.SimpleStatement;
import junit.framework.Assert;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQLTester;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.service.ClientWarn;
public class SASICQLTest extends CQLTester
{
@ -78,4 +81,49 @@ public class SASICQLTest extends CQLTester
Assert.assertEquals(20, rs.size());
}
}
/**
* Tests that a client warning is issued on SASI index creation.
*/
@Test
public void testClientWarningOnCreate()
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, v int)");
ClientWarn.instance.captureWarnings();
createIndex("CREATE CUSTOM INDEX ON %s (v) USING 'org.apache.cassandra.index.sasi.SASIIndex'");
List<String> warnings = ClientWarn.instance.getWarnings();
Assert.assertNotNull(warnings);
Assert.assertEquals(1, warnings.size());
Assert.assertEquals(SASIIndex.USAGE_WARNING, warnings.get(0));
}
/**
* Tests the configuration flag to disable SASI indexes.
*/
@Test
public void testDisableSASIIndexes()
{
createTable("CREATE TABLE %s (k int PRIMARY KEY, v int)");
boolean enableSASIIndexes = DatabaseDescriptor.getEnableSASIIndexes();
try
{
DatabaseDescriptor.setEnableSASIIndexes(false);
createIndex("CREATE CUSTOM INDEX ON %s (v) USING 'org.apache.cassandra.index.sasi.SASIIndex'");
Assert.fail("Should not be able to create a SASI index if they are disabled");
}
catch (RuntimeException e)
{
Throwable cause = e.getCause();
Assert.assertNotNull(cause);
Assert.assertTrue(cause instanceof InvalidRequestException);
Assert.assertTrue(cause.getMessage().contains("SASI indexes are disabled"));
}
finally
{
DatabaseDescriptor.setEnableSASIIndexes(enableSASIIndexes);
}
}
}