FileDocCategorySizeDatePackage
FileCache.javaAPI DocGlassfish v2 API22981Wed Jun 06 08:17:08 BST 2007com.sun.enterprise.web.connector.grizzly

FileCache

public class FileCache extends Object
This class implements a file caching mechanism used to cache static resources.
author
Jeanfrancois Arcand
author
Scott Oaks

Fields Summary
public static final String
DEFAULT_SERVLET_NAME
private final ConcurrentHashMap
fileCache
A ByteBuffer cache of static pages.
private static final ByteBuffer
nullByteBuffer
A dummy instance of ByteBuffer
protected static final ByteBuffer
connectionCloseBB
A connection: close of ByteBuffer
protected static final ByteBuffer
connectionKaBB
A connection: keep-alive of ByteBuffer
private static final String
NEWLINE
HTTP end line.
public static final String
OK
HTTP OK header
private int
port
The port associated with this cache.
private ScheduledThreadPoolExecutor
cacheResourcesThread
Scheduled Thread that clean the cache every XX seconds.
private ConcurrentLinkedQueue
cacheManager
FileCacheEntry cache
private int
secondsMaxAge
Timeout before remove the static resource from the cache.
private int
maxCacheEntries
The maximum entries in the fileCache
private long
minEntrySize
The maximum size of a cached resources.
private long
maxEntrySize
The maximum size of a cached resources.
private long
maxLargeFileCacheSize
The maximum memory mapped bytes
private long
maxSmallFileCacheSize
The maximum cached bytes
private static long
mappedMemorySize
The current cache size in bytes
private static long
heapSize
The current cache size in bytes
private boolean
isEnabled
Is the file cache enabled.
private boolean
isLargeFileCacheEnabled
Is the large FileCache enabled.
private static boolean
isMonitoringEnabled
Is monitoring enabled.
private int
openCacheEntries
The number of current open cache entries
private int
maxOpenCacheEntries
The number of max current open cache entries
private long
maxHeapCacheSize
Max heap space used for cache
private long
maxMappedMemory
Max mapped memory used for cache
private int
countHits
Number of cache lookup hits
private int
countMisses
Number of cache lookup misses
private int
countCacheHits
Number of hits on cached file info
private int
countCacheMisses
Number of misses on cached file info
private int
countMappedHits
Number of hits on cached file info
private int
countMappedMisses
Number of misses on cached file info
private int
headerBBSize
The Header ByteBuffer default size.
Constructors Summary
Methods Summary
public synchronized voidadd(java.lang.String mappedServlet, java.lang.String baseDir, java.lang.String requestURI, org.apache.tomcat.util.http.MimeHeaders headers, boolean xPoweredBy)
Add a resource to the cache. Currently, only static resources served by the DefaultServlet can be cached.


    // ---------------------------------------------------- Methods ----------//
             
            
                          
           
                 
        
        if ( fileCache.get(requestURI) != null) return;
        
        // cache is full.
        if ( fileCache.size() > maxCacheEntries) {
            return;
        }
        
        if ( mappedServlet.equals(DEFAULT_SERVLET_NAME) ){                                     
            File file = new File(baseDir + requestURI);
            ByteBuffer bb = mapFile(file);

            // Always put the answer into the map. If it's null, then
            // we know that it doesn't fit into the cache, so there's no
            // reason to go through this code again.
            if (bb == null)
                bb = nullByteBuffer;
            
            FileCacheEntry entry = cacheManager.poll();
            if ( entry == null){
                entry = new FileCacheEntry();
            }
            entry.bb = bb;
            entry.requestURI = requestURI;
            
            if ( bb != nullByteBuffer){
                entry.lastModified = headers.getHeader("Last-Modified");
                entry.contentType = headers.getHeader("content-type");
                entry.xPoweredBy = xPoweredBy;
                entry.isInHeap = (file.length() < minEntrySize);
                entry.date = headers.getHeader("Date");
                entry.Etag = headers.getHeader("Etag");

                configHeaders(entry);

                if ( isMonitoringEnabled ) {
                    openCacheEntries++;   

                    if ( openCacheEntries > maxOpenCacheEntries){
                        maxOpenCacheEntries = openCacheEntries;
                    }

                    if ( heapSize > maxHeapCacheSize){
                        maxHeapCacheSize = heapSize;
                    }

                    if ( mappedMemorySize > maxMappedMemory){
                        maxMappedMemory = mappedMemorySize;
                    }
                }

                if ( secondsMaxAge > 0 ) {
                    entry.future = cacheResourcesThread.schedule(entry, 
                                                secondsMaxAge, TimeUnit.SECONDS);
                }
            }
            fileCache.put(requestURI,entry);
        }            
    
private voidappendHeaderValue(java.lang.StringBuffer sb, java.lang.String name, java.lang.String value)
Utility to add headers to the HTTP response.

        sb.append(name);
        sb.append(": ");
        sb.append(value);
        sb.append(NEWLINE);
    
private voidconfigHeaders(com.sun.enterprise.web.connector.grizzly.FileCache$FileCacheEntry entry)
Return a ByteBuffer contains the server header.

        if ( entry.headerBuffer == null ) {
            entry.headerBuffer = 
                    ByteBuffer.allocate(getHeaderBBSize());
        }
        
        StringBuffer sb = new StringBuffer();
        sb.append(OK);
        if ( entry.xPoweredBy){
            appendHeaderValue(sb,"X-Powered-By", "Servlet/2.5");
        }     
        appendHeaderValue(sb, "ETag", entry.Etag);   
        appendHeaderValue(sb,"Last-Modified", entry.lastModified);
        appendHeaderValue(sb,"Content-Type", entry.contentType);
        appendHeaderValue(sb,"Content-Length", entry.bb.capacity() + "");
        appendHeaderValue(sb,"Date", entry.date);
        appendHeaderValue(sb,"Server", SelectorThread.SERVER_NAME);
        entry.headerBuffer.put(sb.toString().getBytes());
        entry.headerBuffer.flip();
    
public java.util.concurrent.ConcurrentHashMapgetCache()
Return the FileCache

        return fileCache;
    
public longgetCountContentHits()
Return the Number of hits on cached file content

return
hits on cache file content

        return countMappedHits;
    
public intgetCountContentMisses()
Return the Number of misses on cached file content

return
missed on cached file content

        return countMappedMisses;
    
public longgetCountEntries()
Return the number of current cache entries.

return
current cache entries

        return fileCache.size();
    
public longgetCountHits()
Return the Number of cache lookup hits

return
cache hits

        return countHits;
    
public longgetCountInfoHits()
The Number of hits on cached file info

return
hits on cached file info

        return countCacheHits;
    
public longgetCountInfoMisses()
Return the number of misses on cached file info

return
misses on cache file info

        return countCacheMisses;
    
public longgetCountMisses()
Return the Number of cache lookup misses

return
cache misses

        return countMisses;
    
public longgetCountOpenEntries()
The number of current open cache entries

return
open cache entries

        return openCacheEntries;
    
public intgetFlagEnabled()
Returns flag indicating whether file cache has been enabled

return
1 if file cache has been enabled, 0 otherwise

        return (isEnabled == true?1:0);
    
public intgetHeaderBBSize()
Retunr the header size buffer.

        return headerBBSize;
    
public booleangetLargeFileCacheEnabled()
Is the large file cache support enabled.

        return isLargeFileCacheEnabled;
    
public intgetMaxCacheEntries()
Return the maximum entries this cache can contains.

        return maxCacheEntries;
    
public longgetMaxEntries()
Return the maximum number of cache entries

return
maximum cache entries

        return maxCacheEntries;
    
public longgetMaxEntrySize()
Get the maximum size a FileCacheEntry can have.

        return maxEntrySize;
    
public longgetMaxHeapCacheSize()
Return the maximum heap space used for cache

return
maximum heap size

        return maxHeapCacheSize;
    
public longgetMaxLargeCacheSize()
Get the maximum cache size

        return maxLargeFileCacheSize;
    
public longgetMaxMmapCacheSize()
Return the Maximum Memory Map size to be used for caching

return
maximum Memory Map size

        return maxMappedMemory;
    
public longgetMaxOpenEntries()
Return the maximum number of open cache entries

return
maximum open cache entries

       return maxOpenCacheEntries;        
    
public longgetMaxSmallCacheSize()
Get the maximum cache size

        return maxSmallFileCacheSize;
    
public longgetMinEntrySize()
Get the maximum size a FileCacheEntry can have.

        return minEntrySize;
    
public intgetSecondsMaxAge()
Return the maximum age of a valid cache entry

return
cache entry maximum age

        return secondsMaxAge;
    
public longgetSizeHeapCache()
Return the heap space used for cache

return
heap size

        return heapSize;
    
public static longgetSizeMmapCache()
Return the size of Mapped memory used for caching

return
Mapped memory size

        return mappedMemorySize;
    
public booleanisEnabled()
Is the fileCache enabled.

        return isEnabled;
    
private final com.sun.enterprise.web.connector.grizzly.FileCache$FileCacheEntrymap(byte[] requestBytes, int start, int length)
Return true if the file is cached.

        String uri = "";
        FileCacheEntry entry = null;
        
        if ( !fileCache.isEmpty() ){
            uri = new String(requestBytes,start,length);
            entry = fileCache.get(uri);
            
            if ( isMonitoringEnabled) {
                if (entry != null && entry.bb != null 
                        && entry.bb != nullByteBuffer){
                    if ( entry.isInHeap ) 
                        countCacheHits++;
                    else
                        countMappedHits++;

                    countHits++;
                
                } else {
                  countMisses++;
                }
            }
        }
        return entry;
    
private final java.nio.ByteBuffermapFile(java.io.File file)
Map the file to a ByteBuffer

return
the ByteBuffer

        FileChannel fileChannel = null;
        FileInputStream stream = null;
        try {
            stream = new FileInputStream(file);
            fileChannel = stream.getChannel();
             
            long size = fileChannel.size();
            
            if ( !isLargeFileCacheEnabled ) {
                // Large file support are not enabled
                if ( size > minEntrySize ) {
                    return null;
                }
            } else if ( size > maxEntrySize){
                return null;
            }

            if ( size > minEntrySize )
                mappedMemorySize+= size;
            else
                heapSize+= size;
 
            // Cache full
            if ( mappedMemorySize > maxLargeFileCacheSize ) {
                mappedMemorySize-= size;
                return null;
            } else  if ( heapSize > maxSmallFileCacheSize ) {
                heapSize-= size;
                return null;
            }        
            
            ByteBuffer bb = 
                    fileChannel.map(FileChannel.MapMode.READ_ONLY,0,size);
                                 
            if ( size < minEntrySize) {
                ((MappedByteBuffer)bb).load();
            }
            return bb;
        } catch (IOException ioe) {
            return null;
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException ioe) {
                }
            }
            if (fileChannel != null) {
                try {
                    fileChannel.close();
                } catch (IOException ioe) {
                }
            }
        }
    
public booleansendCache(byte[] req, int start, int length, java.nio.channels.SocketChannel socketChannel, boolean keepAlive)
Send the cache.


        try{
            FileCacheEntry entry = map(req,start,length);
            if ( entry != null && entry.bb != nullByteBuffer){
                sendCache(socketChannel,entry,keepAlive); 
                return true;
            }
        } catch (IOException ex){
            SelectorThread.logger()
                .fine("File Cache: " + ex.getMessage());
            return true;
        } catch (Throwable t){
            // If an unexpected exception occurs, try to serve the page
            // as if it wasn't in a cache.
            SelectorThread.logger()
                .fine("File Cache thread race: " + t.getMessage());
        }
        return false;
    
protected voidsendCache(java.nio.channels.SocketChannel socketChannel, com.sun.enterprise.web.connector.grizzly.FileCache$FileCacheEntry entry, boolean keepAlive)
Send the cached resource.

  
        OutputWriter.flushChannel(socketChannel, entry.headerBuffer.slice());
        ByteBuffer keepAliveBuf = keepAlive ? connectionKaBB.slice():
               connectionCloseBB.slice();
        OutputWriter.flushChannel(socketChannel, keepAliveBuf);        
        OutputWriter.flushChannel(socketChannel, entry.bb.slice());
    
public voidsetCacheManager(java.util.concurrent.ConcurrentLinkedQueue cacheManager)
Set the cache manager used by this instance.

        this.cacheManager = cacheManager;
    
public voidsetHeaderBBSize(int headerBBSize)
Set the size of the header ByteBuffer.

        this.headerBBSize = headerBBSize;
    
public voidsetIsEnabled(boolean isEnabled)
Is the file caching mechanism enabled.

        this.isEnabled = isEnabled;
    
public static voidsetIsMonitoringEnabled(boolean isMe)
Turn monitoring on/off

        isMonitoringEnabled = isMe;
    
public voidsetLargeFileCacheEnabled(boolean isLargeEnabled)
Is the large file cache support enabled.

        this.isLargeFileCacheEnabled = isLargeEnabled;
    
public voidsetMaxCacheEntries(int mEntries)
Set the maximum entries this cache can contains.

        maxCacheEntries = mEntries;
    
public voidsetMaxEntrySize(long mEntrySize)
Set the maximum size a FileCacheEntry can have.

        maxEntrySize = mEntrySize;
    
public voidsetMaxLargeCacheSize(long mCacheSize)
Set the maximum cache size

        maxLargeFileCacheSize = mCacheSize;
    
public voidsetMaxSmallCacheSize(long mCacheSize)
Set the maximum cache size

        maxSmallFileCacheSize = mCacheSize;
    
public voidsetMinEntrySize(long mSize)
Set the maximum size a FileCacheEntry can have.

        minEntrySize = mSize;
    
public voidsetSecondsMaxAge(int sMaxAges)
The timeout in seconds before remove a FileCacheEntry from the fileCache

        secondsMaxAge = sMaxAges;