cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jbel...@apache.org
Subject svn commit: r1025682 - in /cassandra/trunk: CHANGES.txt src/java/org/apache/cassandra/cli/Cli.g src/java/org/apache/cassandra/cli/CliClient.java src/java/org/apache/cassandra/cli/CliUtils.java test/unit/org/apache/cassandra/cli/CliTest.java
Date Wed, 20 Oct 2010 19:18:40 GMT
Author: jbellis
Date: Wed Oct 20 19:18:40 2010
New Revision: 1025682

URL: http://svn.apache.org/viewvc?rev=1025682&view=rev
Log:
cli support for index queries
patch by Pavel Yaskevich; reviewed by jbellis for CASSANDRA-1635

Modified:
    cassandra/trunk/CHANGES.txt
    cassandra/trunk/src/java/org/apache/cassandra/cli/Cli.g
    cassandra/trunk/src/java/org/apache/cassandra/cli/CliClient.java
    cassandra/trunk/src/java/org/apache/cassandra/cli/CliUtils.java
    cassandra/trunk/test/unit/org/apache/cassandra/cli/CliTest.java

Modified: cassandra/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/cassandra/trunk/CHANGES.txt?rev=1025682&r1=1025681&r2=1025682&view=diff
==============================================================================
--- cassandra/trunk/CHANGES.txt (original)
+++ cassandra/trunk/CHANGES.txt Wed Oct 20 19:18:40 2010
@@ -49,6 +49,7 @@ dev
    client API until races can be fixed (CASSANDRA-1630, CASSANDRA-1585)
  * add cli sanity tests (CASSANDRA-1582)
  * update GC settings in cassandra.bat (CASSANDRA-1636)
+ * cli support for index queries (CASSANDRA-1635)
 
 
 0.7-beta2

Modified: cassandra/trunk/src/java/org/apache/cassandra/cli/Cli.g
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/cli/Cli.g?rev=1025682&r1=1025681&r2=1025682&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/cli/Cli.g (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/cli/Cli.g Wed Oct 20 19:18:40 2010
@@ -44,6 +44,7 @@ tokens {
     NODE_SHOW_VERSION;
     NODE_SHOW_TABLES;
     NODE_THRIFT_GET;
+    NODE_THRIFT_GET_WITH_CONDITIONS;
     NODE_THRIFT_SET;
     NODE_THRIFT_COUNT;
     NODE_THRIFT_DEL;
@@ -63,6 +64,8 @@ tokens {
     
     CONVERT_TO_TYPE;
     FUNCTION_CALL;
+    CONDITION;
+    CONDITIONS;
     ARRAY;
     HASH;
     PAIR;
@@ -185,6 +188,17 @@ exitStatement
 getStatement
     : K_GET columnFamilyExpr ('AS' typeIdentifier)?
         -> ^(NODE_THRIFT_GET columnFamilyExpr ( ^(CONVERT_TO_TYPE typeIdentifier) )? )
+    | K_GET columnFamily 'WHERE' getCondition ('AND' getCondition)* ('LIMIT' limit=IntegerLiteral)*
+        -> ^(NODE_THRIFT_GET_WITH_CONDITIONS columnFamily ^(CONDITIONS getCondition+)
^(NODE_LIMIT $limit)*) 
+    ;
+
+getCondition
+    : columnOrSuperColumn operator value
+        -> ^(CONDITION operator columnOrSuperColumn value)
+    ;
+
+operator
+    : '=' | '>' | '<' | '>=' | '<='
     ;
 
 typeIdentifier

Modified: cassandra/trunk/src/java/org/apache/cassandra/cli/CliClient.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/cli/CliClient.java?rev=1025682&r1=1025681&r2=1025682&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/cli/CliClient.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/cli/CliClient.java Wed Oct 20 19:18:40 2010
@@ -135,6 +135,9 @@ public class CliClient 
                 case CliParser.NODE_THRIFT_GET:
                     executeGet(ast);
                     break;
+                case CliParser.NODE_THRIFT_GET_WITH_CONDITIONS:
+                    executeGetWithConditions(ast);
+                    break;       
                 case CliParser.NODE_HELP:
                 	printCmdHelp(ast);
                     break;
@@ -370,6 +373,8 @@ public class CliClient 
                 css_.out.println("get <cf>['<key>']");
                 css_.out.println("get <cf>['<key>']['<col>'] (as <type>)*");
                 css_.out.println("get <cf>['<key>']['<super>']");
+                css_.out.println("get <cf> where <column> = <value> [and
<column> > <value> and ...] [limit <integer>]");
+                css_.out.println("Default LIMIT is 100. Available operations: =, >, >=,
<, <=\n");
                 css_.out.println("get <cf>['<key>']['<super>']['<col>']
(as <type>)*");
                 css_.out.print("Note: `as <type>` is optional, it dynamically converts
column value to the specified type");
                 css_.out.println(", column value validator will be set to <type>.");
@@ -455,6 +460,7 @@ public class CliClient 
             css_.out.println("rename column family <cf> <new_name>          
          Rename a column family.");
             css_.out.println("get <cf>['<key>']                             
          Get a slice of columns.");
             css_.out.println("get <cf>['<key>']['<super>']            
            Get a slice of sub columns.");
+            css_.out.println("get <cf> where <column> = <value> [and <column>
> <value> and ...] [limit int]. ");
             css_.out.println("get <cf>['<key>']['<col>'] (as <type>)*
                     Get a column value.");
             css_.out.println("get <cf>['<key>']['<super>']['<col>']
(as <type>)*       Get a sub column value.");
             css_.out.println("set <cf>['<key>']['<col>'] = <value>
                              Set a column.");
@@ -742,6 +748,100 @@ public class CliClient 
                         formatColumnName(keySpace, columnFamily, column), valueAsString,
column.timestamp);
     }
 
+    /**
+     * Process get operation with conditions (using Thrift get_indexed_slices method)
+     * @param statement - tree representation of the current statement
+     * Format: ^(NODE_THRIFT_GET_WITH_CONDITIONS cf ^(CONDITIONS ^(CONDITION >= column1
value1) ...) ^(NODE_LIMIT int)*)
+     */
+    private void executeGetWithConditions(Tree statement)
+    {
+        if (!CliMain.isConnected() || !hasKeySpace())
+            return;
+
+        IndexClause clause = new IndexClause();
+        String columnFamily = statement.getChild(0).getText();
+        // ^(CONDITIONS ^(CONDITION $column $value) ...)
+        Tree conditions = statement.getChild(1);
+        
+        // fetching column family definition
+        CfDef columnFamilyDef = getCfDef(columnFamily);
+
+        // fetching all columns
+        SlicePredicate predicate = new SlicePredicate();
+        SliceRange sliceRange = new SliceRange();
+        sliceRange.setStart(new byte[0]).setFinish(new byte[0]);
+        predicate.setSlice_range(sliceRange);
+
+        for (int i = 0; i < conditions.getChildCount(); i++)
+        {
+            // ^(CONDITION operator $column $value)
+            Tree condition = conditions.getChild(i);
+
+            // =, >, >=, <, <=
+            String operator = condition.getChild(0).getText();
+            String columnNameString  = CliUtils.unescapeSQLString(condition.getChild(1).getText());
+            // it could be a basic string or function call
+            Tree valueTree = condition.getChild(2);
+
+            try
+            {
+                byte[] value;
+                byte[] columnName = columnNameAsByteArray(columnNameString, columnFamily);
+
+                if (valueTree.getType() == CliParser.FUNCTION_CALL)
+                {
+                    value = convertValueByFunction(valueTree, columnFamilyDef, columnName);
+                }
+                else
+                {
+                    String valueString = CliUtils.unescapeSQLString(valueTree.getText());
+                    value = columnValueAsByteArray(columnName, columnFamily, valueString);
+                }
+
+                // index operator from string
+                IndexOperator idxOperator = CliUtils.getIndexOperator(operator);
+                // adding new index expression into index clause
+                clause.addToExpressions(new IndexExpression(columnName, idxOperator, value));
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.getMessage());
+            }
+        }
+
+        List<KeySlice> slices;
+        clause.setStart_key(new byte[] {});
+
+        // when we have ^(NODE_LIMIT Integer)
+        if (statement.getChildCount() == 3)
+        {
+            Tree limitNode = statement.getChild(2);
+            int limitValue = Integer.valueOf(limitNode.getChild(0).getText());
+
+            if (limitValue == 0)
+            {
+                throw new IllegalArgumentException("LIMIT should be greater than zero.");
+            }
+            
+            clause.setCount(limitValue);    
+        }
+
+        try
+        {
+            ColumnParent parent = new ColumnParent(columnFamily);
+            slices = thriftClient_.get_indexed_slices(parent, clause, predicate, ConsistencyLevel.ONE);
+            printSliceList(columnFamilyDef, slices);
+        }
+        catch (InvalidRequestException e)
+        {
+            throw new RuntimeException(e.getWhy());
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
     // Execute SET statement
     private void executeSet(CommonTree ast)
     throws TException, InvalidRequestException, UnavailableException, TimedOutException,
UnsupportedEncodingException, NoSuchFieldException, InstantiationException, IllegalAccessException
@@ -790,7 +890,7 @@ public class CliClient 
         switch (valueTree.getType())
         {
         case CliParser.FUNCTION_CALL:
-            columnValueInBytes = convertValueByFunction(valueTree, getCfDef(columnFamily),
columnNameInBytes);
+            columnValueInBytes = convertValueByFunction(valueTree, getCfDef(columnFamily),
columnNameInBytes, true);
             break;
         default:
             columnValueInBytes = columnValueAsByteArray(columnNameInBytes, columnFamily,
value);
@@ -1091,7 +1191,6 @@ public class CliClient 
         if (!CliMain.isConnected())
             return;
 
-        assert (ast.getChildCount() >= 1 || ast.getChildCount() <= 3) : "Incorrect
AST Construct!";
         Iterator<CommonTree> iter = ast.getChildren().iterator();
 
         // extract column family
@@ -1116,7 +1215,6 @@ public class CliClient 
             }
             else
             {
-                assert child.getType() == CliParser.NODE_LIMIT;
                 if (child.getChildCount() != 1)
                 {
                     css_.out.println("Invalid limit clause");
@@ -1137,18 +1235,7 @@ public class CliClient 
             css_.out.println("Using default limit of 100");
         }
 
-        List<String> cfnames = new ArrayList<String>();
-        for (CfDef cfd : keyspacesMap.get(keySpace).cf_defs)
-        {
-            cfnames.add(cfd.name);
-        }
-
-        int idx = cfnames.indexOf(columnFamily);
-        if (idx == -1)
-        {
-            css_.out.println("No such column family: " + columnFamily);
-            return;
-        }
+        CfDef columnFamilyDef = getCfDef(columnFamily);
 
         // read all columns and superColumns
         SlicePredicate predicate = new SlicePredicate();
@@ -1163,36 +1250,15 @@ public class CliClient 
         ColumnParent columnParent = new ColumnParent(columnFamily);
         List<KeySlice> keySlices = thriftClient_.get_range_slices(columnParent, predicate,
range, ConsistencyLevel.ONE);
         int toIndex = keySlices.size();
-        List<KeySlice> limitSlices = keySlices.subList(0, toIndex);
 
-        for (KeySlice ks : limitSlices)
+        if (limitCount < keySlices.size())
         {
-            css_.out.printf("-------------------\nRowKey: %s\n", new String(ks.key, "UTF-8"));
-            Iterator<ColumnOrSuperColumn> iterator = ks.getColumnsIterator();
-            while (iterator.hasNext())
-            {
-                ColumnOrSuperColumn columnOrSuperColumn = iterator.next();
-                if (columnOrSuperColumn.column != null)
-                {
-                    Column col = columnOrSuperColumn.column;
-                    css_.out.printf("=> (column=%s, value=%s, timestamp=%d)\n",
-                                    formatColumnName(keySpace, columnFamily, col), new String(col.value,
"UTF-8"), col.timestamp);
-                }
-                else if (columnOrSuperColumn.super_column != null)
-                {
-                    SuperColumn superCol = columnOrSuperColumn.super_column;
-                    css_.out.printf("=> (super_column=%s,", formatSuperColumnName(keySpace,
columnFamily, superCol));
-                    for (Column col : superCol.columns)
-                    {
-                        css_.out.printf("\n     (column=%s, value=%s, timestamp=%d)",
-                                        formatSubcolumnName(keySpace, columnFamily, col),
new String(col.value, "UTF-8"), col.timestamp);
-                    }
-                    css_.out.println(")");
-                }
-            }
+            // limitCount could be Integer.MAX_VALUE
+            toIndex = limitCount;
         }
 
-        css_.out.printf("\n%d row%s returned\n", toIndex, (toIndex == 0 || toIndex > 1
? "s" : ""));
+
+        printSliceList(columnFamilyDef, keySlices.subList(0, toIndex));
     }
 
     private void executeShowVersion() throws TException
@@ -1743,12 +1809,26 @@ public class CliClient 
 
     /**
      * Used to convert value (function argument, string) into byte[]
+     * calls convertValueByFunction method with "withUpdate" set to false
+     * @param functionCall - tree representing function call ^(FUNCTION_CALL function_name
value)
+     * @param columnFamily - column family definition (CfDef) 
+     * @param columnName   - also updates column family metadata for given column
+     * @return byte[] - string value as byte[] 
+     */
+    private byte[] convertValueByFunction(Tree functionCall, CfDef columnFamily, byte[] columnName)
+    {
+        return convertValueByFunction(functionCall, columnFamily, columnName, false);
+    }
+    
+    /**
+     * Used to convert value (function argument, string) into byte[]
      * @param functionCall - tree representing function call ^(FUNCTION_CALL function_name
value)
      * @param columnFamily - column family definition (CfDef)
      * @param columnName   - column name as byte[] (used to update CfDef)
+     * @param withUpdate   - also updates column family metadata for given column
      * @return byte[] - string value as byte[]
      */
-    private byte[] convertValueByFunction(Tree functionCall, CfDef columnFamily, byte[] columnName)
+    private byte[] convertValueByFunction(Tree functionCall, CfDef columnFamily, byte[] columnName,
boolean withUpdate)
     {
         String functionName = functionCall.getChild(0).getText();
         String functionArg  = CliUtils.unescapeSQLString(functionCall.getChild(1).getText());
@@ -1771,7 +1851,10 @@ public class CliClient 
             byte[] value = getBytesAccordingToType(functionArg, validator);
 
             // updating CfDef
-            updateColumnMetaData(columnFamily, columnName, validator.getClass().getName());
+            if (withUpdate)
+            {
+                updateColumnMetaData(columnFamily, columnName, validator.getClass().getName());
+            }
 
             return value;
         }
@@ -1841,4 +1924,61 @@ public class CliClient 
 
         return null;
     }
+
+    /**
+     * Prints out KeySlice list
+     * @param columnFamilyDef - column family definition
+     * @param slices - list of the KeySlice's to print out
+     * @throws UnsupportedEncodingException -  when trying to covert key
+     * @throws NotFoundException - column not found
+     * @throws TException - transfer is broken
+     * @throws IllegalAccessException - can't do operation
+     * @throws InstantiationException - can't instantiate a class
+     * @throws NoSuchFieldException - column not found
+     */
+    private void printSliceList(CfDef columnFamilyDef, List<KeySlice> slices)
+            throws UnsupportedEncodingException, NotFoundException, TException, IllegalAccessException,
InstantiationException, NoSuchFieldException
+    {
+        AbstractType validator;
+        String columnFamilyName = columnFamilyDef.getName();
+
+        for (KeySlice ks : slices)
+        {
+            css_.out.printf("-------------------\n");
+            css_.out.printf("RowKey: %s\n", new String(ks.key, "UTF-8"));
+
+            Iterator<ColumnOrSuperColumn> iterator = ks.getColumnsIterator();
+
+            while (iterator.hasNext())
+            {
+                ColumnOrSuperColumn columnOrSuperColumn = iterator.next();
+
+                if (columnOrSuperColumn.column != null)
+                {
+                    Column col = columnOrSuperColumn.column;
+                    validator = getValidatorForValue(columnFamilyDef, col.getName());
+
+                    css_.out.printf("=> (column=%s, value=%s, timestamp=%d)\n",
+                                    formatColumnName(keySpace, columnFamilyName, col), validator.getString(col.value),
col.timestamp);
+                }
+                else if (columnOrSuperColumn.super_column != null)
+                {
+                    SuperColumn superCol = columnOrSuperColumn.super_column;
+                    css_.out.printf("=> (super_column=%s,", formatSuperColumnName(keySpace,
columnFamilyName, superCol));
+
+                    for (Column col : superCol.columns)
+                    {
+                        validator = getValidatorForValue(columnFamilyDef, col.getName());
+
+                        css_.out.printf("\n     (column=%s, value=%s, timestamp=%d)",
+                                        formatSubcolumnName(keySpace, columnFamilyName, col),
validator.getString(col.value), col.timestamp);
+                    }
+
+                    css_.out.println(")");
+                }
+            }
+        }
+
+        css_.out.printf("\n%d Row%s Returned.\n", slices.size(), (slices.size() > 1 ?
"s" : ""));
+    }
 }

Modified: cassandra/trunk/src/java/org/apache/cassandra/cli/CliUtils.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/cli/CliUtils.java?rev=1025682&r1=1025681&r2=1025682&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/cli/CliUtils.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/cli/CliUtils.java Wed Oct 20 19:18:40 2010
@@ -1,4 +1,6 @@
 package org.apache.cassandra.cli;
+
+import org.apache.cassandra.thrift.IndexOperator;
 /*
  * 
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -95,4 +97,34 @@ public class CliUtils
         return sb.toString();
     }
 
+    /**
+     * Returns IndexOperator from string representation
+     * @param operator - string representing IndexOperator (=, >=, >, <, <=)
+     * @return IndexOperator - enum value of IndexOperator or null if not found
+     */
+    public static IndexOperator getIndexOperator(String operator)
+    {
+        if (operator.equals("="))
+        {
+            return IndexOperator.EQ;
+        }
+        else if (operator.equals(">="))
+        {
+            return IndexOperator.GTE;
+        }
+        else if (operator.equals(">"))
+        {
+            return IndexOperator.GT;
+        }
+        else if (operator.equals("<"))
+        {
+            return IndexOperator.LT;
+        }
+        else if (operator.equals("<="))
+        {
+            return IndexOperator.LTE;
+        }
+
+        return null;
+    }
 }

Modified: cassandra/trunk/test/unit/org/apache/cassandra/cli/CliTest.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/cli/CliTest.java?rev=1025682&r1=1025681&r2=1025682&view=diff
==============================================================================
--- cassandra/trunk/test/unit/org/apache/cassandra/cli/CliTest.java (original)
+++ cassandra/trunk/test/unit/org/apache/cassandra/cli/CliTest.java Wed Oct 20 19:18:40 2010
@@ -33,11 +33,12 @@ public class CliTest extends TestCase
     // please add new statements here so they could be auto-runned by this test.
     private String[] statements = {
         "use TestKeySpace",
-        "create column family CF1 with comparator=UTF8Type and column_metadata=[{ column_name:world,
validation_class:IntegerType }]",
+        "create column family CF1 with comparator=UTF8Type and column_metadata=[{ column_name:world,
validation_class:IntegerType, index_type:0, index_name:IdxName }, { column_name:world2, validation_class:LongType,
index_type:0, index_name:LongIdxName}]",
         "set CF1[hello][world] = 123848374878933948398384",
         "get CF1[hello][world]",
+        "set CF1[hello][world2] = 15",
+        "get CF1 where world2 = long(15)",
         "set CF1['hello'][time_spent_uuid] = timeuuid(a8098c1a-f86e-11da-bd1a-00112444be1e)",
-        "get CF1['hello'][time_spent_uuid] as LexicalUUIDType",
         "create column family CF2 with comparator=IntegerType",
         "set CF2['key'][98349387493847748398334] = 'some text'",
         "get CF2['key'][98349387493847748398334]",
@@ -91,7 +92,14 @@ public class CliTest extends TestCase
             }
             else if (statement.startsWith("get "))
             {
-                assertTrue(result.startsWith("=> (column="));
+                if (statement.contains("where"))
+                {
+                    assertTrue(result.startsWith("-------------------\nRowKey:"));
+                }
+                else
+                {
+                    assertTrue(result.startsWith("=> (column="));
+                }
             }
 
             outStream.reset(); // reset stream so we have only output from next statement
all the time



Mime
View raw message