org.apache.cassandra.thrift.ThriftConversion Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cassandra-all Show documentation
Show all versions of cassandra-all Show documentation
Palantir open source project
The newest version!
/*
* 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.thrift;
import java.nio.ByteBuffer;
import java.util.*;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import org.apache.cassandra.cache.CachingOptions;
import org.apache.cassandra.config.*;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.Operator;
import org.apache.cassandra.cql3.UntypedResultSet;
import org.apache.cassandra.db.ColumnFamilyType;
import org.apache.cassandra.schema.LegacySchemaTables;
import org.apache.cassandra.db.WriteType;
import org.apache.cassandra.db.composites.CellNameType;
import org.apache.cassandra.db.composites.CellNames;
import org.apache.cassandra.db.marshal.*;
import org.apache.cassandra.exceptions.*;
import org.apache.cassandra.io.compress.CompressionParameters;
import org.apache.cassandra.locator.AbstractReplicationStrategy;
import org.apache.cassandra.locator.LocalStrategy;
import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.UUIDGen;
/**
* Static utility methods to convert internal structure to and from thrift ones.
*/
public class ThriftConversion
{
public static org.apache.cassandra.db.ConsistencyLevel fromThrift(ConsistencyLevel cl)
{
switch (cl)
{
case ANY: return org.apache.cassandra.db.ConsistencyLevel.ANY;
case ONE: return org.apache.cassandra.db.ConsistencyLevel.ONE;
case TWO: return org.apache.cassandra.db.ConsistencyLevel.TWO;
case THREE: return org.apache.cassandra.db.ConsistencyLevel.THREE;
case QUORUM: return org.apache.cassandra.db.ConsistencyLevel.QUORUM;
case ALL: return org.apache.cassandra.db.ConsistencyLevel.ALL;
case LOCAL_QUORUM: return org.apache.cassandra.db.ConsistencyLevel.LOCAL_QUORUM;
case EACH_QUORUM: return org.apache.cassandra.db.ConsistencyLevel.EACH_QUORUM;
case SERIAL: return org.apache.cassandra.db.ConsistencyLevel.SERIAL;
case LOCAL_SERIAL: return org.apache.cassandra.db.ConsistencyLevel.LOCAL_SERIAL;
case LOCAL_ONE: return org.apache.cassandra.db.ConsistencyLevel.LOCAL_ONE;
}
throw new AssertionError();
}
public static ConsistencyLevel toThrift(org.apache.cassandra.db.ConsistencyLevel cl)
{
switch (cl)
{
case ANY: return ConsistencyLevel.ANY;
case ONE: return ConsistencyLevel.ONE;
case TWO: return ConsistencyLevel.TWO;
case THREE: return ConsistencyLevel.THREE;
case QUORUM: return ConsistencyLevel.QUORUM;
case ALL: return ConsistencyLevel.ALL;
case LOCAL_QUORUM: return ConsistencyLevel.LOCAL_QUORUM;
case EACH_QUORUM: return ConsistencyLevel.EACH_QUORUM;
case SERIAL: return ConsistencyLevel.SERIAL;
case LOCAL_SERIAL: return ConsistencyLevel.LOCAL_SERIAL;
case LOCAL_ONE: return ConsistencyLevel.LOCAL_ONE;
}
throw new AssertionError();
}
// We never return, but returning a RuntimeException allows to write "throw rethrow(e)" without java complaining
// for methods that have a return value.
public static RuntimeException rethrow(RequestExecutionException e) throws UnavailableException, TimedOutException
{
if (e instanceof RequestFailureException)
throw toThrift((RequestFailureException)e);
else if (e instanceof RequestTimeoutException)
throw toThrift((RequestTimeoutException)e);
else
throw new UnavailableException();
}
public static InvalidRequestException toThrift(RequestValidationException e)
{
return new InvalidRequestException(e.getMessage());
}
public static UnavailableException toThrift(org.apache.cassandra.exceptions.UnavailableException e)
{
return new UnavailableException();
}
public static AuthenticationException toThrift(org.apache.cassandra.exceptions.AuthenticationException e)
{
return new AuthenticationException(e.getMessage());
}
public static TimedOutException toThrift(RequestTimeoutException e)
{
TimedOutException toe = new TimedOutException();
if (e instanceof WriteTimeoutException)
{
WriteTimeoutException wte = (WriteTimeoutException)e;
toe.setAcknowledged_by(wte.received);
if (wte.writeType == WriteType.BATCH_LOG)
toe.setAcknowledged_by_batchlog(false);
else if (wte.writeType == WriteType.BATCH)
toe.setAcknowledged_by_batchlog(true);
else if (wte.writeType == WriteType.CAS)
toe.setPaxos_in_progress(true);
}
return toe;
}
// Thrift does not support RequestFailureExceptions, so we translate them into timeouts
public static TimedOutException toThrift(RequestFailureException e)
{
return new TimedOutException();
}
public static List indexExpressionsFromThrift(List exprs)
{
if (exprs == null)
return null;
if (exprs.isEmpty())
return Collections.emptyList();
List converted = new ArrayList<>(exprs.size());
for (IndexExpression expr : exprs)
{
converted.add(new org.apache.cassandra.db.IndexExpression(expr.column_name,
Operator.valueOf(expr.op.name()),
expr.value));
}
return converted;
}
public static KSMetaData fromThrift(KsDef ksd, CFMetaData... cfDefs) throws ConfigurationException
{
Class extends AbstractReplicationStrategy> cls = AbstractReplicationStrategy.getClass(ksd.strategy_class);
if (cls.equals(LocalStrategy.class))
throw new ConfigurationException("Unable to use given strategy class: LocalStrategy is reserved for internal use.");
return new KSMetaData(ksd.name,
cls,
ksd.strategy_options == null ? Collections.emptyMap() : ksd.strategy_options,
ksd.durable_writes,
Arrays.asList(cfDefs));
}
public static KsDef toThrift(KSMetaData ksm)
{
List cfDefs = new ArrayList<>(ksm.cfMetaData().size());
for (CFMetaData cfm : ksm.cfMetaData().values())
if (cfm.isThriftCompatible()) // Don't expose CF that cannot be correctly handle by thrift; see CASSANDRA-4377 for further details
cfDefs.add(toThrift(cfm));
KsDef ksdef = new KsDef(ksm.name, ksm.strategyClass.getName(), cfDefs);
ksdef.setStrategy_options(ksm.strategyOptions);
ksdef.setDurable_writes(ksm.durableWrites);
return ksdef;
}
public static CFMetaData fromThrift(CfDef cf_def)
throws org.apache.cassandra.exceptions.InvalidRequestException, ConfigurationException
{
return internalFromThrift(cf_def, Collections.emptyList());
}
public static CFMetaData fromThriftForUpdate(CfDef cf_def, CFMetaData toUpdate)
throws org.apache.cassandra.exceptions.InvalidRequestException, ConfigurationException
{
return internalFromThrift(cf_def, toUpdate.allColumns());
}
// Convert a thrift CfDef, given a list of ColumnDefinitions to copy over to the created CFMetadata before the CQL metadata are rebuild
private static CFMetaData internalFromThrift(CfDef cf_def, Collection previousCQLMetadata)
throws org.apache.cassandra.exceptions.InvalidRequestException, ConfigurationException
{
ColumnFamilyType cfType = ColumnFamilyType.create(cf_def.column_type);
if (cfType == null)
throw new org.apache.cassandra.exceptions.InvalidRequestException("Invalid column type " + cf_def.column_type);
applyImplicitDefaults(cf_def);
try
{
AbstractType> rawComparator = TypeParser.parse(cf_def.comparator_type);
AbstractType> subComparator = cfType == ColumnFamilyType.Standard
? null
: cf_def.subcomparator_type == null ? BytesType.instance : TypeParser.parse(cf_def.subcomparator_type);
AbstractType> fullRawComparator = CFMetaData.makeRawAbstractType(rawComparator, subComparator);
AbstractType> keyValidator = cf_def.isSetKey_validation_class() ? TypeParser.parse(cf_def.key_validation_class) : null;
// Convert the REGULAR definitions from the input CfDef
List defs = fromThrift(cf_def.keyspace, cf_def.name, rawComparator, subComparator, cf_def.column_metadata);
// Add the keyAlias if there is one, since that's on CQL metadata that thrift can actually change (for
// historical reasons)
boolean hasKeyAlias = cf_def.isSetKey_alias() && keyValidator != null && !(keyValidator instanceof CompositeType);
if (hasKeyAlias)
defs.add(ColumnDefinition.partitionKeyDef(cf_def.keyspace, cf_def.name, cf_def.key_alias, keyValidator, null));
// for Thrift updates, we should be calculating denseness from just the regular columns & comparator
boolean isDense = CFMetaData.calculateIsDense(fullRawComparator, defs);
// Now add any CQL metadata that we want to copy, skipping the keyAlias if there was one
for (ColumnDefinition def : previousCQLMetadata)
{
// skip all pre-existing REGULAR columns
if (def.kind == ColumnDefinition.Kind.REGULAR)
continue;
// skip previous PARTITION_KEY column def if key_alias has been set by this update already (overwritten)
if (def.kind == ColumnDefinition.Kind.PARTITION_KEY && hasKeyAlias)
continue;
// the table switched from DENSE to SPARSE by adding one or more REGULAR columns;
// in this case we should now drop the COMPACT_VALUE column
if (def.kind == ColumnDefinition.Kind.COMPACT_VALUE && !isDense)
continue;
// skip CLUSTERING_COLUMN column(s) of a sparse table, if:
// a) this is a Standard columnfamily *OR* b) it's a Super columnfamily and the second (subcolumn) component;
// in other words, only keep the clustering column in sparse tables if it's the first (super) component
// of a super column family
if (def.kind == ColumnDefinition.Kind.CLUSTERING_COLUMN && !isDense)
if (cfType == ColumnFamilyType.Standard || def.position() != 0)
continue;
defs.add(def);
}
CellNameType comparator = CellNames.fromAbstractType(fullRawComparator, CFMetaData.calculateIsDense(fullRawComparator, defs));
UUID cfId = Schema.instance.getId(cf_def.keyspace, cf_def.name);
if (cfId == null)
cfId = UUIDGen.getTimeUUID();
// set isDense now so that it doesn't get re-calculated incorrectly later in rebuild() b/c of defined clusterings
CFMetaData newCFMD = new CFMetaData(cf_def.keyspace, cf_def.name, cfType, comparator, cfId).isDense(isDense);
newCFMD.addAllColumnDefinitions(defs);
if (keyValidator != null)
newCFMD.keyValidator(keyValidator);
if (cf_def.isSetGc_grace_seconds())
newCFMD.gcGraceSeconds(cf_def.gc_grace_seconds);
if (cf_def.isSetMin_compaction_threshold())
newCFMD.minCompactionThreshold(cf_def.min_compaction_threshold);
if (cf_def.isSetMax_compaction_threshold())
newCFMD.maxCompactionThreshold(cf_def.max_compaction_threshold);
if (cf_def.isSetCompaction_strategy())
newCFMD.compactionStrategyClass(CFMetaData.createCompactionStrategy(cf_def.compaction_strategy));
if (cf_def.isSetCompaction_strategy_options())
newCFMD.compactionStrategyOptions(new HashMap<>(cf_def.compaction_strategy_options));
if (cf_def.isSetBloom_filter_fp_chance())
newCFMD.bloomFilterFpChance(cf_def.bloom_filter_fp_chance);
if (cf_def.isSetMemtable_flush_period_in_ms())
newCFMD.memtableFlushPeriod(cf_def.memtable_flush_period_in_ms);
if (cf_def.isSetCaching() || cf_def.isSetCells_per_row_to_cache())
newCFMD.caching(CachingOptions.fromThrift(cf_def.caching, cf_def.cells_per_row_to_cache));
if (cf_def.isSetRead_repair_chance())
newCFMD.readRepairChance(cf_def.read_repair_chance);
if (cf_def.isSetDefault_time_to_live())
newCFMD.defaultTimeToLive(cf_def.default_time_to_live);
if (cf_def.isSetDclocal_read_repair_chance())
newCFMD.dcLocalReadRepairChance(cf_def.dclocal_read_repair_chance);
if (cf_def.isSetMin_index_interval())
newCFMD.minIndexInterval(cf_def.min_index_interval);
if (cf_def.isSetMax_index_interval())
newCFMD.maxIndexInterval(cf_def.max_index_interval);
if (cf_def.isSetSpeculative_retry())
newCFMD.speculativeRetry(CFMetaData.SpeculativeRetry.fromString(cf_def.speculative_retry));
if (cf_def.isSetTriggers())
newCFMD.triggers(triggerDefinitionsFromThrift(cf_def.triggers));
return newCFMD.comment(cf_def.comment)
.defaultValidator(TypeParser.parse(cf_def.default_validation_class))
.compressionParameters(CompressionParameters.create(cf_def.compression_options))
.rebuild();
}
catch (SyntaxException | MarshalException e)
{
throw new ConfigurationException(e.getMessage());
}
}
/** applies implicit defaults to cf definition. useful in updates */
private static void applyImplicitDefaults(org.apache.cassandra.thrift.CfDef cf_def)
{
if (!cf_def.isSetComment())
cf_def.setComment("");
if (!cf_def.isSetMin_compaction_threshold())
cf_def.setMin_compaction_threshold(CFMetaData.DEFAULT_MIN_COMPACTION_THRESHOLD);
if (!cf_def.isSetMax_compaction_threshold())
cf_def.setMax_compaction_threshold(CFMetaData.DEFAULT_MAX_COMPACTION_THRESHOLD);
if (cf_def.compaction_strategy == null)
cf_def.compaction_strategy = CFMetaData.DEFAULT_COMPACTION_STRATEGY_CLASS.getSimpleName();
if (cf_def.compaction_strategy_options == null)
cf_def.compaction_strategy_options = Collections.emptyMap();
if (!cf_def.isSetCompression_options())
cf_def.setCompression_options(Collections.singletonMap(CompressionParameters.SSTABLE_COMPRESSION, CFMetaData.DEFAULT_COMPRESSOR));
if (!cf_def.isSetDefault_time_to_live())
cf_def.setDefault_time_to_live(CFMetaData.DEFAULT_DEFAULT_TIME_TO_LIVE);
if (!cf_def.isSetDclocal_read_repair_chance())
cf_def.setDclocal_read_repair_chance(CFMetaData.DEFAULT_DCLOCAL_READ_REPAIR_CHANCE);
// if index_interval was set, use that for the min_index_interval default
if (!cf_def.isSetMin_index_interval())
{
if (cf_def.isSetIndex_interval())
cf_def.setMin_index_interval(cf_def.getIndex_interval());
else
cf_def.setMin_index_interval(CFMetaData.DEFAULT_MIN_INDEX_INTERVAL);
}
if (!cf_def.isSetMax_index_interval())
{
// ensure the max is at least as large as the min
cf_def.setMax_index_interval(Math.max(cf_def.min_index_interval, CFMetaData.DEFAULT_MAX_INDEX_INTERVAL));
}
}
/**
* Create CFMetaData from thrift {@link CqlRow} that contains columns from schema_columnfamilies.
*
* @param columnsRes CqlRow containing columns from schema_columnfamilies.
* @return CFMetaData derived from CqlRow
*/
public static CFMetaData fromThriftCqlRow(CqlRow cf, CqlResult columnsRes)
{
UntypedResultSet.Row cfRow = new UntypedResultSet.Row(convertThriftCqlRow(cf));
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy