Package voldemort.restclient

Source Code of voldemort.restclient.RESTClientFactory

package voldemort.restclient;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

import voldemort.client.LazyStoreClient;
import voldemort.client.StoreClient;
import voldemort.client.StoreClientFactory;
import voldemort.cluster.failuredetector.FailureDetector;
import voldemort.rest.RestUtils;
import voldemort.serialization.DefaultSerializerFactory;
import voldemort.serialization.Serializer;
import voldemort.serialization.SerializerDefinition;
import voldemort.serialization.SerializerFactory;
import voldemort.store.Store;
import voldemort.store.compress.CompressingStore;
import voldemort.store.compress.CompressionStrategyFactory;
import voldemort.store.serialized.SerializingStore;
import voldemort.store.stats.StatTrackingStore;
import voldemort.store.stats.StoreClientFactoryStats;
import voldemort.store.stats.StoreStats;
import voldemort.store.stats.StoreStatsJmx;
import voldemort.store.versioned.InconsistencyResolvingStore;
import voldemort.utils.ByteArray;
import voldemort.utils.JmxUtils;
import voldemort.versioning.ChainedResolver;
import voldemort.versioning.InconsistencyResolver;
import voldemort.versioning.TimeBasedInconsistencyResolver;
import voldemort.versioning.VectorClockInconsistencyResolver;
import voldemort.versioning.Versioned;

import com.linkedin.common.callback.FutureCallback;
import com.linkedin.common.util.None;
import com.linkedin.r2.transport.common.Client;
import com.linkedin.r2.transport.common.bridge.client.TransportClient;
import com.linkedin.r2.transport.http.client.HttpClientFactory;

/**
* Factory used to create a REST client for performing Voldemort operations
*
*/
public class RESTClientFactory implements StoreClientFactory {

    public static final int SHUTDOWN_TIMEOUT = 10;
    private RESTClientConfig config = null;
    private final StoreStats stats;
    private Logger logger = Logger.getLogger(RESTClientFactory.class);
    private SerializerFactory serializerFactory = new DefaultSerializerFactory();
    private HttpClientFactory _clientFactory;
    private TransportClient transportClient = null;
    private final StoreClientFactoryStats RESTClientFactoryStats;
    private Client d2Client;
    private RESTClientFactoryConfig restClientFactoryConfig;

    /**
     * This list holds a reference to all the raw stores created by this
     * factory. When the application invokes 'close' on this factory, it invokes
     * close on all these stores in turn.
     */
    private List<R2Store> rawStoreList = null;

    private HashMap<String, SerializerDefinition> keySerializerMap;
    private HashMap<String, SerializerDefinition> valueSerializerMap;

    public RESTClientFactory(RESTClientFactoryConfig config) {
        this.restClientFactoryConfig = config;
        this.config = new RESTClientConfig(restClientFactoryConfig.getClientConfig());
        this.stats = new StoreStats("aggregate.rest-client-factory");
        this.rawStoreList = new ArrayList<R2Store>();
        // Create the R2 (Netty) Factory object
        // TODO: Add monitoring for R2 factory
        this._clientFactory = new HttpClientFactory();
        this.RESTClientFactoryStats = new StoreClientFactoryStats();
        keySerializerMap = new HashMap<String, SerializerDefinition>();
        valueSerializerMap = new HashMap<String, SerializerDefinition>();
    }

    /**
     * Creates a REST client used to perform Voldemort operations against the
     * Coordinator
     *
     * @param storeName Name of the store to perform the operations on
     * @return
     */
    @Override
    public <K, V> StoreClient<K, V> getStoreClient(String storeName) {
        return getStoreClient(storeName, null);
    }

    /**
     * Creates a REST client used to perform Voldemort operations against the
     * Coordinator
     *
     * @param storeName Name of the store to perform the operations on
     * @param resolver Custom resolver as specified by the application
     * @return
     */
    @Override
    public <K, V> StoreClient<K, V> getStoreClient(final String storeName,
                                                   final InconsistencyResolver<Versioned<V>> resolver) {
        // wrap it in LazyStoreClient here so any direct calls to this method
        // returns a lazy client
        return new LazyStoreClient<K, V>(new Callable<StoreClient<K, V>>() {

            @Override
            public StoreClient<K, V> call() throws Exception {
                Store<K, V, Object> clientStore = getRawStore(storeName, resolver);
                return new RESTClient<K, V>(storeName, clientStore);
            }
        }, true);
    }

    @Override
    public <K, V, T> Store<K, V, T> getRawStore(String storeName,
                                                InconsistencyResolver<Versioned<V>> resolver) {

        Store<K, V, T> clientStore = null;

        // The lowest layer : Transporting request to coordinator
        R2Store r2store = null;
        this.d2Client = restClientFactoryConfig.getD2Client();
        if(this.d2Client == null) {
            logger.info("Using transportclient since d2client is not available");
            Map<String, String> properties = new HashMap<String, String>();
            properties.put(HttpClientFactory.HTTP_POOL_SIZE,
                           Integer.toString(this.config.getMaxR2ConnectionPoolSize()));
            transportClient = _clientFactory.getClient(properties);
            r2store = new R2Store(storeName,
                                  this.config.getHttpBootstrapURL(),
                                  this.transportClient,
                                  this.config);
        } else {
            logger.info("Using d2client");
            r2store = new R2Store(storeName,
                                  this.config.getHttpBootstrapURL(),
                                  this.d2Client,
                                  this.config);
        }

        this.rawStoreList.add(r2store);

        // bootstrap from the coordinator and obtain all the serialization
        // information.
        String serializerInfoXml = r2store.getSerializerInfoXml();
        SerializerDefinition keySerializerDefinition = RestUtils.parseKeySerializerDefinition(serializerInfoXml);
        SerializerDefinition valueSerializerDefinition = RestUtils.parseValueSerializerDefinition(serializerInfoXml);

        synchronized(this) {
            keySerializerMap.put(storeName, keySerializerDefinition);
            valueSerializerMap.put(storeName, valueSerializerDefinition);
        }

        if(logger.isDebugEnabled()) {
            logger.debug("Bootstrapping for " + storeName + ": Key serializer "
                         + keySerializerDefinition);
            logger.debug("Bootstrapping for " + storeName + ": Value serializer "
                         + valueSerializerDefinition);
        }

        // Start building the stack..
        // First, the transport layer
        Store<ByteArray, byte[], byte[]> store = r2store;

        // TODO: Add identifierString to the Mbean name
        if(this.config.isEnableJmx()) {
            StatTrackingStore statStore = new StatTrackingStore(store, this.stats);
            store = statStore;
            JmxUtils.registerMbean(new StoreStatsJmx(statStore.getStats()),
                                   JmxUtils.createObjectName(JmxUtils.getPackageName(store.getClass()),
                                                             store.getName()));
        }

        // Add compression layer
        if(keySerializerDefinition.hasCompression() || valueSerializerDefinition.hasCompression()) {
            store = new CompressingStore(store,
                                         new CompressionStrategyFactory().get(keySerializerDefinition.getCompression()),
                                         new CompressionStrategyFactory().get(valueSerializerDefinition.getCompression()));
        }

        // Add Serialization layer
        Serializer<K> keySerializer = (Serializer<K>) serializerFactory.getSerializer(keySerializerDefinition);
        Serializer<V> valueSerializer = (Serializer<V>) serializerFactory.getSerializer(valueSerializerDefinition);
        clientStore = SerializingStore.wrap(store, keySerializer, valueSerializer, null);

        // Add inconsistency Resolving layer
        InconsistencyResolver<Versioned<V>> secondaryResolver = resolver == null ? new TimeBasedInconsistencyResolver<V>()
                                                                                : resolver;
        clientStore = new InconsistencyResolvingStore<K, V, T>(clientStore,
                                                               new ChainedResolver<Versioned<V>>(new VectorClockInconsistencyResolver<V>(),
                                                                                                 secondaryResolver));
        return clientStore;
    }

    @Override
    public void close() {
        for(R2Store store: this.rawStoreList) {
            store.close();
        }
        // shutdown the transportclient in the case when no r2store is created
        if(this.transportClient != null) {
            final FutureCallback<None> clientShutdownCallback = new FutureCallback<None>();
            this.transportClient.shutdown(clientShutdownCallback);
            try {
                clientShutdownCallback.get();
            } catch(InterruptedException e) {
                logger.error("Interrupted while shutting down the TransportClient: "
                                     + e.getMessage(),
                             e);
            } catch(ExecutionException e) {
                logger.error("Execution exception occurred while shutting down the TransportClient: "
                                     + e.getMessage(),
                             e);
            }
        }

        final FutureCallback<None> factoryShutdownCallback = new FutureCallback<None>();
        this._clientFactory.shutdown(factoryShutdownCallback, SHUTDOWN_TIMEOUT, TimeUnit.SECONDS);
        try {
            factoryShutdownCallback.get();
        } catch(InterruptedException e) {
            logger.error("Interrupted while shutting down the HttpClientFactory: " + e.getMessage(),
                         e);
        } catch(ExecutionException e) {
            logger.error("Execution exception occurred while shutting down the HttpClientFactory: "
                         + e.getMessage(), e);
        }
    }

    @Override
    public FailureDetector getFailureDetector() {
        return null;
    }

    public SerializerDefinition getKeySerializer(String storeName) {
        if(keySerializerMap.containsKey(storeName)) {
            return keySerializerMap.get(storeName);
        }
        return null;
    }

    public SerializerDefinition getValueSerializer(String storeName) {
        if(valueSerializerMap.containsKey(storeName)) {
            return valueSerializerMap.get(storeName);
        }
        return null;
    }

}
TOP

Related Classes of voldemort.restclient.RESTClientFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.