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

FIFOEJBObjectCache

public class FIFOEJBObjectCache extends LruCache implements EJBObjectCache
A FIFO EJB(Local)Object cache that maintains reference count
author
Mahesh Kannan

Fields Summary
protected int
maxCacheSize
protected String
name
protected EJBObjectCacheListener
listener
protected Object
refCountLock
protected int
totalRefCount
protected static boolean
_printRefCount
private static final Logger
_logger
Constructors Summary
public FIFOEJBObjectCache(String name)
default constructor

    
     
        
        try {
            Properties props = System.getProperties();
            _printRefCount = (Boolean.valueOf(props.getProperty
                ("cache.printrefcount"))).booleanValue();
        } catch (Exception ex) {
            _logger.log(Level.FINE, "Cache PrintRefCount property ex", ex);
        }
    
        this.name = name;
    
public FIFOEJBObjectCache(String name, long timeout)
constructor with specified timeout

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

        return new EJBObjectCacheItem(hashCode, key, value, size);
    
protected voiddecrementReferenceCount()

        synchronized (refCountLock) {
            totalRefCount--;
        }
    
protected voiddecrementReferenceCount(int count)

        synchronized (refCountLock) {
            totalRefCount -= count;
        }
    
public java.lang.Objectget(java.lang.Object key)

        int hashCode = hash(key);
        
        return internalGet(hashCode, key, false);
    
public java.lang.Objectget(java.lang.Object key, boolean incrementRefCount)

        int hashCode = hash(key);
        
        return internalGet(hashCode, key, incrementRefCount);
    
public java.util.MapgetStats()

        Map map = new HashMap();
        StringBuffer sbuf = new StringBuffer();
        
        sbuf.append("(totalRef=").append(totalRefCount).append("; ");
        
        sbuf.append("listSize=").append(listSize)
        .append("; curSize/totSize=").append(getEntryCount())
        .append("/").append(maxEntries)
        .append("; trim=").append(trimCount)
        .append("; remove=").append(removalCount)
        .append("; hit/miss=").append(hitCount).append("/").append(missCount)
        .append(")");
        map.put("["+name+"]", sbuf.toString());
        return map;
    
protected voidincrementReferenceCount()

        synchronized (refCountLock) {
            totalRefCount++;
        }
    
public voidinit(int maxEntries, int numberOfVictimsToSelect, long timeout, float loadFactor, java.util.Properties props)

        super.init(maxEntries, loadFactor, props);
        super.timeout = timeout;
        this.maxCacheSize = maxEntries;
        _logger.log(Level.FINE, name + ": FIFOEJBObject cache created....");
    
protected java.lang.ObjectinternalGet(int hashCode, java.lang.Object key, boolean incrementRefCount)

        
        int index = getIndex(hashCode);
        Object value = null;
        CacheItem item = null;
        
        synchronized (bucketLocks[index]) {
            item = buckets[index];
            
            for (; item != null; item = item.next) {
                if ( (hashCode == item.hashCode) && eq(key, item.key) ) {
                    break;
                }
            }
            
            // update the stats in line
            if (item != null) {
                value = item.getValue();
                if (incrementRefCount) {
                    EJBObjectCacheItem eoItem = (EJBObjectCacheItem) item;
                    eoItem.refCount++;
                    if (_printRefCount) {
                        incrementReferenceCount();
                    }
                    if (! eoItem.isTrimmed) {
                        itemRemoved(eoItem);
                    }
                }
            }
        }
        
        if (item != null)
            incrementHitCount();
        else
            incrementMissCount();
        
        return value;
    
protected java.lang.ObjectinternalPut(int hashCode, java.lang.Object key, java.lang.Object value, int size, boolean incrementRefCount)

        
        int index = getIndex(hashCode);
        
        CacheItem item, oldItem = null, overflow = null;
        EJBObjectCacheItem newItem = null;
        Object oldValue = null;
        int oldSize = 0;
        
        // lookup the item
        synchronized (bucketLocks[index]) {
            for (item = buckets[index]; item != null; item = item.next) {
                if ((hashCode == item.hashCode) && eq(key, item.key)) {
                    oldItem = item;
                    break;
                }
            }
            
            // if there was no item in the cache, insert the given item
            if (oldItem == null) {
                newItem = (EJBObjectCacheItem) 
                    createItem(hashCode, key, value, size);
                newItem.isTrimmed = incrementRefCount;
                
                // add the item at the head of the bucket list
                newItem.next = buckets[index];
                buckets[index] = newItem;
                
                if (incrementRefCount) {
                    newItem.refCount++;
                    if (_printRefCount) {
                        incrementReferenceCount();
                    }
                } else {
                    overflow = itemAdded(newItem);
                }
            } else {
                oldValue = oldItem.getValue();
                if (incrementRefCount) {
                    EJBObjectCacheItem oldEJBO = (EJBObjectCacheItem) oldItem;
                    oldEJBO.refCount++;
                    if (_printRefCount) {
                        incrementReferenceCount();
                    }
                }
            }
        }
        
        if (newItem != null) {
            incrementEntryCount();
            // make sure we are are not crossing the threshold
            if ((overflow != null) && (listener != null)) {
                listener.handleOverflow(overflow.key);
            }
        }
        
        return oldValue;
    
protected java.lang.ObjectinternalRemove(java.lang.Object key, boolean decrementRefCount)

        
        int hashCode = hash(key);
        int index = getIndex(hashCode);
        
        CacheItem prev = null, item = null;
        
        synchronized (bucketLocks[index]) {
            for (item = buckets[index]; item != null; item = item.next) {
                if (hashCode == item.hashCode && key.equals(item.key)) {
                    
                    EJBObjectCacheItem eoItem = (EJBObjectCacheItem) item;
                    if (decrementRefCount) {
                        if (eoItem.refCount > 0) {
                            eoItem.refCount--;
                            if (_printRefCount) {
                                decrementReferenceCount();
                            }
                        }
                    }
                    
                    if (eoItem.refCount > 0) {
                        return null;
                    }
                    
                    if (prev == null) {
                        buckets[index] = item.next;
                    } else  {
                        prev.next = item.next;
                    }
                    item.next = null;
                    
                    itemRemoved(item);
                    
                    break;
                    
                }
                prev = item;
            }
        }
        
        if (item != null) {
            decrementEntryCount();
            incrementRemovalCount();
            incrementHitCount();
            return item.value;
        } else {
            incrementMissCount();
            return null;
        }
        
    
protected booleanisThresholdReached()

        return listSize > maxCacheSize;
    
protected voiditemAccessed(CacheItem item)

 
protected voiditemRemoved(CacheItem item)

        LruCacheItem l = (LruCacheItem) item;
        
        // remove the item from the LRU list
        synchronized (this) {
            // if the item is already trimmed from the LRU list, nothing to do.
            if (l.isTrimmed) {
                return;
            }
            
            LruCacheItem prev = l.lPrev;
            LruCacheItem next = l.lNext;
            
            l.isTrimmed = true;
            
            // 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.lNext = l.lPrev = null;
            
            listSize--;
        }
    
public static voidmain(java.lang.String[] args)

        unitTest_1();
    
public voidprint()

        System.out.println("EJBObjectCache:: size: " + getEntryCount() + 
                           "; listSize: " + listSize);
        for (LruCacheItem run = head; run!=null; run=run.lNext) {
            System.out.print("("+run.key+", "+run.value+") ");
        }
        System.out.println();
    
public java.lang.Objectput(java.lang.Object key, java.lang.Object value)

        int hashCode = hash(key);
        
        return internalPut(hashCode, key, value, -1, false);
    
public java.lang.Objectput(java.lang.Object key, java.lang.Object value, boolean incrementRefCount)

        int hashCode = hash(key);
        
        return internalPut(hashCode, key, value, -1, incrementRefCount);
    
public java.lang.Objectremove(java.lang.Object key, boolean decrementRefCount)

        return internalRemove(key, decrementRefCount);
    
public java.lang.Objectremove(java.lang.Object key)

        return internalRemove(key, true);
    
public voidsetEJBObjectCacheListener(EJBObjectCacheListener listener)

        this.listener = listener;
    
public voidtrimExpiredEntries(int maxCount)

        
        int count = 0;
        LruCacheItem item, lastItem = null;
        long currentTime = System.currentTimeMillis();
        
        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;
                    lastItem = item;
                    
                    count++;
                } else {
                    break;
                }
            }
            
            // if there was at least one invalid item then item != tail.
            if (item != tail) {
                lastItem.lPrev = null;
                
                if (item != null)
                    item.lNext = null;
                else
                    head = null;
                
                lastItem = tail; // record the old tail
                tail = item;
            }
            listSize -= count;
            trimCount += count;
        }
        
        if (count > 0) {
            
            ArrayList localVictims = new ArrayList(count);
            // trim the items from the BaseCache from the old tail backwards
            for (item = lastItem; item != null; item = item.lPrev) {
                localVictims.add(item.key);
            }
            
            if (listener != null) {
                listener.handleBatchOverflow(localVictims);
            }
        }
    
static voidunitTest_1()

        
        FIFOEJBObjectCache cache = new FIFOEJBObjectCache("UnitTestCache");
        cache.init(512, 0, 0, (float)1.0, null);
        
        int maxCount = 14;
        ArrayList keys = new ArrayList();
        for (int i=0; i<maxCount; i++) {
            keys.add("K_"+i);
        }
        
        for (int i=0; i<maxCount; i++) {
            String key = (String) keys.get(i);
            System.out.println("****  put(" + key + ", " + key + ", i" + 
                               ((i%2) == 0) + ")");
            cache.put(key, key, ((i%2)==0));
        }
        
        System.out.println("***  Only odd numbered keys must be printed  ***");
        cache.print();
        System.out.println("************************************************");
        
        for (int i=0; i<maxCount; i++) {
            String key = (String) keys.get(i);
            cache.get(key, ((i%2)==1));
        }
        
        System.out.println("****  NONE SHOULD BE PRINTED ****");
        cache.print();
        System.out.println("************************************************");
        
        cache.put("K__15", "K__15", true);
        cache.put("K__16", "K__15", true);
        cache.get("K__16", true);   //K__16 has refCount == 2
        cache.put("K__17", "K__17");//K__17 has refCount == 0
        
        System.out.println("****  Only K__17 must be printed ****");
        cache.print();
        System.out.println("************************************************");
        
        for (int i=0; i<maxCount; i++) {
            String key = (String) keys.get(i);
            if (cache.remove(key) == null) {
                throw new RuntimeException("Remove must have returned null!!");
            }
        }
        
        Object k15 = cache.remove("K__15");
        Object k16_1 = cache.remove("K__16");
        Object k16_2 = cache.remove("K__16");
        Object k17 = cache.remove("K__17");
        
        if (k15 == null) {
            System.out.println("** FAILED for K_15");
        }
        
        if (k16_1 != null) {
            System.out.println("** FAILED for K_16_1");
        }
        
        if (k16_2 == null) {
            System.out.println("** FAILED for K_16_2");
        }
        
        if (k17 == null) {
            System.out.println("** FAILED for K_17");
        }
        
        // Now the list id completely empty, add some more items
        for (int i=0; i<maxCount; i+=2) {
            String key = (String) keys.get(i);
            cache.put(key, key, (i%4)==0);
        }
        cache.print();
        
        
        //Make the FIFO list empty
        for (int i=0; i<maxCount; i+=2) {
            String key = (String) keys.get(i);
            cache.get(key, true);
        }
        cache.print();
        
        // Now the FIFO list id completely empty, add some more items
        for (int i=1; i<maxCount; i+=2) {
            String key = (String) keys.get(i);
            cache.put(key, key, (i%9)==0);
        }
        cache.print();