shorttermquerycache.java

来自「Jive是基于JSP/JAVA技术构架的一个大型BBS论坛系统,这是Jive论坛」· Java 代码 · 共 475 行 · 第 1/2 页

JAVA
475
字号
/** * $RCSfile: ShortTermQueryCache.java,v $ * $Revision: 1.9 $ * $Date: 2002/07/19 20:30:48 $ * * Copyright 1999-2002 CoolServlets, Inc. All Rights Reserved. * * This software is the proprietary information of CoolServlets, Inc. * Use is subject to license terms. */package com.jivesoftware.forum.database;import com.jivesoftware.util.*;import com.jivesoftware.util.LinkedList;import com.jivesoftware.forum.util.TaskEngine;import java.io.*;import java.util.*;/** * An extension of the default cache to temporarily store query results before * they are reloaded from the databases. Objects are automatically moved from * a long-term cache into a short-term cache (instance of this class). When * accessed for the first time, a query update task is scheduled to reload * the data from the database and then move the cache entry from the short-term * cache to the long-term cache. This system gaurantees that threads are never * blocked on trying to read data from query results after cache entry * invalidations. This is important for sites with extreme performance needs. * The consequence is that query results are not always "fresh". For example, * a new thread may not appear in the list of threads in a forum until a short * amount of time has passed. */public class ShortTermQueryCache implements Cache {    /**     * The map the keys and values are stored in.     */    protected Map map;    /**     * Linked list to maintain order that cache objects are accessed     * in, most used to least used.     */    protected LinkedList lastAccessedList;    /**     * Linked list to maintain time that cache objects were initially added     * to the cache, most recently added to oldest added.     */    protected LinkedList ageList;   /**    * Maximum size in bytes that the cache can grow to.    */    private int maxCacheSize;    /**     * Maintains the current size of the cache in bytes.     */    private int cacheSize = 0;    /**     * Maximum length of time objects can exist in cache before expiring.     */    protected long maxLifetime;    /**     * Maintain the number of cache hits and misses. A cache hit occurs every     * time the get method is called and the cache contains the requested     * object. A cache miss represents the opposite occurence.<p>     *     * Keeping track of cache hits and misses lets one measure how efficient     * the cache is; the higher the percentage of hits, the more efficient.     */    protected long cacheHits, cacheMisses = 0L;    /**     * The name of the cache.     */    private String name;    /**     * Create a new cache and specify the maximum size of for the cache in     * bytes, and the maximum lifetime of objects.     *     * @param name a name for the cache.     * @param maxSize the maximum size of the cache in bytes.     * @param maxLifetime the maximum amount of time objects can exist in     *    cache before being deleted. -1 means objects never expire.     */    public ShortTermQueryCache(String name, int maxSize, long maxLifetime) {         this.name = name;        this.maxCacheSize = maxSize;        this.maxLifetime = maxLifetime;        // Our primary data structure is a hash map. The default capacity of 11        // is too small in almost all cases, so we set it bigger.        map = new HashMap(103);        lastAccessedList = new LinkedList();        ageList = new LinkedList();    }    public synchronized Object put(Object key, Object value) {        // Delete an old entry if it exists.        remove(key);        int objectSize = calculateSize(value);        // If the object is bigger than the entire cache, simply don't add it.        if (objectSize > maxCacheSize * .90) {            System.err.println("Cache: " + name + " -- object with key " + key +                    " is too large to fit in cache. Size is " + objectSize);            return value;        }        cacheSize += objectSize;        CacheObject cacheObject = new CacheObject(value, objectSize);        map.put(key, cacheObject);        // Make an entry into the cache order list.        LinkedListNode lastAccessedNode = lastAccessedList.addFirst(key);        // Store the cache order list entry so that we can get back to it        // during later lookups.        cacheObject.lastAccessedListNode = lastAccessedNode;        // Add the object to the age list        LinkedListNode ageNode = ageList.addFirst(key);        // We make an explicit call to currentTimeMillis() so that total accuracy        // of lifetime calculations is better than one second.        ageNode.timestamp = System.currentTimeMillis();        cacheObject.ageListNode = ageNode;        // If cache is too full, remove least used cache entries until it is        // not too full.        cullCache();        return value;    }    public synchronized Object get(Object key) {        // First, clear all entries that have been in cache longer than the        // maximum defined age.        deleteExpiredEntries();        CacheObject cacheObject = (CacheObject)map.get(key);        if (cacheObject == null) {            // The object didn't exist in cache, so increment cache misses.            cacheMisses++;            return null;        }        // If this is the first time the object has been read from cache, we        // need to trigger a cache entry update process so that the entry        // will be refreshed from the database and put back into the long-term        // cache. We also have a special check to make sure that the        // object value is Serializable. This is because Coherence stores        // objects as DataInputStream values from other cluster members before        // a get call has been made locally. Doing this extra check ensures that        // we won't launch an extra cache update task.        if (cacheObject.readCount == 0 && cacheObject.object instanceof Serializable) {            QueryCacheKey queryKey = (QueryCacheKey)key;            long date = maxLifetime + cacheObject.ageListNode.timestamp;            Runnable r = new QueryCacheUpdateTask(queryKey);            TaskEngine.scheduleTask(TaskEngine.HIGH_PRIORITY, r, new java.util.Date(date));        }        // The object exists in cache, so increment cache hits. Also, increment        // the object's read count.        cacheHits++;        cacheObject.readCount++;        // Remove the object from it's current place in the cache order list,        // and re-insert it at the front of the list.        cacheObject.lastAccessedListNode.remove();        lastAccessedList.addFirst(cacheObject.lastAccessedListNode);        return cacheObject.object;    }    public synchronized Object remove(Object key) {        CacheObject cacheObject = (CacheObject)map.get(key);        // If the object is not in cache, stop trying to remove it.        if (cacheObject == null) {            return null;        }        // remove from the hash map        map.remove(key);        // remove from the cache order list        cacheObject.lastAccessedListNode.remove();        cacheObject.ageListNode.remove();        // remove references to linked list nodes        cacheObject.ageListNode = null;        cacheObject.lastAccessedListNode = null;        // removed the object, so subtract its size from the total.        cacheSize -= cacheObject.size;        return cacheObject.object;    }    public synchronized void clear() {        Object [] keys = map.keySet().toArray();        for (int i=0; i<keys.length; i++) {            remove(keys[i]);        }        // Now, reset all containers.        map.clear();        lastAccessedList.clear();        lastAccessedList = new LinkedList();        ageList.clear();        ageList = new LinkedList();        cacheSize = 0;        cacheHits = 0;        cacheMisses = 0;    }    public int size() {        // First, clear all entries that have been in cache longer than the        // maximum defined age.        deleteExpiredEntries();        return map.size();    }    public boolean isEmpty() {        // First, clear all entries that have been in cache longer than the        // maximum defined age.        deleteExpiredEntries();        return map.isEmpty();    }    public Collection values() {        // First, clear all entries that have been in cache longer than the        // maximum defined age.        deleteExpiredEntries();        Object [] cacheObjects = map.values().toArray();        Object [] values = new Object[cacheObjects.length];

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?