mirror of https://github.com/apache/cassandra
Send back client warning if creating too many tables/keyspaces
Patch by marcuse; reviewed by Alex Petrov, Brandon Williams, Yifan Cai for CASSANDRA-16309
This commit is contained in:
parent
1515a6e60c
commit
786cb11e18
|
|
@ -1,4 +1,5 @@
|
|||
4.0-beta4
|
||||
* Send back client warnings when creating too many tables/keyspaces (CASSANDRA-16309)
|
||||
* Add dedicated tcp user timeout for streaming connection (CASSANDRA-16143)
|
||||
* Add generatetokens script for offline token allocation strategy generation (CASSANDRA-16205)
|
||||
* Remove Windows scripts (CASSANDRA-16171)
|
||||
|
|
|
|||
|
|
@ -1404,6 +1404,12 @@ repaired_data_tracking_for_partition_reads_enabled: false
|
|||
# mismatches are less actionable than confirmed ones.
|
||||
report_unconfirmed_repaired_data_mismatches: false
|
||||
|
||||
# Having many tables and/or keyspaces negatively affects performance of many operations in the
|
||||
# cluster. When the number of tables/keyspaces in the cluster exceeds the following thresholds
|
||||
# a client warning will be sent back to the user when creating a table or keyspace.
|
||||
# table_count_warn_threshold: 150
|
||||
# keyspace_count_warn_threshold: 40
|
||||
|
||||
#########################
|
||||
# EXPERIMENTAL FEATURES #
|
||||
#########################
|
||||
|
|
|
|||
|
|
@ -553,6 +553,9 @@ public class Config
|
|||
isClientMode = clientMode;
|
||||
}
|
||||
|
||||
public volatile int table_count_warn_threshold = 150;
|
||||
public volatile int keyspace_count_warn_threshold = 40;
|
||||
|
||||
public static Supplier<Config> getOverrideLoadConfig()
|
||||
{
|
||||
return overrideLoadConfig;
|
||||
|
|
|
|||
|
|
@ -3273,5 +3273,25 @@ public class DatabaseDescriptor
|
|||
conf.auto_optimise_preview_repair_streams = enabled;
|
||||
}
|
||||
|
||||
public static int tableCountWarnThreshold()
|
||||
{
|
||||
return conf.table_count_warn_threshold;
|
||||
}
|
||||
|
||||
public static void setTableCountWarnThreshold(int value)
|
||||
{
|
||||
conf.table_count_warn_threshold = value;
|
||||
}
|
||||
|
||||
public static int keyspaceCountWarnThreshold()
|
||||
{
|
||||
return conf.keyspace_count_warn_threshold;
|
||||
}
|
||||
|
||||
public static void setKeyspaceCountWarnThreshold(int value)
|
||||
{
|
||||
conf.keyspace_count_warn_threshold = value;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,13 @@ import java.util.Set;
|
|||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.audit.AuditLogContext;
|
||||
import org.apache.cassandra.audit.AuditLogEntryType;
|
||||
import org.apache.cassandra.auth.*;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.CQLStatement;
|
||||
import org.apache.cassandra.exceptions.AlreadyExistsException;
|
||||
import org.apache.cassandra.locator.LocalStrategy;
|
||||
|
|
@ -31,12 +35,15 @@ import org.apache.cassandra.schema.KeyspaceMetadata;
|
|||
import org.apache.cassandra.schema.KeyspaceParams.Option;
|
||||
import org.apache.cassandra.schema.Keyspaces;
|
||||
import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
|
||||
import org.apache.cassandra.schema.Schema;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.transport.Event.SchemaChange;
|
||||
import org.apache.cassandra.transport.Event.SchemaChange.Change;
|
||||
|
||||
public final class CreateKeyspaceStatement extends AlterSchemaStatement
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(CreateKeyspaceStatement.class);
|
||||
|
||||
private final KeyspaceAttributes attrs;
|
||||
private final boolean ifNotExists;
|
||||
|
||||
|
|
@ -99,6 +106,20 @@ public final class CreateKeyspaceStatement extends AlterSchemaStatement
|
|||
return String.format("%s (%s)", getClass().getSimpleName(), keyspaceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<String> clientWarnings(KeyspacesDiff diff)
|
||||
{
|
||||
int keyspaceCount = Schema.instance.getKeyspaces().size();
|
||||
if (keyspaceCount > DatabaseDescriptor.keyspaceCountWarnThreshold())
|
||||
{
|
||||
String msg = String.format("Cluster already contains %d keyspaces. Having a large number of keyspaces will significantly slow down schema dependent cluster operations.",
|
||||
keyspaceCount);
|
||||
logger.warn(msg);
|
||||
return ImmutableSet.of(msg);
|
||||
}
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
public static final class Raw extends CQLStatement.Raw
|
||||
{
|
||||
public final String keyspaceName;
|
||||
|
|
|
|||
|
|
@ -23,11 +23,15 @@ import com.google.common.collect.ImmutableSet;
|
|||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.audit.AuditLogContext;
|
||||
import org.apache.cassandra.audit.AuditLogEntryType;
|
||||
import org.apache.cassandra.auth.DataResource;
|
||||
import org.apache.cassandra.auth.IResource;
|
||||
import org.apache.cassandra.auth.Permission;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.*;
|
||||
import org.apache.cassandra.db.marshal.*;
|
||||
import org.apache.cassandra.exceptions.AlreadyExistsException;
|
||||
|
|
@ -45,6 +49,7 @@ import static com.google.common.collect.Iterables.concat;
|
|||
|
||||
public final class CreateTableStatement extends AlterSchemaStatement
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(CreateTableStatement.class);
|
||||
private final String tableName;
|
||||
|
||||
private final Map<ColumnIdentifier, CQL3Type.Raw> rawColumns;
|
||||
|
|
@ -364,6 +369,21 @@ public final class CreateTableStatement extends AlterSchemaStatement
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> clientWarnings(KeyspacesDiff diff)
|
||||
{
|
||||
int tableCount = Schema.instance.getNumberOfTables();
|
||||
if (tableCount > DatabaseDescriptor.tableCountWarnThreshold())
|
||||
{
|
||||
String msg = String.format("Cluster already contains %d tables in %d keyspaces. Having a large number of tables will significantly slow down schema dependent cluster operations.",
|
||||
tableCount,
|
||||
Schema.instance.getKeyspaces().size());
|
||||
logger.warn(msg);
|
||||
return ImmutableSet.of(msg);
|
||||
}
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
private static class DefaultNames
|
||||
{
|
||||
private static final String DEFAULT_CLUSTERING_NAME = "column";
|
||||
|
|
|
|||
|
|
@ -5810,4 +5810,30 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
|||
{
|
||||
DatabaseDescriptor.setAutoOptimisePreviewRepairStreams(enabled);
|
||||
}
|
||||
|
||||
public int getTableCountWarnThreshold()
|
||||
{
|
||||
return DatabaseDescriptor.tableCountWarnThreshold();
|
||||
}
|
||||
|
||||
public void setTableCountWarnThreshold(int value)
|
||||
{
|
||||
if (value < 0)
|
||||
throw new IllegalStateException("Table count warn threshold should be positive, not "+value);
|
||||
logger.info("Changing table count warn threshold from {} to {}", getTableCountWarnThreshold(), value);
|
||||
DatabaseDescriptor.setTableCountWarnThreshold(value);
|
||||
}
|
||||
|
||||
public int getKeyspaceCountWarnThreshold()
|
||||
{
|
||||
return DatabaseDescriptor.keyspaceCountWarnThreshold();
|
||||
}
|
||||
|
||||
public void setKeyspaceCountWarnThreshold(int value)
|
||||
{
|
||||
if (value < 0)
|
||||
throw new IllegalStateException("Keyspace count warn threshold should be positive, not "+value);
|
||||
logger.info("Changing keyspace count warn threshold from {} to {}", getKeyspaceCountWarnThreshold(), value);
|
||||
DatabaseDescriptor.setKeyspaceCountWarnThreshold(value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -837,4 +837,9 @@ public interface StorageServiceMBean extends NotificationEmitter
|
|||
public void setAutoOptimiseFullRepairStreams(boolean enabled);
|
||||
public boolean autoOptimisePreviewRepairStreams();
|
||||
public void setAutoOptimisePreviewRepairStreams(boolean enabled);
|
||||
|
||||
int getTableCountWarnThreshold();
|
||||
void setTableCountWarnThreshold(int value);
|
||||
int getKeyspaceCountWarnThreshold();
|
||||
void setKeyspaceCountWarnThreshold(int value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,22 @@
|
|||
*/
|
||||
package org.apache.cassandra.schema;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.CQLTester;
|
||||
import org.apache.cassandra.cql3.QueryOptions;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.transport.Message;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.transport.Server;
|
||||
import org.apache.cassandra.transport.SimpleClient;
|
||||
import org.apache.cassandra.transport.messages.QueryMessage;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class CreateTableValidationTest extends CQLTester
|
||||
|
|
@ -48,4 +60,43 @@ public class CreateTableValidationTest extends CQLTester
|
|||
// sanity check
|
||||
createTable("CREATE TABLE %s (a int PRIMARY KEY, b int) WITH bloom_filter_fp_chance = 0.1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateKeyspaceTableWarning() throws IOException
|
||||
{
|
||||
requireNetwork();
|
||||
int tableCountWarn = DatabaseDescriptor.tableCountWarnThreshold();
|
||||
int keyspaceCountWarn = DatabaseDescriptor.keyspaceCountWarnThreshold();
|
||||
DatabaseDescriptor.setTableCountWarnThreshold(Schema.instance.getNumberOfTables());
|
||||
DatabaseDescriptor.setKeyspaceCountWarnThreshold(Schema.instance.getKeyspaces().size());
|
||||
|
||||
try (SimpleClient client = newSimpleClient(ProtocolVersion.CURRENT).connect(false))
|
||||
{
|
||||
String createKeyspace = "CREATE KEYSPACE createkswarning%d WITH REPLICATION={'class':'org.apache.cassandra.locator.NetworkTopologyStrategy','datacenter1':'2'}";
|
||||
QueryMessage query = new QueryMessage(String.format(createKeyspace, 1), QueryOptions.DEFAULT);
|
||||
Message.Response resp = client.execute(query);
|
||||
assertTrue(resp.getWarnings().size() > 0);
|
||||
assertTrue(resp.getWarnings().get(0).contains("Having a large number of keyspaces will significantly"));
|
||||
|
||||
DatabaseDescriptor.setKeyspaceCountWarnThreshold(Schema.instance.getKeyspaces().size() + 1);
|
||||
query = new QueryMessage(String.format(createKeyspace, 2), QueryOptions.DEFAULT);
|
||||
resp = client.execute(query);
|
||||
assertTrue(resp.getWarnings() == null || resp.getWarnings().isEmpty());
|
||||
|
||||
query = new QueryMessage(String.format("CREATE TABLE %s.%s (id int primary key, x int)", KEYSPACE, "test1"), QueryOptions.DEFAULT);
|
||||
resp = client.execute(query);
|
||||
assertTrue(resp.getWarnings().size() > 0);
|
||||
assertTrue(resp.getWarnings().get(0).contains("Having a large number of tables"));
|
||||
|
||||
DatabaseDescriptor.setTableCountWarnThreshold(Schema.instance.getNumberOfTables() + 1);
|
||||
query = new QueryMessage(String.format("CREATE TABLE %s.%s (id int primary key, x int)", KEYSPACE, "test2"), QueryOptions.DEFAULT);
|
||||
resp = client.execute(query);
|
||||
assertTrue(resp.getWarnings() == null || resp.getWarnings().isEmpty());
|
||||
}
|
||||
finally
|
||||
{
|
||||
DatabaseDescriptor.setTableCountWarnThreshold(tableCountWarn);
|
||||
DatabaseDescriptor.setKeyspaceCountWarnThreshold(keyspaceCountWarn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue