asmuts 02/01/14 22:41:16
Added: src/java/org/apache/stratum/jcs/engine/memory/lru
LRUMemoryCache.java
Log:
The default memory manager -- a LRU double linked list
I moved this out of the hub today. It looks fine.
Other algorithms could be used. It just makes a simple callback tot he hub to spoll
items to disk. This could be made more general to give the memory manager control of
the hub it we wanted.
Revision Changes Path
1.1
jakarta-turbine-stratum/src/java/org/apache/stratum/jcs/engine/memory/lru/LRUMemoryCache.java
Index: LRUMemoryCache.java
===================================================================
package org.apache.stratum.jcs.engine.memory.lru;
import java.io.*;
import java.util.*;
import org.apache.stratum.jcs.access.*;
import org.apache.stratum.jcs.access.behavior.*;
import org.apache.stratum.jcs.access.exception.*;
import org.apache.stratum.jcs.auxiliary.behavior.*;
import org.apache.stratum.jcs.auxiliary.disk.*;
import org.apache.stratum.jcs.engine.*;
import org.apache.stratum.jcs.engine.behavior.*;
import org.apache.stratum.jcs.engine.control.*;
import org.apache.stratum.jcs.engine.memory.*;
import org.apache.stratum.jcs.engine.memory.behavior.*;
import org.apache.stratum.jcs.utils.log.*;
/////////////////////////////////////////////////////
public class LRUMemoryCache implements IMemoryCache, ICache, Serializable {
private final static boolean debugcmd = false;//true;
// removal
private final static boolean debugR = false;//true;
// MOVE TO MEMORYMANAGER
String cacheName;
protected Map map = new Hashtable();
// LRU double linked list
private MemoryElementDescriptor first;
private MemoryElementDescriptor last;
private int max;
// Region Elemental Attributes
public Attributes attr;
// Cache Attributes
public ICompositeCacheAttributes cattr;
private String source_id =
"org.apache.stratum.jcs.engine.memory.lru.LRUMemoryCache";
// need to convert to log4j
final static protected Logger log = LoggerManager.getLogger(LRUMemoryCache.class);
// The HUB
ICacheHub hub;
// status
private int status = this.STATUS_ERROR;
////////////////////////////////////////////////////////////////////
// for reflection
public LRUMemoryCache ( ) {
// might want to consider this an error state
status = this.STATUS_ERROR;
}
// should use this method
public LRUMemoryCache ( String cacheName, ICompositeCacheAttributes cattr,
ICacheHub hub ) {
initialize( cacheName, cattr, hub );
}
// for post reflection creation initialization
public void initialize( String cacheName, ICompositeCacheAttributes cattr,
ICacheHub hub ) {
this.cacheName = cacheName;
this.cattr = cattr;
this.max = cattr.getMaxObjects();
this.hub = hub;
status = this.STATUS_ALIVE;
}
///////////////////////////////////////////////////
public Serializable getSourceId() {
return this.source_id;
}
public int getCacheType(){
return ICacheType.MEMORY_CACHE;
}
/**
* Puts an item to the cache.
*/
public void update(ICacheElement ce) throws IOException {
// asynchronisly create a MemoryElement
addFirst( ce );
MemoryElementDescriptor old = (MemoryElementDescriptor)map.put(ce.getKey(),
first);
if (first.equals(old)) {
// the same as an existing item.
removeNode(old);
}
// need to spool at a certain percentage synchronously
if (map.size() < this.cattr.getMaxObjects() ) {
return;
} else {
// SPOOL LAST -- need to make this a grouping in a queue
if ( debugcmd ) {
p("IN RAM overflow");
}
// write the last item to disk.
try {
// Might want to rename this "overflow" incase the hub
// wants to do somethign else.
hub.spoolToDisk( last.ce );
} catch(Exception ex) {
// impossible case.
ex.printStackTrace();
throw new IllegalStateException(ex.getMessage());
}
if ( log.logLevel >= log.DEBUG ) {
log.debug( "update: Request to put " + last.ce.getKey() + " on disk cache");
}
}
// if no disk cache is configured, these elements are lost
if (map.size() > this.cattr.getMaxObjects() ) {
// Remove the last item from memory.
map.remove(last.ce.getKey());
removeNode(last);
}
} // end update
// TODO: Implement or modify interface, just implement
// may need insert if we want to distinguish b/wn put and replace
public void put(Serializable key, Serializable val) throws IOException {
// not used
}
public void put(Serializable key, Serializable val, Attributes attr ) throws
IOException {
// not used
}
/**
* Gets an item from the cache.
*/
public Serializable get(Serializable key) throws IOException {
return get( key, true );
}
public Serializable get(Serializable key, boolean container ) throws IOException {
MemoryElementDescriptor me = null;
ICacheElement ce = null;
boolean found = false;
try{
if( log.logLevel >= log.DEBUG ) {
log.debug("get> key="+key);
log.debug("get> key="+key.toString());
}
me = (MemoryElementDescriptor)map.get(key);
if( log.logLevel >= log.DEBUG ) {
log.debug("me =" + me );
}
if ( me == null ) {
} else {
found = true;
ce = me.ce;
//ramHit++;
if ( log.logLevel >= log.DEBUG ) {
log.debug( cacheName + " -- RAM-HIT for " + key );
}
}
} catch( Exception e ) {
log.error( e );
}
try {
if ( !found ) {
// Item not found in all caches.
//miss++;
if ( log.logLevel >= log.DEBUG ) {
log.debug( cacheName + " -- MISS for " + key );
}
return null;
//throw new ObjectNotFoundException( key + " not found in cache" );
}
} catch( Exception e ) {
log.error( e, "Error handling miss" );
return null;
}
try {
makeFirst(me);
} catch( Exception e ) {
log.error( e, "Error making first" );
return null;
}
if ( container ) {
return ce;
} else {
return ce.getVal();
}
} // end get
/** Removes an item from the cache. */
public boolean remove(Serializable key) throws IOException {
if( log.logLevel >= log.DEBUG ) {
log.debug("remove> key="+key ); //+, nonLocal="+nonLocal);
}
//p("remove> key="+key+", nonLocal="+nonLocal);
boolean removed=false;
// handle partial removal
if (key instanceof String && key.toString().endsWith(NAME_COMPONENT_DELIMITER)) {
// remove all keys of the same name hierarchy.
synchronized(map) {
for (Iterator itr = map.entrySet().iterator(); itr.hasNext();) {
Map.Entry entry = (Map.Entry)itr.next();
Object k = entry.getKey();
if (k instanceof String && k.toString().startsWith(key.toString())) {
itr.remove();
removeNode((MemoryElementDescriptor)entry.getValue());
removed = true;
}
}
}
}
else {
// remove single item.
MemoryElementDescriptor ce = (MemoryElementDescriptor)map.remove(key);
if (ce != null) {
removeNode(ce);
removed = true;
}
} // end else not hierarchical removal
return removed;
}
/** Removes all cached items from the cache. */
public void removeAll() throws IOException {
map = new HashMap();
}
/** Prepares for shutdown. */
public void dispose() throws IOException {
}
/** Returns the cache statistics. */
public String getStats() {
return "";
}
/** Returns the current cache size. */
public int getSize() {
return this.map.size();
}
/** Returns the cache status. */
public int getStatus() {
return this.status;
//return this.STATUS_ALIVE;
}
/** Returns the cache name. */
public String getCacheName() {
return this.cattr.getCacheName();
}
///////////////////////////////////////////////
public Iterator getIterator( ) {
//return Collections.enumeration(map.entrySet());
return map.entrySet().iterator();
}
// ////////////////////////////////////////////
// public synchronized void moveToMemory( ICacheElement ce ) {
//
// if ( debugcmd ) {
// p( "moveToMemory> key=" + ce.getKey() );
// }
// if ( log.logLevel >= log.DEBUG ) {
// StringBuffer params = new StringBuffer();
// params.append( "moveToMemory> key=" + ce.getKey() + ", val=" + ce.getVal() );
// params.append( "createTime = " + ce.getCreateTime() );
// log.debug( params.toString() );
// }
//
// // asynchronisly create a MemoryElement
// addFirst( ce );
// MemoryElementDescriptor old = (MemoryElementDescriptor)map.put(
first.ce.getKey(), first);
//
// if (first.equals(old)) {
// // the same as an existing item.
// removeNode(old);
// }
//
// // This may be too slow. Makes sense though. Why not jsut use update then?
// //makeFirst( ce );
//
// if (map.size() < this.cattr.getMaxObjects() ) {
// return;
// } else {
// hub.spoolToDisk( last.ce );
// // Remove the last item from memory.
// map.remove(last.ce.getKey());
// removeNode(last);
// }
//
// return;
//
// } // end moveToMemroy with auxilary member
/////////////////////////////////////////////////////////////////////
// internal mehods
/** Removes the specified node from the link list. */
private void removeNode(MemoryElementDescriptor me) {
if ( debugR ) {
p( "removing node " + me.ce.getKey() );
}
if (me.next == null) {
if (me.prev == null) {
// the only node.
first = last = null;
}
else {
// last but not the first.
last = me.prev;
last.next = null;
me.prev = null;
}
}
else if (me.prev == null) {
// first but not the last.
first = me.next;
first.prev = null;
me.next = null;
}
else {
// neither the first nor the last.
me.prev.next = me.next;
me.next.prev = me.prev;
me.prev = me.next = null;
}
}
/**
* Adds a new node to the end of the link list.
* Currently not used.
*/
private void addLast( CacheElement ce ) {
MemoryElementDescriptor me = new MemoryElementDescriptor(ce);
if (first == null) {
// empty list.
first = me;
}
else {
last.next = me;
me.prev = last;
}
last = me;
return;
}
/** Adds a new node to the start of the link list. */
private void addFirst( ICacheElement ce ) {
MemoryElementDescriptor me = new MemoryElementDescriptor(ce);
if (last == null) {
// empty list.
last = me;
}
else {
first.prev = me;
me.next = first;
}
first = me;
return;
}
/** Moves an existing node to the start of the link list. */
public synchronized void makeFirst( ICacheElement ce) {
makeFirst( new MemoryElementDescriptor(ce) );
}
/** Moves an existing node to the start of the link list. */
public synchronized void makeFirst( MemoryElementDescriptor me) {
// MemoryElementDescriptor me = new MemoryElementDescriptor(ce);
try {
if (me.prev == null) {
// already the first node.
return;
}
me.prev.next = me.next;
if (me.next == null) {
// last but not the first.
last = me.prev;
last.next = null;
}
else {
// neither the last nor the first.
me.next.prev = me.prev;
}
first.prev = me;
me.next = first;
me.prev = null;
first = me;
} catch( Exception e ) {
log.error( e, "Couldn't make first" );
}
return;
}
/** Dump the cache map for debugging. */
public void dumpMap() {
log.debug("dumpingMap");
for (Iterator itr=map.entrySet().iterator(); itr.hasNext();) {
//for ( Iterator itr = memCache.getIterator(); itr.hasNext();) {
Map.Entry e = (Map.Entry)itr.next();
MemoryElementDescriptor me = (MemoryElementDescriptor)e.getValue();
log.debug("dumpMap> key="+e.getKey()+", val="+me.ce.getVal());
}
}
/** Dump the cache entries from first to list for debugging. */
public void dumpCacheEntries() {
log.debug("dumpingCacheEntries");
for (MemoryElementDescriptor me=first; me != null; me=me.next) {
log.debug("dumpCacheEntries> key="+me.ce.getKey()+", val="+me.ce.getVal());
}
}
///////////////////////////////////////////////////
public static void p( String s ) {
System.out.println( "LRUMemoryCache: " + s );
}
} // end LRUMemoryCache
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>