first cleanup of cache code - implemented a new CacheMap which uses
SoftReferences
This commit is contained in:
parent
9558f0722b
commit
7e0f7b441f
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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;
|
|
@ -15,7 +15,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
package com.silverwrist.util.cachemap;
|
||||
package com.silverwrist.util.cache;
|
||||
|
||||
public interface CacheMapStrategy
|
||||
{
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user