You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ee...@apache.org on 2011/03/28 21:08:35 UTC

svn commit: r1086345 - in /cassandra/trunk: interface/ interface/thrift/gen-java/org/apache/cassandra/thrift/ src/avro/ src/java/org/apache/cassandra/config/ src/java/org/apache/cassandra/cql/ src/java/org/apache/cassandra/thrift/

Author: eevans
Date: Mon Mar 28 19:08:34 2011
New Revision: 1086345

URL: http://svn.apache.org/viewvc?rev=1086345&view=rev
Log:
type validated row keys

Patch by Jon Hermes (w/ minor changes); reviewed by eevans for CASSANDRA-2311

Modified:
    cassandra/trunk/interface/cassandra.thrift
    cassandra/trunk/interface/thrift/gen-java/org/apache/cassandra/thrift/CfDef.java
    cassandra/trunk/interface/thrift/gen-java/org/apache/cassandra/thrift/Constants.java
    cassandra/trunk/src/avro/internode.genavro
    cassandra/trunk/src/java/org/apache/cassandra/config/CFMetaData.java
    cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java
    cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java
    cassandra/trunk/src/java/org/apache/cassandra/thrift/ThriftValidation.java

Modified: cassandra/trunk/interface/cassandra.thrift
URL: http://svn.apache.org/viewvc/cassandra/trunk/interface/cassandra.thrift?rev=1086345&r1=1086344&r2=1086345&view=diff
==============================================================================
--- cassandra/trunk/interface/cassandra.thrift (original)
+++ cassandra/trunk/interface/cassandra.thrift Mon Mar 28 19:08:34 2011
@@ -46,7 +46,7 @@ namespace rb CassandraThrift
 #           for every edit that doesn't result in a change to major/minor.
 #
 # See the Semantic Versioning Specification (SemVer) http://semver.org.
-const string VERSION = "19.4.0"
+const string VERSION = "19.5.0"
 
 
 #
@@ -402,6 +402,7 @@ struct CfDef {
     23: optional double memtable_operations_in_millions,
     24: optional bool replicate_on_write=0,
     25: optional double merge_shards_chance,
+    26: optional string key_validation_class,
 }
 
 /* describes a keyspace. */

Modified: cassandra/trunk/interface/thrift/gen-java/org/apache/cassandra/thrift/CfDef.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/interface/thrift/gen-java/org/apache/cassandra/thrift/CfDef.java?rev=1086345&r1=1086344&r2=1086345&view=diff
==============================================================================
--- cassandra/trunk/interface/thrift/gen-java/org/apache/cassandra/thrift/CfDef.java (original)
+++ cassandra/trunk/interface/thrift/gen-java/org/apache/cassandra/thrift/CfDef.java Mon Mar 28 19:08:34 2011
@@ -73,6 +73,7 @@ public class CfDef implements TBase<CfDe
   private static final TField MEMTABLE_OPERATIONS_IN_MILLIONS_FIELD_DESC = new TField("memtable_operations_in_millions", TType.DOUBLE, (short)23);
   private static final TField REPLICATE_ON_WRITE_FIELD_DESC = new TField("replicate_on_write", TType.BOOL, (short)24);
   private static final TField MERGE_SHARDS_CHANCE_FIELD_DESC = new TField("merge_shards_chance", TType.DOUBLE, (short)25);
+  private static final TField KEY_VALIDATION_CLASS_FIELD_DESC = new TField("key_validation_class", TType.STRING, (short)26);
 
   public String keyspace;
   public String name;
@@ -96,6 +97,7 @@ public class CfDef implements TBase<CfDe
   public double memtable_operations_in_millions;
   public boolean replicate_on_write;
   public double merge_shards_chance;
+  public String key_validation_class;
 
   /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
   public enum _Fields implements TFieldIdEnum {
@@ -120,7 +122,8 @@ public class CfDef implements TBase<CfDe
     MEMTABLE_THROUGHPUT_IN_MB((short)22, "memtable_throughput_in_mb"),
     MEMTABLE_OPERATIONS_IN_MILLIONS((short)23, "memtable_operations_in_millions"),
     REPLICATE_ON_WRITE((short)24, "replicate_on_write"),
-    MERGE_SHARDS_CHANCE((short)25, "merge_shards_chance");
+    MERGE_SHARDS_CHANCE((short)25, "merge_shards_chance"),
+    KEY_VALIDATION_CLASS((short)26, "key_validation_class");
 
     private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
 
@@ -179,6 +182,8 @@ public class CfDef implements TBase<CfDe
           return REPLICATE_ON_WRITE;
         case 25: // MERGE_SHARDS_CHANCE
           return MERGE_SHARDS_CHANCE;
+        case 26: // KEY_VALIDATION_CLASS
+          return KEY_VALIDATION_CLASS;
         default:
           return null;
       }
@@ -283,6 +288,8 @@ public class CfDef implements TBase<CfDe
         new FieldValueMetaData(TType.BOOL)));
     tmpMap.put(_Fields.MERGE_SHARDS_CHANCE, new FieldMetaData("merge_shards_chance", TFieldRequirementType.OPTIONAL, 
         new FieldValueMetaData(TType.DOUBLE)));
+    tmpMap.put(_Fields.KEY_VALIDATION_CLASS, new FieldMetaData("key_validation_class", TFieldRequirementType.OPTIONAL, 
+        new FieldValueMetaData(TType.STRING)));
     metaDataMap = Collections.unmodifiableMap(tmpMap);
     FieldMetaData.addStructMetaDataMap(CfDef.class, metaDataMap);
   }
@@ -359,6 +366,9 @@ public class CfDef implements TBase<CfDe
     this.memtable_operations_in_millions = other.memtable_operations_in_millions;
     this.replicate_on_write = other.replicate_on_write;
     this.merge_shards_chance = other.merge_shards_chance;
+    if (other.isSetKey_validation_class()) {
+      this.key_validation_class = other.key_validation_class;
+    }
   }
 
   public CfDef deepCopy() {
@@ -405,6 +415,7 @@ public class CfDef implements TBase<CfDe
 
     setMerge_shards_chanceIsSet(false);
     this.merge_shards_chance = 0.0;
+    this.key_validation_class = null;
   }
 
   public String getKeyspace() {
@@ -936,6 +947,30 @@ public class CfDef implements TBase<CfDe
     __isset_bit_vector.set(__MERGE_SHARDS_CHANCE_ISSET_ID, value);
   }
 
+  public String getKey_validation_class() {
+    return this.key_validation_class;
+  }
+
+  public CfDef setKey_validation_class(String key_validation_class) {
+    this.key_validation_class = key_validation_class;
+    return this;
+  }
+
+  public void unsetKey_validation_class() {
+    this.key_validation_class = null;
+  }
+
+  /** Returns true if field key_validation_class is set (has been asigned a value) and false otherwise */
+  public boolean isSetKey_validation_class() {
+    return this.key_validation_class != null;
+  }
+
+  public void setKey_validation_classIsSet(boolean value) {
+    if (!value) {
+      this.key_validation_class = null;
+    }
+  }
+
   public void setFieldValue(_Fields field, Object value) {
     switch (field) {
     case KEYSPACE:
@@ -1114,6 +1149,14 @@ public class CfDef implements TBase<CfDe
       }
       break;
 
+    case KEY_VALIDATION_CLASS:
+      if (value == null) {
+        unsetKey_validation_class();
+      } else {
+        setKey_validation_class((String)value);
+      }
+      break;
+
     }
   }
 
@@ -1185,6 +1228,9 @@ public class CfDef implements TBase<CfDe
     case MERGE_SHARDS_CHANCE:
       return new Double(getMerge_shards_chance());
 
+    case KEY_VALIDATION_CLASS:
+      return getKey_validation_class();
+
     }
     throw new IllegalStateException();
   }
@@ -1240,6 +1286,8 @@ public class CfDef implements TBase<CfDe
       return isSetReplicate_on_write();
     case MERGE_SHARDS_CHANCE:
       return isSetMerge_shards_chance();
+    case KEY_VALIDATION_CLASS:
+      return isSetKey_validation_class();
     }
     throw new IllegalStateException();
   }
@@ -1455,6 +1503,15 @@ public class CfDef implements TBase<CfDe
         return false;
     }
 
+    boolean this_present_key_validation_class = true && this.isSetKey_validation_class();
+    boolean that_present_key_validation_class = true && that.isSetKey_validation_class();
+    if (this_present_key_validation_class || that_present_key_validation_class) {
+      if (!(this_present_key_validation_class && that_present_key_validation_class))
+        return false;
+      if (!this.key_validation_class.equals(that.key_validation_class))
+        return false;
+    }
+
     return true;
   }
 
@@ -1572,6 +1629,11 @@ public class CfDef implements TBase<CfDe
     if (present_merge_shards_chance)
       builder.append(merge_shards_chance);
 
+    boolean present_key_validation_class = true && (isSetKey_validation_class());
+    builder.append(present_key_validation_class);
+    if (present_key_validation_class)
+      builder.append(key_validation_class);
+
     return builder.toHashCode();
   }
 
@@ -1803,6 +1865,16 @@ public class CfDef implements TBase<CfDe
         return lastComparison;
       }
     }
+    lastComparison = Boolean.valueOf(isSetKey_validation_class()).compareTo(typedOther.isSetKey_validation_class());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetKey_validation_class()) {
+      lastComparison = TBaseHelper.compareTo(this.key_validation_class, typedOther.key_validation_class);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
     return 0;
   }
 
@@ -1999,6 +2071,13 @@ public class CfDef implements TBase<CfDe
             TProtocolUtil.skip(iprot, field.type);
           }
           break;
+        case 26: // KEY_VALIDATION_CLASS
+          if (field.type == TType.STRING) {
+            this.key_validation_class = iprot.readString();
+          } else { 
+            TProtocolUtil.skip(iprot, field.type);
+          }
+          break;
         default:
           TProtocolUtil.skip(iprot, field.type);
       }
@@ -2143,6 +2222,13 @@ public class CfDef implements TBase<CfDe
       oprot.writeDouble(this.merge_shards_chance);
       oprot.writeFieldEnd();
     }
+    if (this.key_validation_class != null) {
+      if (isSetKey_validation_class()) {
+        oprot.writeFieldBegin(KEY_VALIDATION_CLASS_FIELD_DESC);
+        oprot.writeString(this.key_validation_class);
+        oprot.writeFieldEnd();
+      }
+    }
     oprot.writeFieldStop();
     oprot.writeStructEnd();
   }
@@ -2311,6 +2397,16 @@ public class CfDef implements TBase<CfDe
       sb.append(this.merge_shards_chance);
       first = false;
     }
+    if (isSetKey_validation_class()) {
+      if (!first) sb.append(", ");
+      sb.append("key_validation_class:");
+      if (this.key_validation_class == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.key_validation_class);
+      }
+      first = false;
+    }
     sb.append(")");
     return sb.toString();
   }

Modified: cassandra/trunk/interface/thrift/gen-java/org/apache/cassandra/thrift/Constants.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/interface/thrift/gen-java/org/apache/cassandra/thrift/Constants.java?rev=1086345&r1=1086344&r2=1086345&view=diff
==============================================================================
--- cassandra/trunk/interface/thrift/gen-java/org/apache/cassandra/thrift/Constants.java (original)
+++ cassandra/trunk/interface/thrift/gen-java/org/apache/cassandra/thrift/Constants.java Mon Mar 28 19:08:34 2011
@@ -44,6 +44,6 @@ import org.slf4j.LoggerFactory;
 
 public class Constants {
 
-  public static final String VERSION = "19.4.0";
+  public static final String VERSION = "19.5.0";
 
 }

Modified: cassandra/trunk/src/avro/internode.genavro
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/avro/internode.genavro?rev=1086345&r1=1086344&r2=1086345&view=diff
==============================================================================
--- cassandra/trunk/src/avro/internode.genavro (original)
+++ cassandra/trunk/src/avro/internode.genavro Mon Mar 28 19:08:34 2011
@@ -52,6 +52,7 @@ protocol InterNode {
         boolean replicate_on_write = false;
         union { int, null } gc_grace_seconds;
         union { null, string } default_validation_class = null;
+        union { null, string } key_validation_class = null;
         union { null, int } min_compaction_threshold = null;
         union { null, int } max_compaction_threshold = null;
         union { int, null } row_cache_save_period_in_seconds = 0;

Modified: cassandra/trunk/src/java/org/apache/cassandra/config/CFMetaData.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/config/CFMetaData.java?rev=1086345&r1=1086344&r2=1086345&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/config/CFMetaData.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/config/CFMetaData.java Mon Mar 28 19:08:34 2011
@@ -140,6 +140,7 @@ public final class CFMetaData
     private boolean replicateOnWrite;                 // default false
     private int gcGraceSeconds;                       // default 864000 (ten days)
     private AbstractType defaultValidator;            // default BytesType (no-op), use comparator types
+    private AbstractType keyValidator;                // default BytesType (no-op), use comparator types
     private int minCompactionThreshold;               // default 4
     private int maxCompactionThreshold;               // default 32
     private int rowCacheSavePeriodInSeconds;          // default 0 (off)
@@ -159,6 +160,7 @@ public final class CFMetaData
     public CFMetaData replicateOnWrite(boolean prop) {replicateOnWrite = prop; return this;}
     public CFMetaData gcGraceSeconds(int prop) {gcGraceSeconds = prop; return this;}
     public CFMetaData defaultValidator(AbstractType prop) {defaultValidator = prop; return this;}
+    public CFMetaData keyValidator(AbstractType prop) {keyValidator = prop; return this;}
     public CFMetaData minCompactionThreshold(int prop) {minCompactionThreshold = prop; return this;}
     public CFMetaData maxCompactionThreshold(int prop) {maxCompactionThreshold = prop; return this;}
     public CFMetaData rowCacheSavePeriod(int prop) {rowCacheSavePeriodInSeconds = prop; return this;}
@@ -217,6 +219,7 @@ public final class CFMetaData
 
         // Defaults strange or simple enough to not need a DEFAULT_T for
         defaultValidator = BytesType.instance;
+        keyValidator = BytesType.instance;
         comment = "";
         column_metadata = new HashMap<ByteBuffer,ColumnDefinition>();
     }
@@ -308,6 +311,7 @@ public final class CFMetaData
         cf.replicate_on_write = replicateOnWrite;
         cf.gc_grace_seconds = gcGraceSeconds;
         cf.default_validation_class = new Utf8(defaultValidator.getClass().getName());
+        cf.key_validation_class = new Utf8(keyValidator.getClass().getName());
         cf.min_compaction_threshold = minCompactionThreshold;
         cf.max_compaction_threshold = maxCompactionThreshold;
         cf.row_cache_save_period_in_seconds = rowCacheSavePeriodInSeconds;
@@ -328,14 +332,15 @@ public final class CFMetaData
         AbstractType comparator;
         AbstractType subcolumnComparator = null;
         AbstractType validator;
+        AbstractType keyValidator;
+
         try
         {
             comparator = DatabaseDescriptor.getComparator(cf.comparator_type.toString());
             if (cf.subcomparator_type != null)
                 subcolumnComparator = DatabaseDescriptor.getComparator(cf.subcomparator_type.toString());
-            validator = cf.default_validation_class == null
-                        ? BytesType.instance
-                        : DatabaseDescriptor.getComparator(cf.default_validation_class.toString());
+            validator = DatabaseDescriptor.getComparator(cf.default_validation_class.toString());
+            keyValidator = DatabaseDescriptor.getComparator(cf.key_validation_class.toString());
         }
         catch (Exception ex)
         {
@@ -375,6 +380,7 @@ public final class CFMetaData
                       .replicateOnWrite(cf.replicate_on_write)
                       .gcGraceSeconds(cf.gc_grace_seconds)
                       .defaultValidator(validator)
+                      .keyValidator(keyValidator)
                       .columnMetadata(column_metadata);
     }
     
@@ -418,6 +424,11 @@ public final class CFMetaData
         return defaultValidator;
     }
 
+    public AbstractType getKeyValidator()
+    {
+        return keyValidator;
+    }
+
     public Integer getMinCompactionThreshold()
     {
         return minCompactionThreshold;
@@ -482,6 +493,8 @@ public final class CFMetaData
             .append(readRepairChance, rhs.readRepairChance)
             .append(replicateOnWrite, rhs.replicateOnWrite)
             .append(gcGraceSeconds, rhs.gcGraceSeconds)
+            .append(defaultValidator, rhs.defaultValidator)
+            .append(keyValidator, rhs.keyValidator)
             .append(minCompactionThreshold, rhs.minCompactionThreshold)
             .append(maxCompactionThreshold, rhs.maxCompactionThreshold)
             .append(cfId.intValue(), rhs.cfId.intValue())
@@ -510,6 +523,7 @@ public final class CFMetaData
             .append(replicateOnWrite)
             .append(gcGraceSeconds)
             .append(defaultValidator)
+            .append(keyValidator)
             .append(minCompactionThreshold)
             .append(maxCompactionThreshold)
             .append(cfId)
@@ -593,6 +607,7 @@ public final class CFMetaData
         replicateOnWrite = cf_def.replicate_on_write;
         gcGraceSeconds = cf_def.gc_grace_seconds;
         defaultValidator = DatabaseDescriptor.getComparator(cf_def.default_validation_class);
+        keyValidator = DatabaseDescriptor.getComparator(cf_def.key_validation_class);
         minCompactionThreshold = cf_def.min_compaction_threshold;
         maxCompactionThreshold = cf_def.max_compaction_threshold;
         rowCacheSavePeriodInSeconds = cf_def.row_cache_save_period_in_seconds;
@@ -658,6 +673,7 @@ public final class CFMetaData
         def.setReplicate_on_write(cfm.replicateOnWrite);
         def.setGc_grace_seconds(cfm.gcGraceSeconds);
         def.setDefault_validation_class(cfm.defaultValidator.getClass().getName());
+        def.setKey_validation_class(cfm.keyValidator.getClass().getName());
         def.setMin_compaction_threshold(cfm.minCompactionThreshold);
         def.setMax_compaction_threshold(cfm.maxCompactionThreshold);
         def.setRow_cache_save_period_in_seconds(cfm.rowCacheSavePeriodInSeconds);
@@ -732,6 +748,7 @@ public final class CFMetaData
         newDef.comment = def.getComment();
         newDef.comparator_type = def.getComparator_type();
         newDef.default_validation_class = def.getDefault_validation_class();
+        newDef.key_validation_class = def.getKey_validation_class();
         newDef.gc_grace_seconds = def.getGc_grace_seconds();
         newDef.id = def.getId();
         newDef.key_cache_save_period_in_seconds = def.getKey_cache_save_period_in_seconds();
@@ -862,6 +879,7 @@ public final class CFMetaData
             .append("replicateOnWrite", replicateOnWrite)
             .append("gcGraceSeconds", gcGraceSeconds)
             .append("defaultValidator", defaultValidator)
+            .append("keyValidator", keyValidator)
             .append("minCompactionThreshold", minCompactionThreshold)
             .append("maxCompactionThreshold", maxCompactionThreshold)
             .append("rowCacheSavePeriodInSeconds", rowCacheSavePeriodInSeconds)

Modified: cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java?rev=1086345&r1=1086344&r2=1086345&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java Mon Mar 28 19:08:34 2011
@@ -69,6 +69,7 @@ import com.google.common.collect.Maps;
 
 import static org.apache.cassandra.thrift.ThriftValidation.validateKey;
 import static org.apache.cassandra.thrift.ThriftValidation.validateColumnFamily;
+import static org.apache.cassandra.thrift.ThriftValidation.validateKeyType;
 
 public class QueryProcessor
 {
@@ -224,6 +225,7 @@ public class QueryProcessor
 
         for (UpdateStatement update : updateStatements)
         {
+            String cfname = update.getColumnFamily();
             // Avoid unnecessary authorizations.
             if (!(cfamsSeen.contains(update.getColumnFamily())))
             {
@@ -234,7 +236,8 @@ public class QueryProcessor
             // FIXME: keys as ascii is not a Real Solution
             ByteBuffer key = update.getKey().getByteBuffer(AsciiType.instance);
             validateKey(key);
-            validateColumnFamily(keyspace, update.getColumnFamily());
+            validateColumnFamily(keyspace, cfname);
+            validateKeyType(key, keyspace, cfname);
             AbstractType<?> comparator = update.getComparator(keyspace);
             
             RowMutation rm = new RowMutation(keyspace, key);

Modified: cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java?rev=1086345&r1=1086344&r2=1086345&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java Mon Mar 28 19:08:34 2011
@@ -349,6 +349,7 @@ public class CassandraServer implements 
 
         ThriftValidation.validateKey(key);
         ThriftValidation.validateColumnParent(state().getKeyspace(), column_parent);
+        ThriftValidation.validateKeyType(key, state().getKeyspace(), column_parent.column_family);
         ThriftValidation.validateColumnNames(state().getKeyspace(), column_parent, Arrays.asList(column.name));
         ThriftValidation.validateColumnData(state().getKeyspace(), column_parent.column_family, column);
 
@@ -387,7 +388,8 @@ public class CassandraServer implements 
             for (Map.Entry<String, List<Mutation>> columnFamilyMutations : columnFamilyToMutations.entrySet())
             {
                 String cfName = columnFamilyMutations.getKey();
-                
+                ThriftValidation.validateKeyType(key, state().getKeyspace(), cfName);
+
                 // Avoid unneeded authorizations
                 if (!(cfamsSeen.contains(cfName)))
                 {
@@ -423,6 +425,7 @@ public class CassandraServer implements 
 
         ThriftValidation.validateKey(key);
         ThriftValidation.validateColumnPathOrParent(state().getKeyspace(), column_path);
+        ThriftValidation.validateKeyType(key, state().getKeyspace(), column_path.column_family);
 
         RowMutation rm = new RowMutation(state().getKeyspace(), key);
         rm.delete(new QueryPath(column_path), timestamp); 

Modified: cassandra/trunk/src/java/org/apache/cassandra/thrift/ThriftValidation.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/thrift/ThriftValidation.java?rev=1086345&r1=1086344&r2=1086345&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/thrift/ThriftValidation.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/thrift/ThriftValidation.java Mon Mar 28 19:08:34 2011
@@ -23,9 +23,6 @@ package org.apache.cassandra.thrift;
 import java.nio.ByteBuffer;
 import java.util.*;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.ConfigurationException;
 import org.apache.cassandra.config.DatabaseDescriptor;
@@ -50,8 +47,6 @@ import org.apache.cassandra.utils.FBUtil
  */
 public class ThriftValidation
 {
-    private static final Logger logger = LoggerFactory.getLogger(ThriftValidation.class);
-
     public static void validateKey(ByteBuffer key) throws InvalidRequestException
     {
         if (key == null || key.remaining() == 0)
@@ -66,6 +61,19 @@ public class ThriftValidation
         }
     }
 
+    public static void validateKeyType(ByteBuffer key, String ksname, String cfname) throws InvalidRequestException
+    {
+        try
+        {
+            AbstractType<?> keyValidator = DatabaseDescriptor.getCFMetaData(ksname, cfname).getKeyValidator();
+            keyValidator.validate(key);
+        }
+        catch (MarshalException e)
+        {
+            throw new InvalidRequestException(e.toString());
+        }
+    }
+
     public static void validateTable(String tablename) throws KeyspaceNotDefinedException
     {
         if (!DatabaseDescriptor.getTables().contains(tablename))