All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.astyanax.cql.CqlAbstractExecutionImpl Maven / Gradle / Ivy

package com.netflix.astyanax.cql;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.ResultSetFuture;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.Statement;
import com.google.common.util.concurrent.ListenableFuture;
import com.netflix.astyanax.CassandraOperationCategory;
import com.netflix.astyanax.CassandraOperationTracer;
import com.netflix.astyanax.CassandraOperationType;
import com.netflix.astyanax.Execution;
import com.netflix.astyanax.KeyspaceTracerFactory;
import com.netflix.astyanax.connectionpool.OperationResult;
import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
import com.netflix.astyanax.connectionpool.exceptions.IsRetryableException;
import com.netflix.astyanax.connectionpool.exceptions.NotFoundException;
import com.netflix.astyanax.connectionpool.exceptions.OperationException;
import com.netflix.astyanax.cql.CqlKeyspaceImpl.KeyspaceContext;
import com.netflix.astyanax.cql.retrypolicies.JavaDriverBasedRetryPolicy;
import com.netflix.astyanax.cql.util.AsyncOperationResult;
import com.netflix.astyanax.cql.util.CFQueryContext;
import com.netflix.astyanax.model.ColumnFamily;
import com.netflix.astyanax.model.ConsistencyLevel;
import com.netflix.astyanax.retry.RetryPolicy;

/**
 * Abstract class that encapsulates the functionality for executing an operations using the native protocol based java driver
 * Note that class provides only the operation agnostic functionality such as retries, tracking metrics etc. 
 * The actual logic for constructing the query for the operation and then parsing the result set of the operation is left
 * to the implementation of the extending class. 
 * 
 * @author poberai
 *
 * @param 
 */
public abstract class CqlAbstractExecutionImpl implements Execution {
	
	private static final Logger LOG = LoggerFactory.getLogger(CqlAbstractExecutionImpl.class);
	
	// The session for executing the query
	protected final Session session;
	// The keyspace being operated on
	protected final String keyspace;
	// The CF being operated on
	protected final ColumnFamily cf;
	// Factory for vending operation metrics
	protected final KeyspaceTracerFactory tracerFactory;
	// Retry policy
	protected final RetryPolicy retry;
	// ConsistencyLevel
	protected final com.datastax.driver.core.ConsistencyLevel clLevel; 
	
	public CqlAbstractExecutionImpl(KeyspaceContext ksContext, CFQueryContext cfContext) {
		
		this.session = ksContext.getSession();
		this.keyspace = ksContext.getKeyspace();
		this.cf = (cfContext != null) ? cfContext.getColumnFamily() : null;
		this.tracerFactory = ksContext.getTracerFactory();
		
		// process the override retry policy first
		RetryPolicy retryPolicy = ksContext.getConfig().getRetryPolicy();
		retry = (retryPolicy != null) ? retryPolicy : getRetryPolicy(cfContext.getRetryPolicy()); 
		
		clLevel = resolveConsistencyLevel(ksContext, cfContext);
	}

	public CqlAbstractExecutionImpl(KeyspaceContext ksContext, RetryPolicy retryPolicy) {
		
		this.session = ksContext.getSession();
		this.keyspace = ksContext.getKeyspace();
		this.cf = null;
		this.tracerFactory = ksContext.getTracerFactory();
		
		// process the override retry policy first
		retry = (retryPolicy != null) ? retryPolicy : getRetryPolicy(ksContext.getConfig().getRetryPolicy());
		clLevel = resolveConsistencyLevel(ksContext, null);
	}

	@Override
	public OperationResult execute() throws ConnectionException {
		
        ConnectionException lastException = null;
        
        retry.begin();

        do {
        	try {
                return executeOp();
            } catch (RuntimeException ex) {
            	lastException = new OperationException(ex);
            } catch (ConnectionException ex) {
                if (ex instanceof IsRetryableException)
                    lastException = ex;
                else
                    throw ex;
            }
        } while (retry.allowRetry());

        throw lastException;
	}

	
	private OperationResult executeOp() throws ConnectionException {
		CassandraOperationTracer tracer = null;
		
		if (cf != null) {
			tracer = tracerFactory.newTracer(getOperationType(), cf);
		} else {
			tracer = tracerFactory.newTracer(getOperationType());
		}
		
		tracer.start();
		Statement query = getQuery();
		
		if (LOG.isDebugEnabled()) {
			LOG.debug("Query: " + query);
		}
		
        // Set the consistency level on the query
        query.setConsistencyLevel(clLevel);

        // Set the retry policy on the query
        if (retry instanceof JavaDriverBasedRetryPolicy) {
        	JavaDriverBasedRetryPolicy jdRetryPolicy = (JavaDriverBasedRetryPolicy) retry;
        	query.setRetryPolicy(jdRetryPolicy.getJDRetryPolicy());
        }

        ResultSet resultSet = session.execute(query);
        R result = parseResultSet(resultSet);
		OperationResult opResult = new CqlOperationResultImpl(resultSet, result);
		opResult.setAttemptsCount(retry.getAttemptCount());
		tracer.success();
		return opResult;
	}
	
	@Override
	public ListenableFuture> executeAsync() throws ConnectionException {
		final CassandraOperationTracer tracer = tracerFactory.newTracer(getOperationType());
		tracer.start();
		
		Statement query = getQuery();
		
		if (LOG.isDebugEnabled()) {
			LOG.debug("Query: " + query);
		}
		
		ResultSetFuture rsFuture = session.executeAsync(query);
		return new AsyncOperationResult(rsFuture) {
			@Override
			public OperationResult getOperationResult(ResultSet resultSet) {
				R result = null;
				try {
					result = parseResultSet(resultSet);
				} catch (NotFoundException e) {
					LOG.error(e.getStackTrace().toString());
				}
				tracer.success();
				OperationResult opResult = new CqlOperationResultImpl(resultSet, result);
				opResult.setAttemptsCount(retry.getAttemptCount());
				return opResult;
			}
		};
	}
	
	private RetryPolicy getRetryPolicy(RetryPolicy policy) {
		if (policy != null) {
			return policy.duplicate();
		} else {
			return null;
		}
	}
	
	private ConsistencyLevel getDefaultCL(KeyspaceContext ksContext) {
		
		ConsistencyLevel clLevel = ksContext.getConfig().getDefaultReadConsistencyLevel(); 
		
		CassandraOperationCategory op = getOperationType().getCategory();
		switch (op) {
		case READ:
			clLevel = ksContext.getConfig().getDefaultReadConsistencyLevel(); 
			break;
		case WRITE:
			clLevel = ksContext.getConfig().getDefaultWriteConsistencyLevel();
		default:
			clLevel = ksContext.getConfig().getDefaultReadConsistencyLevel(); 
		}
		
		return clLevel;
	}
	
	private com.datastax.driver.core.ConsistencyLevel resolveConsistencyLevel(KeyspaceContext ksContext, CFQueryContext cfContext) {
		ConsistencyLevel clLevel = null; 
		if (cfContext != null) {
			clLevel = cfContext.getConsistencyLevel();
		}
		if (clLevel == null) {
			clLevel = getDefaultCL(ksContext);
		}
		return ConsistencyLevelMapping.getCL(clLevel);
	}
	
	/**
	 * Specify what operation type this is. Used for emitting the right tracers
	 * @return CassandraOperationType
	 */
	public abstract CassandraOperationType getOperationType();
	
	/**
	 * Get the Query for this operation
	 * @return Query
	 */
	public abstract Statement getQuery();

	/**
	 * Parse the result set to get the required response
	 * @param resultSet
	 * @return
	 */
	public abstract R parseResultSet(ResultSet resultSet) throws NotFoundException;
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy