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 + -
显示快捷键?