Introduce helma.objectmodel.ObjectCache interface for switchable cache implementations.
This commit is contained in:
parent
f2180bfa81
commit
59bec76b45
6 changed files with 286 additions and 146 deletions
|
@ -274,7 +274,9 @@ public final class Application implements IPathElement, Runnable {
|
||||||
* Get the application ready to run, initializing the evaluators and type manager.
|
* Get the application ready to run, initializing the evaluators and type manager.
|
||||||
*/
|
*/
|
||||||
public synchronized void init()
|
public synchronized void init()
|
||||||
throws DatabaseException, ScriptingException, MalformedURLException {
|
throws DatabaseException, MalformedURLException,
|
||||||
|
IllegalAccessException, InstantiationException,
|
||||||
|
ClassNotFoundException {
|
||||||
|
|
||||||
// create and init type mananger
|
// create and init type mananger
|
||||||
typemgr = new TypeManager(this);
|
typemgr = new TypeManager(this);
|
||||||
|
|
108
src/helma/objectmodel/ObjectCache.java
Normal file
108
src/helma/objectmodel/ObjectCache.java
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.objectmodel;
|
||||||
|
|
||||||
|
import helma.framework.core.Application;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface Helma object cache classes need to implement.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ObjectCache {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link helma.framework.core.Application Application} instance
|
||||||
|
* for the cache.
|
||||||
|
* @param app the app instance
|
||||||
|
*/
|
||||||
|
void init(Application app);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the application's properties have been updated to let
|
||||||
|
* the cache implementation update its settings.
|
||||||
|
* @param props
|
||||||
|
*/
|
||||||
|
void updateProperties(Properties props);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the collection contains an element for the key.
|
||||||
|
*
|
||||||
|
* @param key the key that we are looking for
|
||||||
|
*/
|
||||||
|
boolean containsKey(Object key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of keys in object array <code>keys</code> that
|
||||||
|
* were not found in the Map.
|
||||||
|
* Those keys that are contained in the Map are nulled out in the array.
|
||||||
|
* @param keys an array of key objects we are looking for
|
||||||
|
* @see ObjectCache#containsKey
|
||||||
|
*/
|
||||||
|
int containsKeys(Object[] keys);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the object associated with the specified key in the
|
||||||
|
* hashtable.
|
||||||
|
* @param key the specified key
|
||||||
|
* @return the element for the key or null if the key
|
||||||
|
* is not defined in the hash table.
|
||||||
|
* @see ObjectCache#put
|
||||||
|
*/
|
||||||
|
Object get(Object key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts the specified element into the hashtable, using the specified
|
||||||
|
* key. The element may be retrieved by doing a get() with the same key.
|
||||||
|
* The key and the element cannot be null.
|
||||||
|
* @param key the specified key in the hashtable
|
||||||
|
* @param value the specified element
|
||||||
|
* @exception NullPointerException If the value of the element
|
||||||
|
* is equal to null.
|
||||||
|
* @see ObjectCache#get
|
||||||
|
* @return the old value of the key, or null if it did not have one.
|
||||||
|
*/
|
||||||
|
Object put(Object key, Object value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the element corresponding to the key. Does nothing if the
|
||||||
|
* key is not present.
|
||||||
|
* @param key the key that needs to be removed
|
||||||
|
* @return the value of key, or null if the key was not found.
|
||||||
|
*/
|
||||||
|
Object remove(Object key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all items currently stored in the cache.
|
||||||
|
*
|
||||||
|
* @return true if the operation succeeded
|
||||||
|
*/
|
||||||
|
boolean clear();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the number of objects currently stored in the cache.
|
||||||
|
* @return the number of cached items
|
||||||
|
*/
|
||||||
|
int size();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array with all objects currently contained in the cache.
|
||||||
|
*/
|
||||||
|
Object[] getCachedObjects();
|
||||||
|
|
||||||
|
}
|
|
@ -542,6 +542,15 @@ public final class Node implements INode, Serializable {
|
||||||
return dbmap;
|
return dbmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param nmgr
|
||||||
|
*/
|
||||||
|
public void setWrappedNodeManager(WrappedNodeManager nmgr) {
|
||||||
|
this.nmgr = nmgr;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
|
|
@ -35,7 +35,7 @@ import java.util.*;
|
||||||
public final class NodeManager {
|
public final class NodeManager {
|
||||||
|
|
||||||
protected Application app;
|
protected Application app;
|
||||||
private CacheMap cache;
|
private ObjectCache cache;
|
||||||
private Replicator replicator;
|
private Replicator replicator;
|
||||||
protected IDatabase db;
|
protected IDatabase db;
|
||||||
protected IDGenerator idgen;
|
protected IDGenerator idgen;
|
||||||
|
@ -51,22 +51,17 @@ public final class NodeManager {
|
||||||
* created in dbHome if one doesn't already exist.
|
* created in dbHome if one doesn't already exist.
|
||||||
*/
|
*/
|
||||||
public NodeManager(Application app, String dbHome, Properties props)
|
public NodeManager(Application app, String dbHome, Properties props)
|
||||||
throws DatabaseException {
|
throws DatabaseException, ClassNotFoundException,
|
||||||
|
IllegalAccessException, InstantiationException {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
|
|
||||||
int cacheSize = Integer.parseInt(props.getProperty("cachesize", "1000"));
|
String cacheImpl = props.getProperty("cacheimpl", "helma.util.CacheMap");
|
||||||
|
|
||||||
// Make actual cache size bigger, since we use it only up to the threshold
|
cache = (ObjectCache) Class.forName(cacheImpl).newInstance();
|
||||||
// cache = new CacheMap ((int) Math.ceil (cacheSize/0.75f), 0.75f);
|
cache.init(app);
|
||||||
cache = new CacheMap(cacheSize, 0.75f);
|
|
||||||
cache.setApplication(app);
|
|
||||||
if (cacheSize != 1000) {
|
|
||||||
app.logEvent("Setting cache size for "+app.getName()+" to " + cacheSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
safe = new WrappedNodeManager(this);
|
safe = new WrappedNodeManager(this);
|
||||||
|
|
||||||
// nullNode = new Node ();
|
|
||||||
logSql = "true".equalsIgnoreCase(props.getProperty("logsql"));
|
logSql = "true".equalsIgnoreCase(props.getProperty("logsql"));
|
||||||
logReplication = "true".equalsIgnoreCase(props.getProperty("logReplication"));
|
logReplication = "true".equalsIgnoreCase(props.getProperty("logReplication"));
|
||||||
|
|
||||||
|
@ -102,9 +97,8 @@ public final class NodeManager {
|
||||||
* app.properties file has been updated. Reread some settings.
|
* app.properties file has been updated. Reread some settings.
|
||||||
*/
|
*/
|
||||||
public void updateProperties(Properties props) {
|
public void updateProperties(Properties props) {
|
||||||
int cacheSize = Integer.parseInt(props.getProperty("cachesize", "1000"));
|
// notify the cache about the properties update
|
||||||
|
cache.updateProperties(props);
|
||||||
cache.setCapacity(cacheSize);
|
|
||||||
logSql = "true".equalsIgnoreCase(props.getProperty("logsql"));
|
logSql = "true".equalsIgnoreCase(props.getProperty("logsql"));
|
||||||
logReplication = "true".equalsIgnoreCase(props.getProperty("logReplication"));
|
logReplication = "true".equalsIgnoreCase(props.getProperty("logReplication"));
|
||||||
}
|
}
|
||||||
|
@ -1788,7 +1782,7 @@ public final class NodeManager {
|
||||||
* Get an array of the the keys currently held in the object cache
|
* Get an array of the the keys currently held in the object cache
|
||||||
*/
|
*/
|
||||||
public Object[] getCacheEntries() {
|
public Object[] getCacheEntries() {
|
||||||
return cache.getEntryArray();
|
return cache.getCachedObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -241,11 +241,13 @@ public class Transactor extends Thread {
|
||||||
int nstate = node.getState();
|
int nstate = node.getState();
|
||||||
|
|
||||||
if (nstate == Node.NEW) {
|
if (nstate == Node.NEW) {
|
||||||
nmgr.registerNode(node); // register node with nodemanager cache
|
|
||||||
nmgr.insertNode(nmgr.db, txn, node);
|
nmgr.insertNode(nmgr.db, txn, node);
|
||||||
dirtyDbMappings.add(node.getDbMapping());
|
dirtyDbMappings.add(node.getDbMapping());
|
||||||
node.setState(Node.CLEAN);
|
node.setState(Node.CLEAN);
|
||||||
|
|
||||||
|
// register node with nodemanager cache
|
||||||
|
nmgr.registerNode(node);
|
||||||
|
|
||||||
if (replicator != null) {
|
if (replicator != null) {
|
||||||
replicator.addNewNode(node);
|
replicator.addNewNode(node);
|
||||||
}
|
}
|
||||||
|
@ -260,6 +262,9 @@ public class Transactor extends Thread {
|
||||||
}
|
}
|
||||||
node.setState(Node.CLEAN);
|
node.setState(Node.CLEAN);
|
||||||
|
|
||||||
|
// update node with nodemanager cache
|
||||||
|
nmgr.registerNode(node);
|
||||||
|
|
||||||
if (replicator != null) {
|
if (replicator != null) {
|
||||||
replicator.addModifiedNode(node);
|
replicator.addModifiedNode(node);
|
||||||
}
|
}
|
||||||
|
@ -270,6 +275,8 @@ public class Transactor extends Thread {
|
||||||
} else if (nstate == Node.DELETED) {
|
} else if (nstate == Node.DELETED) {
|
||||||
nmgr.deleteNode(nmgr.db, txn, node);
|
nmgr.deleteNode(nmgr.db, txn, node);
|
||||||
dirtyDbMappings.add(node.getDbMapping());
|
dirtyDbMappings.add(node.getDbMapping());
|
||||||
|
|
||||||
|
// remove node from nodemanager cache
|
||||||
nmgr.evictNode(node);
|
nmgr.evictNode(node);
|
||||||
|
|
||||||
if (replicator != null) {
|
if (replicator != null) {
|
||||||
|
|
|
@ -30,7 +30,10 @@
|
||||||
package helma.util;
|
package helma.util;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
import helma.framework.core.Application;
|
import helma.framework.core.Application;
|
||||||
|
import helma.objectmodel.ObjectCache;
|
||||||
|
|
||||||
|
|
||||||
/// A Hashtable that expires least-recently-used objects.
|
/// A Hashtable that expires least-recently-used objects.
|
||||||
|
@ -44,7 +47,7 @@ import helma.framework.core.Application;
|
||||||
// <P>
|
// <P>
|
||||||
// @see java.util.Hashtable
|
// @see java.util.Hashtable
|
||||||
|
|
||||||
public class CacheMap {
|
public class CacheMap implements ObjectCache {
|
||||||
|
|
||||||
// Load factor.
|
// Load factor.
|
||||||
private float loadFactor;
|
private float loadFactor;
|
||||||
|
@ -62,6 +65,14 @@ public class CacheMap {
|
||||||
// the application to output messages to
|
// the application to output messages to
|
||||||
private Application app = null;
|
private Application app = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zero argument constructor. Creates a CacheMap with capacity of 1000
|
||||||
|
* and load factor 0.75
|
||||||
|
*/
|
||||||
|
public CacheMap() {
|
||||||
|
this(1000, 0.75f);
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs a new, empty hashtable with the specified initial
|
/// Constructs a new, empty hashtable with the specified initial
|
||||||
// capacity and the specified load factor.
|
// capacity and the specified load factor.
|
||||||
// Unlike a plain Hashtable, an LruHashtable will never grow or
|
// Unlike a plain Hashtable, an LruHashtable will never grow or
|
||||||
|
@ -73,25 +84,25 @@ public class CacheMap {
|
||||||
// is less than or equal to zero.
|
// is less than or equal to zero.
|
||||||
// @exception IllegalArgumentException If the load factor is
|
// @exception IllegalArgumentException If the load factor is
|
||||||
// less than or equal to zero.
|
// less than or equal to zero.
|
||||||
public CacheMap (int initialCapacity, float loadFactor) {
|
public CacheMap(int initialCapacity, float loadFactor) {
|
||||||
// We have to call a superclass constructor, but we're not actually
|
// We have to call a superclass constructor, but we're not actually
|
||||||
// going to use it at all. The only reason we want to extend Hashtable
|
// going to use it at all. The only reason we want to extend Hashtable
|
||||||
// is for type conformance. So, make a parent hash table of minimum
|
// is for type conformance. So, make a parent hash table of minimum
|
||||||
// size and then ignore it.
|
// size and then ignore it.
|
||||||
if ( initialCapacity <= 0 || loadFactor <= 0.0 )
|
if (initialCapacity <= 0 || loadFactor <= 0.0)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
this.loadFactor = loadFactor;
|
this.loadFactor = loadFactor;
|
||||||
// table rotation threshold: we allow each table to gain
|
// table rotation threshold: we allow each table to gain
|
||||||
// initialCapacity/2 entries.
|
// initialCapacity/2 entries.
|
||||||
threshold = initialCapacity / 2;
|
threshold = initialCapacity / 2;
|
||||||
// We deliberately choose the initial capacity of tables large
|
// We deliberately choose the initial capacity of tables large
|
||||||
// enough that it can hold threshold entries without being rehashed,
|
// enough that it can hold threshold entries without being rehashed,
|
||||||
// in other words, make sure our threshold for table rotation is lower
|
// in other words, make sure our threshold for table rotation is lower
|
||||||
// than that of the underlying HashMap for table rehashing.
|
// than that of the underlying HashMap for table rehashing.
|
||||||
eachCapacity = (int) (threshold / loadFactor) + 2;
|
eachCapacity = (int) (threshold / loadFactor) + 2;
|
||||||
// create tables
|
// create tables
|
||||||
oldTable = new HashMap ();
|
oldTable = new HashMap();
|
||||||
newTable = new HashMap (eachCapacity, loadFactor);
|
newTable = new HashMap(eachCapacity, loadFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new, empty hashtable with the specified initial
|
/// Constructs a new, empty hashtable with the specified initial
|
||||||
|
@ -99,41 +110,41 @@ public class CacheMap {
|
||||||
// Unlike a plain Hashtable, an LruHashtable will never grow or
|
// Unlike a plain Hashtable, an LruHashtable will never grow or
|
||||||
// shrink from this initial capacity.
|
// shrink from this initial capacity.
|
||||||
// @param initialCapacity the initial number of buckets
|
// @param initialCapacity the initial number of buckets
|
||||||
public CacheMap (int initialCapacity) {
|
public CacheMap(int initialCapacity) {
|
||||||
this (initialCapacity, 0.75F);
|
this(initialCapacity, 0.75F);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of elements contained in the hashtable.
|
/// Returns the number of elements contained in the hashtable.
|
||||||
public int size() {
|
public int size() {
|
||||||
return newTable.size() + oldTable.size();
|
return newTable.size() + oldTable.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the hashtable contains no elements.
|
/// Returns true if the hashtable contains no elements.
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return size() == 0;
|
return size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Set the capacity of the CacheMap
|
/// Set the capacity of the CacheMap
|
||||||
public void setCapacity(int capacity) {
|
public void setCapacity(int capacity) {
|
||||||
// table rotation threshold: we allow each table to gain
|
// table rotation threshold: we allow each table to gain
|
||||||
// initialCapacity/2 entries.
|
// initialCapacity/2 entries.
|
||||||
int newThreshold = capacity / 2;
|
int newThreshold = capacity / 2;
|
||||||
if (newThreshold != threshold) {
|
if (newThreshold != threshold) {
|
||||||
if (app != null)
|
if (app != null)
|
||||||
app.logEvent ("Setting cache capacity to "+capacity);
|
app.logEvent("Setting cache capacity to " + capacity);
|
||||||
updateThreshold (newThreshold);
|
updateThreshold(newThreshold);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void updateThreshold (int newThreshold) {
|
private synchronized void updateThreshold(int newThreshold) {
|
||||||
threshold = newThreshold;
|
threshold = newThreshold;
|
||||||
eachCapacity = (int) (threshold / loadFactor) + 2;
|
eachCapacity = (int) (threshold / loadFactor) + 2;
|
||||||
// if newtable is larger than threshold, rotate.
|
// if newtable is larger than threshold, rotate.
|
||||||
if (newTable.size() > threshold) {
|
if (newTable.size() > threshold) {
|
||||||
oldTable = newTable;
|
oldTable = newTable;
|
||||||
newTable = new HashMap (eachCapacity, loadFactor);
|
newTable = new HashMap(eachCapacity, loadFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the specified object is an element of the hashtable.
|
/// Returns true if the specified object is an element of the hashtable.
|
||||||
|
@ -142,35 +153,35 @@ public class CacheMap {
|
||||||
// @exception NullPointerException If the value being searched
|
// @exception NullPointerException If the value being searched
|
||||||
// for is equal to null.
|
// for is equal to null.
|
||||||
// @see LruHashtable#containsKey
|
// @see LruHashtable#containsKey
|
||||||
public synchronized boolean containsValue (Object value) {
|
public synchronized boolean containsValue(Object value) {
|
||||||
if (newTable.containsValue (value))
|
if (newTable.containsValue(value))
|
||||||
return true;
|
return true;
|
||||||
if (oldTable.containsValue (value)) {
|
if (oldTable.containsValue(value)) {
|
||||||
// We would like to move the object from the old table to the
|
// We would like to move the object from the old table to the
|
||||||
// new table. However, we need keys to re-add the objects, and
|
// new table. However, we need keys to re-add the objects, and
|
||||||
// there's no good way to find all the keys for the given object.
|
// there's no good way to find all the keys for the given object.
|
||||||
// We'd have to enumerate through all the keys and check each
|
// We'd have to enumerate through all the keys and check each
|
||||||
// one. Yuck. For now we just punt. Anyway, contains() is
|
// one. Yuck. For now we just punt. Anyway, contains() is
|
||||||
// probably not a commonly-used operation.
|
// probably not a commonly-used operation.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the collection contains an element for the key.
|
/// Returns true if the collection contains an element for the key.
|
||||||
// @param key the key that we are looking for
|
// @param key the key that we are looking for
|
||||||
// @see LruHashtable#contains
|
// @see LruHashtable#contains
|
||||||
public synchronized boolean containsKey (Object key) {
|
public synchronized boolean containsKey(Object key) {
|
||||||
if (newTable.containsKey(key))
|
if (newTable.containsKey(key))
|
||||||
return true;
|
return true;
|
||||||
if (oldTable.containsKey (key)) {
|
if (oldTable.containsKey(key)) {
|
||||||
// Move object from old table to new table.
|
// Move object from old table to new table.
|
||||||
Object value = oldTable.get (key);
|
Object value = oldTable.get(key);
|
||||||
newTable.put (key, value);
|
newTable.put(key, value);
|
||||||
oldTable.remove (key);
|
oldTable.remove(key);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of keys in object array <code>keys</code> that
|
/// Returns the number of keys in object array <code>keys</code> that
|
||||||
|
@ -178,21 +189,21 @@ public class CacheMap {
|
||||||
// Those keys that are contained in the Map are nulled out in the array.
|
// Those keys that are contained in the Map are nulled out in the array.
|
||||||
// @param keys an array of key objects we are looking for
|
// @param keys an array of key objects we are looking for
|
||||||
// @see LruHashtable#contains
|
// @see LruHashtable#contains
|
||||||
public synchronized int containsKeys (Object[] keys) {
|
public synchronized int containsKeys(Object[] keys) {
|
||||||
int notfound = 0;
|
int notfound = 0;
|
||||||
for (int i=0; i<keys.length; i++) {
|
for (int i = 0; i < keys.length; i++) {
|
||||||
if (newTable.containsKey(keys[i]))
|
if (newTable.containsKey(keys[i]))
|
||||||
keys[i] = null;
|
keys[i] = null;
|
||||||
else if (oldTable.containsKey (keys[i])) {
|
else if (oldTable.containsKey(keys[i])) {
|
||||||
// Move object from old table to new table.
|
// Move object from old table to new table.
|
||||||
Object value = oldTable.get (keys[i]);
|
Object value = oldTable.get(keys[i]);
|
||||||
newTable.put (keys[i], value);
|
newTable.put(keys[i], value);
|
||||||
oldTable.remove (keys[i]);
|
oldTable.remove(keys[i]);
|
||||||
keys[i] = null;
|
keys[i] = null;
|
||||||
} else
|
} else
|
||||||
notfound++;
|
notfound++;
|
||||||
}
|
}
|
||||||
return notfound;
|
return notfound;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the object associated with the specified key in the
|
/// Gets the object associated with the specified key in the
|
||||||
|
@ -201,19 +212,19 @@ public class CacheMap {
|
||||||
// @returns the element for the key or null if the key
|
// @returns the element for the key or null if the key
|
||||||
// is not defined in the hash table.
|
// is not defined in the hash table.
|
||||||
// @see LruHashtable#put
|
// @see LruHashtable#put
|
||||||
public synchronized Object get (Object key) {
|
public synchronized Object get(Object key) {
|
||||||
Object value;
|
Object value;
|
||||||
value = newTable.get (key);
|
value = newTable.get(key);
|
||||||
if (value != null)
|
if (value != null)
|
||||||
return value;
|
return value;
|
||||||
value = oldTable.get (key);
|
value = oldTable.get(key);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
// Move object from old table to new table.
|
// Move object from old table to new table.
|
||||||
newTable.put (key, value);
|
newTable.put(key, value);
|
||||||
oldTable.remove (key);
|
oldTable.remove(key);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Puts the specified element into the hashtable, using the specified
|
/// Puts the specified element into the hashtable, using the specified
|
||||||
|
@ -225,60 +236,69 @@ public class CacheMap {
|
||||||
// is equal to null.
|
// is equal to null.
|
||||||
// @see LruHashtable#get
|
// @see LruHashtable#get
|
||||||
// @return the old value of the key, or null if it did not have one.
|
// @return the old value of the key, or null if it did not have one.
|
||||||
public synchronized Object put (Object key, Object value) {
|
public synchronized Object put(Object key, Object value) {
|
||||||
|
|
||||||
Object oldValue = newTable.put (key, value);
|
Object oldValue = newTable.put(key, value);
|
||||||
if (oldValue != null)
|
if (oldValue != null)
|
||||||
return oldValue;
|
return oldValue;
|
||||||
oldValue = oldTable.get (key);
|
oldValue = oldTable.get(key);
|
||||||
if (oldValue != null)
|
if (oldValue != null)
|
||||||
oldTable.remove( key );
|
oldTable.remove(key);
|
||||||
// we put a key into newtable that wasn't there before. check if it
|
// we put a key into newtable that wasn't there before. check if it
|
||||||
// grew beyond the threshold
|
// grew beyond the threshold
|
||||||
if (newTable.size() >= threshold) {
|
if (newTable.size() >= threshold) {
|
||||||
// Rotate the tables.
|
// Rotate the tables.
|
||||||
if (app != null)
|
if (app != null)
|
||||||
app.logEvent ("Rotating Cache tables at "+newTable.size()+
|
app.logEvent("Rotating Cache tables at " + newTable.size() +
|
||||||
"/"+oldTable.size()+" (new/old)");
|
"/" + oldTable.size() + " (new/old)");
|
||||||
oldTable = newTable;
|
oldTable = newTable;
|
||||||
newTable = new HashMap (eachCapacity, loadFactor);
|
newTable = new HashMap(eachCapacity, loadFactor);
|
||||||
}
|
}
|
||||||
return oldValue;
|
return oldValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the element corresponding to the key. Does nothing if the
|
/// Removes the element corresponding to the key. Does nothing if the
|
||||||
// key is not present.
|
// key is not present.
|
||||||
// @param key the key that needs to be removed
|
// @param key the key that needs to be removed
|
||||||
// @return the value of key, or null if the key was not found.
|
// @return the value of key, or null if the key was not found.
|
||||||
public synchronized Object remove (Object key) {
|
public synchronized Object remove(Object key) {
|
||||||
Object oldValue = newTable.remove (key);
|
Object oldValue = newTable.remove(key);
|
||||||
if (oldValue == null)
|
if (oldValue == null)
|
||||||
oldValue = oldTable.remove (key);
|
oldValue = oldTable.remove(key);
|
||||||
return oldValue;
|
return oldValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clears the hash table so that it has no more elements in it.
|
/// Clears the hash table so that it has no more elements in it.
|
||||||
public synchronized void clear() {
|
public synchronized boolean clear() {
|
||||||
newTable.clear ();
|
newTable.clear();
|
||||||
oldTable.clear ();
|
oldTable.clear();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the application to use for debug and profiling output
|
/// Set the application to use for debug and profiling output
|
||||||
public void setApplication (Application app) {
|
public void init(Application app) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
|
int cacheSize = Integer.parseInt(app.getProperty("cachesize", "1000"));
|
||||||
|
setCapacity(cacheSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Object[] getEntryArray () {
|
/// The app properties have been modified, reload settings
|
||||||
Object[] k1 = newTable.keySet().toArray();
|
public void updateProperties(Properties props) {
|
||||||
Object[] k2 = oldTable.keySet().toArray();
|
int cacheSize = Integer.parseInt(props.getProperty("cachesize", "1000"));
|
||||||
Object[] k = new Object[k1.length+k2.length];
|
setCapacity(cacheSize);
|
||||||
System.arraycopy (k1, 0, k, 0, k1.length);
|
|
||||||
System.arraycopy (k2, 0, k, k1.length, k2.length);
|
|
||||||
return k;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString () {
|
public synchronized Object[] getCachedObjects() {
|
||||||
return newTable.toString () + oldTable.toString () + hashCode ();
|
Object[] k1 = newTable.keySet().toArray();
|
||||||
|
Object[] k2 = oldTable.keySet().toArray();
|
||||||
|
Object[] k = new Object[k1.length + k2.length];
|
||||||
|
System.arraycopy(k1, 0, k, 0, k1.length);
|
||||||
|
System.arraycopy(k2, 0, k, k1.length, k2.length);
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return newTable.toString() + oldTable.toString() + hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue