http://git-wip-us.apache.org/repos/asf/cassandra/blob/af3fe39d/src/java/org/apache/cassandra/cache/OHCProvider.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cache/OHCProvider.java b/src/java/org/apache/cassandra/cache/OHCProvider.java index 6f75c74..a465bd9 100644 --- a/src/java/org/apache/cassandra/cache/OHCProvider.java +++ b/src/java/org/apache/cassandra/cache/OHCProvider.java @@ -20,6 +20,7 @@ package org.apache.cassandra.cache; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Iterator; +import java.util.UUID; import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.db.TypeSizes; @@ -28,7 +29,7 @@ import org.apache.cassandra.io.util.DataInputBuffer; import org.apache.cassandra.io.util.DataOutputBuffer; import org.apache.cassandra.io.util.DataOutputBufferFixed; import org.apache.cassandra.io.util.RebufferingInputStream; -import org.apache.cassandra.utils.Pair; +import org.apache.cassandra.schema.TableId; import org.caffinitas.ohc.OHCache; import org.caffinitas.ohc.OHCacheBuilder; @@ -129,8 +130,8 @@ public class OHCProvider implements CacheProvider<RowCacheKey, IRowCacheEntry> DataOutputBuffer dataOutput = new DataOutputBufferFixed(buf); try { - dataOutput.writeUTF(rowCacheKey.ksAndCFName.left); - dataOutput.writeUTF(rowCacheKey.ksAndCFName.right); + rowCacheKey.tableId.serialize(dataOutput); + dataOutput.writeUTF(rowCacheKey.indexName != null ? rowCacheKey.indexName : ""); } catch (IOException e) { @@ -144,12 +145,14 @@ public class OHCProvider implements CacheProvider<RowCacheKey, IRowCacheEntry> { @SuppressWarnings("resource") DataInputBuffer dataInput = new DataInputBuffer(buf, false); - String ksName = null; - String cfName = null; + TableId tableId = null; + String indexName = null; try { - ksName = dataInput.readUTF(); - cfName = dataInput.readUTF(); + tableId = TableId.deserialize(dataInput); + indexName = dataInput.readUTF(); + if (indexName.isEmpty()) + indexName = null; } catch (IOException e) { @@ -157,15 +160,15 @@ public class OHCProvider implements CacheProvider<RowCacheKey, IRowCacheEntry> } byte[] key = new byte[buf.getInt()]; buf.get(key); - return new RowCacheKey(Pair.create(ksName, cfName), key); + return new RowCacheKey(tableId, indexName, key); } public int serializedSize(RowCacheKey rowCacheKey) { - return TypeSizes.sizeof(rowCacheKey.ksAndCFName.left) - + TypeSizes.sizeof(rowCacheKey.ksAndCFName.right) - + 4 - + rowCacheKey.key.length; + return rowCacheKey.tableId.serializedSize() + + TypeSizes.sizeof(rowCacheKey.indexName != null ? rowCacheKey.indexName : "") + + 4 + + rowCacheKey.key.length; } }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/af3fe39d/src/java/org/apache/cassandra/cache/RowCacheKey.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cache/RowCacheKey.java b/src/java/org/apache/cassandra/cache/RowCacheKey.java index e02db42..bbf289a 100644 --- a/src/java/org/apache/cassandra/cache/RowCacheKey.java +++ b/src/java/org/apache/cassandra/cache/RowCacheKey.java @@ -19,32 +19,41 @@ package org.apache.cassandra.cache; import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.Objects; + +import com.google.common.annotations.VisibleForTesting; import org.apache.cassandra.db.DecoratedKey; +import org.apache.cassandra.schema.Schema; +import org.apache.cassandra.schema.TableId; +import org.apache.cassandra.schema.TableMetadata; +import org.apache.cassandra.schema.TableMetadataRef; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.ObjectSizes; -import org.apache.cassandra.utils.Pair; public final class RowCacheKey extends CacheKey { public final byte[] key; - private static final long EMPTY_SIZE = ObjectSizes.measure(new RowCacheKey(null, ByteBufferUtil.EMPTY_BYTE_BUFFER)); + private static final long EMPTY_SIZE = ObjectSizes.measure(new RowCacheKey(null, null, new byte[0])); - public RowCacheKey(Pair<String, String> ksAndCFName, byte[] key) + public RowCacheKey(TableId tableId, String indexName, byte[] key) { - super(ksAndCFName); + super(tableId, indexName); this.key = key; } - public RowCacheKey(Pair<String, String> ksAndCFName, DecoratedKey key) + public RowCacheKey(TableMetadata metadata, DecoratedKey key) { - this(ksAndCFName, key.getKey()); + super(metadata); + this.key = ByteBufferUtil.getArray(key.getKey()); + assert this.key != null; } - public RowCacheKey(Pair<String, String> ksAndCFName, ByteBuffer key) + @VisibleForTesting + public RowCacheKey(TableId tableId, String indexName, ByteBuffer key) { - super(ksAndCFName); + super(tableId, indexName); this.key = ByteBufferUtil.getArray(key); assert this.key != null; } @@ -62,13 +71,16 @@ public final class RowCacheKey extends CacheKey RowCacheKey that = (RowCacheKey) o; - return ksAndCFName.equals(that.ksAndCFName) && Arrays.equals(key, that.key); + return tableId.equals(that.tableId) + && Objects.equals(indexName, that.indexName) + && Arrays.equals(key, that.key); } @Override public int hashCode() { - int result = ksAndCFName.hashCode(); + int result = tableId.hashCode(); + result = 31 * result + Objects.hashCode(indexName); result = 31 * result + (key != null ? Arrays.hashCode(key) : 0); return result; } @@ -76,6 +88,7 @@ public final class RowCacheKey extends CacheKey @Override public String toString() { - return String.format("RowCacheKey(ksAndCFName:%s, key:%s)", ksAndCFName, Arrays.toString(key)); + TableMetadataRef tableRef = Schema.instance.getTableMetadataRef(tableId); + return String.format("RowCacheKey(%s, %s, key:%s)", tableRef, indexName, Arrays.toString(key)); } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/af3fe39d/src/java/org/apache/cassandra/config/CFMetaData.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/CFMetaData.java b/src/java/org/apache/cassandra/config/CFMetaData.java deleted file mode 100644 index c8180f3..0000000 --- a/src/java/org/apache/cassandra/config/CFMetaData.java +++ /dev/null @@ -1,1362 +0,0 @@ -/* - * 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.config; - -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.nio.ByteBuffer; -import java.util.*; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.MoreObjects; -import com.google.common.base.Objects; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.builder.HashCodeBuilder; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.cassandra.auth.DataResource; -import org.apache.cassandra.cql3.ColumnIdentifier; -import org.apache.cassandra.cql3.QueryProcessor; -import org.apache.cassandra.cql3.statements.CFStatement; -import org.apache.cassandra.cql3.statements.CreateTableStatement; -import org.apache.cassandra.db.*; -import org.apache.cassandra.db.compaction.AbstractCompactionStrategy; -import org.apache.cassandra.db.marshal.*; -import org.apache.cassandra.dht.IPartitioner; -import org.apache.cassandra.exceptions.ConfigurationException; -import org.apache.cassandra.exceptions.InvalidRequestException; -import org.apache.cassandra.io.util.DataInputPlus; -import org.apache.cassandra.io.util.DataOutputPlus; -import org.apache.cassandra.schema.*; -import org.apache.cassandra.utils.*; -import org.github.jamm.Unmetered; - -/** - * This class can be tricky to modify. Please read http://wiki.apache.org/cassandra/ConfigurationNotes for how to do so safely. - */ -@Unmetered -public final class CFMetaData -{ - public enum Flag - { - SUPER, COUNTER, DENSE, COMPOUND - } - - private static final Pattern PATTERN_WORD_CHARS = Pattern.compile("\\w+"); - - private static final Logger logger = LoggerFactory.getLogger(CFMetaData.class); - - public static final Serializer serializer = new Serializer(); - - //REQUIRED - public final UUID cfId; // internal id, never exposed to user - public final String ksName; // name of keyspace - public final String cfName; // name of this column family - public final Pair<String, String> ksAndCFName; - public final byte[] ksAndCFBytes; - - private final ImmutableSet<Flag> flags; - private final boolean isDense; - private final boolean isCompound; - private final boolean isSuper; - private final boolean isCounter; - private final boolean isView; - private final boolean isIndex; - - public volatile ClusteringComparator comparator; // bytes, long, timeuuid, utf8, etc. This is built directly from clusteringColumns - public final IPartitioner partitioner; // partitioner the table uses - private volatile AbstractType<?> keyValidator; - - // non-final, for now - public volatile TableParams params = TableParams.DEFAULT; - - private volatile Map<ByteBuffer, DroppedColumn> droppedColumns = new HashMap<>(); - private volatile Triggers triggers = Triggers.none(); - private volatile Indexes indexes = Indexes.none(); - - /* - * All CQL3 columns definition are stored in the columnMetadata map. - * On top of that, we keep separated collection of each kind of definition, to - * 1) allow easy access to each kind and 2) for the partition key and - * clustering key ones, those list are ordered by the "component index" of the - * elements. - */ - private volatile Map<ByteBuffer, ColumnDefinition> columnMetadata = new HashMap<>(); - private volatile List<ColumnDefinition> partitionKeyColumns; // Always of size keyValidator.componentsCount, null padded if necessary - private volatile List<ColumnDefinition> clusteringColumns; // Of size comparator.componentsCount or comparator.componentsCount -1, null padded if necessary - private volatile PartitionColumns partitionColumns; // Always non-PK, non-clustering columns - - // For dense tables, this alias the single non-PK column the table contains (since it can only have one). We keep - // that as convenience to access that column more easily (but we could replace calls by partitionColumns().iterator().next() - // for those tables in practice). - private volatile ColumnDefinition compactValueColumn; - - public final DataResource resource; - - /* - * All of these methods will go away once CFMetaData becomes completely immutable. - */ - public CFMetaData params(TableParams params) - { - this.params = params; - return this; - } - - public CFMetaData bloomFilterFpChance(double prop) - { - params = TableParams.builder(params).bloomFilterFpChance(prop).build(); - return this; - } - - public CFMetaData caching(CachingParams prop) - { - params = TableParams.builder(params).caching(prop).build(); - return this; - } - - public CFMetaData comment(String prop) - { - params = TableParams.builder(params).comment(prop).build(); - return this; - } - - public CFMetaData compaction(CompactionParams prop) - { - params = TableParams.builder(params).compaction(prop).build(); - return this; - } - - public CFMetaData compression(CompressionParams prop) - { - params = TableParams.builder(params).compression(prop).build(); - return this; - } - - public CFMetaData dcLocalReadRepairChance(double prop) - { - params = TableParams.builder(params).dcLocalReadRepairChance(prop).build(); - return this; - } - - public CFMetaData defaultTimeToLive(int prop) - { - params = TableParams.builder(params).defaultTimeToLive(prop).build(); - return this; - } - - public CFMetaData gcGraceSeconds(int prop) - { - params = TableParams.builder(params).gcGraceSeconds(prop).build(); - return this; - } - - public CFMetaData maxIndexInterval(int prop) - { - params = TableParams.builder(params).maxIndexInterval(prop).build(); - return this; - } - - public CFMetaData memtableFlushPeriod(int prop) - { - params = TableParams.builder(params).memtableFlushPeriodInMs(prop).build(); - return this; - } - - public CFMetaData minIndexInterval(int prop) - { - params = TableParams.builder(params).minIndexInterval(prop).build(); - return this; - } - - public CFMetaData readRepairChance(double prop) - { - params = TableParams.builder(params).readRepairChance(prop).build(); - return this; - } - - public CFMetaData crcCheckChance(double prop) - { - params = TableParams.builder(params).crcCheckChance(prop).build(); - return this; - } - - public CFMetaData speculativeRetry(SpeculativeRetryParam prop) - { - params = TableParams.builder(params).speculativeRetry(prop).build(); - return this; - } - - public CFMetaData extensions(Map<String, ByteBuffer> extensions) - { - params = TableParams.builder(params).extensions(extensions).build(); - return this; - } - - public CFMetaData droppedColumns(Map<ByteBuffer, DroppedColumn> cols) - { - droppedColumns = cols; - return this; - } - - public CFMetaData triggers(Triggers prop) - { - triggers = prop; - return this; - } - - public CFMetaData indexes(Indexes indexes) - { - this.indexes = indexes; - return this; - } - - private CFMetaData(String keyspace, - String name, - UUID cfId, - boolean isSuper, - boolean isCounter, - boolean isDense, - boolean isCompound, - boolean isView, - List<ColumnDefinition> partitionKeyColumns, - List<ColumnDefinition> clusteringColumns, - PartitionColumns partitionColumns, - IPartitioner partitioner) - { - this.cfId = cfId; - this.ksName = keyspace; - this.cfName = name; - ksAndCFName = Pair.create(keyspace, name); - byte[] ksBytes = FBUtilities.toWriteUTFBytes(ksName); - byte[] cfBytes = FBUtilities.toWriteUTFBytes(cfName); - ksAndCFBytes = Arrays.copyOf(ksBytes, ksBytes.length + cfBytes.length); - System.arraycopy(cfBytes, 0, ksAndCFBytes, ksBytes.length, cfBytes.length); - - this.isDense = isDense; - this.isCompound = isCompound; - this.isSuper = isSuper; - this.isCounter = isCounter; - this.isView = isView; - - EnumSet<Flag> flags = EnumSet.noneOf(Flag.class); - if (isSuper) - flags.add(Flag.SUPER); - if (isCounter) - flags.add(Flag.COUNTER); - if (isDense) - flags.add(Flag.DENSE); - if (isCompound) - flags.add(Flag.COMPOUND); - this.flags = Sets.immutableEnumSet(flags); - - isIndex = cfName.contains("."); - - assert partitioner != null : "This assertion failure is probably due to accessing Schema.instance " + - "from client-mode tools - See CASSANDRA-8143."; - this.partitioner = partitioner; - - // A compact table should always have a clustering - assert isCQLTable() || !clusteringColumns.isEmpty() : String.format("For table %s.%s, isDense=%b, isCompound=%b, clustering=%s", ksName, cfName, isDense, isCompound, clusteringColumns); - - // All tables should have a partition key - assert !partitionKeyColumns.isEmpty() : String.format("Have no partition keys for table %s.%s", ksName, cfName); - - this.partitionKeyColumns = partitionKeyColumns; - this.clusteringColumns = clusteringColumns; - this.partitionColumns = partitionColumns; - - rebuild(); - - this.resource = DataResource.table(ksName, cfName); - } - - // This rebuild informations that are intrinsically duplicate of the table definition but - // are kept because they are often useful in a different format. - private void rebuild() - { - this.comparator = new ClusteringComparator(extractTypes(clusteringColumns)); - - Map<ByteBuffer, ColumnDefinition> newColumnMetadata = Maps.newHashMapWithExpectedSize(partitionKeyColumns.size() + clusteringColumns.size() + partitionColumns.size()); - - for (ColumnDefinition def : partitionKeyColumns) - newColumnMetadata.put(def.name.bytes, def); - for (ColumnDefinition def : clusteringColumns) - newColumnMetadata.put(def.name.bytes, def); - for (ColumnDefinition def : partitionColumns) - newColumnMetadata.put(def.name.bytes, def); - - this.columnMetadata = newColumnMetadata; - - List<AbstractType<?>> keyTypes = extractTypes(partitionKeyColumns); - this.keyValidator = keyTypes.size() == 1 ? keyTypes.get(0) : CompositeType.getInstance(keyTypes); - - if (isCompactTable()) - this.compactValueColumn = CompactTables.getCompactValueColumn(partitionColumns, isSuper()); - } - - public Indexes getIndexes() - { - return indexes; - } - - public static CFMetaData create(String ksName, - String name, - UUID cfId, - boolean isDense, - boolean isCompound, - boolean isSuper, - boolean isCounter, - boolean isView, - List<ColumnDefinition> columns, - IPartitioner partitioner) - { - List<ColumnDefinition> partitions = new ArrayList<>(); - List<ColumnDefinition> clusterings = new ArrayList<>(); - PartitionColumns.Builder builder = PartitionColumns.builder(); - - for (ColumnDefinition column : columns) - { - switch (column.kind) - { - case PARTITION_KEY: - partitions.add(column); - break; - case CLUSTERING: - clusterings.add(column); - break; - default: - builder.add(column); - break; - } - } - - Collections.sort(partitions); - Collections.sort(clusterings); - - return new CFMetaData(ksName, - name, - cfId, - isSuper, - isCounter, - isDense, - isCompound, - isView, - partitions, - clusterings, - builder.build(), - partitioner); - } - - public static List<AbstractType<?>> extractTypes(Iterable<ColumnDefinition> clusteringColumns) - { - List<AbstractType<?>> types = new ArrayList<>(); - for (ColumnDefinition def : clusteringColumns) - types.add(def.type); - return types; - } - - public Set<Flag> flags() - { - return flags; - } - - /** - * There is a couple of places in the code where we need a CFMetaData object and don't have one readily available - * and know that only the keyspace and name matter. This creates such "fake" metadata. Use only if you know what - * you're doing. - */ - public static CFMetaData createFake(String keyspace, String name) - { - return CFMetaData.Builder.create(keyspace, name).addPartitionKey("key", BytesType.instance).build(); - } - - public Triggers getTriggers() - { - return triggers; - } - - // Compiles a system metadata - public static CFMetaData compile(String cql, String keyspace) - { - CFStatement parsed = (CFStatement)QueryProcessor.parseStatement(cql); - parsed.prepareKeyspace(keyspace); - CreateTableStatement statement = (CreateTableStatement) ((CreateTableStatement.RawStatement) parsed).prepare(Types.none()).statement; - - return statement.metadataBuilder() - .withId(generateLegacyCfId(keyspace, statement.columnFamily())) - .build() - .params(statement.params()) - .readRepairChance(0.0) - .dcLocalReadRepairChance(0.0) - .gcGraceSeconds(0) - .memtableFlushPeriod((int) TimeUnit.HOURS.toMillis(1)); - } - - /** - * Generates deterministic UUID from keyspace/columnfamily name pair. - * This is used to generate the same UUID for {@code C* version < 2.1} - * - * Since 2.1, this is only used for system columnfamilies and tests. - */ - public static UUID generateLegacyCfId(String ksName, String cfName) - { - return UUID.nameUUIDFromBytes(ArrayUtils.addAll(ksName.getBytes(), cfName.getBytes())); - } - - public CFMetaData reloadIndexMetadataProperties(CFMetaData parent) - { - TableParams.Builder indexParams = TableParams.builder(parent.params); - - // Depends on parent's cache setting, turn on its index CF's cache. - // Row caching is never enabled; see CASSANDRA-5732 - if (parent.params.caching.cacheKeys()) - indexParams.caching(CachingParams.CACHE_KEYS); - else - indexParams.caching(CachingParams.CACHE_NOTHING); - - indexParams.readRepairChance(0.0) - .dcLocalReadRepairChance(0.0) - .gcGraceSeconds(0); - - return params(indexParams.build()); - } - - public CFMetaData copy() - { - return copy(cfId); - } - - /** - * Clones the CFMetaData, but sets a different cfId - * - * @param newCfId the cfId for the cloned CFMetaData - * @return the cloned CFMetaData instance with the new cfId - */ - public CFMetaData copy(UUID newCfId) - { - return copyOpts(new CFMetaData(ksName, - cfName, - newCfId, - isSuper(), - isCounter(), - isDense(), - isCompound(), - isView(), - copy(partitionKeyColumns), - copy(clusteringColumns), - copy(partitionColumns), - partitioner), - this); - } - - public CFMetaData copy(IPartitioner partitioner) - { - return copyOpts(new CFMetaData(ksName, - cfName, - cfId, - isSuper, - isCounter, - isDense, - isCompound, - isView, - copy(partitionKeyColumns), - copy(clusteringColumns), - copy(partitionColumns), - partitioner), - this); - } - - private static List<ColumnDefinition> copy(List<ColumnDefinition> l) - { - List<ColumnDefinition> copied = new ArrayList<>(l.size()); - for (ColumnDefinition cd : l) - copied.add(cd.copy()); - return copied; - } - - private static PartitionColumns copy(PartitionColumns columns) - { - PartitionColumns.Builder newColumns = PartitionColumns.builder(); - for (ColumnDefinition cd : columns) - newColumns.add(cd.copy()); - return newColumns.build(); - } - - @VisibleForTesting - public static CFMetaData copyOpts(CFMetaData newCFMD, CFMetaData oldCFMD) - { - return newCFMD.params(oldCFMD.params) - .droppedColumns(new HashMap<>(oldCFMD.droppedColumns)) - .triggers(oldCFMD.triggers) - .indexes(oldCFMD.indexes); - } - - /** - * generate a column family name for an index corresponding to the given column. - * This is NOT the same as the index's name! This is only used in sstable filenames and is not exposed to users. - * - * @param info A definition of the column with index - * - * @return name of the index ColumnFamily - */ - public String indexColumnFamilyName(IndexMetadata info) - { - // TODO simplify this when info.index_name is guaranteed to be set - return cfName + Directories.SECONDARY_INDEX_NAME_SEPARATOR + info.name; - } - - /** - * true if this CFS contains secondary index data. - */ - public boolean isIndex() - { - return isIndex; - } - - public DecoratedKey decorateKey(ByteBuffer key) - { - return partitioner.decorateKey(key); - } - - public Map<ByteBuffer, ColumnDefinition> getColumnMetadata() - { - return columnMetadata; - } - - public ReadRepairDecision newReadRepairDecision() - { - double chance = ThreadLocalRandom.current().nextDouble(); - if (params.readRepairChance > chance) - return ReadRepairDecision.GLOBAL; - - if (params.dcLocalReadRepairChance > chance) - return ReadRepairDecision.DC_LOCAL; - - return ReadRepairDecision.NONE; - } - - public AbstractType<?> getColumnDefinitionNameComparator(ColumnDefinition.Kind kind) - { - return (isSuper() && kind == ColumnDefinition.Kind.REGULAR) || (isStaticCompactTable() && kind == ColumnDefinition.Kind.STATIC) - ? staticCompactOrSuperTableColumnNameType() - : UTF8Type.instance; - } - - public AbstractType<?> getKeyValidator() - { - return keyValidator; - } - - public Collection<ColumnDefinition> allColumns() - { - return columnMetadata.values(); - } - - // An iterator over all column definitions but that respect the order of a SELECT *. - // This also "hide" the clustering/regular columns for a non-CQL3 non-dense table for backward compatibility - // sake. - public Iterator<ColumnDefinition> allColumnsInSelectOrder() - { - final boolean isStaticCompactTable = isStaticCompactTable(); - final boolean noNonPkColumns = isCompactTable() && CompactTables.hasEmptyCompactValue(this); - return new AbstractIterator<ColumnDefinition>() - { - private final Iterator<ColumnDefinition> partitionKeyIter = partitionKeyColumns.iterator(); - private final Iterator<ColumnDefinition> clusteringIter = isStaticCompactTable ? Collections.<ColumnDefinition>emptyIterator() : clusteringColumns.iterator(); - private final Iterator<ColumnDefinition> otherColumns = noNonPkColumns - ? Collections.<ColumnDefinition>emptyIterator() - : (isStaticCompactTable - ? partitionColumns.statics.selectOrderIterator() - : partitionColumns.selectOrderIterator()); - - protected ColumnDefinition computeNext() - { - if (partitionKeyIter.hasNext()) - return partitionKeyIter.next(); - - if (clusteringIter.hasNext()) - return clusteringIter.next(); - - return otherColumns.hasNext() ? otherColumns.next() : endOfData(); - } - }; - } - - public Iterable<ColumnDefinition> primaryKeyColumns() - { - return Iterables.concat(partitionKeyColumns, clusteringColumns); - } - - public List<ColumnDefinition> partitionKeyColumns() - { - return partitionKeyColumns; - } - - public List<ColumnDefinition> clusteringColumns() - { - return clusteringColumns; - } - - public PartitionColumns partitionColumns() - { - return partitionColumns; - } - - public ColumnDefinition compactValueColumn() - { - return compactValueColumn; - } - - public ClusteringComparator getKeyValidatorAsClusteringComparator() - { - boolean isCompound = keyValidator instanceof CompositeType; - List<AbstractType<?>> types = isCompound - ? ((CompositeType) keyValidator).types - : Collections.<AbstractType<?>>singletonList(keyValidator); - return new ClusteringComparator(types); - } - - public static ByteBuffer serializePartitionKey(ClusteringPrefix keyAsClustering) - { - // TODO: we should stop using Clustering for partition keys. Maybe we can add - // a few methods to DecoratedKey so we don't have to (note that while using a Clustering - // allows to use buildBound(), it's actually used for partition keys only when every restriction - // is an equal, so we could easily create a specific method for keys for that. - if (keyAsClustering.size() == 1) - return keyAsClustering.get(0); - - ByteBuffer[] values = new ByteBuffer[keyAsClustering.size()]; - for (int i = 0; i < keyAsClustering.size(); i++) - values[i] = keyAsClustering.get(i); - return CompositeType.build(values); - } - - public Map<ByteBuffer, DroppedColumn> getDroppedColumns() - { - return droppedColumns; - } - - public ColumnDefinition getDroppedColumnDefinition(ByteBuffer name) - { - return getDroppedColumnDefinition(name, false); - } - - /** - * Returns a "fake" ColumnDefinition corresponding to the dropped column {@code name} - * of {@code null} if there is no such dropped column. - * - * @param name - the column name - * @param isStatic - whether the column was a static column, if known - */ - public ColumnDefinition getDroppedColumnDefinition(ByteBuffer name, boolean isStatic) - { - DroppedColumn dropped = droppedColumns.get(name); - if (dropped == null) - return null; - - // We need the type for deserialization purpose. If we don't have the type however, - // it means that it's a dropped column from before 3.0, and in that case using - // BytesType is fine for what we'll be using it for, even if that's a hack. - AbstractType<?> type = dropped.type == null ? BytesType.instance : dropped.type; - return isStatic || dropped.kind == ColumnDefinition.Kind.STATIC - ? ColumnDefinition.staticDef(this, name, type) - : ColumnDefinition.regularDef(this, name, type); - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - - if (!(o instanceof CFMetaData)) - return false; - - CFMetaData other = (CFMetaData) o; - - return Objects.equal(cfId, other.cfId) - && Objects.equal(flags, other.flags) - && Objects.equal(ksName, other.ksName) - && Objects.equal(cfName, other.cfName) - && Objects.equal(params, other.params) - && Objects.equal(comparator, other.comparator) - && Objects.equal(keyValidator, other.keyValidator) - && Objects.equal(columnMetadata, other.columnMetadata) - && Objects.equal(droppedColumns, other.droppedColumns) - && Objects.equal(triggers, other.triggers) - && Objects.equal(indexes, other.indexes); - } - - @Override - public int hashCode() - { - return new HashCodeBuilder(29, 1597) - .append(cfId) - .append(ksName) - .append(cfName) - .append(flags) - .append(comparator) - .append(params) - .append(keyValidator) - .append(columnMetadata) - .append(droppedColumns) - .append(triggers) - .append(indexes) - .toHashCode(); - } - - /** - * Updates CFMetaData in-place to match cfm - * - * @return true if any change was made which impacts queries/updates on the table, - * e.g. any columns or indexes were added, removed, or altered; otherwise, false is returned. - * Used to determine whether prepared statements against this table need to be re-prepared. - * @throws ConfigurationException if ks/cf names or cf ids didn't match - */ - @VisibleForTesting - public boolean apply(CFMetaData cfm) throws ConfigurationException - { - logger.debug("applying {} to {}", cfm, this); - - validateCompatibility(cfm); - - partitionKeyColumns = cfm.partitionKeyColumns; - clusteringColumns = cfm.clusteringColumns; - - boolean changeAffectsStatements = !partitionColumns.equals(cfm.partitionColumns); - partitionColumns = cfm.partitionColumns; - - rebuild(); - - params = cfm.params; - - if (!cfm.droppedColumns.isEmpty()) - droppedColumns = cfm.droppedColumns; - - triggers = cfm.triggers; - - changeAffectsStatements |= !indexes.equals(cfm.indexes); - indexes = cfm.indexes; - - logger.debug("application result is {}", this); - - return changeAffectsStatements; - } - - public void validateCompatibility(CFMetaData cfm) throws ConfigurationException - { - // validate - if (!cfm.ksName.equals(ksName)) - throw new ConfigurationException(String.format("Keyspace mismatch (found %s; expected %s)", - cfm.ksName, ksName)); - if (!cfm.cfName.equals(cfName)) - throw new ConfigurationException(String.format("Column family mismatch (found %s; expected %s)", - cfm.cfName, cfName)); - if (!cfm.cfId.equals(cfId)) - throw new ConfigurationException(String.format("Column family ID mismatch (found %s; expected %s)", - cfm.cfId, cfId)); - if (!cfm.flags.equals(flags)) - throw new ConfigurationException(String.format("Column family type mismatch (found %s; expected %s)", cfm.flags, flags)); - } - - - public static Class<? extends AbstractCompactionStrategy> createCompactionStrategy(String className) throws ConfigurationException - { - className = className.contains(".") ? className : "org.apache.cassandra.db.compaction." + className; - Class<AbstractCompactionStrategy> strategyClass = FBUtilities.classForName(className, "compaction strategy"); - if (!AbstractCompactionStrategy.class.isAssignableFrom(strategyClass)) - throw new ConfigurationException(String.format("Specified compaction strategy class (%s) is not derived from AbstractCompactionStrategy", className)); - - return strategyClass; - } - - public static AbstractCompactionStrategy createCompactionStrategyInstance(ColumnFamilyStore cfs, - CompactionParams compactionParams) - { - try - { - Constructor<? extends AbstractCompactionStrategy> constructor = - compactionParams.klass().getConstructor(ColumnFamilyStore.class, Map.class); - return constructor.newInstance(cfs, compactionParams.options()); - } - catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) - { - throw new RuntimeException(e); - } - } - - /** - * Returns the ColumnDefinition for {@code name}. - */ - public ColumnDefinition getColumnDefinition(ColumnIdentifier name) - { - return columnMetadata.get(name.bytes); - } - - // In general it is preferable to work with ColumnIdentifier to make it - // clear that we are talking about a CQL column, not a cell name, but there - // is a few cases where all we have is a ByteBuffer (when dealing with IndexExpression - // for instance) so... - public ColumnDefinition getColumnDefinition(ByteBuffer name) - { - return columnMetadata.get(name); - } - - public static boolean isNameValid(String name) - { - return name != null && !name.isEmpty() - && name.length() <= SchemaConstants.NAME_LENGTH && PATTERN_WORD_CHARS.matcher(name).matches(); - } - - public CFMetaData validate() throws ConfigurationException - { - rebuild(); - - if (!isNameValid(ksName)) - throw new ConfigurationException(String.format("Keyspace name must not be empty, more than %s characters long, or contain non-alphanumeric-underscore characters (got \"%s\")", SchemaConstants.NAME_LENGTH, ksName)); - if (!isNameValid(cfName)) - throw new ConfigurationException(String.format("ColumnFamily name must not be empty, more than %s characters long, or contain non-alphanumeric-underscore characters (got \"%s\")", SchemaConstants.NAME_LENGTH, cfName)); - - params.validate(); - - for (int i = 0; i < comparator.size(); i++) - { - if (comparator.subtype(i) instanceof CounterColumnType) - throw new ConfigurationException("CounterColumnType is not a valid comparator"); - } - if (keyValidator instanceof CounterColumnType) - throw new ConfigurationException("CounterColumnType is not a valid key validator"); - - // Mixing counter with non counter columns is not supported (#2614) - if (isCounter()) - { - for (ColumnDefinition def : partitionColumns()) - if (!(def.type instanceof CounterColumnType) && !CompactTables.isSuperColumnMapColumn(def)) - throw new ConfigurationException("Cannot add a non counter column (" + def.name + ") in a counter column family"); - } - else - { - for (ColumnDefinition def : allColumns()) - if (def.type instanceof CounterColumnType) - throw new ConfigurationException("Cannot add a counter column (" + def.name + ") in a non counter column family"); - } - - if (!indexes.isEmpty() && isSuper()) - throw new ConfigurationException("Secondary indexes are not supported on super column families"); - - // initialize a set of names NOT in the CF under consideration - KeyspaceMetadata ksm = Schema.instance.getKSMetaData(ksName); - Set<String> indexNames = ksm == null ? new HashSet<>() : ksm.existingIndexNames(cfName); - for (IndexMetadata index : indexes) - { - // check index names against this CF _and_ globally - if (indexNames.contains(index.name)) - throw new ConfigurationException("Duplicate index name " + index.name); - indexNames.add(index.name); - - index.validate(this); - } - - return this; - } - - /** - * The type to use to compare column names in "static compact" - * tables or superColum ones. - * <p> - * This exists because for historical reasons, "static compact" tables as - * well as super column ones can have non-UTF8 column names. - * <p> - * This method should only be called for superColumn tables and "static - * compact" ones. For any other table, all column names are UTF8. - */ - public AbstractType<?> staticCompactOrSuperTableColumnNameType() - { - if (isSuper()) - { - ColumnDefinition def = compactValueColumn(); - assert def != null && def.type instanceof MapType; - return ((MapType)def.type).nameComparator(); - } - - assert isStaticCompactTable(); - return clusteringColumns.get(0).type; - } - - public CFMetaData addColumnDefinition(ColumnDefinition def) throws ConfigurationException - { - if (columnMetadata.containsKey(def.name.bytes)) - throw new ConfigurationException(String.format("Cannot add column %s, a column with the same name already exists", def.name)); - - return addOrReplaceColumnDefinition(def); - } - - // This method doesn't check if a def of the same name already exist and should only be used when we - // know this cannot happen. - public CFMetaData addOrReplaceColumnDefinition(ColumnDefinition def) - { - // Adds the definition and rebuild what is necessary. We could call rebuild() but it's not too hard to - // only rebuild the necessary bits. - switch (def.kind) - { - case PARTITION_KEY: - partitionKeyColumns.set(def.position(), def); - break; - case CLUSTERING: - clusteringColumns.set(def.position(), def); - break; - case REGULAR: - case STATIC: - PartitionColumns.Builder builder = PartitionColumns.builder(); - for (ColumnDefinition column : partitionColumns) - if (!column.name.equals(def.name)) - builder.add(column); - builder.add(def); - partitionColumns = builder.build(); - // If dense, we must have modified the compact value since that's the only one we can have. - if (isDense()) - this.compactValueColumn = def; - break; - } - this.columnMetadata.put(def.name.bytes, def); - return this; - } - - public boolean removeColumnDefinition(ColumnDefinition def) - { - assert !def.isPartitionKey(); - boolean removed = columnMetadata.remove(def.name.bytes) != null; - if (removed) - partitionColumns = partitionColumns.without(def); - return removed; - } - - /** - * Adds the column definition as a dropped column, recording the drop with the provided timestamp. - */ - public void recordColumnDrop(ColumnDefinition def, long timeMicros) - { - droppedColumns.put(def.name.bytes, new DroppedColumn(def, timeMicros)); - } - - public void renameColumn(ColumnIdentifier from, ColumnIdentifier to) throws InvalidRequestException - { - ColumnDefinition def = getColumnDefinition(from); - if (def == null) - throw new InvalidRequestException(String.format("Cannot rename unknown column %s in keyspace %s", from, cfName)); - - if (getColumnDefinition(to) != null) - throw new InvalidRequestException(String.format("Cannot rename column %s to %s in keyspace %s; another column of that name already exist", from, to, cfName)); - - if (!def.isPrimaryKeyColumn()) - throw new InvalidRequestException(String.format("Cannot rename non PRIMARY KEY part %s", from)); - - if (!getIndexes().isEmpty()) - { - ColumnFamilyStore store = Keyspace.openAndGetStore(this); - Set<IndexMetadata> dependentIndexes = store.indexManager.getDependentIndexes(def); - if (!dependentIndexes.isEmpty()) - throw new InvalidRequestException(String.format("Cannot rename column %s because it has " + - "dependent secondary indexes (%s)", - from, - dependentIndexes.stream() - .map(i -> i.name) - .collect(Collectors.joining(",")))); - } - - ColumnDefinition newDef = def.withNewName(to); - addOrReplaceColumnDefinition(newDef); - - // removeColumnDefinition doesn't work for partition key (expectedly) but renaming one is fine so we still - // want to update columnMetadata. - if (def.isPartitionKey()) - columnMetadata.remove(def.name.bytes); - else - removeColumnDefinition(def); - } - - /** - * Records a deprecated column for a system table. - */ - public CFMetaData recordDeprecatedSystemColumn(String name, AbstractType<?> type) - { - // As we play fast and loose with the removal timestamp, make sure this is misued for a non system table. - assert SchemaConstants.isSystemKeyspace(ksName); - ByteBuffer bb = ByteBufferUtil.bytes(name); - recordColumnDrop(ColumnDefinition.regularDef(this, bb, type), Long.MAX_VALUE); - return this; - } - - - public boolean isCQLTable() - { - return !isSuper() && !isDense() && isCompound(); - } - - public boolean isCompactTable() - { - return !isCQLTable(); - } - - public boolean isStaticCompactTable() - { - return !isSuper() && !isDense() && !isCompound(); - } - - public boolean hasStaticColumns() - { - return !partitionColumns.statics.isEmpty(); - } - - public boolean isSuper() - { - return isSuper; - } - - public boolean isCounter() - { - return isCounter; - } - - // We call dense a CF for which each component of the comparator is a clustering column, i.e. no - // component is used to store a regular column names. In other words, non-composite static "thrift" - // and CQL3 CF are *not* dense. - public boolean isDense() - { - return isDense; - } - - public boolean isCompound() - { - return isCompound; - } - - public boolean isView() - { - return isView; - } - - public static Set<Flag> flagsFromStrings(Set<String> strings) - { - return strings.stream() - .map(String::toUpperCase) - .map(Flag::valueOf) - .collect(Collectors.toSet()); - } - - public static Set<String> flagsToStrings(Set<Flag> flags) - { - return flags.stream() - .map(Flag::toString) - .map(String::toLowerCase) - .collect(Collectors.toSet()); - } - - - @Override - public String toString() - { - return new ToStringBuilder(this) - .append("cfId", cfId) - .append("ksName", ksName) - .append("cfName", cfName) - .append("flags", flags) - .append("params", params) - .append("comparator", comparator) - .append("partitionColumns", partitionColumns) - .append("partitionKeyColumns", partitionKeyColumns) - .append("clusteringColumns", clusteringColumns) - .append("keyValidator", keyValidator) - .append("columnMetadata", columnMetadata.values()) - .append("droppedColumns", droppedColumns) - .append("triggers", triggers) - .append("indexes", indexes) - .toString(); - } - - public static class Builder - { - private final String keyspace; - private final String table; - private final boolean isDense; - private final boolean isCompound; - private final boolean isSuper; - private final boolean isCounter; - private final boolean isView; - private Optional<IPartitioner> partitioner; - - private UUID tableId; - - private final List<Pair<ColumnIdentifier, AbstractType>> partitionKeys = new ArrayList<>(); - private final List<Pair<ColumnIdentifier, AbstractType>> clusteringColumns = new ArrayList<>(); - private final List<Pair<ColumnIdentifier, AbstractType>> staticColumns = new ArrayList<>(); - private final List<Pair<ColumnIdentifier, AbstractType>> regularColumns = new ArrayList<>(); - - private Builder(String keyspace, String table, boolean isDense, boolean isCompound, boolean isSuper, boolean isCounter, boolean isView) - { - this.keyspace = keyspace; - this.table = table; - this.isDense = isDense; - this.isCompound = isCompound; - this.isSuper = isSuper; - this.isCounter = isCounter; - this.isView = isView; - this.partitioner = Optional.empty(); - } - - public static Builder create(String keyspace, String table) - { - return create(keyspace, table, false, true, false); - } - - public static Builder create(String keyspace, String table, boolean isDense, boolean isCompound, boolean isCounter) - { - return create(keyspace, table, isDense, isCompound, false, isCounter); - } - - public static Builder create(String keyspace, String table, boolean isDense, boolean isCompound, boolean isSuper, boolean isCounter) - { - return new Builder(keyspace, table, isDense, isCompound, isSuper, isCounter, false); - } - - public static Builder createView(String keyspace, String table) - { - return new Builder(keyspace, table, false, true, false, false, true); - } - - public static Builder createDense(String keyspace, String table, boolean isCompound, boolean isCounter) - { - return create(keyspace, table, true, isCompound, isCounter); - } - - public static Builder createSuper(String keyspace, String table, boolean isCounter) - { - return create(keyspace, table, false, false, true, isCounter); - } - - public Builder withPartitioner(IPartitioner partitioner) - { - this.partitioner = Optional.ofNullable(partitioner); - return this; - } - - public Builder withId(UUID tableId) - { - this.tableId = tableId; - return this; - } - - public Builder addPartitionKey(String name, AbstractType type) - { - return addPartitionKey(ColumnIdentifier.getInterned(name, false), type); - } - - public Builder addPartitionKey(ColumnIdentifier name, AbstractType type) - { - this.partitionKeys.add(Pair.create(name, type)); - return this; - } - - public Builder addClusteringColumn(String name, AbstractType type) - { - return addClusteringColumn(ColumnIdentifier.getInterned(name, false), type); - } - - public Builder addClusteringColumn(ColumnIdentifier name, AbstractType type) - { - this.clusteringColumns.add(Pair.create(name, type)); - return this; - } - - public Builder addRegularColumn(String name, AbstractType type) - { - return addRegularColumn(ColumnIdentifier.getInterned(name, false), type); - } - - public Builder addRegularColumn(ColumnIdentifier name, AbstractType type) - { - this.regularColumns.add(Pair.create(name, type)); - return this; - } - - public boolean hasRegulars() - { - return !this.regularColumns.isEmpty(); - } - - public Builder addStaticColumn(String name, AbstractType type) - { - return addStaticColumn(ColumnIdentifier.getInterned(name, false), type); - } - - public Builder addStaticColumn(ColumnIdentifier name, AbstractType type) - { - this.staticColumns.add(Pair.create(name, type)); - return this; - } - - public Set<String> usedColumnNames() - { - Set<String> usedNames = Sets.newHashSetWithExpectedSize(partitionKeys.size() + clusteringColumns.size() + staticColumns.size() + regularColumns.size()); - for (Pair<ColumnIdentifier, AbstractType> p : partitionKeys) - usedNames.add(p.left.toString()); - for (Pair<ColumnIdentifier, AbstractType> p : clusteringColumns) - usedNames.add(p.left.toString()); - for (Pair<ColumnIdentifier, AbstractType> p : staticColumns) - usedNames.add(p.left.toString()); - for (Pair<ColumnIdentifier, AbstractType> p : regularColumns) - usedNames.add(p.left.toString()); - return usedNames; - } - - public CFMetaData build() - { - if (tableId == null) - tableId = UUIDGen.getTimeUUID(); - - List<ColumnDefinition> partitions = new ArrayList<>(partitionKeys.size()); - List<ColumnDefinition> clusterings = new ArrayList<>(clusteringColumns.size()); - PartitionColumns.Builder builder = PartitionColumns.builder(); - - for (int i = 0; i < partitionKeys.size(); i++) - { - Pair<ColumnIdentifier, AbstractType> p = partitionKeys.get(i); - partitions.add(new ColumnDefinition(keyspace, table, p.left, p.right, i, ColumnDefinition.Kind.PARTITION_KEY)); - } - - for (int i = 0; i < clusteringColumns.size(); i++) - { - Pair<ColumnIdentifier, AbstractType> p = clusteringColumns.get(i); - clusterings.add(new ColumnDefinition(keyspace, table, p.left, p.right, i, ColumnDefinition.Kind.CLUSTERING)); - } - - for (Pair<ColumnIdentifier, AbstractType> p : regularColumns) - builder.add(new ColumnDefinition(keyspace, table, p.left, p.right, ColumnDefinition.NO_POSITION, ColumnDefinition.Kind.REGULAR)); - - for (Pair<ColumnIdentifier, AbstractType> p : staticColumns) - builder.add(new ColumnDefinition(keyspace, table, p.left, p.right, ColumnDefinition.NO_POSITION, ColumnDefinition.Kind.STATIC)); - - return new CFMetaData(keyspace, - table, - tableId, - isSuper, - isCounter, - isDense, - isCompound, - isView, - partitions, - clusterings, - builder.build(), - partitioner.orElseGet(DatabaseDescriptor::getPartitioner)); - } - } - - public static class Serializer - { - public void serialize(CFMetaData metadata, DataOutputPlus out, int version) throws IOException - { - UUIDSerializer.serializer.serialize(metadata.cfId, out, version); - } - - public CFMetaData deserialize(DataInputPlus in, int version) throws IOException - { - UUID cfId = UUIDSerializer.serializer.deserialize(in, version); - CFMetaData metadata = Schema.instance.getCFMetaData(cfId); - if (metadata == null) - { - String message = String.format("Couldn't find table for cfId %s. If a table was just " + - "created, this is likely due to the schema not being fully propagated. Please wait for schema " + - "agreement on table creation.", cfId); - throw new UnknownColumnFamilyException(message, cfId); - } - - return metadata; - } - - public long serializedSize(CFMetaData metadata, int version) - { - return UUIDSerializer.serializer.serializedSize(metadata.cfId, version); - } - } - - public static class DroppedColumn - { - // we only allow dropping REGULAR columns, from CQL-native tables, so the names are always of UTF8Type - public final String name; - public final AbstractType<?> type; - - // drop timestamp, in microseconds, yet with millisecond granularity - public final long droppedTime; - - public final ColumnDefinition.Kind kind; - - public DroppedColumn(ColumnDefinition def, long droppedTime) - { - this(def.name.toString(), def.type, droppedTime, def.kind); - } - - public DroppedColumn(String name, AbstractType<?> type, long droppedTime, ColumnDefinition.Kind kind) - { - this.name = name; - this.type = type; - this.droppedTime = droppedTime; - this.kind = kind; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - - if (!(o instanceof DroppedColumn)) - return false; - - DroppedColumn dc = (DroppedColumn) o; - - return name.equals(dc.name) && type.equals(dc.type) && droppedTime == dc.droppedTime; - } - - @Override - public int hashCode() - { - return Objects.hashCode(name, type, droppedTime); - } - - @Override - public String toString() - { - return MoreObjects.toStringHelper(this) - .add("name", name) - .add("type", type) - .add("droppedTime", droppedTime) - .toString(); - } - } -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/af3fe39d/src/java/org/apache/cassandra/config/ColumnDefinition.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/ColumnDefinition.java b/src/java/org/apache/cassandra/config/ColumnDefinition.java deleted file mode 100644 index 65cf837..0000000 --- a/src/java/org/apache/cassandra/config/ColumnDefinition.java +++ /dev/null @@ -1,623 +0,0 @@ -/* - * 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.config; - -import java.nio.ByteBuffer; -import java.util.*; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; -import com.google.common.base.MoreObjects; -import com.google.common.base.Objects; -import com.google.common.collect.Collections2; - -import org.apache.cassandra.cql3.*; -import org.apache.cassandra.cql3.selection.Selectable; -import org.apache.cassandra.cql3.selection.Selector; -import org.apache.cassandra.cql3.selection.SimpleSelector; -import org.apache.cassandra.db.rows.*; -import org.apache.cassandra.db.marshal.*; -import org.apache.cassandra.exceptions.InvalidRequestException; -import org.apache.cassandra.serializers.MarshalException; -import org.apache.cassandra.utils.ByteBufferUtil; - -public class ColumnDefinition extends ColumnSpecification implements Selectable, Comparable<ColumnDefinition> -{ - public static final Comparator<Object> asymmetricColumnDataComparator = - (a, b) -> ((ColumnData) a).column().compareTo((ColumnDefinition) b); - - public static final int NO_POSITION = -1; - - public enum ClusteringOrder - { - ASC, DESC, NONE - } - - /** - * The type of CQL3 column this definition represents. - * There is 4 main type of CQL3 columns: those parts of the partition key, - * those parts of the clustering columns and amongst the others, regular and - * static ones. - * - * IMPORTANT: this enum is serialized as toString() and deserialized by calling - * Kind.valueOf(), so do not override toString() or rename existing values. - */ - public enum Kind - { - // NOTE: if adding a new type, must modify comparisonOrder - PARTITION_KEY, - CLUSTERING, - REGULAR, - STATIC; - - public boolean isPrimaryKeyKind() - { - return this == PARTITION_KEY || this == CLUSTERING; - } - - } - - public final Kind kind; - - /* - * If the column is a partition key or clustering column, its position relative to - * other columns of the same kind. Otherwise, NO_POSITION (-1). - * - * Note that partition key and clustering columns are numbered separately so - * the first clustering column is 0. - */ - private final int position; - - private final Comparator<CellPath> cellPathComparator; - private final Comparator<Object> asymmetricCellPathComparator; - private final Comparator<? super Cell> cellComparator; - - private int hash; - - /** - * These objects are compared frequently, so we encode several of their comparison components - * into a single long value so that this can be done efficiently - */ - private final long comparisonOrder; - - private static long comparisonOrder(Kind kind, boolean isComplex, long position, ColumnIdentifier name) - { - assert position >= 0 && position < 1 << 12; - return (((long) kind.ordinal()) << 61) - | (isComplex ? 1L << 60 : 0) - | (position << 48) - | (name.prefixComparison >>> 16); - } - - public static ColumnDefinition partitionKeyDef(CFMetaData cfm, ByteBuffer name, AbstractType<?> type, int position) - { - return new ColumnDefinition(cfm, name, type, position, Kind.PARTITION_KEY); - } - - public static ColumnDefinition partitionKeyDef(String ksName, String cfName, String name, AbstractType<?> type, int position) - { - return new ColumnDefinition(ksName, cfName, ColumnIdentifier.getInterned(name, true), type, position, Kind.PARTITION_KEY); - } - - public static ColumnDefinition clusteringDef(CFMetaData cfm, ByteBuffer name, AbstractType<?> type, int position) - { - return new ColumnDefinition(cfm, name, type, position, Kind.CLUSTERING); - } - - public static ColumnDefinition clusteringDef(String ksName, String cfName, String name, AbstractType<?> type, int position) - { - return new ColumnDefinition(ksName, cfName, ColumnIdentifier.getInterned(name, true), type, position, Kind.CLUSTERING); - } - - public static ColumnDefinition regularDef(CFMetaData cfm, ByteBuffer name, AbstractType<?> type) - { - return new ColumnDefinition(cfm, name, type, NO_POSITION, Kind.REGULAR); - } - - public static ColumnDefinition regularDef(String ksName, String cfName, String name, AbstractType<?> type) - { - return new ColumnDefinition(ksName, cfName, ColumnIdentifier.getInterned(name, true), type, NO_POSITION, Kind.REGULAR); - } - - public static ColumnDefinition staticDef(CFMetaData cfm, ByteBuffer name, AbstractType<?> type) - { - return new ColumnDefinition(cfm, name, type, NO_POSITION, Kind.STATIC); - } - - public ColumnDefinition(CFMetaData cfm, ByteBuffer name, AbstractType<?> type, int position, Kind kind) - { - this(cfm.ksName, - cfm.cfName, - ColumnIdentifier.getInterned(name, cfm.getColumnDefinitionNameComparator(kind)), - type, - position, - kind); - } - - @VisibleForTesting - public ColumnDefinition(String ksName, - String cfName, - ColumnIdentifier name, - AbstractType<?> type, - int position, - Kind kind) - { - super(ksName, cfName, name, type); - assert name != null && type != null && kind != null; - assert name.isInterned(); - assert (position == NO_POSITION) == !kind.isPrimaryKeyKind(); // The position really only make sense for partition and clustering columns (and those must have one), - // so make sure we don't sneak it for something else since it'd breaks equals() - this.kind = kind; - this.position = position; - this.cellPathComparator = makeCellPathComparator(kind, type); - this.cellComparator = cellPathComparator == null ? ColumnData.comparator : (a, b) -> cellPathComparator.compare(a.path(), b.path()); - this.asymmetricCellPathComparator = cellPathComparator == null ? null : (a, b) -> cellPathComparator.compare(((Cell)a).path(), (CellPath) b); - this.comparisonOrder = comparisonOrder(kind, isComplex(), Math.max(0, position), name); - } - - private static Comparator<CellPath> makeCellPathComparator(Kind kind, AbstractType<?> type) - { - if (kind.isPrimaryKeyKind() || !type.isMultiCell()) - return null; - - AbstractType<?> nameComparator = type.isCollection() - ? ((CollectionType) type).nameComparator() - : ((UserType) type).nameComparator(); - - - return new Comparator<CellPath>() - { - public int compare(CellPath path1, CellPath path2) - { - if (path1.size() == 0 || path2.size() == 0) - { - if (path1 == CellPath.BOTTOM) - return path2 == CellPath.BOTTOM ? 0 : -1; - if (path1 == CellPath.TOP) - return path2 == CellPath.TOP ? 0 : 1; - return path2 == CellPath.BOTTOM ? 1 : -1; - } - - // This will get more complicated once we have non-frozen UDT and nested collections - assert path1.size() == 1 && path2.size() == 1; - return nameComparator.compare(path1.get(0), path2.get(0)); - } - }; - } - - public ColumnDefinition copy() - { - return new ColumnDefinition(ksName, cfName, name, type, position, kind); - } - - public ColumnDefinition withNewName(ColumnIdentifier newName) - { - return new ColumnDefinition(ksName, cfName, newName, type, position, kind); - } - - public ColumnDefinition withNewType(AbstractType<?> newType) - { - return new ColumnDefinition(ksName, cfName, name, newType, position, kind); - } - - public boolean isPartitionKey() - { - return kind == Kind.PARTITION_KEY; - } - - public boolean isClusteringColumn() - { - return kind == Kind.CLUSTERING; - } - - public boolean isStatic() - { - return kind == Kind.STATIC; - } - - public boolean isRegular() - { - return kind == Kind.REGULAR; - } - - public ClusteringOrder clusteringOrder() - { - if (!isClusteringColumn()) - return ClusteringOrder.NONE; - - return type.isReversed() ? ClusteringOrder.DESC : ClusteringOrder.ASC; - } - - public int position() - { - return position; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - return true; - - if (!(o instanceof ColumnDefinition)) - return false; - - ColumnDefinition cd = (ColumnDefinition) o; - - return Objects.equal(ksName, cd.ksName) - && Objects.equal(cfName, cd.cfName) - && Objects.equal(name, cd.name) - && Objects.equal(type, cd.type) - && Objects.equal(kind, cd.kind) - && Objects.equal(position, cd.position); - } - - @Override - public int hashCode() - { - // This achieves the same as Objects.hashcode, but avoids the object array allocation - // which features significantly in the allocation profile and caches the result. - int result = hash; - if(result == 0) - { - result = 31 + (ksName == null ? 0 : ksName.hashCode()); - result = 31 * result + (cfName == null ? 0 : cfName.hashCode()); - result = 31 * result + (name == null ? 0 : name.hashCode()); - result = 31 * result + (type == null ? 0 : type.hashCode()); - result = 31 * result + (kind == null ? 0 : kind.hashCode()); - result = 31 * result + position; - hash = result; - } - return result; - } - - @Override - public String toString() - { - return name.toString(); - } - - public String debugString() - { - return MoreObjects.toStringHelper(this) - .add("name", name) - .add("type", type) - .add("kind", kind) - .add("position", position) - .toString(); - } - - public boolean isPrimaryKeyColumn() - { - return kind.isPrimaryKeyKind(); - } - - /** - * Converts the specified column definitions into column identifiers. - * - * @param definitions the column definitions to convert. - * @return the column identifiers corresponding to the specified definitions - */ - public static Collection<ColumnIdentifier> toIdentifiers(Collection<ColumnDefinition> definitions) - { - return Collections2.transform(definitions, new Function<ColumnDefinition, ColumnIdentifier>() - { - @Override - public ColumnIdentifier apply(ColumnDefinition columnDef) - { - return columnDef.name; - } - }); - } - - public int compareTo(ColumnDefinition other) - { - if (this == other) - return 0; - - if (comparisonOrder != other.comparisonOrder) - return Long.compare(comparisonOrder, other.comparisonOrder); - - return this.name.compareTo(other.name); - } - - public Comparator<CellPath> cellPathComparator() - { - return cellPathComparator; - } - - public Comparator<Object> asymmetricCellPathComparator() - { - return asymmetricCellPathComparator; - } - - public Comparator<? super Cell> cellComparator() - { - return cellComparator; - } - - public boolean isComplex() - { - return cellPathComparator != null; - } - - public boolean isSimple() - { - return !isComplex(); - } - - public CellPath.Serializer cellPathSerializer() - { - // Collections are our only complex so far, so keep it simple - return CollectionType.cellPathSerializer; - } - - public void validateCell(Cell cell) - { - if (cell.isTombstone()) - { - if (cell.value().hasRemaining()) - throw new MarshalException("A tombstone should not have a value"); - if (cell.path() != null) - validateCellPath(cell.path()); - } - else if(type.isUDT()) - { - // To validate a non-frozen UDT field, both the path and the value - // are needed, the path being an index into an array of value types. - ((UserType)type).validateCell(cell); - } - else - { - type.validateCellValue(cell.value()); - if (cell.path() != null) - validateCellPath(cell.path()); - } - } - - private void validateCellPath(CellPath path) - { - if (!isComplex()) - throw new MarshalException("Only complex cells should have a cell path"); - - assert type.isMultiCell(); - if (type.isCollection()) - ((CollectionType)type).nameComparator().validate(path.get(0)); - else - ((UserType)type).nameComparator().validate(path.get(0)); - } - - public static String toCQLString(Iterable<ColumnDefinition> defs) - { - return toCQLString(defs.iterator()); - } - - public static String toCQLString(Iterator<ColumnDefinition> defs) - { - if (!defs.hasNext()) - return ""; - - StringBuilder sb = new StringBuilder(); - sb.append(defs.next().name); - while (defs.hasNext()) - sb.append(", ").append(defs.next().name); - return sb.toString(); - } - - /** - * The type of the cell values for cell belonging to this column. - * - * This is the same than the column type, except for collections where it's the 'valueComparator' - * of the collection. - */ - public AbstractType<?> cellValueType() - { - return type instanceof CollectionType - ? ((CollectionType)type).valueComparator() - : type; - } - - public Selector.Factory newSelectorFactory(CFMetaData cfm, AbstractType<?> expectedType, List<ColumnDefinition> defs, VariableSpecifications boundNames) throws InvalidRequestException - { - return SimpleSelector.newFactory(this, addAndGetIndex(this, defs)); - } - - public AbstractType<?> getExactTypeIfKnown(String keyspace) - { - return type; - } - - /** - * Because legacy-created tables may have a non-text comparator, we cannot determine the proper 'key' until - * we know the comparator. ColumnDefinition.Raw is a placeholder that can be converted to a real ColumnIdentifier - * once the comparator is known with prepare(). This should only be used with identifiers that are actual - * column names. See CASSANDRA-8178 for more background. - */ - public static abstract class Raw extends Selectable.Raw - { - /** - * Creates a {@code ColumnDefinition.Raw} from an unquoted identifier string. - */ - public static Raw forUnquoted(String text) - { - return new Literal(text, false); - } - - /** - * Creates a {@code ColumnDefinition.Raw} from a quoted identifier string. - */ - public static Raw forQuoted(String text) - { - return new Literal(text, true); - } - - /** - * Creates a {@code ColumnDefinition.Raw} from a pre-existing {@code ColumnDefinition} - * (useful in the rare cases where we already have the column but need - * a {@code ColumnDefinition.Raw} for typing purposes). - */ - public static Raw forColumn(ColumnDefinition column) - { - return new ForColumn(column); - } - - /** - * Get the identifier corresponding to this raw column, without assuming this is an - * existing column (unlike {@link #prepare}). - */ - public abstract ColumnIdentifier getIdentifier(CFMetaData cfm); - - public abstract String rawText(); - - @Override - public abstract ColumnDefinition prepare(CFMetaData cfm); - - @Override - public boolean processesSelection() - { - return false; - } - - @Override - public final int hashCode() - { - return toString().hashCode(); - } - - @Override - public final boolean equals(Object o) - { - if(!(o instanceof Raw)) - return false; - - Raw that = (Raw)o; - return this.toString().equals(that.toString()); - } - - private static class Literal extends Raw - { - private final String text; - - public Literal(String rawText, boolean keepCase) - { - this.text = keepCase ? rawText : rawText.toLowerCase(Locale.US); - } - - public ColumnIdentifier getIdentifier(CFMetaData cfm) - { - if (!cfm.isStaticCompactTable()) - return ColumnIdentifier.getInterned(text, true); - - AbstractType<?> columnNameType = cfm.staticCompactOrSuperTableColumnNameType(); - if (columnNameType instanceof UTF8Type) - return ColumnIdentifier.getInterned(text, true); - - // We have a legacy-created table with a non-text comparator. Check if we have a matching column, otherwise assume we should use - // columnNameType - ByteBuffer bufferName = ByteBufferUtil.bytes(text); - for (ColumnDefinition def : cfm.allColumns()) - { - if (def.name.bytes.equals(bufferName)) - return def.name; - } - return ColumnIdentifier.getInterned(columnNameType, columnNameType.fromString(text), text); - } - - public ColumnDefinition prepare(CFMetaData cfm) - { - if (!cfm.isStaticCompactTable()) - return find(cfm); - - AbstractType<?> columnNameType = cfm.staticCompactOrSuperTableColumnNameType(); - if (columnNameType instanceof UTF8Type) - return find(cfm); - - // We have a legacy-created table with a non-text comparator. Check if we have a match column, otherwise assume we should use - // columnNameType - ByteBuffer bufferName = ByteBufferUtil.bytes(text); - for (ColumnDefinition def : cfm.allColumns()) - { - if (def.name.bytes.equals(bufferName)) - return def; - } - return find(columnNameType.fromString(text), cfm); - } - - private ColumnDefinition find(CFMetaData cfm) - { - return find(ByteBufferUtil.bytes(text), cfm); - } - - private ColumnDefinition find(ByteBuffer id, CFMetaData cfm) - { - ColumnDefinition def = cfm.getColumnDefinition(id); - if (def == null) - throw new InvalidRequestException(String.format("Undefined column name %s", toString())); - return def; - } - - public String rawText() - { - return text; - } - - @Override - public String toString() - { - return ColumnIdentifier.maybeQuote(text); - } - } - - // Use internally in the rare case where we need a ColumnDefinition.Raw for type-checking but - // actually already have the column itself. - private static class ForColumn extends Raw - { - private final ColumnDefinition column; - - private ForColumn(ColumnDefinition column) - { - this.column = column; - } - - public ColumnIdentifier getIdentifier(CFMetaData cfm) - { - return column.name; - } - - public ColumnDefinition prepare(CFMetaData cfm) - { - assert cfm.getColumnDefinition(column.name) != null; // Sanity check that we're not doing something crazy - return column; - } - - public String rawText() - { - return column.name.toString(); - } - - @Override - public String toString() - { - return column.name.toCQLString(); - } - } - } - - - -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/af3fe39d/src/java/org/apache/cassandra/config/ReadRepairDecision.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/ReadRepairDecision.java b/src/java/org/apache/cassandra/config/ReadRepairDecision.java deleted file mode 100644 index 1b4b648..0000000 --- a/src/java/org/apache/cassandra/config/ReadRepairDecision.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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.config; - -public enum ReadRepairDecision -{ - NONE, GLOBAL, DC_LOCAL; -}
