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

com.genexus.db.InProcessCache Maven / Gradle / Ivy

Go to download

Core classes for the runtime used by Java and Android apps generated with GeneXus

There is a newer version: 4.7.3
Show newest version
package com.genexus.db;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.genexus.Application;
import com.genexus.CommonUtil;
import com.genexus.ICacheService2;
import com.genexus.Preferences;
import com.genexus.management.CacheItemJMX;
import com.genexus.management.CacheJMX;
import com.genexus.util.DoubleLinkedQueue;


public class InProcessCache implements ICacheService2
{
	protected long cacheStorageSize;
	protected long currentSize;
	protected int cacheDrops;
	protected boolean cacheEnabled;
	protected DoubleLinkedQueue lru = new DoubleLinkedQueue();

	private static final boolean DEBUG = com.genexus.DebugFlag.DEBUG;
	private ConcurrentHashMap cache = new ConcurrentHashMap();
	private Object lockObject = new Object();

	public InProcessCache()
	{
		Preferences prefs = Preferences.getDefaultPreferences();

		cacheStorageSize = prefs.getCACHE_STORAGE_SIZE() * 1024;
		cacheEnabled = prefs.getCACHING();

		//JMX Enabled
		if (Application.isJMXEnabled())
			CacheJMX.CreateCacheJMX(this);
	}

	public boolean isEnabled()
	{
		return cacheEnabled;
	}

	public void setEnabled(boolean value)
	{
		cacheEnabled = value;
	}

	public ConcurrentHashMap getCache()
	{
		return cache;
	}

	public void setCacheStorageSize(long cacheStorageSize)
	{
		this.cacheStorageSize = cacheStorageSize;
	}

	public long getCacheStorageSize()
	{
		return cacheStorageSize;
	}

	public long getCacheCurrentSize()
	{
		return currentSize;
	}

	public int getCacheDrops()
	{
		return cacheDrops;
	}

	public  T get(String cacheid, String key, Class type)
	{
		return get(getKey(cacheid, key), type);
	}

	@Override
	public  List getAll(String cacheid, String[] keys, Class type) {
		String[] prefixedKeys = getKey(cacheid, keys);
		List values = new ArrayList();
		for (String key : prefixedKeys) {
			values.add(get(key, type));
		}
		return values;
	}

	@SuppressWarnings("unchecked")
	private  T get(String key, Class type)
	{
		if(DEBUG)
		{
			getStatsFor(key).hits++;
		}
		CacheValue value = cache.get(key);

		if(value == null)
		{
			return null;
		}
		else
		{
			if(value.hasExpired())
			{ // Si ha expirado el cache, debo eliminar el value del cache
                            clearKey(key, value);
				return null;
			}
			else
			{
				// If cache limit
				if (cacheStorageSize != 0) {
					lru.moveToStart(value); // Muevo el item al comienzo de la LRU
				}
				value.incHits(); //TODO: this is not thread safe, we can miss hits for a value.
				if(DEBUG)
				{
					getStatsFor(key).hitsAfterFullLoaded++;
				}
	
				if ( type.isInstance(value) ) {
				   return (T)value;
				}
				else
					return type.cast(((CachedIFieldGetter)value.getIterator().nextElement()).getValue(0));
			}
		}


	}
	public void clear() {

		//JMX Remove
		if (Application.isJMXEnabled())
			CacheJMX.DestroyCacheJMX();
	}
	
	public void clearKey(String key, CacheValue value) {
		if (value!=null)
		{
			if(DEBUG)
			{
				getStatsFor(value).removeFromStats(value);
			}
			if (cacheStorageSize != 0) {
				synchronized (lockObject) {
					lru.remove(value);
					currentSize -= value.getSize();
				}
			}
			//JMX Remove
			if (Application.isJMXEnabled())
				CacheItemJMX.DestroyCacheItemJMX(value);
			cache.remove(key);
		}
	}
	
	public void clearKey(String key){
		CacheValue value = cache.get(key);
		clearKey(key, value);
	}
	public  void set(String cacheid, String key, T value, int expirationSeconds)
	{
		set(getKey(cacheid, key), value, expirationSeconds);
	}

	@Override
	public  void setAll(String cacheid, String[] keys, T[] values, int expirationSeconds) {
		if (keys!=null && values!=null && keys.length == values.length) {
			String[] prefixedKeys = getKey(cacheid, keys);
			int idx = 0;
			for (String key : prefixedKeys) {
				set(key, values[idx], expirationSeconds);
				idx++;
			}
		}
	}

	private  void set(String key, T value, int expirationSeconds)
	{
		if (value instanceof CacheValue)
			add(key, (CacheValue)value);
		else
		{
			CacheValue cvalue = new CacheValue(key, null);
			cvalue.addItem(value);
			cvalue.setExpiryTime(expirationSeconds);
			add(key, cvalue);
		}	
	}

	public  void set(String cacheid, String key, T value) {
		set(getKey(cacheid, key), value, Preferences.TTL_NO_EXPIRY);		
	}
	private  void set(String key, T value)
	{
		set(key, value, Preferences.TTL_NO_EXPIRY);
	}

	private boolean containsKey(String key) {
            CacheValue value = cache.get(key);
            if(value != null){
                if(value.hasExpired()){
                    clearKey(key, value);
                }
            } 
            return cache.containsKey(key);
	}

	public boolean containtsKey(String cacheid, String key) {
		return containsKey(getKey(cacheid, key));
	}

	public void clear(String cacheid, String key) {
		cache.remove(getKey(cacheid, key));
	}

	public void clearCache(String cacheid) {
		set(cacheid,Long.valueOf(CommonUtil.now().getTime()));
	}

	public void clearAllCaches() {
		cache.clear();
	}
	
	private Long getKeyPrefix(String cacheid)
	{
		Long prefix = get(cacheid, Long.class);
		if (prefix == null)
		{
			prefix = CommonUtil.now(false,false).getTime();
			set(cacheid, Long.valueOf(prefix));
		}
		return prefix;
	}
	private String getKey(String cacheid, String key)
	{
		return formatKey(cacheid, key, getKeyPrefix(cacheid));
	}
	private String[] getKey(String cacheid, String[] keys)
	{
		Long prefix = getKeyPrefix(cacheid);
		String[] prefixedKeys = new String[keys.length];
		for (int idx =0; idx 0) {
			synchronized (lockObject) {
				while (currentSize > cacheStorageSize)
					{
						CacheValue item = (CacheValue)lru.takeFromEnd();
						if(item == null)
						{
							break;
						}
						currentSize -= item.getSize();

						//JMX Remove
						if (Application.isJMXEnabled())
							CacheItemJMX.DestroyCacheItemJMX(item);

						cache.remove(item.getKey().getKey());
						cacheDrops++;
						if(DEBUG)
						{
							getStatsFor(item).removeFromStats(item);
						}
					}	
			}
		}
	
	}

	public void removeExpiredEntries()
	{
		for(Enumeration enum1 = cache.elements(); enum1.hasMoreElements();)
		{
			CacheValue value = (CacheValue)enum1.nextElement();
			if(value.hasExpired())
			{
				if(DEBUG)
				{
					String key = value.getKey().getKey();
					getStatsFor(value).removeFromStats(value);
				}
				if (cacheStorageSize != 0) {
					lru.remove(value);
				}
				currentSize -= value.getSize();

				//JMX Remove
				if (Application.isJMXEnabled())
					CacheItemJMX.DestroyCacheItemJMX(value);

				cache.remove(value.getKey().getKey());
			}
		}
	}

	public void setTimeToLive(int [] value)
	{
		for(int i = 0; i < Preferences.CANT_CATS; i++)
		{
			Preferences.TTL[i] = value[i];
		}
	}

	public void setHitsToLive(int [] value)
	{
		for(int i = 0; i < Preferences.CANT_CATS; i++)
		{
			Preferences.HTL[i] = value[i];
		}
	}

	//------------------------------------ STATS ---------------

	private ConcurrentHashMap cacheStats = new ConcurrentHashMap();
	public void addStats(String key)
	{
		getStatsFor(key);
	}

	public Stats getStatsFor(String key)
	{
		Stats newStats = new Stats(key);
		Stats stats = cacheStats.putIfAbsent(key, newStats);
		return (stats != null) ? stats : newStats;
	}

	public Stats getStatsFor(CacheValue value)
	{
		String key = value.getKey().toString();
		return getStatsFor(key);
	}

	public ConcurrentHashMap getStats()
	{
		return cacheStats;
	}

	public String getStatsSentence(String key)
	{
		return getStatsFor(key).sentence;
	}

	public int getStatsHits(String key)
	{
		return getStatsFor(key).hits;
	}

	public int getStatsHitsCached(String key)
	{
		return getStatsFor(key).hitsAfterFullLoaded;
	}

	public int getStatsFullLoaded(String key)
	{
		return getStatsFor(key).fullLoaded;
	}

	public int getStatsCacheSize(String key)
	{
		return getStatsFor(key).cacheSize;
	}

	public long getStatsTTL(String key)
	{
		return getStatsFor(key).TTL / Preferences.SECONDS_IN_ONE_MINUTE;
	}

	class Stats
	{
		public Stats(String sentence)
		{
			this.sentence = sentence;
			TTL = -1;
		}

		public void removeFromStats(CacheValue value)
		{
			fullLoaded--;
			cacheSize -= value.getSize();
		}

		public void addToStats(CacheValue value)
		{
			fullLoaded++;
			cacheSize += value.getSize();
		}

		public String sentence;
		public int hits;
		public int hitsAfterFullLoaded;
		public int fullLoaded;
		public int cacheSize;
		public long TTL;
	}


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy