second round of cache cleanups - got rid of that bogus pile of monkey spew

that was ReferenceCache, replaced it with the much cleaner ObjectCache (it
uses SoftReferences so that the "sweep" operation is pretty much automatic)
This commit is contained in:
Eric J. Bowersox
2001-11-15 00:30:24 +00:00
parent e290ce2a8c
commit 0437cc7b92
21 changed files with 536 additions and 595 deletions

View File

@@ -0,0 +1,195 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.util.cache;
import java.lang.ref.*;
import java.util.*;
/**
* A chache which stores objects by key value, and is capable of creating them given an instance of
* <CODE>ObjectFactory</CODE> to do the creating. The cache uses <CODE>SoftReferences</CODE> which can
* automatically be removed by the garbage collector if necessary.
*
* @author Eric J. Bowersox &lt;erbo@silcom.com&gt;
* @version X
* @see ObjectFactory
* @see java.lang.ref.SoftReference
*/
public class ObjectCache
{
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private HashMap the_data = new HashMap(); // the actual underlying map
private ObjectFactory factory; // used to create new objects
private ReferenceQueue rq = new ReferenceQueue(); // where our references go when they die
private ArrayList sweeper = new ArrayList(); // temporary used in doing sweeps
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
/**
* Creates a new <CODE>ObjectCache</CODE>.
*
* @param factory The factory object used to create new objects when <CODE>getOrCreate</CODE> is called.
* @exception java.lang.NullPointerException The object factory passed in is <CODE>null</CODE>.
*/
public ObjectCache(ObjectFactory factory)
{
if (factory==null)
throw new NullPointerException("object factory cannot be null!");
this.factory = factory;
} // end constructor
/*--------------------------------------------------------------------------------
* Internal operations
*--------------------------------------------------------------------------------
*/
/**
* "Sweeps" the cache by taking all references that have been cleared and queued by the garbage
* collector and removing them from the map. Should be called fairly often, to minimize wasted
* hashmap slots.
*/
private synchronized void doSweep()
{
Set entries = the_data.entrySet(); // used to find entries with the specified value
Reference r = rq.poll(); // reference that's been cleared
Iterator it;
while (r!=null)
{ // look for this reference in our hash map
it = entries.iterator();
while (it.hasNext())
{ // look for the map entry containing the reference
Map.Entry ntry = (Map.Entry)(it.next());
if (r==(Reference)(ntry.getValue()))
{ // found the entry with this reference - nuke it
sweeper.add(ntry.getKey());
break; // don't need to take this loop any farther
} // end if
} // end while
r = rq.poll(); // get the next cleared reference
} // end while
if (sweeper.isEmpty())
return; // no entries to remove
// Remove all the corresponding keys from the hashmap.
it = sweeper.iterator();
while (it.hasNext())
the_data.remove(it.next());
sweeper.clear(); // reset for next time
} // end doSweep
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
/**
* Retrieves an object from the cache.
*
* @param key The key value of the object to look up.
* @return The corresponding object value, or <CODE>null</CODE> if that object isn't in the cache.
*/
public synchronized Object get(Object key)
{
doSweep();
SoftReference r = (SoftReference)(the_data.get(key));
return ((r==null) ? null : r.get());
} // end get
/**
* Retrieves an object from the cache, creating it if it doesn't already exist.
*
* @param key The key value of the object to look up or create.
* @return The corresponding object value.
* @exception com.silverwrist.util.cache.ObjectFactoryException If an exception occurred while creating
* a new object.
* @see ObjectFactory#newObject(java.lang.Object)
*/
public synchronized Object getOrCreate(Object key) throws ObjectFactoryException
{
doSweep();
SoftReference r = (SoftReference)(the_data.get(key));
Object rc = ((r==null) ? null : r.get());
if (rc==null)
{ // attempt to create a new object
rc = factory.newObject(key);
if (rc!=null)
{ // clear the old reference, throw it away, and put in a new one
if (r!=null)
r.clear();
r = new SoftReference(rc,rq);
the_data.put(key,r);
} // end if
} // end if
return rc;
} // end getOrCreate
/**
* Registers a newly-created object with the cache.
*
* @param key The key value to register this object with.
* @param data The object to be registered.
* @exception com.silverwrist.util.cache.ObjectCacheException If an object with that key value already
* exists in the cache.
*/
public synchronized void register(Object key, Object data)
{
doSweep();
SoftReference old = (SoftReference)(the_data.get(key));
if ((old!=null) && (old.get()!=null))
throw new ObjectCacheException("object already in cache",key);
the_data.put(key,new SoftReference(data,rq));
if (old!=null)
old.clear();
} // end register
/**
* Detaches an object from the cache.
*
* @param key Key value of the object to be detached.
*/
public synchronized void detach(Object key)
{
doSweep();
SoftReference old = (SoftReference)(the_data.remove(key));
if (old!=null)
old.clear();
} // end detach
} // end class ObjectCache

View File

@@ -15,23 +15,37 @@
*
* Contributor(s):
*/
package com.silverwrist.util.rcache;
package com.silverwrist.util.cache;
public class ReferenceCacheException extends RuntimeException
/**
* An exception thrown by the <CODE>ObjectCache</CODE> in unusual circumstances. The main reason why this
* exception would be thrown is if some code tried to register an object that was already in the cache.
*
* @author Eric J. Bowersox &lt;erbo@silcom.com&gt;
* @version X
* @see ObjectCache#register(java.lang.Object,java.lang.Object)
*/
public class ObjectCacheException extends RuntimeException
{
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private Object keyval;
private Object keyval; // key value
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
public ReferenceCacheException(String msg, Object keyval)
/**
* Constructs a new <CODE>ObjectCacheException</CODE>.
*
* @param msg The message to include with this exception.
* @param keyval The key value of the object that caused this exception to be generated.
*/
public ObjectCacheException(String msg, Object keyval)
{
super("[keyval " + keyval.toString() + "]: " + msg);
this.keyval = keyval;
@@ -43,10 +57,15 @@ public class ReferenceCacheException extends RuntimeException
*--------------------------------------------------------------------------------
*/
/**
* Returns the key value of the object that caused this exception to be generated.
*
* @return The key value of the object that caused this exception to be generated.
*/
public Object getKeyVal()
{
return keyval;
} // end getKeyVal
} // end class ReferenceCacheException
} // end class ObjectClassException

View File

@@ -0,0 +1,41 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.util.cache;
/**
* An interface which is used by <CODE>ObjectCache</CODE> to create new objects which match a specified
* key. An instance of an object implementing this interface must be specified to the constructor
* of <CODE>ObjectFactory</CODE>.
*
* @see ObjectCache#Constructor(com.silverwrist.util.cache.ObjectFactory)
* @see ObjectCache#getOrCreate(java.lang.Object)
*/
public interface ObjectFactory
{
/**
* Creates a new instance of an object for the object cache.
*
* @param key The key value of the new object to be created.
* @return The new object instance.
* @exception com.silverwrist.util.cache.ObjectFactoryException An exception was thrown by the
* constructors and/or methods called by <CODE>newObject</CODE>; it is wrapped in this exception.
* @see ObjectCache#getOrCreate(java.lang.Object)
*/
public abstract Object newObject(Object key) throws ObjectFactoryException;
} // end interface ObjectFactory

View File

@@ -0,0 +1,126 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.util.cache;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* The exception which may be thrown by <CODE>ObjectFactory.newObject</CODE>, which wraps any exception
* that might be thrown by constructors or other method calls within the method.
*
* @author Eric J. Bowersox &lt;erbo@silcom.com&gt;
* @version X
* @see ObjectFactory#newObject(java.lang.Object)
*/
public class ObjectFactoryException extends Exception
{
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private Throwable inner = null; // internal "root cause" exception
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
/**
* Creates a new <CODE>ObjectFactoryException</CODE>.
*
* @param t Exception being wrapped by this one.
*/
public ObjectFactoryException(Throwable t)
{
super("Error creating new object: " + t.getMessage());
inner = t;
} // end constructor
/*--------------------------------------------------------------------------------
* Overrides from class Throwable
*--------------------------------------------------------------------------------
*/
/**
* Prints this exception and its backtrace to the standard error stream. Also prints the backtrace
* of any "wrapped" exception.
*
* @see java.lang.System#err
*/
public void printStackTrace()
{
this.printStackTrace(System.err);
} // end printStackTrace
/**
* Prints this exception and its backtrace to the specified <CODE>PrintStream</CODE>. Also prints the
* backtrace of any "wrapped" exception.
*
* @param s <CODE>PrintStream</CODE> to use for output.
*/
public void printStackTrace(PrintStream s)
{
super.printStackTrace(s);
if (inner!=null)
{ // print the inner stack trace
s.print("Root cause: ");
inner.printStackTrace(s);
} // end if
} // end printStackTrace
/**
* Prints this exception and its backtrace to the specified <CODE>PrintWriter</CODE>. Also prints the
* backtrace of any "wrapped" exception.
*
* @param s <CODE>PrintWriter</CODE> to use for output.
*/
public void printStackTrace(PrintWriter s)
{
super.printStackTrace(s);
if (inner!=null)
{ // print the inner stack trace
s.print("Root cause: ");
inner.printStackTrace(s);
} // end if
} // end printStackTrace
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
/**
* Returns the exception wrapped by this exception, or <CODE>null</CODE> if there is none.
*
* @return See above.
*/
public Throwable getException()
{
return inner;
} // end getException
} // end class ObjectFactoryException

View File

@@ -1,161 +0,0 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.util.rcache;
import java.util.*;
public class ReferenceCache
{
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private HashMap the_data;
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
public ReferenceCache()
{
the_data = new HashMap();
} // end constructor
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
public synchronized ReferencedData get(Object key)
{
ReferencedData rc = (ReferencedData)(the_data.get(key));
if (rc!=null)
rc.rd_addRef();
return rc;
} // end get
public synchronized ReferencedData getOrCreate(Object key, ReferencedDataBuilder builder)
throws ReferencedDataBuilderException
{
ReferencedData rc = (ReferencedData)(the_data.get(key));
if (rc==null)
{ // use the builder to build one
rc = builder.build(key);
if (rc!=null)
the_data.put(key,rc);
} // end if
else // just add a reference
rc.rd_addRef();
return rc;
} // end getOrCreate
public void register(ReferencedData data)
{
Object key = data.rd_getKey();
synchronized (this)
{ // see if it's in the cache, if not, add it
if (the_data.get(key)!=null)
throw new ReferenceCacheException("object already in cache",key);
// dump it in the object cache
the_data.put(key,data);
} // end synchronized block
} // end register
public synchronized void detach(Object key)
{
the_data.remove(key);
} // end detach
public void sweep()
{
int count = 0;
synchronized (this)
{ // bail out early if possible
if (the_data.size()==0)
return;
// provide a storage bin for all keys we decide to 86
Object keyzap[] = new Object[the_data.size()];
Iterator it = the_data.values().iterator();
while (it.hasNext())
{ // check each value we contain in turn
ReferencedData rd = (ReferencedData)(it.next());
if (rd.rd_unreferenced())
keyzap[count++] = rd.rd_getKey();
} // end while
for (int i=0; i<count; i++)
the_data.remove(keyzap[i]);
} // end synchronized block
} // end sweep
public List sweepReturn()
{
ArrayList rc = new ArrayList();
int count = 0;
synchronized (this)
{ // bail out early if possible
if (the_data.size()>0)
{ // provide a storage bin for all keys we decide to 86
Object keyzap[] = new Object[the_data.size()];
Iterator it = the_data.values().iterator();
while (it.hasNext())
{ // check each value we contain in turn
ReferencedData rd = (ReferencedData)(it.next());
if (rd.rd_unreferenced())
keyzap[count++] = rd.rd_getKey();
else
{ // add another reference and tack it onto the list
rd.rd_addRef();
rc.add(rd);
} // end else
} // end while
for (int i=0; i<count; i++)
the_data.remove(keyzap[i]);
} // end if
} // end synchronized block
return Collections.unmodifiableList(rc);
} // end sweepReturn
} // end ReferenceCache

View File

@@ -1,30 +0,0 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.util.rcache;
public interface ReferencedData
{
public abstract int rd_addRef();
public abstract int rd_release();
public abstract boolean rd_unreferenced();
public abstract Object rd_getKey();
} // end interface ReferencedData

View File

@@ -1,24 +0,0 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.util.rcache;
public interface ReferencedDataBuilder
{
public abstract ReferencedData build(Object key) throws ReferencedDataBuilderException;
} // end interface ReferencedDataBuilder

View File

@@ -1,52 +0,0 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.util.rcache;
public class ReferencedDataBuilderException extends Exception
{
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private Exception target;
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
public ReferencedDataBuilderException(Exception target)
{
super("Error building new object: " + target.getMessage());
this.target = target;
} // end constructor
/*--------------------------------------------------------------------------------
* External operations
*--------------------------------------------------------------------------------
*/
public Exception getTarget()
{
return target;
} // end getTarget
} // end class ReferencedDataBuilderException