IDEMPIERE-5046 Implement background reset of expire cache (#987)

This commit is contained in:
hengsin 2021-11-19 22:55:04 +08:00 committed by GitHub
parent c5c334d5e9
commit 2c5efb3031
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 90 additions and 19 deletions

View File

@ -584,24 +584,26 @@ public final class Adempiere
} }
} }
private static void createThreadPool() { private static synchronized void createThreadPool() {
int max = Runtime.getRuntime().availableProcessors() * 20; if (threadPoolExecutor == null) {
int defaultMax = max; int max = Runtime.getRuntime().availableProcessors() * 20;
Properties properties = Ini.getProperties(); int defaultMax = max;
String maxSize = properties.getProperty("MaxThreadPoolSize"); Properties properties = Ini.getProperties();
if (maxSize != null) { String maxSize = properties.getProperty("MaxThreadPoolSize");
try { if (maxSize != null) {
max = Integer.parseInt(maxSize); try {
} catch (Exception e) {} max = Integer.parseInt(maxSize);
} } catch (Exception e) {}
if (max <= 0) { }
max = defaultMax; if (max <= 0) {
} max = defaultMax;
}
// start thread pool // start thread pool
threadPoolExecutor = new ScheduledThreadPoolExecutor(max); threadPoolExecutor = new ScheduledThreadPoolExecutor(max);
Trx.startTrxMonitor(); Trx.startTrxMonitor();
}
} }
/** /**
@ -690,11 +692,18 @@ public final class Adempiere
public static synchronized void stop() { public static synchronized void stop() {
if (threadPoolExecutor != null) { if (threadPoolExecutor != null) {
threadPoolExecutor.shutdown(); threadPoolExecutor.shutdown();
threadPoolExecutor = null;
} }
log = null; log = null;
} }
public static ScheduledThreadPoolExecutor getThreadPoolExecutor() { /**
*
* @return {@link ScheduledThreadPoolExecutor}
*/
public static synchronized ScheduledThreadPoolExecutor getThreadPoolExecutor() {
if (threadPoolExecutor == null)
createThreadPool();
return threadPoolExecutor; return threadPoolExecutor;
} }

View File

@ -454,19 +454,43 @@ public class CCache<K,V> implements CacheInterface, Map<K, V>, Serializable
public void newRecord(int record_ID) { public void newRecord(int record_ID) {
} }
/**
*
* @return max size of cache
*/
public int getMaxSize() { public int getMaxSize() {
return m_maxSize; return m_maxSize;
} }
/**
*
* @return true if cache is distributed (using hazelcast)
*/
public boolean isDistributed() { public boolean isDistributed() {
return m_distributed; return m_distributed;
} }
/**
*
* @return cache hit count
*/
public long getHit() { public long getHit() {
return m_hit.get(); return m_hit.get();
} }
/**
*
* @return cache miss count
*/
public long getMiss() { public long getMiss() {
return m_miss.get(); return m_miss.get();
} }
/**
*
* @return true if cache has expire
*/
public boolean isExpire() {
return m_expire > 0 && m_timeExp > 0 && m_timeExp < System.currentTimeMillis();
}
} // CCache } // CCache

View File

@ -24,9 +24,11 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
import org.adempiere.base.Core; import org.adempiere.base.Core;
import org.compiere.Adempiere;
import org.idempiere.distributed.ICacheService; import org.idempiere.distributed.ICacheService;
import org.idempiere.distributed.IClusterMember; import org.idempiere.distributed.IClusterMember;
import org.idempiere.distributed.IClusterService; import org.idempiere.distributed.IClusterService;
@ -46,7 +48,10 @@ public class CacheMgt
public static synchronized CacheMgt get() public static synchronized CacheMgt get()
{ {
if (s_cache == null) if (s_cache == null)
{
s_cache = new CacheMgt(); s_cache = new CacheMgt();
startCacheMonitor();
}
return s_cache; return s_cache;
} // get } // get
@ -68,7 +73,9 @@ public class CacheMgt
private static CLogger log = CLogger.getCLogger(CacheMgt.class); private static CLogger log = CLogger.getCLogger(CacheMgt.class);
/** Cache change listeners **/ /** Cache change listeners **/
private List<CacheChangeListener> m_listeners = new ArrayList<CacheChangeListener>(); private List<CacheChangeListener> m_listeners = new ArrayList<CacheChangeListener>();
/** Background monitor to clear expire cache */
private static final CacheMgt.CacheMonitor s_monitor = new CacheMgt.CacheMonitor();
/** Default maximum cache size **/
public static int MAX_SIZE = 1000; public static int MAX_SIZE = 1000;
static static
{ {
@ -441,4 +448,35 @@ public class CacheMgt
return maxSize <= 0 ? false : size() > maxSize; return maxSize <= 0 ? false : size() > maxSize;
} }
} }
private static synchronized void startCacheMonitor()
{
Adempiere.getThreadPoolExecutor().scheduleWithFixedDelay(s_monitor, 5, 5, TimeUnit.MINUTES);
}
private static class CacheMonitor implements Runnable
{
public void run()
{
CacheMgt instance = CacheMgt.get();
if (!instance.m_instances.isEmpty())
{
CacheInterface[] caches = instance.m_instances.toArray(new CacheInterface[0]);
for(int i = 0; i < caches.length; i++)
{
if (!(caches[i] instanceof CCache<?, ?>))
continue;
CCache<?, ?> cache = (CCache<?, ?>) caches[i];
if (cache.isDistributed() || cache.getExpireMinutes() <= 0)
continue;
if (cache.isExpire())
{
cache.reset();
}
}
}
}
}
} // CCache } // CCache