Read lock promotion
[music.git] / src / main / java / org / onap / music / service / impl / MusicCassaCore.java
index 0786457..0d2e3f0 100644 (file)
@@ -30,13 +30,24 @@ import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
 
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.onap.music.datastore.Condition;
 import org.onap.music.datastore.MusicDataStore;
 import org.onap.music.datastore.MusicDataStoreHandle;
 import org.onap.music.datastore.PreparedQueryObject;
+import org.onap.music.datastore.jsonobjects.JsonDelete;
+import org.onap.music.datastore.jsonobjects.JsonIndex;
+import org.onap.music.datastore.jsonobjects.JsonInsert;
+import org.onap.music.datastore.jsonobjects.JsonKeySpace;
+import org.onap.music.datastore.jsonobjects.JsonSelect;
+import org.onap.music.datastore.jsonobjects.JsonTable;
+import org.onap.music.datastore.jsonobjects.JsonUpdate;
 import org.onap.music.eelf.logging.EELFLoggerDelegate;
 import org.onap.music.eelf.logging.format.AppMessages;
 import org.onap.music.eelf.logging.format.ErrorSeverity;
 import org.onap.music.eelf.logging.format.ErrorTypes;
+import org.onap.music.exceptions.MusicDeadlockException;
 import org.onap.music.exceptions.MusicLockingException;
 import org.onap.music.exceptions.MusicQueryException;
 import org.onap.music.exceptions.MusicServiceException;
@@ -55,8 +66,6 @@ import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.TableMetadata;
 
-import org.onap.music.datastore.*;
-
 public class MusicCassaCore implements MusicCoreService {
 
     private static CassaLockStore mLockHandle = null;
@@ -108,6 +117,10 @@ public class MusicCassaCore implements MusicCoreService {
     }
 
     public String createLockReference(String fullyQualifiedKey, LockType locktype) throws MusicLockingException {
+        return createLockReference(fullyQualifiedKey, locktype, null);
+    }
+
+    public String createLockReference(String fullyQualifiedKey, LockType locktype, String owner) throws MusicLockingException {
         String[] splitString = fullyQualifiedKey.split("\\.");
         String keyspace = splitString[0];
         String table = splitString[1];
@@ -116,20 +129,55 @@ public class MusicCassaCore implements MusicCoreService {
         logger.info(EELFLoggerDelegate.applicationLogger,"Creating lock reference for lock name:" + lockName);
         long start = System.currentTimeMillis();
         String lockReference = null;
+
+        try {
+            boolean deadlock = getLockingServiceHandle().checkForDeadlock(keyspace, table, lockName, locktype, owner, false);
+            if (deadlock) {
+                MusicDeadlockException e = new MusicDeadlockException("Deadlock detected when " + owner + " tried to create lock on " + keyspace + "." + table + "." + lockName);
+                e.setValues(owner, keyspace, table, lockName);
+                throw e;
+            }
+        } catch (MusicDeadlockException e) {
+            //just threw this, no need to wrap it
+            throw e;
+        } catch (MusicServiceException | MusicQueryException e) {
+            logger.error(EELFLoggerDelegate.applicationLogger, e);
+            throw new MusicLockingException("Unable to check for deadlock. " + e.getMessage(), e);
+        }
         
         try {
-            lockReference = "" + getLockingServiceHandle().genLockRefandEnQueue(keyspace, table, lockName, locktype);
+            lockReference = "" + getLockingServiceHandle().genLockRefandEnQueue(keyspace, table, lockName, locktype, owner);
         } catch (MusicLockingException | MusicServiceException | MusicQueryException e) {
-            e.printStackTrace();
-            throw new MusicLockingException("Unable to create lock reference. " + e.getMessage());
+            logger.error(EELFLoggerDelegate.applicationLogger, e);
+            throw new MusicLockingException("Unable to create lock reference. " + e.getMessage(), e);
         } catch (Exception e) {
             logger.error(EELFLoggerDelegate.applicationLogger, e);
-            throw new MusicLockingException("Unable to create lock reference. " + e.getMessage());
+            throw new MusicLockingException("Unable to create lock reference. " + e.getMessage(), e);
         }
         long end = System.currentTimeMillis();
         logger.info(EELFLoggerDelegate.applicationLogger,"Time taken to create lock reference:" + (end - start) + " ms");
         return lockReference;
     }
+    
+    public ReturnType promoteLock(String lockId) throws MusicLockingException {
+        String[] splitString = lockId.split("\\.");
+        String keyspace = splitString[0].substring(1);//remove '$'
+        String table = splitString[1];
+        String primaryKeyValue = splitString[2].substring(0, splitString[2].lastIndexOf("$"));
+        String localFullyQualifiedKey = lockId.substring(1, lockId.lastIndexOf("$"));
+        String lockRef = lockId.substring(lockId.lastIndexOf("$")+1); //lockRef is "$" to end
+        
+        logger.info(EELFLoggerDelegate.applicationLogger,"Attempting to promote lock " + lockId);
+
+        try {
+            return getLockingServiceHandle().promoteLock(keyspace, table, primaryKeyValue, lockRef);
+        } catch (MusicServiceException e) {
+            throw new MusicLockingException("Unable to promote lock. ", e);
+        } catch (MusicQueryException e) {
+            throw new MusicLockingException("Unable to promote lock. ", e);
+        }
+        
+    }
 
 
     public ReturnType acquireLockWithLease(String fullyQualifiedKey, String lockReference, long leasePeriod)
@@ -177,13 +225,19 @@ public class MusicCassaCore implements MusicCoreService {
             return new ReturnType(ResultType.FAILURE, lockId + " is not a lock holder");//not top of the lock store q
         }
         
+        if (getLockingServiceHandle().checkForDeadlock(keyspace, table, primaryKeyValue, lockInfo.getLocktype(), lockInfo.getOwner(), true)) {
+            MusicDeadlockException e = new MusicDeadlockException("Deadlock detected when " + lockInfo.getOwner()  + " tried to create lock on " + keyspace + "." + table + "." + primaryKeyValue);
+            e.setValues(lockInfo.getOwner(), keyspace, table, primaryKeyValue);
+            throw e;
+        }
+
         //check to see if the value of the key has to be synced in case there was a forceful release
         String syncTable = keyspace+".unsyncedKeys_"+table;
         String query = "select * from "+syncTable+" where key='"+localFullyQualifiedKey+"';";
         PreparedQueryObject readQueryObject = new PreparedQueryObject();
         readQueryObject.appendQueryString(query);
         ResultSet results = MusicDataStoreHandle.getDSHandle().executeQuorumConsistencyGet(readQueryObject);
-        if (results.all().size() != 0) {
+        if (!results.all().isEmpty()) {
             logger.info("In acquire lock: Since there was a forcible release, need to sync quorum!");
             try {
                 syncQuorum(keyspace, table, primaryKeyValue);
@@ -311,7 +365,7 @@ public class MusicCassaCore implements MusicCoreService {
         String table = splitString[1];
         String primaryKeyValue = splitString[2];
         try {
-               return getLockingServiceHandle().getCurrentLockHolders(keyspace, table, primaryKeyValue);
+            return getLockingServiceHandle().getCurrentLockHolders(keyspace, table, primaryKeyValue);
         } catch (MusicLockingException | MusicServiceException | MusicQueryException e) {
             logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), AppMessages.LOCKINGERROR+fullyQualifiedKey ,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR);
         }
@@ -413,6 +467,19 @@ public class MusicCassaCore implements MusicCoreService {
         return destroyLockRef(fullyQualifiedKey, lockReference);
     }
 
+    @Override
+    public List<String> releaseAllLocksForOwner(String ownerId, String keyspace, String table) throws MusicLockingException, MusicServiceException, MusicQueryException {
+//        System.out.println("IN RELEASEALLLOCKSFOROWNER, ");
+
+        List<String> lockIds = getLockingServiceHandle().getAllLocksForOwner(ownerId, keyspace, table);
+        for (String lockId : lockIds) {
+//            System.out.println(" LOCKID = " + lockId);
+            //return "$" + keyspace + "." + table + "." + lockName + "$" + String.valueOf(lockRef);
+            releaseLock("$" + keyspace + "." + table + "." + lockId, true);
+        }
+        return lockIds;
+    }
+
     /**
      *
      * @param lockName
@@ -813,6 +880,270 @@ public class MusicCassaCore implements MusicCoreService {
         //deprecated
         return null;
     }
+    
+    //Methods added for ORM changes
+    
+    public ResultType createKeyspace(JsonKeySpace jsonKeySpaceObject,String consistencyInfo) 
+            throws MusicServiceException,MusicQueryException {
+        ResultType result = nonKeyRelatedPut(jsonKeySpaceObject.genCreateKeyspaceQuery(), consistencyInfo);
+        logger.info(EELFLoggerDelegate.applicationLogger, " Keyspace Creation Process completed successfully");
+
+        return result;
+    }
+    
+    public ResultType dropKeyspace(JsonKeySpace jsonKeySpaceObject, String consistencyInfo) 
+            throws MusicServiceException,MusicQueryException {
+        ResultType result = nonKeyRelatedPut(jsonKeySpaceObject.genDropKeyspaceQuery(),
+                    consistencyInfo);
+        logger.info(EELFLoggerDelegate.applicationLogger, " Keyspace deletion Process completed successfully");
+        return result;
+    }
+    
+    public ResultType createTable(JsonTable jsonTableObject, String consistencyInfo) 
+            throws MusicServiceException, MusicQueryException {
+        ResultType result = null;
+        try {
+            result = createTable(jsonTableObject.getKeyspaceName(), 
+                    jsonTableObject.getTableName(), jsonTableObject.genCreateTableQuery(), consistencyInfo);
+            
+        } catch (MusicServiceException ex) {
+            logger.error(EELFLoggerDelegate.errorLogger, ex.getMessage(), AppMessages.UNKNOWNERROR, ErrorSeverity.WARN,
+                    ErrorTypes.MUSICSERVICEERROR);
+            throw new MusicServiceException(ex.getMessage());
+        }
+        logger.info(EELFLoggerDelegate.applicationLogger, " Table Creation Process completed successfully ");
+        return result;
+    }
+    
+    public ResultType dropTable(JsonTable jsonTableObject,String consistencyInfo) 
+            throws MusicServiceException,MusicQueryException {
+        ResultType result = nonKeyRelatedPut(jsonTableObject.genDropTableQuery(),
+                    consistencyInfo);
+        logger.info(EELFLoggerDelegate.applicationLogger, " Table deletion Process completed successfully ");
+        
+        return result;
+    }
+    
+    @Override
+    public ResultType createIndex(JsonIndex jsonIndexObject, String consistencyInfo) 
+            throws MusicServiceException, MusicQueryException{
+        ResultType result = nonKeyRelatedPut(jsonIndexObject.genCreateIndexQuery(),
+                    consistencyInfo);
+        
+        logger.info(EELFLoggerDelegate.applicationLogger, " Index creation Process completed successfully ");
+        return result;
+    }
+    
+    /**
+     * This method performs DDL operation on cassandra.
+     *
+     * @param queryObject query object containing prepared query and values
+     * @return ResultSet
+     * @throws MusicServiceException
+     */
+    public  ResultSet select(JsonSelect jsonSelect, MultivaluedMap<String, String> rowParams) 
+            throws MusicServiceException, MusicQueryException {
+        ResultSet results = null;
+        try {
+            results = get(jsonSelect.genSelectQuery(rowParams));
+        } catch (MusicServiceException e) {
+            logger.error(EELFLoggerDelegate.errorLogger,e.getMessage());
+            throw new MusicServiceException(e.getMessage());
+        }
+        return results;
+    }
+    
+    /**
+     * Select Critical
+     */
+    public ResultSet selectCritical(JsonInsert jsonInsertObj, MultivaluedMap<String, String> rowParams)
+            throws MusicLockingException, MusicQueryException, MusicServiceException {
+        
+        ResultSet results = null;
+        String consistency = "";
+        if(null != jsonInsertObj && null != jsonInsertObj.getConsistencyInfo()) {
+            consistency = jsonInsertObj.getConsistencyInfo().get("type");
+        }
+        
+        String lockId = jsonInsertObj.getConsistencyInfo().get("lockId");
+        
+        PreparedQueryObject queryObject = jsonInsertObj.genSelectCriticalPreparedQueryObj(rowParams);
+        
+        if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
+            results = criticalGet(jsonInsertObj.getKeyspaceName(), jsonInsertObj.getTableName(), 
+                    jsonInsertObj.getPrimaryKeyVal(), queryObject,lockId);
+        } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
+            results = atomicGet(jsonInsertObj.getKeyspaceName(), jsonInsertObj.getTableName(),
+                    jsonInsertObj.getPrimaryKeyVal(), queryObject);
+        }
+        
+        return results;
+    }
+    
+    /**
+     * this is insert row into Table
+     */
+    public ReturnType insertIntoTable(JsonInsert jsonInsertObj)
+            throws MusicLockingException, MusicQueryException, MusicServiceException {
+        
+        String consistency = "";
+        if(null != jsonInsertObj && null != jsonInsertObj.getConsistencyInfo()) {
+            consistency = jsonInsertObj.getConsistencyInfo().get("type");
+        }
+        
+        ReturnType result = null;
+        
+        try {
+            PreparedQueryObject queryObj = null;
+            queryObj = jsonInsertObj.genInsertPreparedQueryObj();
+            
+            if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL)) {
+                result = eventualPut(jsonInsertObj.genInsertPreparedQueryObj());
+            } else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
+                String lockId = jsonInsertObj.getConsistencyInfo().get("lockId");
+                if(lockId == null) {
+                    logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
+                            + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
+                    return new ReturnType(ResultType.FAILURE, "LockId cannot be null. Create lock "
+                            + "and acquire lock or use ATOMIC instead of CRITICAL");
+                }
+                result = criticalPut(jsonInsertObj.getKeyspaceName(), 
+                        jsonInsertObj.getTableName(), jsonInsertObj.getPrimaryKeyVal(), jsonInsertObj.genInsertPreparedQueryObj(), lockId,null);
+            } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
+                result = atomicPut(jsonInsertObj.getKeyspaceName(), jsonInsertObj.getTableName(), 
+                        jsonInsertObj.getPrimaryKeyVal(), jsonInsertObj.genInsertPreparedQueryObj(), null);
+            }
+        } catch (Exception ex) {
+            logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR  ,ErrorSeverity
+                .WARN, ErrorTypes.MUSICSERVICEERROR, ex);
+            return new ReturnType(ResultType.FAILURE, ex.getMessage());
+        }
+        
+        return result;
+    }
+    
+     /**
+     * This is insert row into Table
+     */
+    public ReturnType updateTable(JsonUpdate jsonUpdateObj, MultivaluedMap<String, String> rowParams)
+            throws MusicLockingException, MusicQueryException, MusicServiceException {
+        
+        ReturnType result = null;
+        String consistency = "";
+        if(null != jsonUpdateObj && null != jsonUpdateObj.getConsistencyInfo()) {
+            consistency = jsonUpdateObj.getConsistencyInfo().get("type");
+        }
+        PreparedQueryObject queryObject = jsonUpdateObj.genUpdatePreparedQueryObj(rowParams);
+        
+        Condition conditionInfo;
+        if (jsonUpdateObj.getConditions() == null) {
+            conditionInfo = null;
+        } else {
+            // to avoid parsing repeatedly, just send the select query to obtain row
+            PreparedQueryObject selectQuery = new PreparedQueryObject();
+            selectQuery.appendQueryString("SELECT *  FROM " + jsonUpdateObj.getKeyspaceName() + "." + jsonUpdateObj.getTableName() + " WHERE "
+                + jsonUpdateObj.getRowIdString() + ";");
+            selectQuery.addValue(jsonUpdateObj.getPrimarKeyValue());
+            conditionInfo = new Condition(jsonUpdateObj.getConditions(), selectQuery);
+        }
+
+        
+        if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL)) {
+            result = eventualPut(queryObject);
+        } else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
+            String lockId = jsonUpdateObj.getConsistencyInfo().get("lockId");
+            if(lockId == null) {
+                logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
+                        + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
+               
+                return new ReturnType(ResultType.FAILURE, "LockId cannot be null. Create lock "
+                        + "and acquire lock or use ATOMIC instead of CRITICAL");
+            }
+            result = criticalPut(jsonUpdateObj.getKeyspaceName(), jsonUpdateObj.getTableName(), jsonUpdateObj.getPrimarKeyValue(),
+                            queryObject, lockId, conditionInfo);
+        } else if (consistency.equalsIgnoreCase("atomic_delete_lock")) {
+            // this function is mainly for the benchmarks
+            try {
+                result = atomicPutWithDeleteLock(jsonUpdateObj.getKeyspaceName(), jsonUpdateObj.getTableName(),
+                        jsonUpdateObj.getPrimarKeyValue(), queryObject, conditionInfo);
+            } catch (MusicLockingException e) {
+                logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN,
+                    ErrorTypes.GENERALSERVICEERROR, e);
+                throw new MusicLockingException(AppMessages.UNKNOWNERROR.toString());
+                
+            }
+        } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
+            try {
+                result = atomicPut(jsonUpdateObj.getKeyspaceName(), jsonUpdateObj.getTableName(), jsonUpdateObj.getPrimarKeyValue(),
+                    queryObject, conditionInfo);
+            } catch (MusicLockingException e) {
+                logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR  ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR, e);
+                throw new MusicLockingException(AppMessages.UNKNOWNERROR.toString());
+            }
+        } else if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL_NB)) {
+            try {
+                result = eventualPut_nb(queryObject, jsonUpdateObj.getKeyspaceName(),
+                        jsonUpdateObj.getTableName(), jsonUpdateObj.getPrimarKeyValue());
+            }catch (Exception e) {
+                return new ReturnType(ResultType.FAILURE, e.getMessage());
+            }
+            
+        }
+        
+        return result;
+    }
+    
+    /**
+     * This method is for Delete From Table
+     */
+    public ReturnType deleteFromTable(JsonDelete jsonDeleteObj, MultivaluedMap<String, String> rowParams)
+            throws MusicLockingException, MusicQueryException, MusicServiceException {
+        
+        ReturnType result = null;
+        String consistency = "";
+        if(null != jsonDeleteObj && null != jsonDeleteObj.getConsistencyInfo()) {
+            consistency = jsonDeleteObj.getConsistencyInfo().get("type");
+        }
+        PreparedQueryObject queryObject = jsonDeleteObj.genDeletePreparedQueryObj(rowParams);
+        
+        // get the conditional, if any
+        Condition conditionInfo;
+        if (jsonDeleteObj.getConditions() == null) {
+            conditionInfo = null;
+        } else {
+            // to avoid parsing repeatedly, just send the select query to obtain row
+            PreparedQueryObject selectQuery = new PreparedQueryObject();
+            selectQuery.appendQueryString("SELECT *  FROM " + jsonDeleteObj.getKeyspaceName() + "." + jsonDeleteObj.getTableName() + " WHERE "
+                + jsonDeleteObj.getRowIdString() + ";");
+            selectQuery.addValue(jsonDeleteObj.getPrimarKeyValue());
+            conditionInfo = new Condition(jsonDeleteObj.getConditions(), selectQuery);
+        }
+        
+        if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL))
+            result = eventualPut(queryObject);
+        else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
+            String lockId = jsonDeleteObj.getConsistencyInfo().get("lockId");
+            if(lockId == null) {
+                logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or"
+                    + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR);
+               
+                return new ReturnType(ResultType.FAILURE, "LockId cannot be null. Create lock "
+                        + "and acquire lock or use ATOMIC instead of CRITICAL");
+            }
+            result = criticalPut(jsonDeleteObj.getKeyspaceName(), 
+                    jsonDeleteObj.getTableName(), jsonDeleteObj.getPrimarKeyValue(),
+                queryObject, lockId, conditionInfo);
+        } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
+            result = atomicPut(jsonDeleteObj.getKeyspaceName(), 
+                    jsonDeleteObj.getTableName(), jsonDeleteObj.getPrimarKeyValue(),
+                queryObject, conditionInfo);
+        } else if(consistency.equalsIgnoreCase(MusicUtil.EVENTUAL_NB)) {                    
+            result = eventualPut_nb(queryObject, jsonDeleteObj.getKeyspaceName(), 
+                    jsonDeleteObj.getTableName(), jsonDeleteObj.getPrimarKeyValue());
+        }
+        
+        return result;
+    }
 
 
 }