You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by do...@apache.org on 2010/04/01 06:49:38 UTC
svn commit: r929843 - in
/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache: CacheLine.java
HardRefCacheLine.java SoftRefCacheLine.java UtilCache.java
Author: doogie
Date: Thu Apr 1 04:49:37 2010
New Revision: 929843
URL: http://svn.apache.org/viewvc?rev=929843&view=rev
Log:
Backround removal of items due to ttl expiration.
Modified:
ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/CacheLine.java
ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/HardRefCacheLine.java
ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/SoftRefCacheLine.java
ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/UtilCache.java
Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/CacheLine.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/CacheLine.java?rev=929843&r1=929842&r2=929843&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/CacheLine.java (original)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/CacheLine.java Thu Apr 1 04:49:37 2010
@@ -18,35 +18,33 @@
*******************************************************************************/
package org.ofbiz.base.util.cache;
-public abstract class CacheLine<V> {
- public long loadTime;
- public final long expireTime;
-
- protected CacheLine(long loadTime, long expireTime) {
- this.expireTime = expireTime;
- this.loadTime = loadTime;
+import java.util.concurrent.TimeUnit;
+
+import org.ofbiz.base.concurrent.ExecutionPool;
+
+public abstract class CacheLine<V> extends ExecutionPool.Pulse {
+ protected CacheLine(long loadTimeNanos, long expireTimeNanos) {
+ super(loadTimeNanos, expireTimeNanos);
+ // FIXME: this seems very odd to me (ARH)
+ //if (loadTime <= 0) {
+ // hasExpired = true;
+ //}
}
- abstract CacheLine<V> changeLine(boolean useSoftReference, long expireTime);
+ abstract CacheLine<V> changeLine(boolean useSoftReference, long expireTimeNanos);
+ abstract void remove();
+ boolean differentExpireTime(long expireTimeNanos) {
+ return this.expireTimeNanos - loadTimeNanos - expireTimeNanos != 0;
+ }
public abstract V getValue();
public abstract boolean isInvalid();
- public long getExpireTime() {
- return this.expireTime;
+ void cancel() {
}
- public boolean hasExpired() {
- // check this BEFORE checking to see if expireTime <= 0, ie if time expiration is enabled
- // check to see if we are using softReference first, slight performance increase
- if (isInvalid()) return true;
-
- // check if expireTime <= 0, ie if time expiration is not enabled
- if (expireTime <= 0) return false;
-
- // check if the time was saved for this; if the time was not saved, but expire time is > 0, then we don't know when it was saved so expire it to be safe
- if (loadTime <= 0) return true;
-
- return (loadTime + expireTime) < System.currentTimeMillis();
+ @Override
+ public void run() {
+ remove();
}
}
Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/HardRefCacheLine.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/HardRefCacheLine.java?rev=929843&r1=929842&r2=929843&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/HardRefCacheLine.java (original)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/HardRefCacheLine.java Thu Apr 1 04:49:37 2010
@@ -19,26 +19,14 @@
package org.ofbiz.base.util.cache;
@SuppressWarnings("serial")
-public final class HardRefCacheLine<V> extends CacheLine<V> {
+public abstract class HardRefCacheLine<V> extends CacheLine<V> {
public final V value;
- public HardRefCacheLine(V value, long loadTime, long expireTime) {
- super(loadTime, expireTime);
+ public HardRefCacheLine(V value, long loadTimeNanos, long expireTimeNanos) {
+ super(loadTimeNanos, expireTimeNanos);
this.value = value;
}
- CacheLine<V> changeLine(boolean useSoftReference, long expireTime) {
- if (useSoftReference) {
- return new SoftRefCacheLine<V>(getValue(), loadTime, expireTime);
- } else {
- if (this.expireTime == expireTime) {
- return this;
- } else {
- return new HardRefCacheLine<V>(getValue(), loadTime, expireTime);
- }
- }
- }
-
@Override
public V getValue() {
return value;
Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/SoftRefCacheLine.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/SoftRefCacheLine.java?rev=929843&r1=929842&r2=929843&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/SoftRefCacheLine.java (original)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/cache/SoftRefCacheLine.java Thu Apr 1 04:49:37 2010
@@ -19,26 +19,14 @@
package org.ofbiz.base.util.cache;
@SuppressWarnings("serial")
-public final class SoftRefCacheLine<V> extends CacheLine<V> {
+public abstract class SoftRefCacheLine<V> extends CacheLine<V> {
public final CacheSoftReference<V> ref;
- public SoftRefCacheLine(V value, long loadTime, long expireTime) {
- super(loadTime, expireTime);
+ public SoftRefCacheLine(V value, long loadTimeNanos, long expireTimeNanos) {
+ super(loadTimeNanos, expireTimeNanos);
this.ref = new CacheSoftReference<V>(value);
}
- CacheLine<V> changeLine(boolean useSoftReference, long expireTime) {
- if (useSoftReference) {
- if (this.expireTime == expireTime) {
- return this;
- } else {
- return new SoftRefCacheLine<V>(getValue(), loadTime, expireTime);
- }
- } else {
- return new HardRefCacheLine<V>(getValue(), loadTime, expireTime);
- }
- }
-
@Override
public V getValue() {
return ref.get();
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=929843&r1=929842&r2=929843&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:49:37 2010
@@ -34,6 +34,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -46,6 +47,7 @@ import javolution.util.FastSet;
import jdbm.helper.FastIterator;
import jdbm.htree.HTree;
+import org.ofbiz.base.concurrent.ExecutionPool;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.ObjectType;
import org.ofbiz.base.util.UtilObject;
@@ -100,7 +102,7 @@ public class UtilCache<K, V> implements
/** Specifies the amount of time since initial loading before an element will be reported as expired.
* If set to 0, elements will never expire.
*/
- protected long expireTime = 0;
+ protected long expireTimeNanos = 0;
/** Specifies whether or not to use soft references for this cache, defaults to false */
protected boolean useSoftReference = false;
@@ -127,11 +129,11 @@ public class UtilCache<K, V> implements
* @param cacheName The name of the cache.
* @param useSoftReference Specifies whether or not to use soft references for this cache.
*/
- private UtilCache(String cacheName, int sizeLimit, int maxInMemory, long expireTime, boolean useSoftReference, boolean useFileSystemStore, String propName, String... propNames) {
+ private UtilCache(String cacheName, int sizeLimit, int maxInMemory, long expireTimeMillis, boolean useSoftReference, boolean useFileSystemStore, String propName, String... propNames) {
this.name = cacheName;
this.sizeLimit = sizeLimit;
this.maxInMemory = maxInMemory;
- this.expireTime = expireTime;
+ this.expireTimeNanos = TimeUnit.NANOSECONDS.convert(expireTimeMillis, TimeUnit.MILLISECONDS);
this.useSoftReference = useSoftReference;
this.useFileSystemStore = useFileSystemStore;
setPropertiesParams(propName);
@@ -218,7 +220,7 @@ public class UtilCache<K, V> implements
}
value = getPropertyParam(res, propNames, "expireTime");
if (UtilValidate.isNotEmpty(value)) {
- this.expireTime = Long.parseLong(value);
+ this.expireTimeNanos = TimeUnit.NANOSECONDS.convert(Long.parseLong(value), TimeUnit.MILLISECONDS);
}
value = getPropertyParam(res, propNames, "useSoftReference");
if (value != null) {
@@ -284,27 +286,90 @@ public class UtilCache<K, V> implements
* @param value The value of the element
*/
public V put(K key, V value) {
- return put(key, value, expireTime);
+ return putInternal(key, value, expireTimeNanos);
}
- private CacheLine<V> createCacheLine(V value, long expireTime) {
- long loadTime = expireTime > 0 ? System.currentTimeMillis() : 0;
+ CacheLine<V> createSoftRefCacheLine(final Object key, V value, long loadTimeNanos, long expireTimeNanos) {
+ return tryRegister(loadTimeNanos, new SoftRefCacheLine<V>(value, loadTimeNanos, expireTimeNanos) {
+ @Override
+ CacheLine<V> changeLine(boolean useSoftReference, long expireTimeNanos) {
+ if (useSoftReference) {
+ if (differentExpireTime(expireTimeNanos)) {
+ return this;
+ } else {
+ return createSoftRefCacheLine(key, getValue(), loadTimeNanos, expireTimeNanos);
+ }
+ } else {
+ return createHardRefCacheLine(key, getValue(), loadTimeNanos, expireTimeNanos);
+ }
+ }
+
+ @Override
+ void remove() {
+ removeInternal(key, this);
+ }
+ });
+ }
+
+ CacheLine<V> createHardRefCacheLine(final Object key, V value, long loadTimeNanos, long expireTimeNanos) {
+ return tryRegister(loadTimeNanos, new HardRefCacheLine<V>(value, loadTimeNanos, expireTimeNanos) {
+ @Override
+ CacheLine<V> changeLine(boolean useSoftReference, long expireTimeNanos) {
+ if (useSoftReference) {
+ return createSoftRefCacheLine(key, getValue(), loadTimeNanos, expireTimeNanos);
+ } else {
+ if (differentExpireTime(expireTimeNanos)) {
+ return this;
+ } else {
+ return createHardRefCacheLine(key, getValue(), loadTimeNanos, expireTimeNanos);
+ }
+ }
+ }
+
+ @Override
+ void remove() {
+ removeInternal(key, this);
+ }
+ });
+ }
+
+ private CacheLine<V> tryRegister(long loadTimeNanos, CacheLine<V> line) {
+ if (loadTimeNanos > 0) {
+ ExecutionPool.addPulse(line);
+ }
+ return line;
+ }
+
+ private CacheLine<V> createCacheLine(K key, V value, long expireTimeNanos) {
+ long loadTimeNanos = expireTimeNanos > 0 ? System.nanoTime() : 0;
if (useSoftReference) {
- return new SoftRefCacheLine<V>(value, loadTime, expireTime);
+ return createSoftRefCacheLine(key, value, loadTimeNanos, expireTimeNanos);
} else {
- return new HardRefCacheLine<V>(value, loadTime, expireTime);
+ return createHardRefCacheLine(key, value, loadTimeNanos, expireTimeNanos);
}
}
+ private V cancel(CacheLine<V> line) {
+ // FIXME: this is a race condition, the item could expire
+ // between the time it is replaced, and it is cancelled
+ V oldValue = line.getValue();
+ ExecutionPool.removePulse(line);
+ line.cancel();
+ return oldValue;
+ }
/** Puts or loads the passed element into the cache
* @param key The key for the element, used to reference it in the hastables and LRU linked list
* @param value The value of the element
- * @param expireTime how long to keep this key in the cache
+ * @param expireTimeMillis how long to keep this key in the cache
*/
- public V put(K key, V value, long expireTime) {
+ public V put(K key, V value, long expireTimeMillis) {
+ return putInternal(key, value, TimeUnit.NANOSECONDS.convert(expireTimeMillis, TimeUnit.MILLISECONDS));
+ }
+
+ V putInternal(K key, V value, long expireTimeNanos) {
Object nulledKey = fromKey(key);
- CacheLine<V> oldCacheLine = memoryTable.put(nulledKey, createCacheLine(value, expireTime));
- V oldValue = oldCacheLine == null ? null : oldCacheLine.getValue();
+ CacheLine<V> oldCacheLine = memoryTable.put(nulledKey, createCacheLine(key, value, expireTimeNanos));
+ V oldValue = oldCacheLine == null ? null : cancel(oldCacheLine);
if (fileTable != null) {
try {
if (oldValue == null) oldValue = fileTable.get(nulledKey);
@@ -324,7 +389,6 @@ public class UtilCache<K, V> implements
}
/** Gets an element from the cache according to the specified key.
- * If the requested element hasExpired, it is removed before it is looked up which causes the function to return null.
* @param key The key for the element, used to reference it in the hastables and LRU linked list
* @return The value of the element specified by the key
*/
@@ -347,21 +411,15 @@ public class UtilCache<K, V> implements
} else {
hitCount.incrementAndGet();
}
- memoryTable.put(nulledKey, createCacheLine(value, expireTime));
+ memoryTable.put(nulledKey, createCacheLine((K) key, value, expireTimeNanos));
return value;
} else {
missCountNotFound.incrementAndGet();
}
} else if (line.isInvalid()) {
- removeInternal(key, false);
+ removeInternal(key, line);
if (countGet) missCountSoftRef.incrementAndGet();
line = null;
- } else if (line.hasExpired()) {
- // note that print.info in debug.properties cannot be checked through UtilProperties here, it would cause infinite recursion...
- // if (Debug.infoOn()) Debug.logInfo("Element has expired with key " + key, module);
- removeInternal(key, false);
- if (countGet) missCountExpired.incrementAndGet();
- line = null;
} else {
if (countGet) hitCount.incrementAndGet();
}
@@ -453,14 +511,34 @@ public class UtilCache<K, V> implements
oldValue = null;
Debug.logError(e, module);
}
- memoryTable.remove(nulledKey);
+ oldCacheLine = memoryTable.remove(nulledKey);
} else {
oldCacheLine = memoryTable.remove(nulledKey);
oldValue = oldCacheLine != null ? oldCacheLine.getValue() : null;
}
+ if (oldCacheLine != null) {
+ cancel(oldCacheLine);
+ }
return postRemove((K) key, oldValue, countRemove);
}
+ protected synchronized void removeInternal(Object key, CacheLine<V> existingCacheLine) {
+ Object nulledKey = fromKey(key);
+ cancel(existingCacheLine);
+ if (!memoryTable.remove(nulledKey, existingCacheLine)) {
+ return;
+ }
+ if (fileTable != null) {
+ try {
+ fileTable.remove(nulledKey);
+ jdbmMgr.commit();
+ } catch (IOException e) {
+ Debug.logError(e, module);
+ }
+ }
+ noteRemoval((K) key, existingCacheLine.getValue());
+ }
+
V postRemove(K key, V oldValue, boolean countRemove) {
if (oldValue != null) {
noteRemoval((K) key, oldValue);
@@ -632,15 +710,15 @@ public class UtilCache<K, V> implements
* If 0, elements never expire.
* @param expireTime The expire time for the cache elements
*/
- public void setExpireTime(long expireTime) {
+ public void setExpireTime(long expireTimeMillis) {
// if expire time was <= 0 and is now greater, fill expire table now
- if (this.expireTime <= 0 && expireTime > 0) {
- this.expireTime = expireTime;
+ if (expireTimeMillis > 0) {
+ this.expireTimeNanos = TimeUnit.NANOSECONDS.convert(expireTimeMillis, TimeUnit.MILLISECONDS);
for (Map.Entry<?, CacheLine<V>> entry: memoryTable.entrySet()) {
- entry.setValue(entry.getValue().changeLine(useSoftReference, expireTime));
+ entry.setValue(entry.getValue().changeLine(useSoftReference, expireTimeNanos));
}
- } else if (this.expireTime <= 0 && expireTime > 0) {
- this.expireTime = expireTime;
+ } else {
+ this.expireTimeNanos = 0;
// if expire time was > 0 and is now <=, do nothing, just leave the load times in place, won't hurt anything...
}
}
@@ -649,7 +727,7 @@ public class UtilCache<K, V> implements
* @return The expire time for the cache elements
*/
public long getExpireTime() {
- return expireTime;
+ return TimeUnit.MILLISECONDS.convert(expireTimeNanos, TimeUnit.NANOSECONDS);
}
/** Set whether or not the cache lines should use a soft reference to the data */
@@ -657,7 +735,7 @@ public class UtilCache<K, V> implements
if (this.useSoftReference != useSoftReference) {
this.useSoftReference = useSoftReference;
for (Map.Entry<?, CacheLine<V>> entry: memoryTable.entrySet()) {
- entry.setValue(entry.getValue().changeLine(useSoftReference, expireTime));
+ entry.setValue(entry.getValue().changeLine(useSoftReference, expireTimeNanos));
}
}
}
@@ -692,7 +770,6 @@ public class UtilCache<K, V> implements
}
/** Returns a boolean specifying whether or not an element with the specified key is in the cache.
- * If the requested element hasExpired, it is removed before it is looked up which causes the function to return false.
* @param key The key for the element, used to reference it in the hastables and LRU linked list
* @return True is the cache contains an element corresponding to the specified key, otherwise false
*/
@@ -714,7 +791,7 @@ public class UtilCache<K, V> implements
}
}
return false;
- } else if (line.hasExpired()) {
+ } else if (line.isInvalid()) {
removeInternal(key, false);
return false;
} else {
@@ -803,7 +880,7 @@ public class UtilCache<K, V> implements
public boolean hasExpired(Object key) {
CacheLine<V> line = memoryTable.get(fromKey(key));
if (line == null) return false;
- return line.hasExpired();
+ return line.isInvalid();
}
/** Clears all expired cache entries; also clear any cache entries where the SoftReference in the CacheLine object has been cleared by the gc */