Author: ivol37 at gmail.com
Date: Fri Jan 7 12:16:13 2011
New Revision: 576
Log:
[AMDATU-251] It appeared that no persistence manager was started if a keyspace
was added and no keyspace-global ColumFamilyProviders existed. Also the
fallback added for AMDATU-250 was incorrect; if a keyspace with a name was
added that already existed, a InvalidRequestException was thrown invoking the
fallback logic. Therefore refactored the API a but such that there is a clear
difference between adding a keyspace that already exists and a real error. This
could even be the actual cause of AMDATU-250.
Modified:
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/CassandraDaemonService.java
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/service/CassandraDaemonServiceImpl.java
trunk/amdatu-cassandra/cassandra-listener/src/main/java/org/amdatu/cassandra/listener/service/ColumnFamilyHandler.java
trunk/amdatu-cassandra/cassandra-persistencemanager/src/main/java/org/amdatu/cassandra/persistencemanager/service/CassandraPersistenceManagerFactoryImpl.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/CassandraDaemonIntegrationTest.java
Modified:
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/CassandraDaemonService.java
==============================================================================
---
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/CassandraDaemonService.java
(original)
+++
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/CassandraDaemonService.java
Fri Jan 7 12:16:13 2011
@@ -80,25 +80,27 @@
boolean keyspaceExists(String keyspaceName) throws TException,
InvalidRequestException;
/**
- * Adds a keyspace with the specified name and throws an
InvalidRequestException if
- * a keyspace with that name already exists. Note that keyspaces in
Cassandra are
- * case-sensitive.
+ * Adds a keyspace with the specified name. If the keyspace was added true
is returned. If a keyspace with that name
+ * already exsisted, false is returned. Note that keyspaces in Cassandra
are case-sensitive. If for any reason
+ * creation of the keyspace failed, an InvalidRequestException or
TException is thrown.
*
* @param name Name of the keyspace to add (case-sensitive)
+ * * @return true if a new keyspace was added, false if a keyspace with
this name already existed.
* @throws InvalidRequestException In case a keyspace with the specified
name already exists.
* @throws TException In case an error occurred while adding the keyspace
*/
- void addKeyspace(String name) throws InvalidRequestException, TException;
+ boolean addKeyspace(String name) throws InvalidRequestException,
TException;
/**
* Drops the keyspace with the specified name. All data (i.e.
ColumnFamily's) contained
- * by the keyspace are also removed. Note that keyspace names are case
sensitive.
+ * by the keyspace are also removed. Note that keyspace names are case
sensitive. If no keyspace
+ * exists with the specified name, false is returned. If the keyspace was
removed true is returned.
*
* @param keyspace Name of the keyspace to remove.
* @throws InvalidRequestException In case no keyspace with the specified
name exists
* @throws TException In case an error occurred while removing the keyspace
*/
- void dropKeyspace(String keyspace) throws InvalidRequestException,
TException;
+ boolean dropKeyspace(String keyspace) throws InvalidRequestException,
TException;
/**
* Returns a list of all available ColumnFamily's in the specified
keyspace. Note that
@@ -126,20 +128,23 @@
boolean columnFamilyExists(String keyspaceName, String columnFamilyName)
throws NotFoundException, InvalidRequestException;
/**
- * Adds a new ColumnFamily to the specified keyspace. If a ColumnFamily
with that name already exists
- * an exception is thrown. Note that ColumnFamily's in Cassandra are
case-sensitive
+ * Adds a new ColumnFamily to the specified keyspace. Returns true if a
new ColumnFamily was created.
+ * If a ColumnFamily with that name already exists false is returned. Note
that ColumnFamily's in Cassandra
+ * are case-sensitive.
*
* @param keyspace Name of the keyspace to add the ColumnFamily to
* @param cfName Name of the ColumnFamily to add
* @param columnType Column type of the ColumnFamily to add
* @param comparatorType Comparator type of the ColumnFamily to add
* @param subComparatorType Sub Comparator type of the ColumnFamily to add
+ * @return true if a new ColumnFamily was added, false if a ColumnFamily
with this name already existed.
* @throws InvalidRequestException In case a ColumnFamily with the
specified name already exists in
* the target keyspace
* @throws TException If an error occurred while adding the ColumnFamily
+ * @throws NotFoundException In case the keyspace could not be found
*/
- void addColumnFamily(String keyspace, String cfName, String columnType,
String comparatorType,
- String subComparatorType) throws InvalidRequestException, TException;
+ boolean addColumnFamily(String keyspace, String cfName, String columnType,
String comparatorType,
+ String subComparatorType) throws NotFoundException,
InvalidRequestException, TException;
/**
* Verifies if the ColumnFamily specified by keyspace and ColumFamily name
already present in
Modified:
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/service/CassandraDaemonServiceImpl.java
==============================================================================
---
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/service/CassandraDaemonServiceImpl.java
(original)
+++
trunk/amdatu-cassandra/cassandra-application/src/main/java/org/amdatu/cassandra/application/service/CassandraDaemonServiceImpl.java
Fri Jan 7 12:16:13 2011
@@ -122,53 +122,36 @@
return keyspaceNames;
}
- public void addKeyspace(String name) throws InvalidRequestException,
TException {
- List<CfDef> empty = new ArrayList<CfDef>();
- KsDef ksDef = new KsDef(name, DEFAULT_PLACEMENT_STRATEGY,
DEFAULT_REPLICATION_FACTOR, empty);
- try {
+ public synchronized boolean addKeyspace(String name) throws
InvalidRequestException, TException {
+ if (!keyspaceExists(name)) {
+ List<CfDef> empty = new ArrayList<CfDef>();
+ KsDef ksDef = new KsDef(name, DEFAULT_PLACEMENT_STRATEGY,
DEFAULT_REPLICATION_FACTOR, empty);
m_cassandraServer.system_add_keyspace(ksDef);
- } catch (InvalidRequestException e) {
- // FIXME: This is a fallback for recovering from issue AMDATU-250.
Hopefully it will be fixed in
- // subsequent Cassandra versions. In case added a columnfamily
fails on a InvalidRequestException
- // we retry adding the column family for a maximum of 3 times.
Most of the times, the second try
- // already succeeds.
- int retry = 0;
- boolean failure = true;
- while (retry < 3 && failure) {
- retry++;
- m_logService.log(LogService.LOG_WARNING, "Failed to add
keyspace '" + name + "', retry " + retry);
- try {
- // Wait 1 second before retrying
- Thread.sleep(1000);
- }
- catch (InterruptedException e2) {
- }
- try {
- failure = false;
- m_cassandraServer.system_add_keyspace(ksDef);
- } catch (InvalidRequestException e2) {
- if (retry >= 3) {
- throw e2;
- }
- failure = true;
- }
- }
- m_logService.log(LogService.LOG_WARNING, "Successfully recovered
from this Cassandra error, keyspace '" + name + "' added");
+ // Publish an event that a new keyspace has been added
+ Map<String, String> properties = new HashMap<String, String>();
+ properties.put(EVENT_ADMIN_KEYSPACE_ADDED, name);
+ m_eventAdmin.sendEvent(new Event(EVENT_ADMIN_TOPIC, properties));
+ m_logService.log(LogService.LOG_INFO, "Keyspace '" + name + "' has
been added");
+ return true;
+ } else {
+ m_logService.log(LogService.LOG_DEBUG, "Keyspace '" + name + "'
was not added since it already existed");
+ return false;
}
- // Publish an event that a new keyspace has been added
- Map<String, String> properties = new HashMap<String, String>();
- properties.put(EVENT_ADMIN_KEYSPACE_ADDED, name);
- m_eventAdmin.sendEvent(new Event(EVENT_ADMIN_TOPIC, properties));
}
- public void dropKeyspace(String keyspace) throws InvalidRequestException,
TException {
- m_cassandraServer.system_drop_keyspace(keyspace);
-
- // Publish an event that a keyspace has been dropped
- Map<String, String> properties = new HashMap<String, String>();
- properties.put(EVENT_ADMIN_KEYSPACE_DROPPED, keyspace);
- m_eventAdmin.sendEvent(new Event(EVENT_ADMIN_TOPIC, properties));
+ public synchronized boolean dropKeyspace(String keyspace) throws
InvalidRequestException, TException {
+ if (keyspaceExists(keyspace)) {
+ m_cassandraServer.system_drop_keyspace(keyspace);
+
+ // Publish an event that a keyspace has been dropped
+ Map<String, String> properties = new HashMap<String, String>();
+ properties.put(EVENT_ADMIN_KEYSPACE_DROPPED, keyspace);
+ m_eventAdmin.sendEvent(new Event(EVENT_ADMIN_TOPIC, properties));
+ return true;
+ } else {
+ return false;
+ }
}
public boolean columnFamilyExists(String keyspaceName, String
columnFamilyName) throws NotFoundException, InvalidRequestException {
@@ -192,49 +175,26 @@
return cfNames;
}
- public void addColumnFamily(String keyspace, String cfName, String
columnType, String comparatorType,
- String subComparatorType) throws InvalidRequestException, TException {
+ public synchronized boolean addColumnFamily(String keyspace, String
cfName, String columnType, String comparatorType,
+ String subComparatorType) throws InvalidRequestException, TException,
NotFoundException {
if (keyspace.equals(Table.SYSTEM_TABLE)) {
throw new InvalidRequestException("ColumnFamily's cannot be added
to Cassandra's system keyspace");
}
- CfDef cfDef = new CfDef(keyspace, cfName);
- cfDef.column_type = columnType;
- cfDef.comparator_type = comparatorType;
- cfDef.subcomparator_type = subComparatorType;
- try {
+ if (!columnFamilyExists(keyspace, cfName)) {
+ CfDef cfDef = new CfDef(keyspace, cfName);
+ cfDef.column_type = columnType;
+ cfDef.comparator_type = comparatorType;
+ cfDef.subcomparator_type = subComparatorType;
+
m_cassandraServer.set_keyspace(keyspace);
m_cassandraServer.system_add_column_family(cfDef);
- } catch (InvalidRequestException e) {
- // FIXME: This is a fallback for recovering from issue AMDATU-250.
Hopefully it will be fixed in
- // subsequent Cassandra versions. In case added a columnfamily
fails on a InvalidRequestException
- // we retry adding the column family for a maximum of 3 times.
Most of the times, the second try
- // already succeeds.
- int retry = 0;
- boolean failure = true;
- while (retry < 3 && failure) {
- retry++;
- m_logService.log(LogService.LOG_WARNING, "Failed to add
ColumnFamily '" + cfName + "' to keyspace '" + keyspace
- + "', retry " + retry);
- try {
- // Wait 1 second before retrying
- Thread.sleep(1000);
- }
- catch (InterruptedException e2) {
- }
-
- try {
- failure = false;
- m_cassandraServer.system_add_column_family(cfDef);
- } catch (InvalidRequestException e2) {
- if (retry >= 3) {
- throw e2;
- }
- failure = true;
- }
- }
- m_logService.log(LogService.LOG_WARNING, "Successfully recovered
from this Cassandra error, ColumnFamily '" + cfName
- + "' added to keyspace '" + keyspace);
+ m_logService.log(LogService.LOG_INFO, "ColumnFamily '" + cfName +
"' has been added to keyspace '" + keyspace + "'");
+ return true;
+ } else {
+ m_logService.log(LogService.LOG_DEBUG, "ColumnFamily '" + cfName +
"' was not added to keyspace '" + keyspace + "' since it already existed");
+ return false;
}
+
}
public boolean isColumnFamilyChanged(String keyspace, String cfName,
String columnType, String comparatorType,
Modified:
trunk/amdatu-cassandra/cassandra-listener/src/main/java/org/amdatu/cassandra/listener/service/ColumnFamilyHandler.java
==============================================================================
---
trunk/amdatu-cassandra/cassandra-listener/src/main/java/org/amdatu/cassandra/listener/service/ColumnFamilyHandler.java
(original)
+++
trunk/amdatu-cassandra/cassandra-listener/src/main/java/org/amdatu/cassandra/listener/service/ColumnFamilyHandler.java
Fri Jan 7 12:16:13 2011
@@ -70,6 +70,7 @@
d.put(EventConstants.EVENT_TOPIC, new
String[]{CassandraDaemonService.EVENT_ADMIN_TOPIC});
m_context.registerService( EventHandler.class.getName(), this, d );
}
+
public void start() {
try {
// Register all currently available keyspace/columnfamily
combinations.
@@ -77,7 +78,6 @@
for (KsDef keyspace : keyspaces) {
String keyspaceName = keyspace.getName();
m_pmFactory.createCassandraPersistenceManager(keyspaceName);
-
List<CfDef> columnFamilies = keyspace.getCf_defs();
for (CfDef columnFamily : columnFamilies) {
addServiceFor(keyspaceName, columnFamily.getName());
@@ -92,7 +92,7 @@
}
}
- private void stop() {
+ public void stop() {
// Since we registered all services, we should also remove them.
for (Component component : m_services.values()) {
m_dependencyManager.remove(component);
@@ -112,12 +112,7 @@
// Never add ColumnFamily's to Cassandra's system
keyspace, this is a reserved keyspace
if (!Table.SYSTEM_TABLE.equals(keyspace)) {
// Create if it does not yet exist
- if (!m_daemonService.keyspaceExists(keyspace)) {
- m_daemonService.addKeyspace(keyspace);
-
m_pmFactory.createCassandraPersistenceManager(keyspace);
-
- m_logService.log(LogService.LOG_INFO,
"Keyspace '" + keyspace + "' added");
- }
+ m_daemonService.addKeyspace(keyspace);
addOrUpdateColumnFamily(keyspace, columnFamily);
}
}
@@ -156,10 +151,8 @@
String comparatorType = colDef.getCompareWith().value;
String subComparatorType = colDef.getCompareSubcolumnsWith().value;
- if (!m_daemonService.columnFamilyExists(ksName, cfName)) {
- m_daemonService.addColumnFamily(ksName, cfName, columnType,
comparatorType, subComparatorType);
+ if (m_daemonService.addColumnFamily(ksName, cfName, columnType,
comparatorType, subComparatorType)) {
waitForColumnFamilyAndRegisterService(ksName, cfName);
- m_logService.log(LogService.LOG_INFO, "ColumnFamily '" + cfName +
"' added to keyspace '" + ksName + "'");
}
else {
// Since Cassandra does not (yet) support updating columnType,
comparatorType or subComparatorType
@@ -186,7 +179,6 @@
}
addServiceFor(keyspace, columnFamily);
}
-
}.start();
}
@@ -266,6 +258,8 @@
}
private static class KeySpaceColumnFamilyCombination extends
HashMap<String, Object> {
+ private static final long serialVersionUID = 6574039194678276636L;
+
public KeySpaceColumnFamilyCombination(String keyspace, String
columnFamily) {
put("keyspace", keyspace);
put("columnFamily", columnFamily);
@@ -288,7 +282,11 @@
if (keyspaceAdded != null) {
// If a keyspace was added, we must add ColumnFamily's for all
keyspace-global ColumnFamilyProvider's
// (this are all ColumnFamilyProvider's that defined keyspace
null)
- m_logService.log(LogService.LOG_DEBUG, "Recieved keyspace
added event for keyspace '" + keyspaceAdded + "' ");
+ String keyspaceName = keyspaceAdded.toString();
+ m_logService.log(LogService.LOG_DEBUG, "Recieved keyspace
added event for keyspace '" + keyspaceName + "' ");
+
+ // First register a new cassandra persistence manager for this
new keyspace
+ m_pmFactory.createCassandraPersistenceManager(keyspaceName);
ServiceReference[] servRefs =
m_context.getAllServiceReferences(ColumnFamilyProvider.class.getName(), null);
if (servRefs != null) {
Modified:
trunk/amdatu-cassandra/cassandra-persistencemanager/src/main/java/org/amdatu/cassandra/persistencemanager/service/CassandraPersistenceManagerFactoryImpl.java
==============================================================================
---
trunk/amdatu-cassandra/cassandra-persistencemanager/src/main/java/org/amdatu/cassandra/persistencemanager/service/CassandraPersistenceManagerFactoryImpl.java
(original)
+++
trunk/amdatu-cassandra/cassandra-persistencemanager/src/main/java/org/amdatu/cassandra/persistencemanager/service/CassandraPersistenceManagerFactoryImpl.java
Fri Jan 7 12:16:13 2011
@@ -32,8 +32,10 @@
public class CassandraPersistenceManagerFactoryImpl implements
CassandraPersistenceManagerFactory {
// Instances injected by the Felix dependency manager
private volatile DependencyManager m_dependencyManager;
+ private volatile LogService m_logService;
public void createCassandraPersistenceManager(String keyspaceId) {
+ m_logService.log(LogService.LOG_DEBUG, "Launching
CassandraPersistenceManager for keyspace '" + keyspaceId + "'");
Dictionary<String, String> serviceProperties = new Hashtable<String,
String>();
serviceProperties.put(CassandraPersistenceManager.KEYSPACE_AWARE_KEY,
keyspaceId);
Modified:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/CassandraDaemonIntegrationTest.java
==============================================================================
---
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/CassandraDaemonIntegrationTest.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/CassandraDaemonIntegrationTest.java
Fri Jan 7 12:16:13 2011
@@ -129,14 +129,10 @@
// -1- Test adding/updating/removing keyspaces
int beforeCount = m_daemonService.getKeyspaces().size();
m_daemonService.addKeyspace(KEYSPACE);
- Assert.assertTrue("Keyspace '" + KEYSPACE + "' does not exist after
creation", m_daemonService
- .keyspaceExists(KEYSPACE));
- try {
- // Try to create keyspace with the same name twice, should throw a
InvalidRequestException
- m_daemonService.addKeyspace(KEYSPACE);
- Assert.fail("InvalidRequestException expected but not thrown");
- }
- catch (InvalidRequestException e) {}
+ Assert.assertTrue("Keyspace '" + KEYSPACE + "' does not exist after
creation", m_daemonService.keyspaceExists(KEYSPACE));
+
+ // Try to create keyspace with the same name twice, should return false
+ Assert.assertFalse(m_daemonService.addKeyspace(KEYSPACE));
// Case sensitivity check: Cassandra is case-sensitive!
m_daemonService.addKeyspace(KEYSPACE.toLowerCase());
@@ -155,24 +151,16 @@
+ allKeyspaces.size(), allKeyspaces.size() == beforeCount + 3);
// -2- Test adding/updating ColumnFamily's to the keyspace
- m_daemonService.addColumnFamily(KEYSPACE, COLUMNFAMILY,
ColumnType.STANDARD.value,
- CompareType.BYTESTYPE.value, null);
+ m_daemonService.addColumnFamily(KEYSPACE, COLUMNFAMILY,
ColumnType.STANDARD.value, CompareType.BYTESTYPE.value, null);
Assert.assertTrue("ColumnFamily '" + COLUMNFAMILY + "' does not exist
after creation", m_daemonService
.columnFamilyExists(KEYSPACE, COLUMNFAMILY));
- try {
- // Try to create ColumnFamily with the same name twice, should
throw a InvalidRequestException
- m_daemonService.addColumnFamily(KEYSPACE, COLUMNFAMILY,
ColumnType.STANDARD.value,
- CompareType.BYTESTYPE.value, null);
- Assert.fail("InvalidRequestException expected but not thrown");
- }
- catch (InvalidRequestException e) {}
+ // Try to create ColumnFamily with the same name twice, should return
false
+ Assert.assertFalse(m_daemonService.addColumnFamily(KEYSPACE,
COLUMNFAMILY, ColumnType.STANDARD.value, CompareType.BYTESTYPE.value, null));
// Case sensitivity check
- m_daemonService.addColumnFamily(KEYSPACE, COLUMNFAMILY.toLowerCase(),
ColumnType.STANDARD.value,
- CompareType.BYTESTYPE.value, null);
- m_daemonService.addColumnFamily(KEYSPACE, COLUMNFAMILY.toUpperCase(),
ColumnType.STANDARD.value,
- CompareType.BYTESTYPE.value, null);
+ m_daemonService.addColumnFamily(KEYSPACE, COLUMNFAMILY.toLowerCase(),
ColumnType.STANDARD.value, CompareType.BYTESTYPE.value, null);
+ m_daemonService.addColumnFamily(KEYSPACE, COLUMNFAMILY.toUpperCase(),
ColumnType.STANDARD.value, CompareType.BYTESTYPE.value, null);
// Rest registration of column family's and keyspaces using
ColumnFamilyProvider's
testColumnFamilyProvider();