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);
+ }
}