You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by xe...@apache.org on 2012/04/23 07:08:11 UTC

git commit: Add way to force the cassandra-cli to refresh it's schema patch by Dave Brosius; reviewed by Pavel Yaskevich for CASSANDRA-4052

Updated Branches:
  refs/heads/cassandra-1.1 5cd473632 -> 3868cf5f2


Add way to force the cassandra-cli to refresh it's schema
patch by Dave Brosius; reviewed by Pavel Yaskevich for CASSANDRA-4052


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/3868cf5f
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/3868cf5f
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/3868cf5f

Branch: refs/heads/cassandra-1.1
Commit: 3868cf5f2996818ca702e1c409a856e2d285558f
Parents: 5cd4736
Author: Pavel Yaskevich <xe...@apache.org>
Authored: Sun Apr 22 22:04:04 2012 -0700
Committer: Pavel Yaskevich <xe...@apache.org>
Committed: Sun Apr 22 22:04:04 2012 -0700

----------------------------------------------------------------------
 CHANGES.txt                                      |    1 +
 src/java/org/apache/cassandra/cli/CliClient.java |  211 ++++++++++++++++-
 2 files changed, 201 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/3868cf5f/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 16b2165..5a491be 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -14,6 +14,7 @@
    (CASSANDRA-2261)
  * Move CfDef and KsDef validation out of thrift (CASSANDRA-4037)
  * Expose repairing by a user provided range (CASSANDRA-3912)
+ * Add way to force the cassandra-cli to refresh it's schema (CASSANDRA-4052)
 
 
 1.1-dev

http://git-wip-us.apache.org/repos/asf/cassandra/blob/3868cf5f/src/java/org/apache/cassandra/cli/CliClient.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cli/CliClient.java b/src/java/org/apache/cassandra/cli/CliClient.java
index 6c3872b..ded2c2b 100644
--- a/src/java/org/apache/cassandra/cli/CliClient.java
+++ b/src/java/org/apache/cassandra/cli/CliClient.java
@@ -17,6 +17,7 @@
  */
 package org.apache.cassandra.cli;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintStream;
@@ -49,6 +50,12 @@ import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.utils.UUIDGen;
 import org.apache.thrift.TBaseHelper;
 import org.apache.thrift.TException;
+import org.codehaus.jackson.JsonEncoding;
+import org.codehaus.jackson.JsonFactory;
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.type.TypeReference;
 import org.yaml.snakeyaml.constructor.Constructor;
 import org.yaml.snakeyaml.Loader;
 import org.yaml.snakeyaml.TypeDescription;
@@ -149,12 +156,14 @@ public class CliClient
     private Map<String, KsDef> keyspacesMap = new HashMap<String, KsDef>();
     private Map<String, AbstractType<?>> cfKeysComparators;
     private ConsistencyLevel consistencyLevel = ConsistencyLevel.ONE;
+    private final CfAssumptions assumptions = new CfAssumptions();
     private CliUserHelp help;
     public CliClient(CliSessionState cliSessionState, Cassandra.Client thriftClient)
     {
         this.sessionState = cliSessionState;
         this.thriftClient = thriftClient;
         this.cfKeysComparators = new HashMap<String, AbstractType<?>>();
+        assumptions.readAssumptions();
     }
 
     private CliUserHelp getHelp()
@@ -301,6 +310,7 @@ public class CliClient
     private void cleanupAndExit()
     {
         CliMain.disconnect();
+        assumptions.writeAssumptions();
         System.exit(0);
     }
 
@@ -309,7 +319,10 @@ public class CliClient
     {
         // Lazily lookup keyspace meta-data.
         if (!(keyspacesMap.containsKey(keyspace)))
+        {
             keyspacesMap.put(keyspace, thriftClient.describe_keyspace(keyspace));
+            assumptions.replayAssumptions(keyspace);
+        }
 
         return keyspacesMap.get(keyspace);
     }
@@ -1054,7 +1067,8 @@ public class CliClient
             String mySchemaVersion = thriftClient.system_update_keyspace(updatedKsDef);
             sessionState.out.println(mySchemaVersion);
             validateSchemaIsSettled(mySchemaVersion);
-            keyspacesMap.put(keyspaceName, thriftClient.describe_keyspace(keyspaceName));
+            keyspacesMap.remove(keyspaceName);
+            getKSMetaData(keySpace);
         }
         catch (InvalidRequestException e)
         {
@@ -1504,16 +1518,27 @@ public class CliClient
             return;
 
         String cfName = CliCompiler.getColumnFamily(statement, keyspacesMap.get(keySpace).cf_defs);
-        CfDef columnFamily = getCfDef(cfName);
 
         // VALIDATOR | COMPARATOR | KEYS | SUB_COMPARATOR
         String assumptionElement = statement.getChild(1).getText().toUpperCase();
-        // used to store in this.cfKeysComparator
-        AbstractType<?> comparator;
+
 
         // Could be UTF8Type, IntegerType, LexicalUUIDType etc.
         String defaultType = CliUtils.unescapeSQLString(statement.getChild(2).getText());
-
+        
+        if (applyAssumption(cfName, assumptionElement, defaultType))
+        {
+            assumptions.addAssumption(keySpace, cfName, assumptionElement, defaultType);
+            sessionState.out.println(String.format("Assumption for column family '%s' added successfully.", cfName));
+        }
+    }
+    
+    private boolean applyAssumption(String cfName, String assumptionElement, String defaultType)
+    {
+        CfDef columnFamily = getCfDef(cfName);
+        // used to store in this.cfKeysComparator
+        AbstractType<?> comparator;
+        
         try
         {
             comparator = TypeParser.parse(defaultType);
@@ -1529,7 +1554,7 @@ public class CliClient
                 String functions = Function.getFunctionNames();
                 sessionState.out.println("Type '" + defaultType + "' was not found. Available: " + functions
                                          + " Or any class which extends o.a.c.db.marshal.AbstractType.");
-                return;
+                return false;
             }
         }
 
@@ -1556,10 +1581,10 @@ public class CliClient
         {
             String elements = "VALIDATOR, COMPARATOR, KEYS, SUB_COMPARATOR.";
             sessionState.out.println(String.format("'%s' is invalid. Available: %s", assumptionElement, elements));
-            return;
+            return false;
         }
 
-        sessionState.out.println(String.format("Assumption for column family '%s' added successfully.", columnFamily.getName()));
+        return true;
     }
 
     // SHOW API VERSION
@@ -1923,6 +1948,7 @@ public class CliClient
             keySpace = keySpaceName;
             this.username = username != null ? username : "default";
 
+            keyspacesMap.remove(keySpace);
             CliMain.updateCompletor(CliUtils.getCfNamesByKeySpace(getKSMetaData(keySpace)));
             sessionState.out.println("Authenticated to keyspace: " + keySpace);
         }
@@ -2100,14 +2126,15 @@ public class CliClient
     }
 
     // DESCRIBE KEYSPACE (<keyspace> | <column_family>)?
-    private void executeDescribe(Tree statement) throws TException, InvalidRequestException
+    private void executeDescribe(Tree statement) throws TException, InvalidRequestException, NotFoundException
     {
         if (!CliMain.isConnected())
             return;
 
         int argCount = statement.getChildCount();
-
-        KsDef currentKeySpace = keyspacesMap.get(keySpace);
+        
+        keyspacesMap.remove(keySpace);
+        KsDef currentKeySpace = getKSMetaData(keySpace);
 
         if (argCount > 1) // in case somebody changes Cli grammar
             throw new RuntimeException("`describe` command take maximum one argument. See `help describe;`");
@@ -2921,4 +2948,166 @@ public class CliClient
     {
         sessionState.out.println("Elapsed time: " + (System.currentTimeMillis() - startTime) + " msec(s).");
     }
+    
+    class CfAssumptions
+    {
+        //Map<KeySpace, Map<ColumnFamily, Map<Property, Value>>>
+        private Map<String, Map<String, Map<String, String>>> assumptions;
+        private boolean assumptionsChanged;
+        private File assumptionDirectory;
+        
+        public CfAssumptions()
+        {
+            assumptions = new HashMap<String, Map<String, Map<String, String>>>();
+            assumptionsChanged = false;
+            assumptionDirectory = new File(System.getProperty("user.home"), ".cassandra-cli");
+            assumptionDirectory.mkdirs();
+        }
+        
+        public void addAssumption(String keyspace, String columnFamily, String property, String value)
+        {
+            Map<String, Map<String, String>> ksAssumes = assumptions.get(keyspace);
+            if (ksAssumes == null)
+            {
+                ksAssumes = new HashMap<String, Map<String, String>>();
+                assumptions.put(keyspace, ksAssumes);
+            }
+            
+            Map<String, String> cfAssumes = ksAssumes.get(columnFamily);
+            if (cfAssumes == null)
+            {
+                cfAssumes = new HashMap<String, String>();
+                ksAssumes.put(columnFamily, cfAssumes);
+            }
+            
+            cfAssumes.put(property, value);
+            assumptionsChanged = true;
+        }
+        
+        public void replayAssumptions(String keyspace)
+        {
+            if (!CliMain.isConnected() || !hasKeySpace())
+                return;
+            
+            Map<String, Map<String, String>> cfAssumes = assumptions.get(keyspace);
+            if (cfAssumes != null)
+            {
+                for (Map.Entry<String, Map<String, String>> cfEntry : cfAssumes.entrySet())
+                {
+                    String columnFamily = cfEntry.getKey();
+                    Map<String, String> props = cfEntry.getValue();
+                    
+                    for (Map.Entry<String, String> propEntry : props.entrySet())
+                    {
+                        applyAssumption(columnFamily, propEntry.getKey(), propEntry.getValue());
+                    }
+                }
+            }
+        }
+        
+        private void readAssumptions()
+        {
+            File assumptionFile = new File(assumptionDirectory, "assumptions.json");
+            if (assumptionFile.isFile())
+            {
+                try
+                {
+                    JsonFactory f = new JsonFactory();
+                    JsonParser p = f.createJsonParser(assumptionFile);
+                    JsonToken token = p.nextToken();
+                    while (token != JsonToken.END_OBJECT)
+                    {
+                        if (token == JsonToken.FIELD_NAME)
+                        {
+                            String keyspace = p.getText();
+                            Map<String, Map<String, String>> ksAssumes = assumptions.get(keyspace);
+                            if (ksAssumes == null)
+                            {
+                                ksAssumes = new HashMap<String, Map<String, String>>();
+                                assumptions.put(keyspace,  ksAssumes);
+                            }
+                            token = p.nextToken();
+                            while (token != JsonToken.END_ARRAY)
+                            {
+                                if (token == JsonToken.FIELD_NAME)
+                                {
+                                    String columnFamily = p.getText();
+                                    Map<String, String> cfAssumes = ksAssumes.get(columnFamily);
+                                    if (cfAssumes == null)
+                                    {
+                                        cfAssumes = new HashMap<String, String>();
+                                        ksAssumes.put(columnFamily, cfAssumes);
+                                    }
+                                    
+                                    token = p.nextToken();
+                                    while (token != JsonToken.END_ARRAY)
+                                    {
+                                        if (token == JsonToken.FIELD_NAME)
+                                        {
+                                            String prop = p.getText();
+                                            p.nextToken();
+                                            String value = p.getText();
+                                            cfAssumes.put(prop, value);
+                                        }
+                                        
+                                        token = p.nextToken();
+                                    }
+                                }
+                                token = p.nextToken();
+                            }
+                        }
+                        token = p.nextToken();
+                    }
+                    sessionState.out.println("Column Family assumptions read from " + assumptionFile);
+                }
+                catch (Exception e)
+                {
+                    sessionState.err.println("Failed reading " + assumptionFile + " file");
+                }
+            }
+        }
+        
+        private void writeAssumptions()
+        {
+            if (assumptionsChanged)
+            {
+                File assumptionFile = new File(assumptionDirectory, "assumptions.json");
+                try
+                {
+                    JsonFactory f = new JsonFactory();
+                    JsonGenerator g = f.createJsonGenerator(assumptionFile, JsonEncoding.UTF8);
+                    g.useDefaultPrettyPrinter();
+                    g.writeStartObject();
+                    for (Map.Entry<String, Map<String, Map<String, String>>> ksEntry : assumptions.entrySet())
+                    {
+                        g.writeFieldName(ksEntry.getKey());
+                        g.writeStartArray();
+                        for (Map.Entry<String, Map<String, String>> cfEntry : ksEntry.getValue().entrySet())
+                        {
+                            g.writeStartObject();
+                            g.writeFieldName(cfEntry.getKey());
+                            g.writeStartArray();
+                            for (Map.Entry<String, String> asEntry : cfEntry.getValue().entrySet())
+                            {
+                                g.writeStartObject();
+                                g.writeStringField(asEntry.getKey(), asEntry.getValue());
+                                g.writeEndObject();
+                            }
+                            g.writeEndArray();
+                            g.writeEndObject();
+                        }
+                        g.writeEndArray();
+                    }
+                    g.writeEndObject();
+                    g.close();
+                    sessionState.out.println("Column Family assumptions written to " + assumptionFile);
+                    assumptionsChanged = false;
+                }
+                catch (Exception e)
+                {
+                    sessionState.err.println("Failed writing " + assumptionFile + " file");
+                }
+            }
+        }
+    }
 }