package hu.sztaki.ilab.longneck.process.block; import hu.sztaki.ilab.longneck.Field; import hu.sztaki.ilab.longneck.Record; import hu.sztaki.ilab.longneck.process.VariableSpace; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import org.apache.commons.collections.map.LRUMap; /** * Block that caches block outputs as key-value pairs it contains. * * Each thread has its own internal cache (LRUMap). Cache key is the field * value defined in the "apply-to" parameter. Note that only one field name * is permitted here! Cache value is a list of fields defined in the * "output-fields" parameter * * @author Bendig LorĂ¡nd <lbendig@ilab.sztaki.hu> */ public class Caching extends AbstractAtomicBlock implements CompoundBlock { /** The list of inside blocks. */ private List<? extends Block> blocks; /** The thread-local cache. */ // private CacheMapBuilder localCache; /** Internal cache */ // transient private Map<String, List<Field>> cache = null; private Map<String, List<Field>> cache; /** Maximum size. */ private int size = 100; /** Value of the cache */ private List<String> outputFields; public Caching() { // localCache = new CacheMapBuilder(size); cache = (Map<String, List<Field>>) (Collections.synchronizedMap(new LRUMap(size))); } public int getSize() { return size; } public void setSize(int size) { this.size = size; } @Override public List<Block> getBlocks() { return (List<Block>) blocks; } @Override public void setBlocks(List<? extends Block> blocks) { this.blocks = blocks; } @Override public boolean hasPosition(int pos) { return (blocks.size() - 1 >= pos); } public void setOutputFields(List<String> outputFields) { this.outputFields = outputFields; } public List<String> getOutputFields() { return outputFields; } public void setOutputFields(String outputFields) { // Assign filtered list this.outputFields = BlockUtils.splitIdentifiers(outputFields); } @Override public void apply(Record record, VariableSpace parentScope) { } public List<Field> getCacheElement(String key) { // if (cache == null) { // cache = localCache.get(); // } // return cache.get(sourceInfo.getLine() + "_" + key); return cache.get(sourceInfo.getLine() + "_" + key); } public void putCacheElement(String key, List<Field> value) { // if (cache == null) { // cache = localCache.get(); // } cache.put((sourceInfo.getLine() + "_" + key) , value); } @Override public Caching clone() { Caching copy = (Caching) super.clone(); if (blocks != null) { copy.blocks = new ArrayList<Block>(blocks.size()); for (Block b : blocks) { ((List<Block>) copy.blocks).add(b.clone()); } } // copy.localCache = new CacheMapBuilder(size); // copy.cache = null; copy.cache = (Map<String, List<Field>>) (Collections.synchronizedMap(new LRUMap(size))); copy.cache.putAll(cache); if (outputFields != null) { copy.outputFields = new ArrayList<String>(outputFields.size()); copy.outputFields.addAll(outputFields); } return copy; } // public static class CacheMapBuilder extends ThreadLocal<Map> { // private final int size; // // public CacheMapBuilder(int size) { // this.size = size; // } // // public int getSize() { // return size; // } // // @Override // protected Map initialValue() { // return new LRUMap(size); // } // } @Override public int hashCode() { int hash = 7; hash = 59 * hash + (this.blocks != null ? this.blocks.hashCode() : 0); hash = 59 * hash + this.size; hash = 59 * hash + (this.outputFields != null ? this.outputFields.hashCode() : 0); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Caching other = (Caching) obj; if (super.equals(obj) == false) { return false; } if (this.blocks != other.blocks && (this.blocks == null || !this.blocks.equals(other.blocks))) { return false; } if (this.size != other.size) { return false; } if (this.outputFields != other.outputFields && (this.outputFields == null || !this.outputFields.equals(other.outputFields))) { return false; } return true; } }