com.impetus.client.cassandra.thrift.ThriftClientFactory Maven / Gradle / Ivy
/**
* Copyright 2012 Impetus Infotech.
*
* 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.impetus.client.cassandra.thrift;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import net.dataforte.cassandra.pool.ConnectionPool;
import net.dataforte.cassandra.pool.PoolConfiguration;
import net.dataforte.cassandra.pool.PoolProperties;
import org.apache.cassandra.thrift.Cassandra;
import org.apache.thrift.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.impetus.client.cassandra.common.CassandraClientFactory;
import com.impetus.client.cassandra.common.CassandraUtilities;
import com.impetus.client.cassandra.config.CassandraPropertyReader;
import com.impetus.client.cassandra.query.CassandraEntityReader;
import com.impetus.client.cassandra.schemamanager.CassandraSchemaManager;
import com.impetus.client.cassandra.service.CassandraHost;
import com.impetus.client.cassandra.service.CassandraHostConfiguration;
import com.impetus.client.cassandra.service.CassandraRetryService;
import com.impetus.kundera.Constants;
import com.impetus.kundera.KunderaException;
import com.impetus.kundera.PersistenceProperties;
import com.impetus.kundera.client.Client;
import com.impetus.kundera.configure.schema.api.SchemaManager;
import com.impetus.kundera.metadata.KunderaMetadataManager;
import com.impetus.kundera.metadata.model.PersistenceUnitMetadata;
import com.impetus.kundera.service.Host;
import com.impetus.kundera.service.HostConfiguration;
import com.impetus.kundera.service.policy.LeastActiveBalancingPolicy;
import com.impetus.kundera.service.policy.RoundRobinBalancingPolicy;
/**
* A factory of {@link ThriftClient} Currently it uses Pelops for Connection
* pooling. Need to replace it with our own pooling. Most of the code is
* borrowed from {@link PelopsClientFactory}
*
* @author amresh.singh
*/
public class ThriftClientFactory extends CassandraClientFactory
{
/** The logger. */
private static Logger logger = LoggerFactory.getLogger(ThriftClientFactory.class);
protected HostConfiguration configuration;
@Override
public SchemaManager getSchemaManager(Map externalProperty)
{
if (schemaManager == null)
{
initializePropertyReader();
schemaManager = new CassandraSchemaManager(ThriftClientFactory.class.getName(), externalProperties,
kunderaMetadata);
}
return schemaManager;
}
/**
*
*/
private void initializePropertyReader()
{
if (propertyReader == null)
{
propertyReader = new CassandraPropertyReader(externalProperties, kunderaMetadata.getApplicationMetadata()
.getPersistenceUnitMetadata(getPersistenceUnit()));
propertyReader.read(getPersistenceUnit());
}
}
@Override
public void destroy()
{
if (indexManager != null)
{
indexManager.close();
}
if (schemaManager != null)
{
schemaManager.dropSchema();
}
schemaManager = null;
externalProperties = null;
for (Object connectionPool : hostPools.values())
{
if (connectionPool != null && connectionPool.getClass().isAssignableFrom(ConnectionPool.class))
{
((ConnectionPool) connectionPool).close(true);
}
}
((CassandraRetryService) hostRetryService).shutdown();
}
@Override
public void initialize(Map externalProperty)
{
reader = new CassandraEntityReader(kunderaMetadata);
initializePropertyReader();
setExternalProperties(externalProperty);
String loadBalancingPolicyName = CassandraPropertyReader.csmd != null ? CassandraPropertyReader.csmd
.getConnectionProperties().getProperty(Constants.LOADBALANCING_POLICY) : null;
initializeLoadBalancer(loadBalancingPolicyName);
configuration = new CassandraHostConfiguration(externalProperties, CassandraPropertyReader.csmd,
getPersistenceUnit(), kunderaMetadata);
hostRetryService = new CassandraRetryService(configuration, this);
// initialize timestamp generator.
initializeTimestampGenerator(externalProperty);
}
@Override
protected Object createPoolOrConnection()
{
PersistenceUnitMetadata persistenceUnitMetadata = kunderaMetadata.getApplicationMetadata()
.getPersistenceUnitMetadata(getPersistenceUnit());
Properties props = persistenceUnitMetadata.getProperties();
String keyspace = null;
if (externalProperties != null)
{
keyspace = (String) externalProperties.get(PersistenceProperties.KUNDERA_KEYSPACE);
}
if (keyspace == null)
{
keyspace = (String) props.get(PersistenceProperties.KUNDERA_KEYSPACE);
}
for (Host host : ((CassandraHostConfiguration) configuration).getCassandraHosts())
{
PoolConfiguration prop = new PoolProperties();
prop.setHost(host.getHost());
prop.setPort(host.getPort());
prop.setKeySpace(keyspace);
CassandraUtilities.setPoolConfigPolicy((CassandraHost) host, prop);
try
{
ConnectionPool pool = new ConnectionPool(prop);
hostPools.put(host, pool);
}
catch (TException e)
{
logger.warn("Node {} are down, Caused by {} .", host.getHost(), e.getMessage());
if (host.isRetryHost())
{
logger.warn("Scheduling node for future retry");
((CassandraRetryService) hostRetryService).add((CassandraHost) host);
}
}
}
return null;
}
@Override
protected Client instantiateClient(String persistenceUnit)
{
ConnectionPool pool = getPoolUsingPolicy();
return new ThriftClient(this, indexManager, reader, persistenceUnit, pool, externalProperties, kunderaMetadata, timestampGenerator);
}
/**
*
* @return pool an the basis of LoadBalancing policy.
*/
private ConnectionPool getPoolUsingPolicy()
{
if (!hostPools.isEmpty())
{
return (ConnectionPool) loadBalancingPolicy.getPool(hostPools.values());
}
throw new KunderaException("All hosts are down. please check servers manully.");
}
@Override
public boolean isThreadSafe()
{
return false;
}
/**
*
* @param host
* @param port
* @return
*/
private ConnectionPool getNewPool(String host, int port)
{
CassandraHost cassandraHost = ((CassandraHostConfiguration) configuration).getCassandraHost(host, port);
hostPools.remove(cassandraHost);
if (cassandraHost.isRetryHost())
{
logger.warn("Scheduling node for future retry");
((CassandraRetryService) hostRetryService).add((CassandraHost) cassandraHost);
}
return getPoolUsingPolicy();
}
@Override
protected void initializeLoadBalancer(String loadBalancingPolicyName)
{
if (loadBalancingPolicyName != null)
{
switch (LoadBalancer.getValue(loadBalancingPolicyName))
{
case ROUNDROBIN:
loadBalancingPolicy = new RoundRobinBalancingPolicy();
break;
case LEASTACTIVE:
loadBalancingPolicy = new ThriftLeastActiveBalancingPolcy();
break;
default:
loadBalancingPolicy = new RoundRobinBalancingPolicy();
break;
}
}
loadBalancingPolicy = new RoundRobinBalancingPolicy();
}
Connection getConnection(ConnectionPool pool)
{
ConnectionPool connectionPool = pool;
boolean success = false;
while (!success)
{
try
{
success = true;
Cassandra.Client client = connectionPool.getConnection();
if (logger.isDebugEnabled())
{
logger.debug("Returning connection of {} :{} .", pool.getPoolProperties().getHost(), pool
.getPoolProperties().getPort());
}
return new Connection(client, connectionPool);
}
catch (TException te)
{
success = false;
logger.warn("{} :{} host appears to be down, trying for next ", pool.getPoolProperties().getHost(),
pool.getPoolProperties().getPort());
connectionPool = getNewPool(pool.getPoolProperties().getHost(), pool.getPoolProperties().getPort());
}
}
throw new KunderaException("All hosts are down. please check servers manully.");
}
void releaseConnection(ConnectionPool pool, Cassandra.Client conn)
{
if (pool != null && conn != null)
{
pool.release(conn);
}
}
/**
* Adds a pool in hostPools map for given host.
*
* @param cassandraHost
* @return true id added successfully.
*/
public boolean addCassandraHost(CassandraHost cassandraHost)
{
String keysapce = KunderaMetadataManager.getPersistenceUnitMetadata(kunderaMetadata, getPersistenceUnit())
.getProperties().getProperty(PersistenceProperties.KUNDERA_KEYSPACE);
PoolConfiguration prop = new PoolProperties();
prop.setHost(cassandraHost.getHost());
prop.setPort(cassandraHost.getPort());
prop.setKeySpace(keysapce);
CassandraUtilities.setPoolConfigPolicy(cassandraHost, prop);
try
{
if (logger.isInfoEnabled())
{
logger.info("Initializing connection for keyspace {},host {},port {}", keysapce,
cassandraHost.getHost(), cassandraHost.getPort());
}
ConnectionPool pool = new ConnectionPool(prop);
hostPools.put(cassandraHost, pool);
return true;
}
catch (TException e)
{
logger.warn("Node " + cassandraHost.getHost() + " are still down");
return false;
}
}
/**
* Extends LeastActiveBalancingPolicy class and provide own implementation
* in order to support least active balancing policy.
*
* @author Kuldeep.Mishra
*
*/
private class ThriftLeastActiveBalancingPolcy extends LeastActiveBalancingPolicy
{
/**
*
* @return pool object for host which has least active connections
* determined by maxActive connection.
*
*/
@Override
public Object getPool(Collection
© 2015 - 2024 Weber Informatics LLC | Privacy Policy