Author: gdusbabek
Date: Fri Sep  3 20:24:48 2010
New Revision: 992452

URL: http://svn.apache.org/viewvc?rev=992452&view=rev
Log:
UpdateKeyspace migration. patch by gdusbabek, reviewed by stuhood. 
CASSANDRA-1285

Added:
    
cassandra/trunk/src/java/org/apache/cassandra/db/migration/UpdateKeyspace.java
Modified:
    cassandra/trunk/src/avro/internode.genavro
    cassandra/trunk/src/java/org/apache/cassandra/db/migration/Migration.java
    cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java
    cassandra/trunk/test/system/test_thrift_server.py
    cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java

Modified: cassandra/trunk/src/avro/internode.genavro
URL: 
http://svn.apache.org/viewvc/cassandra/trunk/src/avro/internode.genavro?rev=992452&r1=992451&r2=992452&view=diff
==============================================================================
--- cassandra/trunk/src/avro/internode.genavro (original)
+++ cassandra/trunk/src/avro/internode.genavro Fri Sep  3 20:24:48 2010
@@ -107,6 +107,12 @@ protocol InterNode {
         string old_ksname;
         string new_ksname;
     }
+    
+    @namespace("org.apache.cassandra.db.migration.avro")
+    record UpdateKeyspace {
+        org.apache.cassandra.config.avro.KsDef oldKs;
+        org.apache.cassandra.config.avro.KsDef newKs;
+    }
 
     @namespace("org.apache.cassandra.db.migration.avro")
     record Migration {
@@ -114,6 +120,6 @@ protocol InterNode {
         org.apache.cassandra.utils.avro.UUID new_version;
         bytes row_mutation;
         string classname;
-        union { 
AddColumnFamily,DropColumnFamily,RenameColumnFamily,AddKeyspace,DropKeyspace,RenameKeyspace
 } migration;
+        union { 
AddColumnFamily,DropColumnFamily,RenameColumnFamily,AddKeyspace,DropKeyspace,RenameKeyspace,UpdateKeyspace
 } migration;
     }
 }

Modified: 
cassandra/trunk/src/java/org/apache/cassandra/db/migration/Migration.java
URL: 
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/migration/Migration.java?rev=992452&r1=992451&r2=992452&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/db/migration/Migration.java 
(original)
+++ cassandra/trunk/src/java/org/apache/cassandra/db/migration/Migration.java 
Fri Sep  3 20:24:48 2010
@@ -66,7 +66,7 @@ import static com.google.common.base.Cha
  */
 public abstract class Migration
 {
-    private static final Logger logger = 
LoggerFactory.getLogger(Migration.class);
+    protected static final Logger logger = 
LoggerFactory.getLogger(Migration.class);
     
     public static final String NAME_VALIDATOR_REGEX = "\\w+";
     public static final String MIGRATIONS_CF = "Migrations";

Added: 
cassandra/trunk/src/java/org/apache/cassandra/db/migration/UpdateKeyspace.java
URL: 
http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/db/migration/UpdateKeyspace.java?rev=992452&view=auto
==============================================================================
--- 
cassandra/trunk/src/java/org/apache/cassandra/db/migration/UpdateKeyspace.java 
(added)
+++ 
cassandra/trunk/src/java/org/apache/cassandra/db/migration/UpdateKeyspace.java 
Fri Sep  3 20:24:48 2010
@@ -0,0 +1,78 @@
+package org.apache.cassandra.db.migration;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.ConfigurationException;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.config.KSMetaData;
+import org.apache.cassandra.utils.FBUtilities;
+import org.apache.cassandra.utils.UUIDGen;
+
+import java.io.IOException;
+
+/**
+ * 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.
+ */
+
+
+public class UpdateKeyspace extends Migration
+{
+    private KSMetaData newKsm;
+    private KSMetaData oldKsm;
+    
+    /** Required no-arg constructor */
+    protected UpdateKeyspace() { }
+    
+    /** create migration based on thrift parameters */
+    public UpdateKeyspace(KSMetaData ksm) throws ConfigurationException, 
IOException
+    {
+        super(UUIDGen.makeType1UUIDFromHost(FBUtilities.getLocalAddress()), 
DatabaseDescriptor.getDefsVersion());
+        
+        assert ksm != null;
+        assert ksm.cfMetaData() != null;
+        if (ksm.cfMetaData().size() > 0)
+            throw new ConfigurationException("Updated keyspace must not 
contain any column families");
+    
+        // create the new ksm by merging the one passed in with the cf defs 
from the exisitng ksm.
+        oldKsm = DatabaseDescriptor.getKSMetaData(ksm.name);
+        if (oldKsm == null)
+            throw new ConfigurationException(ksm.name + " cannot be updated 
because it doesn't exist.");
+        this.newKsm = new KSMetaData(ksm.name, ksm.strategyClass, 
ksm.strategyOptions, ksm.replicationFactor, 
oldKsm.cfMetaData().values().toArray(new CFMetaData[]{}));
+        rm = makeDefinitionMutation(newKsm, oldKsm, newVersion);
+    }
+    
+    void applyModels() throws IOException
+    {
+        DatabaseDescriptor.clearTableDefinition(oldKsm, newVersion);
+        DatabaseDescriptor.setTableDefinition(newKsm, newVersion);
+        logger.info("Keyspace updated. Please perform any manual operations.");
+    }
+
+    public void subdeflate(org.apache.cassandra.db.migration.avro.Migration mi)
+    {
+        org.apache.cassandra.db.migration.avro.UpdateKeyspace uks = new 
org.apache.cassandra.db.migration.avro.UpdateKeyspace();
+        uks.newKs = newKsm.deflate();
+        uks.oldKs = oldKsm.deflate();
+        mi.migration = uks;
+    }
+
+    public void subinflate(org.apache.cassandra.db.migration.avro.Migration mi)
+    {
+        org.apache.cassandra.db.migration.avro.UpdateKeyspace uks = 
(org.apache.cassandra.db.migration.avro.UpdateKeyspace)mi.migration;
+        newKsm = KSMetaData.inflate(uks.newKs);
+        oldKsm = KSMetaData.inflate(uks.oldKs);
+    }
+}

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=992452&r1=992451&r2=992452&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java 
(original)
+++ cassandra/trunk/src/java/org/apache/cassandra/thrift/CassandraServer.java 
Fri Sep  3 20:24:48 2010
@@ -26,6 +26,8 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeoutException;
 
 import org.apache.cassandra.db.migration.Migration;
+import org.apache.cassandra.db.migration.UpdateKeyspace;
+import org.apache.cassandra.utils.FBUtilities;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -476,7 +478,7 @@ public class CassandraServer implements 
             def.setColumn_metadata(cdef_list);
             cfDefs.add(def);
         }
-        return new KsDef(ksm.name, ksm.strategyClass.toString(), 
ksm.replicationFactor, cfDefs);
+        return new KsDef(ksm.name, ksm.strategyClass.getName(), 
ksm.replicationFactor, cfDefs);
     }
 
     public List<KeySlice> get_range_slices(ColumnParent column_parent, 
SlicePredicate predicate, KeyRange range, ConsistencyLevel consistency_level)
@@ -864,16 +866,47 @@ public class CassandraServer implements 
         }
     }
 
-
+    /** update an existing keyspace, but do not allow column family 
modifications. */
     public String system_update_keyspace(KsDef ks_def) throws 
InvalidRequestException, TException
     {
-        throw new InvalidRequestException("Not implemented");
+        checkKeyspaceAndLoginAuthorized(AccessLevel.FULL);
+        
+        if (ks_def.getCf_defs() != null && ks_def.getCf_defs().size() > 0)
+            throw new InvalidRequestException("Keyspace update must not 
contain any column family definitions.");
+        
+        if (StorageService.instance.getLiveNodes().size() < 
ks_def.replication_factor)
+            throw new InvalidRequestException("Not enough live nodes to 
support this keyspace");
+        if (DatabaseDescriptor.getTableDefinition(ks_def.name) == null)
+            throw new InvalidRequestException("Keyspace does not exist.");
+        
+        try
+        {
+            KSMetaData ksm = new KSMetaData(
+                    ks_def.name, 
+                    (Class<? extends 
AbstractReplicationStrategy>)FBUtilities.<AbstractReplicationStrategy>classForName(ks_def.strategy_class,
 "keyspace replication strategy"),
+                    ks_def.strategy_options,
+                    ks_def.replication_factor);
+            applyMigrationOnStage(new UpdateKeyspace(ksm));
+            return DatabaseDescriptor.getDefsVersion().toString();
+        }
+        catch (ConfigurationException e)
+        {
+            InvalidRequestException ex = new 
InvalidRequestException(e.getMessage());
+            ex.initCause(e);
+            throw ex;
+        }
+        catch (IOException e)
+        {
+            InvalidRequestException ex = new 
InvalidRequestException(e.getMessage());
+            ex.initCause(e);
+            throw ex;
+        }
     }
 
-    
     public String system_update_column_family(CfDef cf_def) throws 
InvalidRequestException, TException
     {
-        throw new InvalidRequestException("Not implemented");
+        checkKeyspaceAndLoginAuthorized(AccessLevel.FULL);
+        return null;
     }
 
     private CFMetaData convertToCFMetaData(CfDef cf_def) throws 
InvalidRequestException, ConfigurationException

Modified: cassandra/trunk/test/system/test_thrift_server.py
URL: 
http://svn.apache.org/viewvc/cassandra/trunk/test/system/test_thrift_server.py?rev=992452&r1=992451&r2=992452&view=diff
==============================================================================
--- cassandra/trunk/test/system/test_thrift_server.py (original)
+++ cassandra/trunk/test/system/test_thrift_server.py Fri Sep  3 20:24:48 2010
@@ -1163,6 +1163,19 @@ class TestMutations(ThriftTester):
         
         _set_keyspace('CreateKeyspace')
         
+        # modify invlid
+        modified_keyspace = KsDef('CreateKeyspace', 
'org.apache.cassandra.locator.OldNetworkTopologyStrategy', {}, 2, [])
+        def fail_too_high_rf():
+            client.system_update_keyspace(modified_keyspace)
+        _expect_exception(fail_too_high_rf, InvalidRequestException)
+        
+        # modify valid
+        modified_keyspace.replication_factor = 1
+        client.system_update_keyspace(modified_keyspace)
+        modks = client.describe_keyspace('CreateKeyspace')
+        assert modks.replication_factor == modified_keyspace.replication_factor
+        assert modks.strategy_class == modified_keyspace.strategy_class
+        
         # rename
         client.system_rename_keyspace('CreateKeyspace', 'RenameKeyspace')
         renameks = client.describe_keyspace('RenameKeyspace')
@@ -1176,7 +1189,7 @@ class TestMutations(ThriftTester):
         def get_second_ks():
             client.describe_keyspace('RenameKeyspace')
         _expect_exception(get_second_ks, NotFoundException)
-    
+        
     def test_create_then_drop_ks(self):
         keyspace = KsDef('AddThenDrop', 
                 strategy_class='org.apache.cassandra.locator.SimpleStrategy',

Modified: cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java
URL: 
http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java?rev=992452&r1=992451&r2=992452&view=diff
==============================================================================
--- cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java (original)
+++ cassandra/trunk/test/unit/org/apache/cassandra/db/DefsTest.java Fri Sep  3 
20:24:48 2010
@@ -23,7 +23,7 @@ import java.io.IOException;
 import java.util.*;
 import java.util.concurrent.ExecutionException;
 
-import org.apache.commons.lang.StringUtils;
+import org.apache.cassandra.locator.OldNetworkTopologyStrategy;
 import org.junit.Test;
 
 import org.apache.cassandra.CleanupHelper;
@@ -459,4 +459,51 @@ public class DefsTest extends CleanupHel
         IColumn col = cfam.getColumn("col0".getBytes());
         assert Arrays.equals("value0".getBytes(), col.value());
     }
+    
+    @Test
+    public void testUpdateKeyspace() throws ConfigurationException, 
IOException, ExecutionException, InterruptedException
+    {
+        // create a keyspace to serve as existing.
+        CFMetaData cf = new CFMetaData("UpdatedKeyspace", "AddedStandard1", 
ColumnFamilyType.Standard, ClockType.Timestamp, UTF8Type.instance, null, 
TimestampReconciler.instance, "A new cf for a new ks", 0, false, 1.0, 0, 
864000, BytesType.instance, Collections.<byte[], ColumnDefinition>emptyMap());
+        KSMetaData oldKs = new KSMetaData(cf.tableName, SimpleStrategy.class, 
null, 5, cf);
+        
+        new AddKeyspace(oldKs).apply();
+        
+        assert DatabaseDescriptor.getTableDefinition(cf.tableName) != null;
+        assert DatabaseDescriptor.getTableDefinition(cf.tableName) == oldKs;
+        
+        // anything with cf defs should fail.
+        CFMetaData cf2 = new CFMetaData(cf.tableName, "AddedStandard2", 
ColumnFamilyType.Standard, ClockType.Timestamp, UTF8Type.instance, null, 
TimestampReconciler.instance, "A new cf for a new ks", 0, false, 1.0, 0, 
864000, BytesType.instance, Collections.<byte[], ColumnDefinition>emptyMap());
+        KSMetaData newBadKs = new KSMetaData(cf.tableName, 
SimpleStrategy.class, null, 4, cf2);
+        try
+        {
+            new UpdateKeyspace(newBadKs).apply();
+            throw new AssertionError("Should not have been able to update a KS 
with a KS that described column families.");
+        }
+        catch (ConfigurationException ex)
+        {
+            // expected.
+        }
+        
+        // names should match.
+        KSMetaData newBadKs2 = new KSMetaData(cf.tableName + "trash", 
SimpleStrategy.class, null, 4);
+        try
+        {
+            new UpdateKeyspace(newBadKs2).apply();
+            throw new AssertionError("Should not have been able to update a KS 
with an invalid KS name.");
+        }
+        catch (ConfigurationException ex)
+        {
+            // expected.
+        }
+        
+        KSMetaData newKs = new KSMetaData(cf.tableName, 
OldNetworkTopologyStrategy.class, null, 1);
+        new UpdateKeyspace(newKs).apply();
+        
+        KSMetaData newFetchedKs = DatabaseDescriptor.getKSMetaData(newKs.name);
+        assert newFetchedKs.replicationFactor == newKs.replicationFactor;
+        assert newFetchedKs.replicationFactor != oldKs.replicationFactor;
+        assert newFetchedKs.strategyClass.equals(newKs.strategyClass);
+        assert !newFetchedKs.strategyClass.equals(oldKs.strategyClass);
+    }
 }


Reply via email to