You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jcs-dev@jakarta.apache.org by hc...@apache.org on 2005/01/19 11:59:11 UTC
cvs commit: jakarta-turbine-jcs/auxiliary-builds/jdk15/yajcache/cache/src/net/sf/yajcache/soft SoftRefCache.java SoftRefCacheCleaner.java SoftRefCacheSafe.java
hchar 2005/01/19 02:59:11
Added: auxiliary-builds/jdk15/yajcache/cache/src/net/sf/yajcache/soft
SoftRefCache.java SoftRefCacheCleaner.java
SoftRefCacheSafe.java
Log:
no message
Revision Changes Path
1.1 jakarta-turbine-jcs/auxiliary-builds/jdk15/yajcache/cache/src/net/sf/yajcache/soft/SoftRefCache.java
Index: SoftRefCache.java
===================================================================
/*
* SoftRefCache.java
*
* Created on 17 January 2005, 04:25
*/
package net.sf.yajcache.soft;
import java.lang.ref.ReferenceQueue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import net.sf.yajcache.core.CacheEntry;
import net.sf.yajcache.core.ICache;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Cache implemented using Soft References.
*
* @author Hanson Char
*/
public class SoftRefCache<V> implements ICache<V> {
private static final boolean debug = true;
private Log log = debug ? LogFactory.getLog(this.getClass()) : null;
private final ReferenceQueue<V> refq = new ReferenceQueue<V>();
private final String name;
private final Class<V> valueType;
private final Map<String, KeyedSoftRef<V>> map;
private final KeyedSoftRefCollector<V> collector;
public String getName() {
return this.name;
}
public Class<V> getValueType() {
return this.valueType;
}
public SoftRefCache(String name, Class<V> valueType, int initialCapacity,
float loadFactor, int concurrencyLevel)
{
map = new ConcurrentHashMap<String,KeyedSoftRef<V>>(initialCapacity, loadFactor, concurrencyLevel);
collector = new KeyedSoftRefCollector<V>(refq, map);
this.name = name;
this.valueType = valueType;
}
public SoftRefCache(String name, Class<V> valueType, int initialCapacity) {
map = new ConcurrentHashMap<String,KeyedSoftRef<V>>(initialCapacity);
collector = new KeyedSoftRefCollector<V>(refq, map);
this.name = name;
this.valueType = valueType;
}
public SoftRefCache(String name, Class<V> valueType) {
map = new ConcurrentHashMap<String,KeyedSoftRef<V>>();
collector = new KeyedSoftRefCollector<V>(refq, map);
this.name = name;
this.valueType = valueType;
}
public boolean isEmpty() {
this.collector.run();
return map.isEmpty();
}
public int size() {
this.collector.run();
return map.size();
}
// @tothink: SoftReference.get() doesn't seem to be thread-safe.
// But do we really want to synchronize upon invoking get() ?
// It's not thread-safe, but what's the worst consequence ?
public V get(String key) {
this.collector.run();
KeyedSoftRef<V> ref = map.get(key);
if (ref == null)
return null;
V val = ref.get();
if (val == null) {
// already garbage collected. So try to clean up the key.
SoftRefCacheCleaner.inst.cleanupKey(this.map, key);
}
// cache value exists.
// try to refresh the soft reference.
// this.renewSoftReference(key, val);
return val;
}
// private void renewSoftReference(String key, V val) {
// if (debug)
// log.debug("get: try to refresh the soft reference.");
// KeyedSoftRef<V> oldRef =
// map.put(key, new KeyedSoftRef<V>(key, val, refq));
// // Check for race conditon.
// if (oldRef == null) {
// // key has just been removed by another thread.
// if (debug)
// log.debug("get: key has just been removed by another thread.");
// return;
// }
// V oldVal = oldRef.get();
// // if oldVal is null, it means the GC just cleared it.
// while (oldVal != null && oldVal != val) {
// // race condition occurred
// // put back the old stuff
// if (debug)
// log.debug("get: race condition occurred. put back the old stuff");
// val = oldVal;
// oldRef = map.put(key, oldRef);
//
// if (oldRef == null) {
// // key has just been removed by another thread.
// if (debug)
// log.debug("get: key has just been removed by another thread.");
// oldRef = map.remove(key);
//
// if (oldRef == null) {
// // again, key has just been removed by another thread.
// if (debug)
// log.debug("again: key has just been removed by another thread.");
// break;
// }
// }
// oldVal = oldRef.get();
// }
// return;
// }
public V get(Object key) {
return key == null ? null : this.get(key.toString());
}
public V put(String key, V value) {
this.collector.run();
KeyedSoftRef<V> oldRef = map.put(key, new KeyedSoftRef<V>(key, value, refq));
if (oldRef == null)
return null;
V ret = oldRef.get();
oldRef.clear();
return ret;
}
public void putAll(Map<? extends String, ? extends V> map) {
for (Map.Entry<? extends String, ? extends V> e : map.entrySet())
this.put(e.getKey(), e.getValue());
}
public V remove(String key) {
this.collector.run();
KeyedSoftRef<V> oldRef = map.remove(key);
if (oldRef == null)
return null;
V ret = oldRef.get();
oldRef.clear();
return ret;
}
public V remove(Object key) {
return key == null ? null : this.remove(key.toString());
}
public void clear() {
this.collector.run();
map.clear();
}
public Set<String> keySet() {
this.collector.run();
return map.keySet();
}
public Set<Map.Entry<String,V>> entrySet() {
this.collector.run();
Set<Map.Entry<String,KeyedSoftRef<V>>> fromSet = map.entrySet();
Set<Map.Entry<String,V>> toSet = new HashSet<Map.Entry<String,V>>();
for (Map.Entry<String,KeyedSoftRef<V>> item : fromSet) {
KeyedSoftRef<V> ref = item.getValue();
V val = ref.get();
if (val != null) {
Map.Entry<String,V> e = new CacheEntry<V>(item.getKey(), val);
toSet.add(e);
}
}
return toSet;
}
public Collection<V> values() {
this.collector.run();
Collection<KeyedSoftRef<V>> fromSet = map.values();
List<V> toCol = new ArrayList<V>(fromSet.size());
for (KeyedSoftRef<V> ref : fromSet) {
V val = ref.get();
if (val != null) {
toCol.add(val);
}
}
return toCol;
}
public boolean containsKey(Object key) {
if (key == null)
return false;
return this.get(key.toString()) != null;
}
public boolean containsValue(Object value) {
this.collector.run();
Collection<KeyedSoftRef<V>> fromSet = map.values();
for (KeyedSoftRef<V> ref : fromSet) {
V val = ref.get();
if (value.equals(val))
return true;
}
return false;
}
/** Returns the number of Soft References collected by GC. */
public int getCollectorCount() {
return this.collector.getCount();
}
}
1.1 jakarta-turbine-jcs/auxiliary-builds/jdk15/yajcache/cache/src/net/sf/yajcache/soft/SoftRefCacheCleaner.java
Index: SoftRefCacheCleaner.java
===================================================================
/*
* SoftRefCacheCleaner.java
*
* Created on 19 January 2005, 05:12
*/
package net.sf.yajcache.soft;
import java.util.Map;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author Hanson Char
*/
enum SoftRefCacheCleaner {
inst;
private static final boolean debug = true;
private Log log = debug ? LogFactory.getLog(this.getClass()) : null;
private volatile int countTryKeyClean;
private volatile int countRemovedByOthers;
private volatile int countKeyCleaned;
private volatile int countDataRace;
private volatile int countDataRaceAndRemovedByOthers;
private volatile int countBye;
<V> void cleanupKey(Map<String, KeyedSoftRef<V>> map, String key) {
V val = null;
// already garbage collected. So try to clean up the key.
if (debug)
log.debug("Try to clean up the key");
this.countTryKeyClean++;
KeyedSoftRef<V> oldRef = map.remove(key);
// If oldRef is null, the key has just been
// cleaned up by another thread.
if (oldRef == null) {
if (debug)
log.debug("Key has just been removed by another thread.");
this.countRemovedByOthers++;
return;
}
// Check for race condition.
V oldVal = oldRef.get();
if (val == oldVal) {
oldRef.clear();
if (debug)
log.debug("Key removed and Soft Reference cleared.");
this.countKeyCleaned++;
return;
}
do {
if (debug)
log.debug("Race condition occurred. So put back the old stuff.");
this.countDataRace++;
// race condition occurred
// put back the old stuff
val = oldVal;
oldRef = map.put(key, oldRef);
if (oldRef == null) {
// key has just been cleaned up by another thread.
if (debug)
log.debug("Key has just been removed by another thread.");
this.countDataRaceAndRemovedByOthers++;
return;
}
oldVal = oldRef.get();
} while (oldVal != val);
if (debug)
log.debug("Bye.");
this.countBye++;
return;
}
public int getCountTryKeyClean() {
return countTryKeyClean;
}
public int getCountRemovedByOthers() {
return countRemovedByOthers;
}
public int getCountKeyCleaned() {
return countKeyCleaned;
}
public int getCountDataRace() {
return countDataRace;
}
public int getCountDataRaceAndRemovedByOthers() {
return countDataRaceAndRemovedByOthers;
}
public int getCountBye() {
return countBye;
}
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}
1.1 jakarta-turbine-jcs/auxiliary-builds/jdk15/yajcache/cache/src/net/sf/yajcache/soft/SoftRefCacheSafe.java
Index: SoftRefCacheSafe.java
===================================================================
/*
* SoftRefCacheSafe.java
*
* Created on 18 January 2005, 23:21
*/
package net.sf.yajcache.soft;
import java.io.Serializable;
import java.util.Map;
import net.sf.yajcache.core.ICacheSafe;
import net.sf.yajcache.util.BeanUtils;
import net.sf.yajcache.util.SerializeUtils;
/**
*
* @author Hanson Char
*/
public class SoftRefCacheSafe<V> extends SoftRefCache<V>
implements ICacheSafe<V>
{
public SoftRefCacheSafe(String name, Class<V> valueType,
int initialCapacity, float loadFactor, int concurrencyLevel)
{
super(name, valueType, initialCapacity, loadFactor, concurrencyLevel);
}
public SoftRefCacheSafe(String name, Class<V> valueType,
int initialCapacity)
{
super(name, valueType, initialCapacity);
}
public SoftRefCacheSafe(String name, Class<V> valueType) {
super(name, valueType);
}
public V getCopy(String key) {
V val = this.get(key);
return this.dup(val);
}
public V putCopy(String key, V value) {
return this.put(key, this.dup(value));
}
public void putAll(Map<? extends String, ? extends V> map) {
for (Map.Entry<? extends String, ? extends V> e : map.entrySet())
this.put(e.getKey(), e.getValue());
}
public void putAllCopies(Map<? extends String, ? extends V> map) {
for (Map.Entry<? extends String, ? extends V> e : map.entrySet())
this.put(e.getKey(), this.dup(e.getValue()));
}
public V getBeanCopy(String key) {
V val = this.get(key);
return BeanUtils.inst.cloneDeep(val);
}
public V putBeanCopy(String key, V value) {
return this.put(key, BeanUtils.inst.cloneDeep(value));
}
public void putAllBeanCopies(Map<? extends String, ? extends V> map) {
for (Map.Entry<? extends String, ? extends V> e : map.entrySet())
this.put(e.getKey(), BeanUtils.inst.cloneDeep(e.getValue()));
}
public V getBeanClone(String key) {
V val = this.get(key);
return BeanUtils.inst.cloneShallow(val);
}
public V putBeanClone(String key, V value) {
return this.put(key, BeanUtils.inst.cloneShallow(value));
}
public void putAllBeanClones(Map<? extends String, ? extends V> map) {
for (Map.Entry<? extends String, ? extends V> e : map.entrySet())
this.put(e.getKey(), BeanUtils.inst.cloneShallow(e.getValue()));
}
private V dup(V val) {
if (val instanceof Serializable) {
return (V)SerializeUtils.inst.dup((Serializable)val);
}
return val;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: turbine-jcs-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: turbine-jcs-dev-help@jakarta.apache.org