first cleanup of cache code - implemented a new CacheMap which uses

SoftReferences
This commit is contained in:
Eric J. Bowersox 2001-11-14 06:00:35 +00:00
parent 9558f0722b
commit 7e0f7b441f
5 changed files with 168 additions and 62 deletions

View File

@ -15,8 +15,9 @@
*
* Contributor(s):
*/
package com.silverwrist.util.cachemap;
package com.silverwrist.util.cache;
import java.lang.ref.*;
import java.util.*;
public class CacheMap implements Map
@ -92,6 +93,7 @@ public class CacheMap implements Map
private CacheMapStrategy strategy; // strategy routine to use to purge entries
private HashMap base_map; // maps keys to CacheMapEntry values
private ArrayList element_list; // the actual elements
private ReferenceQueue rq; // holds references that the garbage collector has cleared
/*--------------------------------------------------------------------------------
* Constructors
@ -112,6 +114,7 @@ public class CacheMap implements Map
this.strategy = strategy;
this.base_map = new HashMap(10);
this.element_list = new ArrayList(10);
this.rq = new ReferenceQueue();
} // end constructor
@ -127,6 +130,66 @@ public class CacheMap implements Map
} // end constructor
/*--------------------------------------------------------------------------------
* Internal operations
*--------------------------------------------------------------------------------
*/
private void doSweep()
{
Reference r = rq.poll();
ArrayList ditch = new ArrayList();
Iterator it;
while (r!=null)
{ // look for the dead reference in the element list
it = element_list.iterator();
while (it.hasNext())
{ // check each cache map entry in return
CacheMapEntry ntry = (CacheMapEntry)(it.next());
if (ntry.matchReference(r))
{ // remove the offending entry and save it in the temporary list
it.remove();
ditch.add(ntry);
break;
} // end if
} // end while
r = rq.poll(); // get next dead reference
} // end while
if (ditch.isEmpty())
return; // nothing to prune
it = ditch.iterator();
while (it.hasNext())
{ // clear all entries from the base hashmap as well
CacheMapEntry ntry = (CacheMapEntry)(it.next());
base_map.remove(ntry.getKey());
ntry.discard();
} // end while
} // end doSweep
public synchronized void doShrink(int num_remove)
{
// Sort the element list to figure out which elements to remove.
Collections.sort(element_list,new CacheOrdering(strategy));
// The elements we want to remove are at the end of the array, so start from there.
for (int i=0; i<num_remove; i++)
{ // remove the "removed" entries from the hash map
CacheMapEntry cme = (CacheMapEntry)(element_list.remove(element_list.size() - 1));
base_map.remove(cme.getKey());
} // end for
} // end doShrink
/*--------------------------------------------------------------------------------
* Implementations from interface Map
*--------------------------------------------------------------------------------
@ -134,24 +197,28 @@ public class CacheMap implements Map
public int size()
{
doSweep();
return base_map.size();
} // end size
public boolean isEmpty()
{
doSweep();
return base_map.isEmpty();
} // end isEmpty
public boolean containsKey(Object key)
{
doSweep();
return base_map.containsKey(key);
} // end containsKey
public boolean containsValue(Object value)
{
doSweep();
Iterator it = element_list.iterator();
while (it.hasNext())
{ // look at all the CacheMapEntry values we have
@ -178,6 +245,7 @@ public class CacheMap implements Map
public Object get(Object key)
{
doSweep();
CacheMapEntry cme = (CacheMapEntry)(base_map.get(key));
if (cme==null)
return null;
@ -188,16 +256,17 @@ public class CacheMap implements Map
public Object put(Object key, Object value)
{
doSweep();
Object rc = null;
CacheMapEntry cme = (CacheMapEntry)(base_map.get(key));
if (cme==null)
{ // create a new CacheMapEntry for this key
cme = new CacheMapEntry(key,value);
cme = new CacheMapEntry(key,value,rq);
synchronized (this)
{ // insert it into the basic object
if (base_map.size()==capacity)
shrink();
doShrink((element_list.size() * shrink_percentage) / 100);
element_list.add(cme);
base_map.put(cme.getKey(),cme);
@ -207,7 +276,7 @@ public class CacheMap implements Map
else
{ // we have an old value - replace it and touch the entry
cme.touch();
rc = cme.setValue(value);
rc = cme.setValue(value,rq);
} // end else
@ -217,6 +286,7 @@ public class CacheMap implements Map
public Object remove(Object key)
{
doSweep();
Object rc = null;
CacheMapEntry cme = (CacheMapEntry)(base_map.get(key));
if (cme!=null)
@ -230,6 +300,8 @@ public class CacheMap implements Map
} // end synchronized block
cme.discard(); // zap the reference
} // end if
return rc;
@ -238,10 +310,12 @@ public class CacheMap implements Map
public void putAll(Map map)
{
doSweep();
synchronized (this)
{ // make sure we have enough space in the CacheMap for all the new elements!
while ((map.size() + base_map.size()) > capacity)
shrink();
int nover = (map.size() + base_map.size()) - capacity;
if (nover>0)
doShrink(nover);
} // end synchronized block
@ -258,6 +332,14 @@ public class CacheMap implements Map
public synchronized void clear()
{
base_map.clear();
Iterator it = element_list.iterator();
while (it.hasNext())
{ // discard all entries we have
CacheMapEntry cme = (CacheMapEntry)(it.next());
cme.discard();
} // end while
element_list.clear();
} // end clear
@ -270,13 +352,13 @@ public class CacheMap implements Map
public Collection values()
{
return null; // not implemented
throw new UnsupportedOperationException("CacheMap.values() is not implemented");
} // end values
public Set entrySet()
{
return null; // not implemented
throw new UnsupportedOperationException("CacheMap.entrySet() is not implemented");
} // end entrySet
@ -284,6 +366,7 @@ public class CacheMap implements Map
{
if ((o==null) || !(o instanceof Map))
return false; // not a map
doSweep();
Map other = (Map)o;
if (other.size()!=base_map.size())
return false; // size does matter!
@ -314,6 +397,7 @@ public class CacheMap implements Map
public int hashCode()
{
doSweep();
int rc = 0;
Iterator it = base_map.values().iterator();
while (it.hasNext())
@ -384,17 +468,16 @@ public class CacheMap implements Map
// Figure out how many elements to remove.
int num_remove = (element_list.size() * shrink_percentage) / 100;
// Sort the element list to figure out which elements to remove.
Collections.sort(element_list,new CacheOrdering(strategy));
// The elements we want to remove are at the end of the array, so start from there.
for (int i=0; i<num_remove; i++)
{ // remove the "removed" entries from the hash map
CacheMapEntry cme = (CacheMapEntry)(element_list.remove(element_list.size() - 1));
base_map.remove(cme.getKey());
} // end for
// Try a sweep first.
int n1 = base_map.size();
doSweep();
n1 -= base_map.size();
if (n1<num_remove)
doShrink(num_remove - n1);
} // end shrink
} // end class CacheMap

View File

@ -15,31 +15,40 @@
*
* Contributor(s):
*/
package com.silverwrist.util.cachemap;
package com.silverwrist.util.cache;
import java.lang.ref.*;
import java.util.*;
class CacheMapEntry implements Map.Entry
final class CacheMapEntry implements Map.Entry
{
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private Object key;
private Object value;
private int hits = 0;
private long timestamp;
private Object key; // the key for this entry
private SoftReference value; // reference to (discardable) value
private int hits = 0; // number of hits on this entry
private long timestamp; // timestamp of this entry
/*--------------------------------------------------------------------------------
* Constructor
* Constructors
*--------------------------------------------------------------------------------
*/
CacheMapEntry(Object key, Object value)
{
this.key = key;
this.value = value;
this.value = new SoftReference(value);
this.timestamp = System.currentTimeMillis();
} // end constructor
CacheMapEntry(Object key, Object value, ReferenceQueue q)
{
this.key = key;
this.value = new SoftReference(value,q);
this.timestamp = System.currentTimeMillis();
} // end constructor
@ -52,12 +61,13 @@ class CacheMapEntry implements Map.Entry
protected void finalize()
{
key = null;
value.clear();
value = null;
} // end finalize
/*--------------------------------------------------------------------------------
* Implementations from interface MapEntry
* Implementations from interface Map.Entry
*--------------------------------------------------------------------------------
*/
@ -69,14 +79,14 @@ class CacheMapEntry implements Map.Entry
public final Object getValue()
{
return value;
return value.get();
} // end getValue
public final Object setValue(Object o)
{
Object rc = value;
value = o;
Object rc = value.get();
value = new SoftReference(o);
return rc;
} // end setValue
@ -88,36 +98,17 @@ class CacheMapEntry implements Map.Entry
return false;
Map.Entry other = (Map.Entry)o;
// compare the keys
// compare the keys only (the values may change)
if (key==null)
{ // the other key must be null
if (other.getKey()!=null)
return false;
} // end if
return (other.getKey()==null);
else
{ // the other key must be equal to us
if ((other.getKey()==null) || (!(key.equals(other.getKey()))))
return false;
} // end else
// compare the values
if (value==null)
return (other.getValue()==null);
else
return ((other.getValue()!=null) && value.equals(other.getValue()));
return ((other.getKey()!=null) && key.equals(other.getKey()));
} // end equals
public final int hashCode()
{
int rc = 0;
if (key!=null)
rc ^= key.hashCode();
if (value!=null)
rc ^= value.hashCode();
return rc;
return ((key==null) ? 0 : key.hashCode());
} // end hashCode
@ -126,6 +117,38 @@ class CacheMapEntry implements Map.Entry
*--------------------------------------------------------------------------------
*/
final Object setValue(Object o, ReferenceQueue q)
{
Object rc = value.get();
value.clear();
value = new SoftReference(o,q);
return rc;
} // end setValue
final boolean isCleared()
{
return (value.get()==null);
} // end isCleared
final boolean matchReference(Reference r)
{
if (r instanceof SoftReference)
return (value==(SoftReference)r);
else
return false;
} // end matchReference
final void discard()
{
key = null;
value.clear();
value = null;
} // end discard
final int getHits()
{
return hits;

View File

@ -15,7 +15,7 @@
*
* Contributor(s):
*/
package com.silverwrist.util.cachemap;
package com.silverwrist.util.cache;
public interface CacheMapStrategy
{

View File

@ -19,7 +19,7 @@ package com.silverwrist.venice.core.impl;
import java.sql.*;
import java.util.Random;
import com.silverwrist.util.cachemap.*;
import com.silverwrist.util.cache.CacheMap;
import com.silverwrist.venice.core.*;
import com.silverwrist.venice.db.*;
@ -38,12 +38,12 @@ class AdvertisementImpl implements Advertisement
*--------------------------------------------------------------------------------
*/
private DataPool datapool;
private int adid;
private String imagepath;
private short style;
private String caption;
private String linkurl;
private DataPool datapool; // data pool reference
private int adid; // ad ID
private String imagepath; // image path
private short style; // ad style
private String caption; // ad caption
private String linkurl; // ad link URL
/*--------------------------------------------------------------------------------
* Constructor

View File

@ -19,7 +19,7 @@ package com.silverwrist.venice.servlets.format;
import java.io.*;
import com.silverwrist.util.IOUtil;
import com.silverwrist.util.cachemap.CacheMap;
import com.silverwrist.util.cache.CacheMap;
public class StaticRender implements ContentRender
{