FileDocCategorySizeDatePackage
ResourceCache.javaAPI DocApache Tomcat 6.0.1411535Fri Jul 20 04:20:32 BST 2007org.apache.naming.resources

ResourceCache

public class ResourceCache extends Object
Implements a special purpose cache.
author
Remy Maucherat
version
$Revision: 467222 $

Fields Summary
protected Random
random
Random generator used to determine elements to free.
protected CacheEntry[]
cache
Cache. Path -> Cache entry.
protected HashMap
notFoundCache
Not found cache.
protected int
cacheMaxSize
Max size of resources which will have their content cached.
protected int
maxAllocateIterations
Max amount of removals during a make space.
protected long
desiredEntryAccessRatio
Entry hit ratio at which an entry will never be removed from the cache. Compared with entry.access / hitsCount
protected int
spareNotFoundEntries
Spare amount of not found entries.
protected int
cacheSize
Current cache size in KB.
protected long
accessCount
Number of accesses to the cache.
protected long
hitsCount
Number of cache hits.
Constructors Summary
public ResourceCache()

    
Methods Summary
public booleanallocate(int space)


        int toFree = space - (cacheMaxSize - cacheSize);

        if (toFree <= 0) {
            return true;
        }

        // Increase the amount to free so that allocate won't have to run right
        // away again
        toFree += (cacheMaxSize / 20);

        int size = notFoundCache.size();
        if (size > spareNotFoundEntries) {
            notFoundCache.clear();
            cacheSize -= size;
            toFree -= size;
        }

        if (toFree <= 0) {
            return true;
        }

        int attempts = 0;
        int entriesFound = 0;
        long totalSpace = 0;
        int[] toRemove = new int[maxAllocateIterations];
        while (toFree > 0) {
            if (attempts == maxAllocateIterations) {
                // Give up, no changes are made to the current cache
                return false;
            }
            if (toFree > 0) {
                // Randomly select an entry in the array
                int entryPos = -1;
                boolean unique = false;
                while (!unique) {
                    unique = true;
                    entryPos = random.nextInt(cache.length) ;
                    // Guarantee uniqueness
                    for (int i = 0; i < entriesFound; i++) {
                        if (toRemove[i] == entryPos) {
                            unique = false;
                        }
                    }
                }
                long entryAccessRatio = 
                    ((cache[entryPos].accessCount * 100) / accessCount);
                if (entryAccessRatio < desiredEntryAccessRatio) {
                    toRemove[entriesFound] = entryPos;
                    totalSpace += cache[entryPos].size;
                    toFree -= cache[entryPos].size;
                    entriesFound++;
                }
            }
            attempts++;
        }

        // Now remove the selected entries
        java.util.Arrays.sort(toRemove, 0, entriesFound);
        CacheEntry[] newCache = new CacheEntry[cache.length - entriesFound];
        int pos = 0;
        int n = -1;
        if (entriesFound > 0) {
            n = toRemove[0];
            for (int i = 0; i < cache.length; i++) {
                if (i == n) {
                    if ((pos + 1) < entriesFound) {
                        n = toRemove[pos + 1];
                        pos++;
                    } else {
                        pos++;
                        n = -1;
                    }
                } else {
                    newCache[i - pos] = cache[i];
                }
            }
        }
        cache = newCache;
        cacheSize -= totalSpace;

        return true;

    
private static final intfind(CacheEntry[] map, java.lang.String name)
Find a map elemnt given its name in a sorted array of map elements. This will return the index for the closest inferior or equal item in the given array.


        int a = 0;
        int b = map.length - 1;

        // Special cases: -1 and 0
        if (b == -1) {
            return -1;
        }
        if (name.compareTo(map[0].name) < 0) {
            return -1;
        }
        if (b == 0) {
            return 0;
        }

        int i = 0;
        while (true) {
            i = (b + a) / 2;
            int result = name.compareTo(map[i].name);
            if (result > 0) {
                a = i;
            } else if (result == 0) {
                return i;
            } else {
                b = i;
            }
            if ((b - a) == 1) {
                int result2 = name.compareTo(map[b].name);
                if (result2 < 0) {
                    return a;
                } else {
                    return b;
                }
            }
        }

    
public longgetAccessCount()
Return the access count. Note: Update is not synced, so the number may not be completely accurate.



    // ------------------------------------------------------------- Properties


                           
       
        return accessCount;
    
public intgetCacheMaxSize()
Return the maximum size of the cache in KB.

        return cacheMaxSize;
    
public intgetCacheSize()
Return the current cache size in KB.

        return cacheSize;
    
public longgetDesiredEntryAccessRatio()
Return desired entry access ratio.

        return desiredEntryAccessRatio;
    
public longgetHitsCount()
Return the number of cache hits. Note: Update is not synced, so the number may not be completely accurate.

        return hitsCount;
    
public intgetMaxAllocateIterations()
Return the maximum amount of iterations during a space allocation.

        return maxAllocateIterations;
    
public intgetSpareNotFoundEntries()
Return the amount of spare not found entries.

        return spareNotFoundEntries;
    
private final booleaninsertCache(CacheEntry newElement)
Insert into the right place in a sorted MapElement array, and prevent duplicates.

        CacheEntry[] oldCache = cache;
        int pos = find(oldCache, newElement.name);
        if ((pos != -1) && (newElement.name.equals(oldCache[pos].name))) {
            return false;
        }
        CacheEntry[] newCache = new CacheEntry[cache.length + 1];
        System.arraycopy(oldCache, 0, newCache, 0, pos + 1);
        newCache[pos + 1] = newElement;
        System.arraycopy
            (oldCache, pos + 1, newCache, pos + 2, oldCache.length - pos - 1);
        cache = newCache;
        return true;
    
public voidload(CacheEntry entry)

        if (entry.exists) {
            if (insertCache(entry)) {
                cacheSize += entry.size;
            }
        } else {
            int sizeIncrement = (notFoundCache.get(entry.name) == null) ? 1 : 0;
            notFoundCache.put(entry.name, entry);
            cacheSize += sizeIncrement;
        }
    
public CacheEntrylookup(java.lang.String name)


        CacheEntry cacheEntry = null;
        CacheEntry[] currentCache = cache;
        accessCount++;
        int pos = find(currentCache, name);
        if ((pos != -1) && (name.equals(currentCache[pos].name))) {
            cacheEntry = currentCache[pos];
        }
        if (cacheEntry == null) {
            try {
                cacheEntry = (CacheEntry) notFoundCache.get(name);
            } catch (Exception e) {
                // Ignore: the reliability of this lookup is not critical
            }
        }
        if (cacheEntry != null) {
            hitsCount++;
        }
        return cacheEntry;

    
private final CacheEntryremoveCache(java.lang.String name)
Insert into the right place in a sorted MapElement array.

        CacheEntry[] oldCache = cache;
        int pos = find(oldCache, name);
        if ((pos != -1) && (name.equals(oldCache[pos].name))) {
            CacheEntry[] newCache = new CacheEntry[cache.length - 1];
            System.arraycopy(oldCache, 0, newCache, 0, pos);
            System.arraycopy(oldCache, pos + 1, newCache, pos, 
                             oldCache.length - pos - 1);
            cache = newCache;
            return oldCache[pos];
        }
        return null;
    
public voidsetCacheMaxSize(int cacheMaxSize)
Set the maximum size of the cache in KB.

        this.cacheMaxSize = cacheMaxSize;
    
public voidsetDesiredEntryAccessRatio(long desiredEntryAccessRatio)
Set the desired entry access ratio.

        this.desiredEntryAccessRatio = desiredEntryAccessRatio;
    
public voidsetMaxAllocateIterations(int maxAllocateIterations)
Set the maximum amount of iterations during a space allocation.

        this.maxAllocateIterations = maxAllocateIterations;
    
public voidsetSpareNotFoundEntries(int spareNotFoundEntries)
Set the amount of spare not found entries.

        this.spareNotFoundEntries = spareNotFoundEntries;
    
public booleanunload(java.lang.String name)

        CacheEntry removedEntry = removeCache(name);
        if (removedEntry != null) {
            cacheSize -= removedEntry.size;
            return true;
        } else if (notFoundCache.remove(name) != null) {
            cacheSize--;
            return true;
        }
        return false;