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

com.netflix.astyanax.connectionpool.impl.AbstractExecuteWithFailoverImpl Maven / Gradle / Ivy

There is a newer version: 3.10.2
Show newest version
/*******************************************************************************
 * Copyright 2011 Netflix
 * 
 * Licensed 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.
 ******************************************************************************/
package com.netflix.astyanax.connectionpool.impl;

import com.netflix.astyanax.connectionpool.Connection;
import com.netflix.astyanax.connectionpool.ConnectionPool;
import com.netflix.astyanax.connectionpool.ConnectionPoolConfiguration;
import com.netflix.astyanax.connectionpool.ConnectionPoolMonitor;
import com.netflix.astyanax.connectionpool.ExecuteWithFailover;
import com.netflix.astyanax.connectionpool.Host;
import com.netflix.astyanax.connectionpool.HostConnectionPool;
import com.netflix.astyanax.connectionpool.Operation;
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.UnknownException;

/**
 * Abstract class that provides a basic impl of {@link ExecuteWithFailover}. 
 * 
 * This is used within the context of a {@link AbstractHostPartitionConnectionPool} implementation, where 
 * the abstract failover class repeatedly attempts to borrow a connection from the implementing {@link ConnectionPool}
 * and also releases the connection as cleanup. It also maintains stats about the attempts and informs latency metrics 
 * on the exceptions when executing {@link Operation}s or borrowing {@link Connection}s from the pool. 

* * Note that extending classes need to implement functionality to {@link AbstractExecuteWithFailoverImpl#borrowConnection(Operation)} that must be used * to execute the operation. They also need to implement {@link AbstractExecuteWithFailoverImpl#canRetry()} to tell this class * when to stop borrowing connections on failed attempts. * * @param * @param * * @author elandau * * @see {@link AbstractHostPartitionConnectionPool#executeWithFailover(Operation, com.netflix.astyanax.retry.RetryPolicy)} for references to this. * @see {@link RoundRobinExecuteWithFailover} as an example class that extends the functionality. * @see {@link RoundRobinConnectionPoolImpl} as an example of a {@link ConnectionPool} that employs the {@link RoundRobinExecuteWithFailover} for it's failover impl * */ public abstract class AbstractExecuteWithFailoverImpl implements ExecuteWithFailover { protected Connection connection = null; private long startTime; private long poolStartTime; private int attemptCounter = 0; private final ConnectionPoolMonitor monitor; protected final ConnectionPoolConfiguration config; /** * Public constructor * @param config * @param monitor * @throws ConnectionException */ public AbstractExecuteWithFailoverImpl(ConnectionPoolConfiguration config, ConnectionPoolMonitor monitor) throws ConnectionException { this.monitor = monitor; this.config = config; startTime = poolStartTime = System.currentTimeMillis(); } /** * @return {@link Host} */ final public Host getCurrentHost() { HostConnectionPool pool = getCurrentHostConnectionPool(); if (pool != null) return pool.getHost(); else return Host.NO_HOST; } /** * @return {@link HostConnectionPool} */ abstract public HostConnectionPool getCurrentHostConnectionPool(); /** * @param operation * @return {@link Connection} * @throws ConnectionException */ abstract public Connection borrowConnection(Operation operation) throws ConnectionException; /** * @return boolean */ abstract public boolean canRetry(); /** * Basic impl that repeatedly borrows a conn and tries to execute the operation while maintaining metrics for * success, conn attempts, failures and latencies for operation executions * * @param operation * @return {@link OperationResult} */ @Override public OperationResult tryOperation(Operation operation) throws ConnectionException { Operation filteredOperation = config.getOperationFilterFactory().attachFilter(operation); while (true) { attemptCounter++; try { connection = borrowConnection(filteredOperation); startTime = System.currentTimeMillis(); OperationResult result = connection.execute(filteredOperation); result.setAttemptsCount(attemptCounter); monitor.incOperationSuccess(getCurrentHost(), result.getLatency()); return result; } catch (Exception e) { ConnectionException ce = (e instanceof ConnectionException) ? (ConnectionException) e : new UnknownException(e); try { informException(ce); monitor.incFailover(ce.getHost(), ce); } catch (ConnectionException ex) { monitor.incOperationFailure(getCurrentHost(), ex); throw ex; } } finally { releaseConnection(); } } } protected void releaseConnection() { if (connection != null) { connection.getHostConnectionPool().returnConnection(connection); connection = null; } } private void informException(ConnectionException connectionException) throws ConnectionException { connectionException .setHost(getCurrentHost()) .setLatency(System.currentTimeMillis() - startTime) .setAttempt(this.attemptCounter) .setLatencyWithPool(System.currentTimeMillis() - poolStartTime); if (connectionException instanceof IsRetryableException) { if (!canRetry()) { throw connectionException; } } else { // Most likely an operation error throw connectionException; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy