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):
|
* Contributor(s):
|
||||||
*/
|
*/
|
||||||
package com.silverwrist.util.cachemap;
|
package com.silverwrist.util.cache;
|
||||||
|
|
||||||
|
import java.lang.ref.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class CacheMap implements Map
|
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 CacheMapStrategy strategy; // strategy routine to use to purge entries
|
||||||
private HashMap base_map; // maps keys to CacheMapEntry values
|
private HashMap base_map; // maps keys to CacheMapEntry values
|
||||||
private ArrayList element_list; // the actual elements
|
private ArrayList element_list; // the actual elements
|
||||||
|
private ReferenceQueue rq; // holds references that the garbage collector has cleared
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------------
|
||||||
* Constructors
|
* Constructors
|
||||||
|
@ -112,6 +114,7 @@ public class CacheMap implements Map
|
||||||
this.strategy = strategy;
|
this.strategy = strategy;
|
||||||
this.base_map = new HashMap(10);
|
this.base_map = new HashMap(10);
|
||||||
this.element_list = new ArrayList(10);
|
this.element_list = new ArrayList(10);
|
||||||
|
this.rq = new ReferenceQueue();
|
||||||
|
|
||||||
} // end constructor
|
} // end constructor
|
||||||
|
|
||||||
|
@ -127,6 +130,66 @@ public class CacheMap implements Map
|
||||||
|
|
||||||
} // end constructor
|
} // 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
|
* Implementations from interface Map
|
||||||
*--------------------------------------------------------------------------------
|
*--------------------------------------------------------------------------------
|
||||||
|
@ -134,24 +197,28 @@ public class CacheMap implements Map
|
||||||
|
|
||||||
public int size()
|
public int size()
|
||||||
{
|
{
|
||||||
|
doSweep();
|
||||||
return base_map.size();
|
return base_map.size();
|
||||||
|
|
||||||
} // end size
|
} // end size
|
||||||
|
|
||||||
public boolean isEmpty()
|
public boolean isEmpty()
|
||||||
{
|
{
|
||||||
|
doSweep();
|
||||||
return base_map.isEmpty();
|
return base_map.isEmpty();
|
||||||
|
|
||||||
} // end isEmpty
|
} // end isEmpty
|
||||||
|
|
||||||
public boolean containsKey(Object key)
|
public boolean containsKey(Object key)
|
||||||
{
|
{
|
||||||
|
doSweep();
|
||||||
return base_map.containsKey(key);
|
return base_map.containsKey(key);
|
||||||
|
|
||||||
} // end containsKey
|
} // end containsKey
|
||||||
|
|
||||||
public boolean containsValue(Object value)
|
public boolean containsValue(Object value)
|
||||||
{
|
{
|
||||||
|
doSweep();
|
||||||
Iterator it = element_list.iterator();
|
Iterator it = element_list.iterator();
|
||||||
while (it.hasNext())
|
while (it.hasNext())
|
||||||
{ // look at all the CacheMapEntry values we have
|
{ // look at all the CacheMapEntry values we have
|
||||||
|
@ -178,6 +245,7 @@ public class CacheMap implements Map
|
||||||
|
|
||||||
public Object get(Object key)
|
public Object get(Object key)
|
||||||
{
|
{
|
||||||
|
doSweep();
|
||||||
CacheMapEntry cme = (CacheMapEntry)(base_map.get(key));
|
CacheMapEntry cme = (CacheMapEntry)(base_map.get(key));
|
||||||
if (cme==null)
|
if (cme==null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -188,16 +256,17 @@ public class CacheMap implements Map
|
||||||
|
|
||||||
public Object put(Object key, Object value)
|
public Object put(Object key, Object value)
|
||||||
{
|
{
|
||||||
|
doSweep();
|
||||||
Object rc = null;
|
Object rc = null;
|
||||||
CacheMapEntry cme = (CacheMapEntry)(base_map.get(key));
|
CacheMapEntry cme = (CacheMapEntry)(base_map.get(key));
|
||||||
if (cme==null)
|
if (cme==null)
|
||||||
{ // create a new CacheMapEntry for this key
|
{ // create a new CacheMapEntry for this key
|
||||||
cme = new CacheMapEntry(key,value);
|
cme = new CacheMapEntry(key,value,rq);
|
||||||
|
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{ // insert it into the basic object
|
{ // insert it into the basic object
|
||||||
if (base_map.size()==capacity)
|
if (base_map.size()==capacity)
|
||||||
shrink();
|
doShrink((element_list.size() * shrink_percentage) / 100);
|
||||||
element_list.add(cme);
|
element_list.add(cme);
|
||||||
base_map.put(cme.getKey(),cme);
|
base_map.put(cme.getKey(),cme);
|
||||||
|
|
||||||
|
@ -207,7 +276,7 @@ public class CacheMap implements Map
|
||||||
else
|
else
|
||||||
{ // we have an old value - replace it and touch the entry
|
{ // we have an old value - replace it and touch the entry
|
||||||
cme.touch();
|
cme.touch();
|
||||||
rc = cme.setValue(value);
|
rc = cme.setValue(value,rq);
|
||||||
|
|
||||||
} // end else
|
} // end else
|
||||||
|
|
||||||
|
@ -217,6 +286,7 @@ public class CacheMap implements Map
|
||||||
|
|
||||||
public Object remove(Object key)
|
public Object remove(Object key)
|
||||||
{
|
{
|
||||||
|
doSweep();
|
||||||
Object rc = null;
|
Object rc = null;
|
||||||
CacheMapEntry cme = (CacheMapEntry)(base_map.get(key));
|
CacheMapEntry cme = (CacheMapEntry)(base_map.get(key));
|
||||||
if (cme!=null)
|
if (cme!=null)
|
||||||
|
@ -230,6 +300,8 @@ public class CacheMap implements Map
|
||||||
|
|
||||||
} // end synchronized block
|
} // end synchronized block
|
||||||
|
|
||||||
|
cme.discard(); // zap the reference
|
||||||
|
|
||||||
} // end if
|
} // end if
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -238,10 +310,12 @@ public class CacheMap implements Map
|
||||||
|
|
||||||
public void putAll(Map map)
|
public void putAll(Map map)
|
||||||
{
|
{
|
||||||
|
doSweep();
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{ // make sure we have enough space in the CacheMap for all the new elements!
|
{ // make sure we have enough space in the CacheMap for all the new elements!
|
||||||
while ((map.size() + base_map.size()) > capacity)
|
int nover = (map.size() + base_map.size()) - capacity;
|
||||||
shrink();
|
if (nover>0)
|
||||||
|
doShrink(nover);
|
||||||
|
|
||||||
} // end synchronized block
|
} // end synchronized block
|
||||||
|
|
||||||
|
@ -258,6 +332,14 @@ public class CacheMap implements Map
|
||||||
public synchronized void clear()
|
public synchronized void clear()
|
||||||
{
|
{
|
||||||
base_map.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();
|
element_list.clear();
|
||||||
|
|
||||||
} // end clear
|
} // end clear
|
||||||
|
@ -270,13 +352,13 @@ public class CacheMap implements Map
|
||||||
|
|
||||||
public Collection values()
|
public Collection values()
|
||||||
{
|
{
|
||||||
return null; // not implemented
|
throw new UnsupportedOperationException("CacheMap.values() is not implemented");
|
||||||
|
|
||||||
} // end values
|
} // end values
|
||||||
|
|
||||||
public Set entrySet()
|
public Set entrySet()
|
||||||
{
|
{
|
||||||
return null; // not implemented
|
throw new UnsupportedOperationException("CacheMap.entrySet() is not implemented");
|
||||||
|
|
||||||
} // end entrySet
|
} // end entrySet
|
||||||
|
|
||||||
|
@ -284,6 +366,7 @@ public class CacheMap implements Map
|
||||||
{
|
{
|
||||||
if ((o==null) || !(o instanceof Map))
|
if ((o==null) || !(o instanceof Map))
|
||||||
return false; // not a map
|
return false; // not a map
|
||||||
|
doSweep();
|
||||||
Map other = (Map)o;
|
Map other = (Map)o;
|
||||||
if (other.size()!=base_map.size())
|
if (other.size()!=base_map.size())
|
||||||
return false; // size does matter!
|
return false; // size does matter!
|
||||||
|
@ -314,6 +397,7 @@ public class CacheMap implements Map
|
||||||
|
|
||||||
public int hashCode()
|
public int hashCode()
|
||||||
{
|
{
|
||||||
|
doSweep();
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
Iterator it = base_map.values().iterator();
|
Iterator it = base_map.values().iterator();
|
||||||
while (it.hasNext())
|
while (it.hasNext())
|
||||||
|
@ -384,17 +468,16 @@ public class CacheMap implements Map
|
||||||
// Figure out how many elements to remove.
|
// Figure out how many elements to remove.
|
||||||
int num_remove = (element_list.size() * shrink_percentage) / 100;
|
int num_remove = (element_list.size() * shrink_percentage) / 100;
|
||||||
|
|
||||||
// Sort the element list to figure out which elements to remove.
|
// Try a sweep first.
|
||||||
Collections.sort(element_list,new CacheOrdering(strategy));
|
int n1 = base_map.size();
|
||||||
|
doSweep();
|
||||||
// The elements we want to remove are at the end of the array, so start from there.
|
n1 -= base_map.size();
|
||||||
for (int i=0; i<num_remove; i++)
|
if (n1<num_remove)
|
||||||
{ // remove the "removed" entries from the hash map
|
doShrink(num_remove - n1);
|
||||||
CacheMapEntry cme = (CacheMapEntry)(element_list.remove(element_list.size() - 1));
|
|
||||||
base_map.remove(cme.getKey());
|
|
||||||
|
|
||||||
} // end for
|
|
||||||
|
|
||||||
} // end shrink
|
} // end shrink
|
||||||
|
|
||||||
} // end class CacheMap
|
} // end class CacheMap
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,31 +15,40 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
*/
|
*/
|
||||||
package com.silverwrist.util.cachemap;
|
package com.silverwrist.util.cache;
|
||||||
|
|
||||||
|
import java.lang.ref.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
class CacheMapEntry implements Map.Entry
|
final class CacheMapEntry implements Map.Entry
|
||||||
{
|
{
|
||||||
/*--------------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------------
|
||||||
* Attributes
|
* Attributes
|
||||||
*--------------------------------------------------------------------------------
|
*--------------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private Object key;
|
private Object key; // the key for this entry
|
||||||
private Object value;
|
private SoftReference value; // reference to (discardable) value
|
||||||
private int hits = 0;
|
private int hits = 0; // number of hits on this entry
|
||||||
private long timestamp;
|
private long timestamp; // timestamp of this entry
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------------
|
||||||
* Constructor
|
* Constructors
|
||||||
*--------------------------------------------------------------------------------
|
*--------------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CacheMapEntry(Object key, Object value)
|
CacheMapEntry(Object key, Object value)
|
||||||
{
|
{
|
||||||
this.key = key;
|
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();
|
this.timestamp = System.currentTimeMillis();
|
||||||
|
|
||||||
} // end constructor
|
} // end constructor
|
||||||
|
@ -52,12 +61,13 @@ class CacheMapEntry implements Map.Entry
|
||||||
protected void finalize()
|
protected void finalize()
|
||||||
{
|
{
|
||||||
key = null;
|
key = null;
|
||||||
|
value.clear();
|
||||||
value = null;
|
value = null;
|
||||||
|
|
||||||
} // end finalize
|
} // end finalize
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------------
|
||||||
* Implementations from interface MapEntry
|
* Implementations from interface Map.Entry
|
||||||
*--------------------------------------------------------------------------------
|
*--------------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -69,14 +79,14 @@ class CacheMapEntry implements Map.Entry
|
||||||
|
|
||||||
public final Object getValue()
|
public final Object getValue()
|
||||||
{
|
{
|
||||||
return value;
|
return value.get();
|
||||||
|
|
||||||
} // end getValue
|
} // end getValue
|
||||||
|
|
||||||
public final Object setValue(Object o)
|
public final Object setValue(Object o)
|
||||||
{
|
{
|
||||||
Object rc = value;
|
Object rc = value.get();
|
||||||
value = o;
|
value = new SoftReference(o);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
} // end setValue
|
} // end setValue
|
||||||
|
@ -88,36 +98,17 @@ class CacheMapEntry implements Map.Entry
|
||||||
return false;
|
return false;
|
||||||
Map.Entry other = (Map.Entry)o;
|
Map.Entry other = (Map.Entry)o;
|
||||||
|
|
||||||
// compare the keys
|
// compare the keys only (the values may change)
|
||||||
if (key==null)
|
if (key==null)
|
||||||
{ // the other key must be null
|
return (other.getKey()==null);
|
||||||
if (other.getKey()!=null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
} // end if
|
|
||||||
else
|
else
|
||||||
{ // the other key must be equal to us
|
return ((other.getKey()!=null) && key.equals(other.getKey()));
|
||||||
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()));
|
|
||||||
|
|
||||||
} // end equals
|
} // end equals
|
||||||
|
|
||||||
public final int hashCode()
|
public final int hashCode()
|
||||||
{
|
{
|
||||||
int rc = 0;
|
return ((key==null) ? 0 : key.hashCode());
|
||||||
if (key!=null)
|
|
||||||
rc ^= key.hashCode();
|
|
||||||
if (value!=null)
|
|
||||||
rc ^= value.hashCode();
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
} // end 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()
|
final int getHits()
|
||||||
{
|
{
|
||||||
return hits;
|
return hits;
|
|
@ -15,7 +15,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
*/
|
*/
|
||||||
package com.silverwrist.util.cachemap;
|
package com.silverwrist.util.cache;
|
||||||
|
|
||||||
public interface CacheMapStrategy
|
public interface CacheMapStrategy
|
||||||
{
|
{
|
|
@ -19,7 +19,7 @@ package com.silverwrist.venice.core.impl;
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import com.silverwrist.util.cachemap.*;
|
import com.silverwrist.util.cache.CacheMap;
|
||||||
import com.silverwrist.venice.core.*;
|
import com.silverwrist.venice.core.*;
|
||||||
import com.silverwrist.venice.db.*;
|
import com.silverwrist.venice.db.*;
|
||||||
|
|
||||||
|
@ -38,12 +38,12 @@ class AdvertisementImpl implements Advertisement
|
||||||
*--------------------------------------------------------------------------------
|
*--------------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private DataPool datapool;
|
private DataPool datapool; // data pool reference
|
||||||
private int adid;
|
private int adid; // ad ID
|
||||||
private String imagepath;
|
private String imagepath; // image path
|
||||||
private short style;
|
private short style; // ad style
|
||||||
private String caption;
|
private String caption; // ad caption
|
||||||
private String linkurl;
|
private String linkurl; // ad link URL
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------------
|
||||||
* Constructor
|
* Constructor
|
||||||
|
|
|
@ -19,7 +19,7 @@ package com.silverwrist.venice.servlets.format;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import com.silverwrist.util.IOUtil;
|
import com.silverwrist.util.IOUtil;
|
||||||
import com.silverwrist.util.cachemap.CacheMap;
|
import com.silverwrist.util.cache.CacheMap;
|
||||||
|
|
||||||
public class StaticRender implements ContentRender
|
public class StaticRender implements ContentRender
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user