| 1 25 26 package org.nemesis.forum.util.cache; 27 28 import java.util.Collection ; 29 import java.util.Collections ; 30 import java.util.HashMap ; 31 32 import org.nemesis.forum.util.LinkedList; 33 import org.nemesis.forum.util.LinkedListNode; 34 35 36 public class Cache implements Cacheable { 37 38 44 protected static long currentTime = System.currentTimeMillis(); 45 46 50 protected static CacheTimer timer = new CacheTimer(1000L); 51 52 56 protected HashMap cachedObjectsHash; 57 58 62 protected LinkedList lastAccessedList; 63 64 68 protected LinkedList ageList; 69 70 74 protected int maxSize = 128 * 1024; 75 76 79 protected int size = 0; 80 81 85 protected long maxLifetime = -1; 86 87 95 protected long cacheHits, cacheMisses = 0L; 96 97 101 public Cache() { 102 cachedObjectsHash = new HashMap (103); 105 106 lastAccessedList = new LinkedList(); 107 ageList = new LinkedList(); 108 } 109 110 116 public Cache(int maxSize) { 117 this(); 118 this.maxSize = maxSize; 119 } 120 121 132 public Cache(long maxLifetime) { 133 this(); 134 this.maxLifetime = maxLifetime; 135 } 136 137 145 public Cache(int maxSize, long maxLifetime) { 146 this(); 147 this.maxSize = maxSize; 148 this.maxLifetime = maxLifetime; 149 } 150 151 156 public int getSize() { 157 return size; 158 } 159 160 167 public int getMaxSize() { 168 return maxSize; 169 } 170 171 178 public void setMaxSize(int maxSize) { 179 this.maxSize = maxSize; 180 cullCache(); 183 } 184 185 190 public synchronized int getNumElements() { 191 return cachedObjectsHash.size(); 192 } 193 194 200 public synchronized void add(Object key, Cacheable object) { 201 202 if (cachedObjectsHash.containsKey(key)) { 204 return; 205 } 206 int objectSize = object.getSize(); 207 if (objectSize > maxSize * .90) { 209 return; 210 } 211 size += objectSize; 212 CacheObject cacheObject = new CacheObject(object, objectSize); 213 cachedObjectsHash.put(key, cacheObject); 214 LinkedListNode lastAccessedNode = lastAccessedList.addFirst(key); 216 cacheObject.lastAccessedListNode = lastAccessedNode; 219 LinkedListNode ageNode = ageList.addFirst(key); 221 ageNode.timestamp = System.currentTimeMillis(); 224 cacheObject.ageListNode = ageNode; 225 226 cullCache(); 229 } 230 231 240 public synchronized Cacheable get(Object key) { 241 deleteExpiredEntries(); 244 245 CacheObject cacheObject = (CacheObject) cachedObjectsHash.get(key); 246 if (cacheObject == null) { 247 cacheMisses++; 249 return null; 250 } 251 252 cacheHits++; 254 255 cacheObject.lastAccessedListNode.remove(); 258 lastAccessedList.addFirst(cacheObject.lastAccessedListNode); 259 260 return cacheObject.object; 261 } 262 263 268 public synchronized void remove(Object key) { 269 270 CacheObject cacheObject = (CacheObject) cachedObjectsHash.get(key); 271 if (cacheObject == null) { 273 return; 274 } 275 cachedObjectsHash.remove(key); 277 cacheObject.lastAccessedListNode.remove(); 279 cacheObject.ageListNode.remove(); 280 cacheObject.ageListNode = null; 282 cacheObject.lastAccessedListNode = null; 283 size -= cacheObject.size; 285 } 286 287 290 public synchronized void clear() { 291 292 Object [] keys = cachedObjectsHash.keySet().toArray(); 293 for (int i = 0; i < keys.length; i++) { 294 remove(keys[i]); 295 } 296 297 cachedObjectsHash.clear(); 299 cachedObjectsHash = new HashMap (103); 300 lastAccessedList.clear(); 301 lastAccessedList = new LinkedList(); 302 ageList.clear(); 303 ageList = new LinkedList(); 304 305 size = 0; 306 cacheHits = 0; 307 cacheMisses = 0; 308 } 309 310 316 public Collection values() { 317 return Collections.unmodifiableCollection(cachedObjectsHash.values()); 318 } 319 320 330 public long getCacheHits() { 331 return cacheHits; 332 } 333 334 344 public long getCacheMisses() { 345 return cacheMisses; 346 } 347 348 352 private final void deleteExpiredEntries() { 353 if (maxLifetime <= 0) { 355 return; 356 } 357 358 LinkedListNode node = ageList.getLast(); 363 if (node == null) { 365 return; 366 } 367 368 long expireTime = currentTime - maxLifetime; 372 373 while (expireTime > node.timestamp) { 374 375 remove(node.object); 377 378 node = ageList.getLast(); 380 if (node == null) { 382 return; 383 } 384 } 385 } 386 387 393 private final void cullCache() { 394 if (size >= maxSize * .97) { 397 deleteExpiredEntries(); 399 int desiredSize = (int) (maxSize * .90); 400 while (size > desiredSize) { 401 remove(lastAccessedList.getLast().object); 403 } 404 } 405 } 406 } 407 | Popular Tags |