package com.alibaba.excel.cache; import java.io.File; import java.util.HashMap; import java.util.UUID; import org.ehcache.CacheManager; import org.ehcache.config.CacheConfiguration; import org.ehcache.config.builders.CacheConfigurationBuilder; import org.ehcache.config.builders.CacheManagerBuilder; import org.ehcache.config.builders.ResourcePoolsBuilder; import org.ehcache.config.units.MemoryUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.util.FileUtils; /** * Default cache * * @author Jiaju Zhuang */ public class Ehcache implements ReadCache { private static final Logger LOGGER = LoggerFactory.getLogger(Ehcache.class); private static final int BATCH_COUNT = 1000; private static final int DEBUG_WRITE_SIZE = 100 * 10000; private static final int DEBUG_CACHE_MISS_SIZE = 1000; /** * Key index */ private int index = 0; private HashMap dataMap = new HashMap(BATCH_COUNT * 4 / 3 + 1); private static CacheManager fileCacheManager; private static CacheConfiguration fileCacheConfiguration; private static CacheManager activeCacheManager; private CacheConfiguration activeCacheConfiguration; /** * Bulk storage data */ private org.ehcache.Cache fileCache; /** * Currently active cache */ private org.ehcache.Cache activeCache; private String cacheAlias; /** * Count the number of cache misses */ private int cacheMiss = 0; public Ehcache(int maxCacheActivateSize) { activeCacheConfiguration = CacheConfigurationBuilder .newCacheConfigurationBuilder(Integer.class, HashMap.class, ResourcePoolsBuilder.newResourcePoolsBuilder().heap(maxCacheActivateSize, MemoryUnit.MB)) .withSizeOfMaxObjectGraph(1000 * 1000L).withSizeOfMaxObjectSize(maxCacheActivateSize, MemoryUnit.MB) .build(); } static { File cacheFile = FileUtils.createCacheTmpFile(); fileCacheManager = CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(cacheFile)).build(true); activeCacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(true); fileCacheConfiguration = CacheConfigurationBuilder .newCacheConfigurationBuilder(Integer.class, HashMap.class, ResourcePoolsBuilder.newResourcePoolsBuilder().disk(10, MemoryUnit.GB)) .withSizeOfMaxObjectGraph(1000 * 1000L).withSizeOfMaxObjectSize(10, MemoryUnit.GB).build(); } @Override public void init(AnalysisContext analysisContext) { cacheAlias = UUID.randomUUID().toString(); fileCache = fileCacheManager.createCache(cacheAlias, fileCacheConfiguration); activeCache = activeCacheManager.createCache(cacheAlias, activeCacheConfiguration); } @Override public void put(String value) { dataMap.put(index, value); if ((index + 1) % BATCH_COUNT == 0) { fileCache.put(index / BATCH_COUNT, dataMap); dataMap = new HashMap(BATCH_COUNT * 4 / 3 + 1); } index++; if (LOGGER.isDebugEnabled()) { if (index % DEBUG_WRITE_SIZE == 0) { LOGGER.debug("Already put :{}", index); } } } @Override public String get(Integer key) { if (key == null || key < 0) { return null; } int route = key / BATCH_COUNT; HashMap dataMap = activeCache.get(route); if (dataMap == null) { dataMap = fileCache.get(route); activeCache.put(route, dataMap); if (LOGGER.isDebugEnabled()) { if (cacheMiss++ % DEBUG_CACHE_MISS_SIZE == 0) { LOGGER.debug("Cache misses count:{}", cacheMiss); } } } return dataMap.get(key); } @Override public void putFinished() { if (CollectionUtils.isEmpty(dataMap)) { return; } fileCache.put(index / BATCH_COUNT, dataMap); } @Override public void destroy() { fileCacheManager.removeCache(cacheAlias); activeCacheManager.removeCache(cacheAlias); } }