1 23 24 29 30 package com.sun.appserv.util.cache; 31 32 import java.util.ArrayList ; 33 import java.util.Map ; 34 import java.util.Properties ; 35 import java.util.ResourceBundle ; 36 37 41 public class LruCache extends BaseCache { 42 43 public static final long NO_TIMEOUT = -1; 45 46 protected LruCacheItem head; 48 protected LruCacheItem tail; 49 50 protected int trimCount; 52 53 protected int listSize; 54 protected long timeout = NO_TIMEOUT; 55 56 protected int defaultMaxEntries = Constants.DEFAULT_MAX_ENTRIES; 57 protected boolean isUnbounded = false; 58 59 62 public LruCache() { } 63 64 69 public LruCache(int defaultMaxEntries) { 70 this.defaultMaxEntries = defaultMaxEntries; 71 } 72 73 81 public void init(int maxEntries, long timeout, float loadFactor, Properties props) { 82 83 if (maxEntries <= 0) { 85 maxEntries = defaultMaxEntries; 86 87 isUnbounded = true; 89 } 90 setTimeout(timeout); 91 92 super.init(maxEntries, loadFactor, props); 93 } 94 95 99 public void setTimeout(long timeout) { 100 if (timeout > 0) 102 this.timeout = timeout; 103 } 104 105 115 protected CacheItem createItem(int hashCode, Object key, 116 Object value, int size) { 117 return new LruCacheItem(hashCode, key, value, size); 118 } 119 120 127 protected CacheItem trimLru(long currentTime) { 128 129 LruCacheItem trimItem = tail; 130 131 if (tail != head) { 132 tail = trimItem.lPrev; 133 if(tail == null) { 134 tail = head = null; 136 } else { 137 tail.lNext = null; 138 trimItem.lPrev = null; 139 } 140 } else { 141 tail = head = null; 142 } 143 144 if (trimItem != null) { 145 trimItem.isTrimmed = true; 146 trimItem.lPrev = null; 147 trimCount++; 148 listSize--; 149 } 150 151 return trimItem; 152 } 153 154 165 protected CacheItem itemAdded(CacheItem item) { 166 boolean updateThreshold = false; 167 CacheItem overflow = null; 168 LruCacheItem lc = (LruCacheItem) item; 169 170 lc.lastAccessed = System.currentTimeMillis(); 172 173 synchronized (this) { 175 if (head != null) { 176 head.lPrev = lc; 177 lc.lNext = head; 178 lc.lPrev = null; 179 head = lc; 180 } 181 else { 182 head = tail = lc; 183 lc.lPrev = lc.lNext = null; 184 } 185 186 listSize++; 187 188 if (isThresholdReached()) { 189 if (!isUnbounded) 190 overflow = trimLru(lc.lastAccessed); 191 else 192 updateThreshold = true; 193 } 194 } 195 196 if (updateThreshold) 198 super.handleOverflow(); 199 200 return overflow; 201 } 202 203 209 protected void itemAccessed(CacheItem item) { 210 LruCacheItem lc = (LruCacheItem) item; 211 212 synchronized (this) { 213 214 if (lc.isTrimmed) 216 return; 217 218 lc.lastAccessed = System.currentTimeMillis(); 220 221 LruCacheItem prev = lc.lPrev; 222 LruCacheItem next = lc.lNext; 223 if (prev != null) { 225 lc.lPrev = null; 227 lc.lNext = head; 228 head.lPrev = lc; 229 head = lc; 230 231 prev.lNext = next; 233 if (next != null) 234 next.lPrev = prev; 235 else 236 tail = prev; 237 } 238 } 239 } 240 241 247 protected void itemRefreshed(CacheItem item, int oldSize) { 248 itemAccessed(item); 249 } 250 251 257 protected void itemRemoved(CacheItem item) { 258 LruCacheItem l = (LruCacheItem) item; 259 260 synchronized (this) { 262 LruCacheItem prev = l.lPrev; 263 LruCacheItem next = l.lNext; 264 265 if (l.isTrimmed) 267 return; 268 269 if (prev != null) 271 prev.lNext = next; 272 else 273 head = next; 274 275 if (next != null) 276 next.lPrev = prev; 277 else 278 tail = prev; 279 280 l.lPrev = l.lNext = null; 281 listSize--; 282 } 283 } 284 285 294 public void trimExpiredEntries(int maxCount) { 295 296 int count = 0; 297 LruCacheItem item; 298 long currentTime = System.currentTimeMillis(); 299 ArrayList list = new ArrayList (); 300 301 synchronized (this) { 302 for (item = tail; item != null && count < maxCount; 304 item = item.lPrev) { 305 306 if (timeout != NO_TIMEOUT && 307 (item.lastAccessed + timeout) <= currentTime) { 308 item.isTrimmed = true; 309 list.add(item); 310 311 count++; 312 } else 313 break; 314 } 315 316 if (item != tail) { 318 if (item != null) 319 item.lNext = null; 320 else 321 head = null; 322 323 tail = item; 324 } 325 listSize -= count; 326 trimCount += count; 327 } 328 329 for (int index=list.size()-1; index >= 0; index--) { 331 trimItem((LruCacheItem) list.get(index)); 332 } 333 } 334 335 336 339 340 346 public Object getStatByName(String key) { 347 Object stat = super.getStatByName(key); 348 349 if (stat == null && key != null) { 350 if (key.equals(Constants.STAT_LRUCACHE_LIST_LENGTH)) 351 stat = new Integer (listSize); 352 else if (key.equals(Constants.STAT_LRUCACHE_TRIM_COUNT)) 353 stat = new Integer (trimCount); 354 } 355 return stat; 356 } 357 358 public Map getStats() { 359 Map stats = super.getStats(); 360 stats.put(Constants.STAT_LRUCACHE_LIST_LENGTH, new Integer (listSize)); 361 stats.put(Constants.STAT_LRUCACHE_TRIM_COUNT, new Integer (trimCount)); 362 363 return stats; 364 } 365 366 367 protected static class LruCacheItem extends CacheItem { 368 369 protected LruCacheItem lNext; 371 protected LruCacheItem lPrev; 372 protected boolean isTrimmed; 373 protected long lastAccessed; 374 375 protected LruCacheItem(int hashCode, Object key, Object value, int size) { 376 super(hashCode, key, value, size); 377 } 378 } 379 } 380 381 | Popular Tags |