You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by jm...@apache.org on 2022/04/07 19:53:51 UTC

[cassandra] branch trunk updated: Add guardrail to disallow creation of secondary indexes

This is an automated email from the ASF dual-hosted git repository.

jmckenzie pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 910bbb9b5f Add guardrail to disallow creation of secondary indexes
910bbb9b5f is described below

commit 910bbb9b5fced249696930c2e38240a9b0f51bb5
Author: Josh McKenzie <jm...@apache.org>
AuthorDate: Tue Mar 29 14:18:10 2022 -0400

    Add guardrail to disallow creation of secondary indexes
    
    Patch by Josh McKenzie; reviewed by Chris Lohfink for CASSANDRA-17498
---
 CHANGES.txt                                        |  1 +
 conf/cassandra.yaml                                |  2 +
 src/java/org/apache/cassandra/config/Config.java   |  1 +
 .../apache/cassandra/config/GuardrailsOptions.java | 14 ++++
 .../statements/schema/CreateIndexStatement.java    |  2 +
 .../apache/cassandra/db/guardrails/Guardrails.java | 20 ++++++
 .../cassandra/db/guardrails/GuardrailsConfig.java  |  5 ++
 .../cassandra/db/guardrails/GuardrailsMBean.java   | 11 +++
 .../guardrails/GuardrailSecondaryIndexTester.java  | 84 ++++++++++++++++++++++
 9 files changed, 140 insertions(+)

diff --git a/CHANGES.txt b/CHANGES.txt
index 9ded13f525..54fa1e8ec6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 4.1
+ * Add guardrail for creation of secondary indexes (CASSANDRA-17498)
  * Add guardrail to disallow creation of uncompressed tables (CASSANDRA-17504)
  * Add guardrail to disallow creation of new COMPACT STORAGE tables (CASSANDRA-17522)
  * repair vtables should expose a completed field due to lack of filtering options in CQL (CASSANDRA-17520)
diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml
index df1eeb259b..1a876ca934 100644
--- a/conf/cassandra.yaml
+++ b/conf/cassandra.yaml
@@ -1619,6 +1619,8 @@ drop_compact_storage_enabled: false
 # The two thresholds default to -1 to disable.
 # secondary_indexes_per_table_warn_threshold: -1
 # secondary_indexes_per_table_fail_threshold: -1
+# Guardrail to enable or disable the creation of secondary indexes
+# secondary_indexes_enabled: true
 # Guardrail to warn or fail when creating more materialized views per table than threshold.
 # The two thresholds default to -1 to disable.
 # materialized_views_per_table_warn_threshold: -1
diff --git a/src/java/org/apache/cassandra/config/Config.java b/src/java/org/apache/cassandra/config/Config.java
index 00db7ea859..e0dc5767c6 100644
--- a/src/java/org/apache/cassandra/config/Config.java
+++ b/src/java/org/apache/cassandra/config/Config.java
@@ -800,6 +800,7 @@ public class Config
     public volatile Set<ConsistencyLevel> write_consistency_levels_warned = Collections.emptySet();
     public volatile Set<ConsistencyLevel> write_consistency_levels_disallowed = Collections.emptySet();
     public volatile boolean user_timestamps_enabled = true;
+    public volatile boolean secondary_indexes_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/GuardrailsOptions.java b/src/java/org/apache/cassandra/config/GuardrailsOptions.java
index 405cca7ee3..d08f8c555a 100644
--- a/src/java/org/apache/cassandra/config/GuardrailsOptions.java
+++ b/src/java/org/apache/cassandra/config/GuardrailsOptions.java
@@ -332,6 +332,20 @@ public class GuardrailsOptions implements GuardrailsConfig
                                   x -> config.user_timestamps_enabled = x);
     }
 
+    @Override
+    public boolean getSecondaryIndexesEnabled()
+    {
+        return config.secondary_indexes_enabled;
+    }
+
+    public void setSecondaryIndexesEnabled(boolean enabled)
+    {
+        updatePropertyWithLogging("secondary_indexes_enabled",
+                                  enabled,
+                                  () -> config.secondary_indexes_enabled,
+                                  x -> config.secondary_indexes_enabled = x);
+    }
+
     @Override
     public boolean getUncompressedTablesEnabled()
     {
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 686a9cd5d1..7a3a41e618 100644
--- a/src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java
@@ -84,6 +84,8 @@ public final class CreateIndexStatement extends AlterSchemaStatement
     {
         attrs.validate();
 
+        Guardrails.createSecondaryIndexesEnabled.ensureEnabled("Creating secondary indexes", state);
+
         if (attrs.isCustom && attrs.customClass.equals(SASIIndex.class.getName()) && !DatabaseDescriptor.getSASIIndexesEnabled())
             throw new InvalidRequestException("SASI indexes are disabled. Enable in cassandra.yaml to use.");
 
diff --git a/src/java/org/apache/cassandra/db/guardrails/Guardrails.java b/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
index 6e08660b2a..824160491f 100644
--- a/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
+++ b/src/java/org/apache/cassandra/db/guardrails/Guardrails.java
@@ -98,6 +98,14 @@ public final class Guardrails implements GuardrailsMBean
                             : format("Tables cannot have more than %s secondary indexes, aborting the creation of secondary index %s",
                                      threshold, what));
 
+    /**
+     * Guardrail disabling user's ability to create secondary indexes
+     */
+    public static final DisableFlag createSecondaryIndexesEnabled =
+    new DisableFlag("secondary_indexes",
+                    state -> !CONFIG_PROVIDER.getOrCreate(state).getSecondaryIndexesEnabled(),
+                    "User creation of secondary indexes");
+
     /**
      * Guardrail on the number of materialized views per table.
      */
@@ -355,6 +363,18 @@ public final class Guardrails implements GuardrailsMBean
         DEFAULT_CONFIG.setSecondaryIndexesPerTableThreshold(warn, fail);
     }
 
+    @Override
+    public boolean getSecondaryIndexesEnabled()
+    {
+        return DEFAULT_CONFIG.getSecondaryIndexesEnabled();
+    }
+
+    @Override
+    public void setSecondaryIndexesEnabled(boolean enabled)
+    {
+        DEFAULT_CONFIG.setSecondaryIndexesEnabled(enabled);
+    }
+
     @Override
     public int getMaterializedViewsPerTableWarnThreshold()
     {
diff --git a/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java b/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
index 3b3473a288..f95989fcf7 100644
--- a/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
+++ b/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java
@@ -93,6 +93,11 @@ public interface GuardrailsConfig
      */
     int getSecondaryIndexesPerTableFailThreshold();
 
+    /**
+     * @return Whether creation of secondary indexes is allowed.
+     */
+    boolean getSecondaryIndexesEnabled();
+
     /**
      * @return The threshold to warn when creating more materialized views per table than threshold.
      */
diff --git a/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java b/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
index 77f0d2dfc4..8d151a1032 100644
--- a/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
+++ b/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java
@@ -119,6 +119,17 @@ public interface GuardrailsMBean
      */
     void setSecondaryIndexesPerTableThreshold(int warn, int fail);
 
+    /**
+     * @return Whether secondary index creation is active or not on the node
+     */
+    boolean getSecondaryIndexesEnabled();
+
+    /**
+     * Enables or disables the ability to create secondary indexes
+     * @param enabled
+     */
+    void setSecondaryIndexesEnabled(boolean enabled);
+
     /**
      * @return The threshold to warn when creating more materialized views per table than threshold.
      * -1 means disabled.
diff --git a/test/unit/org/apache/cassandra/db/guardrails/GuardrailSecondaryIndexTester.java b/test/unit/org/apache/cassandra/db/guardrails/GuardrailSecondaryIndexTester.java
new file mode 100644
index 0000000000..53ba1b5eb6
--- /dev/null
+++ b/test/unit/org/apache/cassandra/db/guardrails/GuardrailSecondaryIndexTester.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.db.guardrails;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static java.lang.String.format;
+
+/**
+ * Tests the guardrail for disabling user creation of secondary indexes, {@link Guardrails#setSecondaryIndexesEnabled(boolean)}.
+ */
+public class GuardrailSecondaryIndexTester extends GuardrailTester
+{
+    public GuardrailSecondaryIndexTester()
+    {
+        super(Guardrails.createSecondaryIndexesEnabled);
+    }
+
+    @Before
+    public void setupTest()
+    {
+        createTable("CREATE TABLE %s (k int PRIMARY KEY, v1 int, v2 int, v3 int, v4 int)");
+    }
+
+    private void setGuardrail(boolean enabled)
+    {
+        guardrails().setSecondaryIndexesEnabled(enabled);
+    }
+
+    @Test
+    public void testCreateIndex() throws Throwable
+    {
+        setGuardrail(true);
+        assertValid(String.format("CREATE INDEX %s ON %s.%s(%s)", "v1_idx", keyspace(), currentTable(), "v1"));
+        assertValid(String.format("CREATE INDEX %s ON %s.%s(%s)", "v2_idx", keyspace(), currentTable(), "v2"));
+
+        setGuardrail(false);
+        assertFails(String.format("CREATE INDEX %s ON %s.%s(%s)", "v3_idx", keyspace(), currentTable(), "v3"), "Creating secondary indexes");
+        assertFails(String.format("CREATE INDEX %s ON %s.%s(%s)", "v4_idx", keyspace(), currentTable(), "v4"), "Creating secondary indexes");
+        assertFails(String.format("CREATE INDEX %s ON %s.%s(%s)", "v2_idx", keyspace(), currentTable(), "v2"), "Creating secondary indexes");
+
+        setGuardrail(true);
+        assertValid(String.format("CREATE INDEX %s ON %s.%s(%s)", "v3_idx", keyspace(), currentTable(), "v3"));
+        assertValid(String.format("CREATE INDEX %s ON %s.%s(%s)", "v4_idx", keyspace(), currentTable(), "v4"));
+
+        // Confirm can drop in either state
+        setGuardrail(false);
+        dropIndex(format("DROP INDEX %s.%s", keyspace(), "v1_idx"));
+
+        setGuardrail(true);
+        dropIndex(format("DROP INDEX %s.%s", keyspace(), "v2_idx"));
+    }
+
+    @Test
+    public void testCustomIndex() throws Throwable
+    {
+        // 2i guardrail will also affect custom indexes
+        setGuardrail(false);
+        assertFails(format("CREATE CUSTOM INDEX ON %%s (%s) USING 'org.apache.cassandra.index.sasi.SASIIndex'", "v4"),
+                    format("Creating secondary indexes", currentTable())
+        );
+
+        // Confirm custom creation will work on flip
+        setGuardrail(true);
+        assertValid(format("CREATE CUSTOM INDEX ON %%s (%s) USING 'org.apache.cassandra.index.sasi.SASIIndex'", "v4"));
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org