svn commit: r929838 - in /ofbiz/trunk/framework: base/src/org/ofbiz/base/util/cache/CacheLineTable.java base/src/org/ofbiz/base/util/cache/UtilCache.java webtools/src/org/ofbiz/webtools/UtilCacheEvents.java

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r929838 - in /ofbiz/trunk/framework: base/src/org/ofbiz/base/util/cache/CacheLineTable.java base/src/org/ofbiz/base/util/cache/UtilCache.java webtools/src/org/ofbiz/webtools/UtilCacheEvents.java

doogie-3
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()) {