FileDocCategorySizeDatePackage
LruCache.javaAPI DocGlassfish v2 API11154Fri May 04 22:33:00 BST 2007com.sun.ejb.containers.util.cache

LruCache

public class LruCache extends BaseCache
LRUCache in-memory bounded cache with an LRU list

Fields Summary
protected static final Logger
_logger
protected String
cacheName
public static final long
NO_TIMEOUT
protected LruCacheItem
head
protected LruCacheItem
tail
protected int
trimCount
protected int
listSize
protected long
timeout
Constructors Summary
public LruCache()
default constructor


           
       
public LruCache(long timeout)
constructor with specified timeout

        this.timeout = timeout;
    
Methods Summary
protected CacheItemcreateItem(int hashCode, java.lang.Object key, java.lang.Object value, int size)
create new item

param
hashCode for the entry
param
key Object key
param
value Object value
param
size size in bytes of the item subclasses may override to provide their own CacheItem extensions e.g. one that permits persistence.

        return new LruCacheItem(hashCode, key, value, size);
    
public java.lang.ObjectgetStatByName(java.lang.String key)
get the desired statistic counter

param
key to corresponding stat
return
an Object corresponding to the stat See also: Constant.java for the key

        Object stat = super.getStatByName(key);

        if (stat == null && key != null) {
            if (key.equals(Constants.STAT_LRUCACHE_LIST_LENGTH))
                stat = new Integer(listSize);
            else if (key.equals(Constants.STAT_LRUCACHE_TRIM_COUNT))
                stat = new Integer(trimCount);
        }
        return stat;
    
public java.util.MapgetStats()

        Map stats = super.getStats();
        stats.put(Constants.STAT_LRUCACHE_LIST_LENGTH, new Integer(listSize));
        stats.put(Constants.STAT_LRUCACHE_TRIM_COUNT, new Integer(trimCount));

        return stats;
    
protected voiditemAccessed(CacheItem item)
this item is accessed

param
item CacheItem accessed Cache bucket is already synchronized by the caller

        LruCacheItem lc = (LruCacheItem) item;

        synchronized (this) {

            // if the item is already trimmed from the LRU list, nothing to do.
            if (lc.isTrimmed)
                return;

            // update the timestamp
            lc.lastAccessed = System.currentTimeMillis();

            LruCacheItem prev = lc.lPrev;
            LruCacheItem next = lc.lNext;

            // update the LRU list
            if (prev != null) {
                // put the item at the head of LRU list
                lc.lPrev = null;
                lc.lNext = head;
                head.lPrev = lc;
                head = lc;
    
                // patch up the previous neighbors
                prev.lNext = next;
                if (next != null)
                    next.lPrev = prev;
                else
                    tail = prev;
           }
        }
    
protected CacheItemitemAdded(CacheItem item)
/** this item is just added to the cache

param
item CacheItem that was created
return
a overflow item; may be null this function checks if adding the new item results in a overflow; if so, it returns the item to be removed. Cache bucket is already synchronized by the caller

        CacheItem overflow = null;
        LruCacheItem lc = (LruCacheItem) item;

        // set the timestamp
        lc.lastAccessed = System.currentTimeMillis();

        // update the LRU
        synchronized (this) {
            if (head != null) {
                head.lPrev = lc;
                lc.lNext = head;
		lc.lPrev = null;
		head = lc;
            }
            else {
                head = tail = lc;
		lc.lPrev = lc.lNext = null;
            }

            listSize++;

            if ( isThresholdReached() ) {
                overflow = trimLru(lc.lastAccessed);
            }
        }

        return overflow;
    
protected voiditemRefreshed(CacheItem item, int oldSize)
item value has been refreshed

param
item CacheItem that was refreshed
param
oldSize size of the previous value that was refreshed Cache bucket is already synchronized by the caller

        itemAccessed(item);   
    
protected voiditemRemoved(CacheItem item)
item value has been removed from the cache

param
item CacheItem that was just removed Cache bucket is already synchronized by the caller

        LruCacheItem l = (LruCacheItem) item;

        // remove the item from the LRU list
        synchronized (this) {
            LruCacheItem prev = l.lPrev;
            LruCacheItem next = l.lNext;

            // if the item is already trimmed from the LRU list, nothing to do.
            if (l.isTrimmed)
                return;

            // patch up the neighbors and make sure head/tail are correct
            if (prev != null)
                prev.lNext = next;
            else
                head = next;

            if (next != null)
                next.lPrev = prev;
            else
                tail = prev;

	    l.lPrev = l.lNext = null;
            listSize--;
        }
    
public voidsetCacheName(java.lang.String name)

        this.cacheName = name;
    
public voidtrimExpiredEntries(int maxCount)
trim the expired entries from the cache.

param
maxCount maximum number of invalid entries to trim specify Integer.MAX_VALUE to trim all invalid entries This call is to be scheduled by a thread managed by the container. NOTE: this algorithm assumes that all the entries in the cache have identical timeout (otherwise traversing from tail won't be right).

        
        int count = 0;
        LruCacheItem item;
        long currentTime = System.currentTimeMillis();
	ArrayList list = new ArrayList();

        synchronized (this) {
            // traverse LRU list till we reach a valid item; 
            // remove them at once
            for (item = tail; item != null && count < maxCount;
                 item = item.lPrev) {

                if ( (timeout != NO_TIMEOUT) && 
                     ((item.lastAccessed + timeout) <= currentTime) ) {
                    item.isTrimmed = true;
		    list.add(item);

                    count++;
                } else {
                    break;
                }
            }

            // if there was at least one invalid item then item != tail.
            if (item != tail) {
                if (item != null)
                    item.lNext = null;
                else
                    head = null;

                tail = item;
            }
            listSize -= count;
            trimCount += count;
        }
        
        // trim the items from the BaseCache from the old tail backwards
        for (int index=list.size()-1; index >= 0; index--) {
            trimItem((LruCacheItem) list.get(index));
        }
    
protected CacheItemtrimLru(long currentTime)
trim one item from the LRU list

param
currentTime of this operation
return
the item trimmed from cache list synchronization is handled by the caller


        LruCacheItem trimItem = tail;

        if (tail != head) {
            tail = trimItem.lPrev;
            if (tail == null) {
                _logger.log(Level.WARNING, 
                    "[" + cacheName + "]: trimLru(), resetting head and tail");
                // do not let the tail go past the head
                tail = head = null;
            } else {
                tail.lNext = null;
            }
        } else {
            tail = head = null;
        }
        
        if (trimItem != null) {
            trimItem.isTrimmed = true;
            trimItem.lPrev = null;
            trimCount++;
            listSize--;
        }

        return trimItem;