Package com.netflix.evcache.pool.standalone

Source Code of com.netflix.evcache.pool.standalone.SimpleEVCacheClientPoolImpl

/**
* Copyright 2013 Netflix, Inc.
*
* 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.evcache.pool.standalone;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;

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

import com.netflix.config.ConfigurationManager;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
import com.netflix.evcache.pool.EVCacheClient;
import com.netflix.servo.annotations.DataSourceType;
import com.netflix.servo.annotations.Monitor;

/**
* A Simple EVCache Client pool given a list of memcached nodes.
*
* @author smadappa
*
*/
public class SimpleEVCacheClientPoolImpl extends AbstractEVCacheClientPoolImpl implements SimpleEVCacheClientPoolImplMBean {
    private static Logger log = LoggerFactory.getLogger(SimpleEVCacheClientPoolImpl.class);

    private DynamicStringProperty _serverList; //List of servers
    private List<EVCacheClient> memcachedInstances;

    /**
     * Default constructor.
     */
    public SimpleEVCacheClientPoolImpl() {
    }

    /**
     * {@inheritDoc}
     */
    public void init(final String appName) {
        super.init(appName);
        this._serverList = DynamicPropertyFactory.getInstance().getStringProperty(appName + ".EVCacheClientPool.hosts", "");
        _serverList.addCallback(this);
        int size = getPoolSize().get() < 0 ? 1 : getPoolSize().get();
        memcachedInstances = new ArrayList<EVCacheClient>(size);

        try {
            refresh();
        } catch (Throwable t) {
            if (log.isDebugEnabled()) log.debug("Error Refreshing EVCache Instance list for " + appName , t);
        }
    }

    /**
     * {@inheritDoc}
     */
    public EVCacheClient getEVCacheClient() {
        if (memcachedInstances == null || memcachedInstances.isEmpty()) return null;
        try {
            if (memcachedInstances.size() == 1) return memcachedInstances.get(0); //Frequently used scenario
            final long currentVal = getNumOfOps().incrementAndGet();
            final int index = (int) currentVal % memcachedInstances.size();
            return memcachedInstances.get(index);
        } catch (Throwable t) {
            log.error("Exception trying to get an readable EVCache Instance.", t);
            return null;
        }
    }

    private List<InetSocketAddress> getMemcachedSocketAddressList(final List<String> discoveredHostsInZone) {
        final List<InetSocketAddress> memcachedNodesInZone = new ArrayList<InetSocketAddress>(discoveredHostsInZone.size());
        for (String hostAddress : discoveredHostsInZone) {
            final int colonIndex = hostAddress.lastIndexOf(':');
            final String hostName = hostAddress.substring(0, colonIndex);
            final String portNum = hostAddress.substring(colonIndex + 1);
            memcachedNodesInZone.add(new InetSocketAddress(hostName, Integer.parseInt(portNum)));
        }
        return memcachedNodesInZone;
    }

    private void setupNewClients(List<EVCacheClient> newClients) {
        final List<EVCacheClient> currentClients = memcachedInstances;
        memcachedInstances = newClients;
        if (currentClients == null || currentClients.isEmpty()) return;

        //Now since we have replace the old instances shutdown all the old clients
        if (log.isDebugEnabled()) log.debug("Replaced an existing Pool for app " + getAppName()
                + " ;\n\tOldClients : " + currentClients + ";\n\tNewClients : " + newClients);
        for (EVCacheClient client : currentClients) {
            if (!client.isShutdown()) {
                if (log.isDebugEnabled()) log.debug("Shutting down in Fallback -> AppName : " + getAppName() + "; client {" + client + "};");
                try {
                    if (client.getConnectionObserver() != null) {
                        final boolean obsRemoved = client.removeConnectionObserver();
                        if (log.isDebugEnabled()) log.debug("Connection observer removed " + obsRemoved);
                    }
                    final boolean status = client.shutdown(60, TimeUnit.SECONDS);
                    if (log.isDebugEnabled()) log.debug("Shutting down {" + client + "} ; status : " + status);
                } catch (Exception ex) {
                    log.error("Exception while shutting down the old Client", ex);
                }
            }
        }
    }

    private synchronized void refresh() throws IOException {
        try {
            final List<String> instances = discoverInstances();
            if (instances == null || instances.isEmpty()) return; //if no instances are found then bail immediately.

            final List<InetSocketAddress> memInstances = getMemcachedSocketAddressList(instances);
            final int poolSize = getPoolSize().get();
            final List<EVCacheClient> newClients = new ArrayList<EVCacheClient>(poolSize);
            for (int i = 0; i < poolSize; i++) {
                final int maxQueueSize = ConfigurationManager.getConfigInstance().getInt(getAppName() + ".max.queue.length", 16384);
                final EVCacheClient client = new SimpleEVCacheClientImpl(getAppName(), i, maxQueueSize, getReadTimeout(), memInstances);
                newClients.add(client);
                if (log.isDebugEnabled()) log.debug("AppName :" + getAppName() + "; intit : client.getId() : " + client.getId());
            }
            setupNewClients(newClients);
        } catch (Throwable t) {
            log.error("Exception while refreshing the Server list", t);
        }
    }

    /**
     * Discover memcached instances suitable for our use from the Discovery Service.
     *
     * @throws IllegalStateException if an error occurred in the Discovery
     *    service
     */
    private List<String> discoverInstances() throws IOException {
        if (isShutdown()) {
            return Collections.<String>emptyList();
        }

        final List<String> instances = new ArrayList<String>();
        final String serverList = _serverList.get();
        final StringTokenizer stk = new StringTokenizer(serverList, ",");

        /* Iterate all the discovered instances to find usable ones */
        while (stk.hasMoreTokens()) {
            final String token = stk.nextToken();
            final String memcachedHost;
            final String memcachedPort;
            final int index = token.indexOf(":");
            if (index == -1) {
                memcachedHost = token;
                memcachedPort = "11211";
            } else {
                memcachedHost = token.substring(0, index);
                memcachedPort = token.substring(index + 1);
            }
            instances.add(memcachedHost + ":" + memcachedPort);
        }
        return instances;
    }

    /**
     * {@inheritDoc}
     */
    public void shutdown() {
        super.shutdown();
        for (EVCacheClient client : memcachedInstances) {
            shutdownClient(client);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Monitor(name = "Instances", type = DataSourceType.COUNTER)
    public int getInstanceCount() {
        if (memcachedInstances.size() == 0) return 0;
        return memcachedInstances.get(0).getConnectionObserver().getActiveServerCount();
    }

    /**
     * {@inheritDoc}
     */
    public List<String> getInstances() {
        final List<String> instanceList = new ArrayList<String>(memcachedInstances.size());
        for (EVCacheClient client : memcachedInstances) {
            instanceList.add(client.toString());
        }
        return instanceList;
    }

    /**
     * {@inheritDoc}
     */
    public void refreshPool() {
        try {
            refresh();
        } catch (Throwable t) {
            if (log.isDebugEnabled()) log.debug("Error Refreshing EVCache Instance list from MBean : " + getAppName() , t);
        }
    }

    /**
     * {@inheritDoc}
     */
    public EVCacheClient getEVCacheClientExcludeZone(String zone) {
        return getEVCacheClient();
    }

    /**
     * {@inheritDoc}
     */
    public EVCacheClient[] getAllEVCacheClients() {
        final EVCacheClient[] clientArr = new EVCacheClient[1];
        clientArr[0] = getEVCacheClient();
        return clientArr;
    }

    /**
     * {@inheritDoc}
     */
    public void run() {
        try {
            refresh();
        } catch (Throwable t) {
            if (log.isDebugEnabled()) log.debug("Error Refreshing EVCache Instance list for " + getAppName() , t);
        }
    }

    /**
     * {@inheritDoc}
     */
    public boolean supportsFallback() {
        return false;
    }

    /**
     * {@inheritDoc}
     */
    public int getClusterSize() {
        return 1;
    }

    /**
     * String representation of this instance.
     */
    public String toString() {
        return "SimpleEVCacheClientPoolImpl ["  + super.toString()
                + ", _serverList=" + _serverList + ", memcachedInstances=" + memcachedInstances
                + "]";
    }
}
TOP

Related Classes of com.netflix.evcache.pool.standalone.SimpleEVCacheClientPoolImpl

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.