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();

Reply via email to