Author: doogie
Date: Thu Apr 1 04:46:53 2010 New Revision: 929838 URL: http://svn.apache.org/viewvc?rev=929838&view=rev Log: Inline CacheLineTable into UtilCache. This removes the CacheLineTable class completely. The getCacheLine() method now throws UnsupportedOperationException. Removed: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/CacheLineTable.java Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/UtilCache.java ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/UtilCacheEvents.java Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/UtilCache.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/UtilCache.java?rev=929838&r1=929837&r2=929838&view=diff ============================================================================== --- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/UtilCache.java (original) +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/UtilCache.java Thu Apr 1 04:46:53 2010 @@ -18,25 +18,36 @@ *******************************************************************************/ package org.ofbiz.base.util.cache; +import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import com.reardencommerce.kernel.collections.shared.evictable.ConcurrentLinkedHashMap; + import javolution.util.FastList; +import javolution.util.FastMap; import javolution.util.FastSet; +import jdbm.helper.FastIterator; +import jdbm.htree.HTree; + import org.ofbiz.base.util.Debug; +import org.ofbiz.base.util.ObjectType; import org.ofbiz.base.util.UtilValidate; /** @@ -64,9 +75,6 @@ public class UtilCache<K, V> implements /** The name of the UtilCache instance, is also the key for the instance in utilCacheTable. */ private final String name; - /** A hashtable containing a CacheLine object with a value and a loadTime for each element. */ - private final CacheLineTable<K, V> cacheLineTable; - /** A count of the number of cache hits */ protected AtomicLong hitCount = new AtomicLong(0); @@ -103,6 +111,14 @@ public class UtilCache<K, V> implements /** The set of listeners to receive notifcations when items are modidfied(either delibrately or because they were expired). */ protected Set<CacheListener<K, V>> listeners = new CopyOnWriteArraySet<CacheListener<K, V>>(); + protected transient HTree<Object, CacheLine<V>> fileTable = null; + protected Map<Object, CacheLine<V>> memoryTable = null; + + protected JdbmRecordManager jdbmMgr; + + // weak ref on this + private static final ConcurrentMap<String, JdbmRecordManager> fileManagers = new ConcurrentHashMap<String, JdbmRecordManager>(); + /** Constructor which specifies the cacheName as well as the sizeLimit, expireTime and useSoftReference. * The passed sizeLimit, expireTime and useSoftReference will be overridden by values from cache.properties if found. * @param sizeLimit The sizeLimit member is set to this value @@ -121,7 +137,39 @@ public class UtilCache<K, V> implements setPropertiesParams(propNames); int maxMemSize = this.maxInMemory; if (maxMemSize == 0) maxMemSize = sizeLimit; - this.cacheLineTable = new CacheLineTable<K, V>(this.fileStore, this.name, this.useFileSystemStore, maxMemSize); + if (maxMemSize == 0) { + memoryTable = FastMap.newInstance(); + } else { + memoryTable = ConcurrentLinkedHashMap.create(ConcurrentLinkedHashMap.EvictionPolicy.LRU, maxMemSize); + } + if (this.useFileSystemStore) { + // create the manager the first time it is needed + jdbmMgr = fileManagers.get(fileStore); + if (jdbmMgr == null) { + Debug.logImportant("Creating file system cache store for cache with name: " + cacheName, module); + try { + String ofbizHome = System.getProperty("ofbiz.home"); + if (ofbizHome == null) { + Debug.logError("No ofbiz.home property set in environment", module); + } else { + jdbmMgr = new JdbmRecordManager(ofbizHome + "/" + fileStore); + } + } catch (IOException e) { + Debug.logError(e, "Error creating file system cache store for cache with name: " + cacheName, module); + } + fileManagers.putIfAbsent(fileStore, jdbmMgr); + } + jdbmMgr = fileManagers.get(fileStore); + if (jdbmMgr != null) { + try { + this.fileTable = HTree.createInstance(jdbmMgr); + jdbmMgr.setNamedObject(cacheName, this.fileTable.getRecid()); + jdbmMgr.commit(); + } catch (IOException e) { + Debug.logError(e, module); + } + } + } } private static String getNextDefaultIndex(String cacheName) { @@ -186,12 +234,48 @@ public class UtilCache<K, V> implements } } - public CacheLineTable<K, V> getCacheLineTable() { - return cacheLineTable; + private Object fromKey(Object key) { + return key == null ? ObjectType.NULL : key; + } + + @SuppressWarnings("unchecked") + private K toKey(Object key) { + return key == ObjectType.NULL ? null : (K) key; + } + + @SuppressWarnings("unchecked") + private void addAllFileTableValues(List<CacheLine<V>> values) throws IOException { + FastIterator<CacheLine<V>> iter = fileTable.values(); + CacheLine<V> value = iter.next(); + while (value != null) { + values.add(value); + value = iter.next(); + } + } + + private void addAllFileTableKeys(Set<Object> keys) throws IOException { + FastIterator<Object> iter = fileTable.keys(); + Object key = null; + while ((key = iter.next()) != null) { + keys.add(key); + } + } + + public Object getCacheLineTable() { + throw new UnsupportedOperationException(); } public boolean isEmpty() { - return cacheLineTable.isEmpty(); + if (fileTable != null) { + try { + return fileTable.keys().next() == null; + } catch (IOException e) { + Debug.logError(e, module); + return false; + } + } else { + return memoryTable.isEmpty(); + } } /** Puts or loads the passed element into the cache @@ -217,16 +301,29 @@ public class UtilCache<K, V> implements * @param expireTime how long to keep this key in the cache */ public V put(K key, V value, long expireTime) { - CacheLine<V> oldCacheLine = cacheLineTable.put(key, createCacheLine(value, expireTime)); - - if (oldCacheLine == null) { + CacheLine<V> oldCacheLine = putInternal(fromKey(key), createCacheLine(value, expireTime)); + V oldValue = oldCacheLine == null ? null : oldCacheLine.getValue(); + if (oldValue == null) { noteAddition(key, value); return null; } else { - noteUpdate(key, value, oldCacheLine.getValue()); - return oldCacheLine.getValue(); + noteUpdate(key, value, oldValue); + return oldValue; } + } + CacheLine<V> putInternal(Object key, CacheLine<V> newCacheLine) { + CacheLine<V> oldCacheLine = memoryTable.put(key, newCacheLine); + if (fileTable != null) { + try { + if (oldCacheLine == null) oldCacheLine = fileTable.get(key); + fileTable.put(key, newCacheLine); + jdbmMgr.commit(); + } catch (IOException e) { + Debug.logError(e, module); + } + } + return oldCacheLine; } /** Gets an element from the cache according to the specified key. @@ -244,12 +341,19 @@ public class UtilCache<K, V> implements } protected CacheLine<V> getInternalNoCheck(Object key) { - CacheLine<V> line = cacheLineTable.get(key); - return line; + CacheLine<V> value = memoryTable.get(key); + if (value == null && fileTable != null) { + try { + value = fileTable.get(key); + } catch (IOException e) { + Debug.logError(e, module); + } + } + return value; } protected CacheLine<V> getInternal(Object key, boolean countGet) { - CacheLine<V> line = getInternalNoCheck(key); + CacheLine<V> line = getInternalNoCheck(fromKey(key)); if (line == null) { if (countGet) missCountNotFound.incrementAndGet(); } else if (line.isInvalid()) { @@ -269,27 +373,46 @@ public class UtilCache<K, V> implements } public Collection<V> values() { - if (cacheLineTable.isEmpty()) { - return Collections.emptyList(); - } - - List<V> valuesList = FastList.newInstance(); - for (K key: cacheLineTable.keySet()) { - CacheLine<V> line = this.getInternal(key, false); - if (line == null) { - continue; - } else { + if (fileTable != null) { + List<V> values = FastList.newInstance(); + try { + FastIterator<CacheLine<V>> iter = fileTable.values(); + CacheLine<V> value = iter.next(); + while (value != null) { + values.add(value.getValue()); + value = iter.next(); + } + } catch (IOException e) { + Debug.logError(e, module); + } + return values; + } else { + List<V> valuesList = FastList.newInstance(); + for (CacheLine<V> line: memoryTable.values()) { valuesList.add(line.getValue()); } + return valuesList; } - - return valuesList; } public long getSizeInBytes() { long totalSize = 0; - for (CacheLine<V> line: cacheLineTable.values()) { - totalSize += line.getSizeInBytes(); + if (fileTable != null) { + try { + FastIterator<CacheLine<V>> iter = fileTable.values(); + CacheLine<V> value = iter.next(); + while (value != null) { + totalSize += value.getSizeInBytes(); + value = iter.next(); + } + } catch (IOException e) { + Debug.logError(e, module); + return 0; + } + } else { + for (CacheLine<V> line: memoryTable.values()) { + totalSize += line.getSizeInBytes(); + } } return totalSize; } @@ -305,11 +428,25 @@ public class UtilCache<K, V> implements /** This is used for internal remove calls because we only want to count external calls */ @SuppressWarnings("unchecked") protected synchronized V removeInternal(Object key, boolean countRemove) { - CacheLine<V> line = cacheLineTable.remove(key); - if (line != null) { - noteRemoval((K) key, line.getValue()); + if (key == null) { + if (Debug.verboseOn()) Debug.logVerbose("In UtilCache tried to remove with null key, using NullObject" + this.name, module); + } + Object nulledKey = fromKey(key); + CacheLine<V> oldCacheLine = getInternalNoCheck(nulledKey); + if (fileTable != null) { + try { + fileTable.remove(nulledKey); + jdbmMgr.commit(); + } catch (IOException e) { + Debug.logError(e, module); + } + } + memoryTable.remove(nulledKey); + if (oldCacheLine != null) { + V oldValue = oldCacheLine.getValue(); + noteRemoval((K) key, oldValue); if (countRemove) removeHitCount.incrementAndGet(); - return line.getValue(); + return oldValue; } else { if (countRemove) removeMissCount.incrementAndGet(); return null; @@ -318,11 +455,35 @@ public class UtilCache<K, V> implements /** Removes all elements from this cache */ public synchronized void clear() { - for (K key: cacheLineTable.keySet()) { - CacheLine<V> line = getInternalNoCheck(key); - noteRemoval(key, line == null ? null : line.getValue()); + if (fileTable != null) { + // FIXME: erase from memory too + Set<Object> keys = new HashSet<Object>(); + try { + addAllFileTableKeys(keys); + } catch (IOException e) { + Debug.logError(e, module); + } + for (Object key: keys) { + try { + CacheLine<V> value = fileTable.get(key); + noteRemoval(toKey(key), value.getValue()); + removeHitCount.incrementAndGet(); + fileTable.remove(key); + jdbmMgr.commit(); + } catch (IOException e) { + Debug.logError(e, module); + } + } + memoryTable.clear(); + } else { + Iterator<Map.Entry<Object, CacheLine<V>>> it = memoryTable.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<Object, CacheLine<V>> entry = it.next(); + noteRemoval(toKey(entry.getKey()), entry.getValue().getValue()); + removeHitCount.incrementAndGet(); + it.remove(); + } } - cacheLineTable.clear(); clearCounters(); } @@ -418,9 +579,22 @@ public class UtilCache<K, V> implements return getMaxInMemory(); } - public void setMaxInMemory(int newMaxInMemory) { - cacheLineTable.setLru(newMaxInMemory); - this.maxInMemory = newMaxInMemory; + public void setMaxInMemory(int newInMemory) { + this.maxInMemory = newInMemory; + Map<Object, CacheLine<V>> oldmap = this.memoryTable; + + if (newInMemory > 0) { + if (this.memoryTable instanceof ConcurrentLinkedHashMap) { + ((ConcurrentLinkedHashMap) this.memoryTable).setCapacity(newInMemory); + return; + } else { + this.memoryTable = ConcurrentLinkedHashMap.create(ConcurrentLinkedHashMap.EvictionPolicy.LRU, newInMemory); + } + } else { + this.memoryTable = FastMap.newInstance(); + } + + this.memoryTable.putAll(oldmap); } public int getMaxInMemory() { @@ -443,8 +617,9 @@ public class UtilCache<K, V> implements // if expire time was <= 0 and is now greater, fill expire table now if (this.expireTime <= 0 && expireTime > 0) { for (K key: getCacheLineKeys()) { - CacheLine<V> line = getInternalNoCheck(key); - cacheLineTable.put(key, line.changeLine(useSoftReference, expireTime)); + Object nulledKey = fromKey(key); + CacheLine<V> line = getInternalNoCheck(nulledKey); + putInternal(nulledKey, line.changeLine(useSoftReference, expireTime)); } } else if (this.expireTime <= 0 && expireTime > 0) { // if expire time was > 0 and is now <=, do nothing, just leave the load times in place, won't hurt anything... @@ -464,9 +639,10 @@ public class UtilCache<K, V> implements public void setUseSoftReference(boolean useSoftReference) { if (this.useSoftReference != useSoftReference) { this.useSoftReference = useSoftReference; - for (K key: cacheLineTable.keySet()) { - CacheLine<V> line = cacheLineTable.get(key); - cacheLineTable.put(key, line.changeLine(useSoftReference, line.expireTime)); + for (K key: getCacheLineKeys()) { + Object nulledKey = fromKey(key); + CacheLine<V> line = getInternalNoCheck(nulledKey); + putInternal(nulledKey, line.changeLine(useSoftReference, expireTime)); } } } @@ -484,7 +660,20 @@ public class UtilCache<K, V> implements * @return The number of elements currently in the cache */ public int size() { - return cacheLineTable.size(); + if (fileTable != null) { + int size = 0; + try { + FastIterator<Object> iter = fileTable.keys(); + while (iter.next() != null) { + size++; + } + } catch (IOException e) { + Debug.logError(e, module); + } + return size; + } else { + return memoryTable.size(); + } } /** Returns a boolean specifying whether or not an element with the specified key is in the cache. @@ -507,15 +696,84 @@ public class UtilCache<K, V> implements * This behavior is necessary for now for the persisted cache feature. */ public Set<? extends K> getCacheLineKeys() { - return cacheLineTable.keySet(); + // note that this must be a HashSet and not a FastSet in order to have a null value + Set<Object> keys; + + if (fileTable != null) { + keys = new HashSet<Object>(); + try { + addAllFileTableKeys(keys); + } catch (IOException e) { + Debug.logError(e, module); + } + if (keys.remove(ObjectType.NULL)) { + keys.add(null); + } + } else { + if (memoryTable.containsKey(ObjectType.NULL)) { + keys = new HashSet<Object>(memoryTable.keySet()); + keys.remove(ObjectType.NULL); + keys.add(null); + } else { + keys = memoryTable.keySet(); + } + } + return Collections.unmodifiableSet((Set<? extends K>) keys); } public Collection<? extends CacheLine<V>> getCacheLineValues() { - return cacheLineTable.values(); + Collection<CacheLine<V>> values; + if (fileTable != null) { + values = FastList.newInstance(); + try { + FastIterator<CacheLine<V>> iter = fileTable.values(); + CacheLine<V> value = iter.next(); + while (value != null) { + values.add(value); + value = iter.next(); + } + } catch (IOException e) { + Debug.logError(e, module); + } + } else { + values = memoryTable.values(); + } + return values; + } + + private Map<String, Object> createLineInfo(int keyNum, K key, CacheLine<V> line) { + Map<String, Object> lineInfo = FastMap.newInstance(); + lineInfo.put("elementKey", key); + if (line.loadTime > 0) { + lineInfo.put("expireTime", new Date(line.loadTime + line.expireTime)); + } + lineInfo.put("lineSize", line.getSizeInBytes()); + lineInfo.put("keyNum", keyNum); + return lineInfo; } public Collection<? extends Map<String, Object>> getLineInfos() { - return cacheLineTable.getLineInfos(); + List<Map<String, Object>> lineInfos = FastList.newInstance(); + int keyIndex = 0; + for (K key: getCacheLineKeys()) { + Object nulledKey = fromKey(key); + CacheLine<V> line; + if (fileTable != null) { + try { + line = fileTable.get(nulledKey); + } catch (IOException e) { + Debug.logError(e, module); + line = null; + } + } else { + line = memoryTable.get(nulledKey); + } + if (line != null) { + lineInfos.add(createLineInfo(keyIndex, key, line)); + } + keyIndex++; + } + return lineInfos; } /** Returns a boolean specifying whether or not the element corresponding to the key has expired. @@ -527,15 +785,16 @@ public class UtilCache<K, V> implements * @return True is the element corresponding to the specified key has expired, otherwise false */ public boolean hasExpired(Object key) { - CacheLine<V> line = getInternalNoCheck(key); + CacheLine<V> line = getInternalNoCheck(fromKey(key)); if (line == null) return false; return line.hasExpired(); } /** Clears all expired cache entries; also clear any cache entries where the SoftReference in the CacheLine object has been cleared by the gc */ public void clearExpired() { - for (K key: cacheLineTable.keySet()) { - if (hasExpired(key)) { + for (K key: getCacheLineKeys()) { + CacheLine<V> line = getInternalNoCheck(key); + if (line.isInvalid()) { removeInternal(key, false); } } Modified: ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/UtilCacheEvents.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/UtilCacheEvents.java?rev=929838&r1=929837&r2=929838&view=diff ============================================================================== --- ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/UtilCacheEvents.java (original) +++ ofbiz/trunk/framework/webtools/src/org/ofbiz/webtools/UtilCacheEvents.java Thu Apr 1 04:46:53 2010 @@ -79,8 +79,7 @@ public class UtilCacheEvents { if (utilCache != null) { Object key = null; - // no LRU, try looping through the keySet to see if we find the specified index... - Iterator<?> ksIter = utilCache.getCacheLineTable().keySet().iterator(); + Iterator<?> ksIter = utilCache.getCacheLineKeys().iterator(); int curNum = 0; while (ksIter.hasNext()) { |
Free forum by Nabble | Edit this page |