mirror of https://github.com/apache/cassandra
Add guardrail to disallow creation of uncompressed sstables
Patch by Josh McKenzie; reviewed by David Capwell for CASSANDRA-17504
This commit is contained in:
parent
01c4404fff
commit
105d69fdc5
|
|
@ -1,4 +1,5 @@
|
|||
4.1
|
||||
* 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)
|
||||
* remove outdated code from cqlsh (CASSANDRA-17490)
|
||||
|
|
|
|||
|
|
@ -1609,6 +1609,8 @@ drop_compact_storage_enabled: false
|
|||
# The two thresholds default to -1 to disable.
|
||||
# tables_warn_threshold: -1
|
||||
# tables_fail_threshold: -1
|
||||
# Guardrail to enable or disable the ability to create uncompressed tables
|
||||
# uncompressed_tables_enabled: true
|
||||
# Guardrail to warn or fail when creating/altering a table with more columns per table than threshold.
|
||||
# The two thresholds default to -1 to disable.
|
||||
# columns_per_table_warn_threshold: -1
|
||||
|
|
|
|||
|
|
@ -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 uncompressed_tables_enabled = true;
|
||||
public volatile boolean compact_tables_enabled = true;
|
||||
public volatile boolean read_before_write_list_operations_enabled = true;
|
||||
public volatile DataStorageSpec collection_size_warn_threshold = DISABLED_SIZE_GUARDRAIL;
|
||||
|
|
|
|||
|
|
@ -332,6 +332,20 @@ public class GuardrailsOptions implements GuardrailsConfig
|
|||
x -> config.user_timestamps_enabled = x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getUncompressedTablesEnabled()
|
||||
{
|
||||
return config.uncompressed_tables_enabled;
|
||||
}
|
||||
|
||||
public void setUncompressedTablesEnabled(boolean enabled)
|
||||
{
|
||||
updatePropertyWithLogging("uncompressed_tables_enabled",
|
||||
enabled,
|
||||
() -> config.uncompressed_tables_enabled,
|
||||
x -> config.uncompressed_tables_enabled = x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getCompactTablesEnabled()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import org.apache.cassandra.transport.messages.ResultMessage;
|
|||
abstract public class AlterSchemaStatement implements CQLStatement.SingleKeyspaceCqlStatement, SchemaTransformation
|
||||
{
|
||||
protected final String keyspaceName; // name of the keyspace affected by the statement
|
||||
protected ClientState state;
|
||||
|
||||
protected AlterSchemaStatement(String keyspaceName)
|
||||
{
|
||||
|
|
@ -46,7 +47,10 @@ abstract public class AlterSchemaStatement implements CQLStatement.SingleKeyspac
|
|||
|
||||
public void validate(ClientState state)
|
||||
{
|
||||
// no-op; validation is performed while executing the statement, in apply()
|
||||
// validation is performed while executing the statement, in apply()
|
||||
|
||||
// Cache our ClientState for use by guardrails
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public ResultMessage execute(QueryState state, QueryOptions options, long queryStartNanoTime)
|
||||
|
|
|
|||
|
|
@ -171,7 +171,6 @@ public abstract class AlterTableStatement extends AlterSchemaStatement
|
|||
|
||||
private final Collection<Column> newColumns;
|
||||
private final boolean ifColumnNotExists;
|
||||
private ClientState state;
|
||||
|
||||
private AddColumns(String keyspaceName, String tableName, Collection<Column> newColumns, boolean ifTableExists, boolean ifColumnNotExists)
|
||||
{
|
||||
|
|
@ -184,9 +183,6 @@ public abstract class AlterTableStatement extends AlterSchemaStatement
|
|||
public void validate(ClientState state)
|
||||
{
|
||||
super.validate(state);
|
||||
|
||||
// save the query state to use it for guardrails validation in #apply
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public KeyspaceMetadata apply(KeyspaceMetadata keyspace, TableMetadata table)
|
||||
|
|
@ -461,6 +457,9 @@ public abstract class AlterTableStatement extends AlterSchemaStatement
|
|||
throw ire("read_repair must be set to 'NONE' for transiently replicated keyspaces");
|
||||
}
|
||||
|
||||
if (!params.compression.isEnabled())
|
||||
Guardrails.uncompressedTablesEnabled.ensureEnabled(state);
|
||||
|
||||
return keyspace.withSwapped(keyspace.tables.withSwapped(table.withSwapped(params)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,6 +117,9 @@ public final class CreateTableStatement extends AlterSchemaStatement
|
|||
throw ire("read_repair must be set to 'NONE' for transiently replicated keyspaces");
|
||||
}
|
||||
|
||||
if (!table.params.compression.isEnabled())
|
||||
Guardrails.uncompressedTablesEnabled.ensureEnabled(state);
|
||||
|
||||
return schema.withAddedOrUpdated(keyspace.withSwapped(keyspace.tables.with(table)));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -129,6 +129,14 @@ public final class Guardrails implements GuardrailsMBean
|
|||
state -> !CONFIG_PROVIDER.getOrCreate(state).getUserTimestampsEnabled(),
|
||||
"User provided timestamps (USING TIMESTAMP)");
|
||||
|
||||
/**
|
||||
* Guardrail disabling user's ability to turn off compression
|
||||
*/
|
||||
public static final DisableFlag uncompressedTablesEnabled =
|
||||
new DisableFlag("uncompressed_tables_enabled",
|
||||
state -> !CONFIG_PROVIDER.getOrCreate(state).getUncompressedTablesEnabled(),
|
||||
"Uncompressed table");
|
||||
|
||||
/**
|
||||
* Guardrail disabling the creation of new COMPACT STORAGE tables
|
||||
*/
|
||||
|
|
@ -464,6 +472,18 @@ public final class Guardrails implements GuardrailsMBean
|
|||
DEFAULT_CONFIG.setUserTimestampsEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getUncompressedTablesEnabled()
|
||||
{
|
||||
return DEFAULT_CONFIG.getUncompressedTablesEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUncompressedTablesEnabled(boolean enabled)
|
||||
{
|
||||
DEFAULT_CONFIG.setUncompressedTablesEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getCompactTablesEnabled()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@ public interface GuardrailsConfig
|
|||
*/
|
||||
int getMaterializedViewsPerTableWarnThreshold();
|
||||
|
||||
|
||||
/**
|
||||
* @return The threshold to warn when partition keys in select more than threshold.
|
||||
*/
|
||||
|
|
@ -136,6 +135,13 @@ public interface GuardrailsConfig
|
|||
*/
|
||||
boolean getUserTimestampsEnabled();
|
||||
|
||||
/**
|
||||
* Returns whether tables can be uncompressed
|
||||
*
|
||||
* @return {@code true} if user's can disable compression, {@code false} otherwise.
|
||||
*/
|
||||
boolean getUncompressedTablesEnabled();
|
||||
|
||||
/**
|
||||
* Returns whether users can create new COMPACT STORAGE tables
|
||||
*
|
||||
|
|
|
|||
|
|
@ -211,6 +211,20 @@ public interface GuardrailsMBean
|
|||
*/
|
||||
void setUserTimestampsEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Returns whether users can disable compression on tables
|
||||
*
|
||||
* @return {@code true} if users can disable compression on a table, {@code false} otherwise.
|
||||
*/
|
||||
boolean getUncompressedTablesEnabled();
|
||||
|
||||
/**
|
||||
* Sets whether users can disable compression on tables
|
||||
*
|
||||
* @param enabled {@code true} if users can disable compression on a table, {@code false} otherwise.
|
||||
*/
|
||||
void setUncompressedTablesEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Returns whether users can create new COMPACT STORAGE tables
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.schema.Schema;
|
||||
import org.apache.cassandra.schema.TableMetadata;
|
||||
|
||||
public class GuardrailAllowUncompressedTables extends GuardrailTester
|
||||
{
|
||||
private void setGuardrail(boolean enabled)
|
||||
{
|
||||
guardrails().setUncompressedTablesEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the guardrail has been set, creating tables with compression disabled should work
|
||||
*/
|
||||
@Test
|
||||
public void createSuccess()
|
||||
{
|
||||
setGuardrail(true);
|
||||
String table = createTableName();
|
||||
schemaChange(String.format("CREATE TABLE %s.%s (k int primary key, v int) WITH compression={'sstable_compression':''}", KEYSPACE, table));
|
||||
TableMetadata tmd = Schema.instance.getTableMetadata(KEYSPACE, table);
|
||||
Assert.assertFalse(tmd.params.compression.isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* If the guardrail is false, creating tables with compression disabled should fail
|
||||
*/
|
||||
@Test
|
||||
public void createFailure() throws Throwable
|
||||
{
|
||||
setGuardrail(false);
|
||||
String table = createTableName();
|
||||
assertFails(String.format("CREATE TABLE %s.%s (k int primary key, v int) WITH compression={'sstable_compression':''}", KEYSPACE, table), "Uncompressed table is not allowed");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void alterSuccess()
|
||||
{
|
||||
setGuardrail(true);
|
||||
String table = createTableName();
|
||||
schemaChange(String.format("CREATE TABLE %s.%s (k int primary key, v int)", KEYSPACE, table));
|
||||
schemaChange(String.format("ALTER TABLE %s.%s WITH compression = {'sstable_compression': ''}", KEYSPACE, table));
|
||||
TableMetadata tmd = Schema.instance.getTableMetadata(KEYSPACE, table);
|
||||
Assert.assertFalse(tmd.params.compression.isEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void alterFailure() throws Throwable
|
||||
{
|
||||
setGuardrail(false);
|
||||
String table = createTableName();
|
||||
schemaChange(String.format("CREATE TABLE %s.%s (k int primary key, v int)", KEYSPACE, table));
|
||||
assertFails(String.format("ALTER TABLE %s.%s WITH compression = {'sstable_compression': ''}", KEYSPACE, table), "Uncompressed table is not allowed");
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue