
com.netflix.evcache.pool.EVCacheClientPoolManager Maven / Gradle / Ivy
The newest version!
package com.netflix.evcache.pool;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.netflix.archaius.api.Property;
import com.netflix.evcache.EVCacheImpl;
import com.netflix.evcache.EVCacheInMemoryCache;
import com.netflix.evcache.connection.ConnectionFactoryBuilder;
import com.netflix.evcache.connection.IConnectionBuilder;
import com.netflix.evcache.event.EVCacheEventListener;
import com.netflix.evcache.util.EVCacheConfig;
import net.spy.memcached.transcoders.Transcoder;
/**
* A manager that holds Pools for each EVCache app. When this class is
* initialized all the EVCache apps defined in the property evcache.appsToInit
* will be initialized and added to the pool. If a service knows all the EVCache
* app it uses, then it can define this property and pass a list of EVCache apps
* that needs to be initialized.
*
* An EVCache app can also be initialized by Injecting
* EVCacheClientPoolManager
and calling
* initEVCache()
*
*
* This typically should be done in the client libraries that need to initialize
* an EVCache app. For Example VHSViewingHistoryLibrary in its initLibrary
* initializes EVCACHE_VH by calling
*
*
* {@literal @}Inject
* public VHSViewingHistoryLibrary(EVCacheClientPoolManager instance,...) {
* ....
* instance.initEVCache("EVCACHE_VH");
* ...
* }
*
*
* @author smadappa
*
*/
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings({ "PRMC_POSSIBLY_REDUNDANT_METHOD_CALLS", "DM_CONVERT_CASE", "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD" })
@Singleton
public class EVCacheClientPoolManager {
/**
* NOTE : Should be the only static referenced variables
* **/
private static final Logger log = LoggerFactory.getLogger(EVCacheClientPoolManager.class);
private volatile static EVCacheClientPoolManager instance;
private final Property defaultReadTimeout;
private final Property logEnabledApps;
private final Property defaultRefreshInterval;
private final Map poolMap = new ConcurrentHashMap();
private final Map> scheduledTaskMap = new HashMap>();
private final EVCacheScheduledExecutor asyncExecutor;
private final EVCacheExecutor syncExecutor;
private final List evcacheEventListenerList;
private final IConnectionBuilder connectionFactoryProvider;
private final EVCacheNodeList evcacheNodeList;
private final EVCacheConfig evcConfig;
@Inject
public EVCacheClientPoolManager(IConnectionBuilder connectionFactoryprovider, EVCacheNodeList evcacheNodeList, EVCacheConfig evcConfig) {
instance = this;
this.connectionFactoryProvider = connectionFactoryprovider;
this.evcacheNodeList = evcacheNodeList;
this.evcConfig = evcConfig;
this.evcacheEventListenerList = new CopyOnWriteArrayList();
String clientCurrentInstanceId = null;
if(clientCurrentInstanceId == null) clientCurrentInstanceId= System.getenv("EC2_INSTANCE_ID");
if(clientCurrentInstanceId == null) clientCurrentInstanceId= System.getenv("NETFLIX_INSTANCE_ID");
if(log.isInfoEnabled()) log.info("\nClient Current InstanceId from env = " + clientCurrentInstanceId);
if(clientCurrentInstanceId == null && EVCacheConfig.getInstance().getPropertyRepository() != null) clientCurrentInstanceId = EVCacheConfig.getInstance().getPropertyRepository().get("EC2_INSTANCE_ID", String.class).orElse(null).get();
if(clientCurrentInstanceId == null && EVCacheConfig.getInstance().getPropertyRepository() != null) clientCurrentInstanceId = EVCacheConfig.getInstance().getPropertyRepository().get("NETFLIX_INSTANCE_ID", String.class).orElse(null).get();
if(clientCurrentInstanceId != null && !clientCurrentInstanceId.equalsIgnoreCase("localhost")) {
this.defaultReadTimeout = EVCacheConfig.getInstance().getPropertyRepository().get("default.read.timeout", Integer.class).orElse(20);
if(log.isInfoEnabled()) log.info("\nClient Current InstanceId = " + clientCurrentInstanceId + " which is probably a cloud location. The default.read.timeout = " + defaultReadTimeout);
} else { //Assuming this is not in cloud so bump up the timeouts
this.defaultReadTimeout = EVCacheConfig.getInstance().getPropertyRepository().get("default.read.timeout", Integer.class).orElse(750);
if(log.isInfoEnabled()) log.info("\n\nClient Current InstanceId = " + clientCurrentInstanceId + ". Probably a non-cloud instance. The default.read.timeout = " + defaultReadTimeout + "\n\n");
}
this.logEnabledApps = EVCacheConfig.getInstance().getPropertyRepository().get("EVCacheClientPoolManager.log.apps", String.class).orElse("*");
this.defaultRefreshInterval = EVCacheConfig.getInstance().getPropertyRepository().get("EVCacheClientPoolManager.refresh.interval", Integer.class).orElse(60);
this.asyncExecutor = new EVCacheScheduledExecutor(Runtime.getRuntime().availableProcessors(),Runtime.getRuntime().availableProcessors(), 30, TimeUnit.SECONDS, new ThreadPoolExecutor.CallerRunsPolicy(), "scheduled");
asyncExecutor.prestartAllCoreThreads();
this.syncExecutor = new EVCacheExecutor(Runtime.getRuntime().availableProcessors(),Runtime.getRuntime().availableProcessors(), 30, TimeUnit.SECONDS, new ThreadPoolExecutor.CallerRunsPolicy(), "pool");
syncExecutor.prestartAllCoreThreads();
initAtStartup();
}
public IConnectionBuilder getConnectionFactoryProvider() {
return connectionFactoryProvider;
}
public void addEVCacheEventListener(EVCacheEventListener listener) {
this.evcacheEventListenerList.add(listener);
}
public void addEVCacheEventListener(EVCacheEventListener listener, int index) {
if(index < evcacheEventListenerList.size()) {
this.evcacheEventListenerList.add(index, listener);
} else {
this.evcacheEventListenerList.add(listener);
}
}
public void removeEVCacheEventListener(EVCacheEventListener listener) {
this.evcacheEventListenerList.remove(listener);
}
public List getEVCacheEventListeners() {
return this.evcacheEventListenerList;
}
public EVCacheConfig getEVCacheConfig() {
return this.evcConfig;
}
/**
* @deprecated. Please use DependencyInjection (@Inject) to obtain
* {@link EVCacheClientPoolManager}. The use of this can result in
* unintended behavior where you will not be able to talk to evcache
* instances.
*/
@Deprecated
public static EVCacheClientPoolManager getInstance() {
if (instance == null) {
new EVCacheClientPoolManager(new ConnectionFactoryBuilder(), new SimpleNodeListProvider(), EVCacheConfig.getInstance());
if (!EVCacheConfig.getInstance().getPropertyRepository().get("evcache.use.simple.node.list.provider", Boolean.class).orElse(false).get()) {
if(log.isDebugEnabled()) log.debug("Please make sure EVCacheClientPoolManager is injected first. This is not the appropriate way to init EVCacheClientPoolManager."
+ " If you are using simple node list provider please set evcache.use.simple.node.list.provider property to true.", new Exception());
}
}
return instance;
}
public void initAtStartup() {
final String appsToInit = EVCacheConfig.getInstance().getPropertyRepository().get("evcache.appsToInit", String.class).orElse("").get();
if (appsToInit != null && appsToInit.length() > 0) {
final StringTokenizer apps = new StringTokenizer(appsToInit, ",");
while (apps.hasMoreTokens()) {
final String app = getAppName(apps.nextToken());
if (log.isDebugEnabled()) log.debug("Initializing EVCache - " + app);
initEVCache(app);
}
}
}
/**
* Will init the given EVCache app call. If one is already initialized for
* the given app method returns without doing anything.
*
* @param app
* - name of the evcache app
*/
public final synchronized EVCacheClientPool initEVCache(String app) {
return initEVCache(app, false);
}
public final synchronized EVCacheClientPool initEVCache(String app, boolean isDuet) {
if (app == null || (app = app.trim()).length() == 0) throw new IllegalArgumentException("param app name null or space");
final String APP = getAppName(app);
if (poolMap.containsKey(APP)) return poolMap.get(APP);
final EVCacheClientPool pool = new EVCacheClientPool(APP, evcacheNodeList, asyncExecutor, this, isDuet);
scheduleRefresh(pool);
poolMap.put(APP, pool);
return pool;
}
private void scheduleRefresh(EVCacheClientPool pool) {
final ScheduledFuture> task = asyncExecutor.scheduleWithFixedDelay(pool, 30, defaultRefreshInterval.get(), TimeUnit.SECONDS);
scheduledTaskMap.put(pool, task);
}
/**
* Given the appName get the EVCacheClientPool. If the app is already
* created then will return the existing instance. If not one will be
* created and returned.
*
* @param _app
* - name of the evcache app
* @return the Pool for the give app.
* @throws IOException
*/
public EVCacheClientPool getEVCacheClientPool(String _app) {
final String app = getAppName(_app);
final EVCacheClientPool evcacheClientPool = poolMap.get(app);
if (evcacheClientPool != null) return evcacheClientPool;
initEVCache(app);
return poolMap.get(app);
}
public Map getAllEVCacheClientPool() {
return new HashMap(poolMap);
}
@PreDestroy
public void shutdown() {
asyncExecutor.shutdown();
syncExecutor.shutdown();
for (EVCacheClientPool pool : poolMap.values()) {
pool.shutdown();
}
}
public boolean shouldLog(String appName) {
if ("*".equals(logEnabledApps.get())) return true;
if (logEnabledApps.get().indexOf(appName) != -1) return true;
return false;
}
public Property getDefaultReadTimeout() {
return defaultReadTimeout;
}
public Property getDefaultRefreshInterval() {
return defaultRefreshInterval;
}
public EVCacheScheduledExecutor getEVCacheScheduledExecutor() {
return asyncExecutor;
}
public EVCacheExecutor getEVCacheExecutor() {
return syncExecutor;
}
private String getAppName(String _app) {
_app = _app.toUpperCase();
Boolean ignoreAlias = EVCacheConfig.getInstance().getPropertyRepository()
.get("EVCacheClientPoolManager." + _app + ".ignoreAlias", Boolean.class)
.orElseGet("EVCacheClientPoolManager.ignoreAlias")
.orElse(false).get();
final String app = ignoreAlias ? _app :
EVCacheConfig.getInstance().getPropertyRepository()
.get("EVCacheClientPoolManager." + _app + ".alias", String.class)
.orElse(_app).get().toUpperCase();
if (log.isDebugEnabled()) log.debug("Original App Name : " + _app + "; Alias App Name : " + app);
if(app != null && app.length() > 0) return app.toUpperCase();
return _app;
}
private WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
private final Map> inMemoryMap = new ConcurrentHashMap>();
@SuppressWarnings("unchecked")
public EVCacheInMemoryCache createInMemoryCache(Transcoder tc, EVCacheImpl impl) {
final String name = impl.getCachePrefix() == null ? impl.getAppName() : impl.getAppName() + impl.getCachePrefix();
EVCacheInMemoryCache cache = (EVCacheInMemoryCache) inMemoryMap.get(name);
if(cache == null) {
writeLock.lock();
if((cache = getInMemoryCache(name)) == null) {
cache = new EVCacheInMemoryCache(impl.getAppName(), tc, impl);
inMemoryMap.put(name, cache);
}
writeLock.unlock();
}
return cache;
}
@SuppressWarnings("unchecked")
public EVCacheInMemoryCache getInMemoryCache(String appName) {
return (EVCacheInMemoryCache) inMemoryMap.get(appName);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy