1 23 24 package com.sun.ejb.containers.util.cache; 25 26 import com.sun.appserv.util.cache.Cache; 27 import com.sun.appserv.util.cache.CacheListener; 28 import com.sun.appserv.util.cache.Constants; 29 import com.sun.logging.*; 30 31 import java.util.ArrayList ; 32 import java.util.Map ; 33 import java.util.Properties ; 34 import java.util.ResourceBundle ; 35 import java.util.logging.*; 36 37 41 public class LruCache extends BaseCache { 42 43 protected static Logger _logger; 44 static { 45 _logger=LogDomains.getLogger(LogDomains.EJB_LOGGER); 46 } 47 protected String cacheName; 48 49 public static final long NO_TIMEOUT = -1; 51 52 protected LruCacheItem head; 54 protected LruCacheItem tail; 55 56 protected int trimCount; 58 59 protected int listSize; 60 protected long timeout = NO_TIMEOUT; 61 62 65 public LruCache() { } 66 67 70 public LruCache(long timeout) { 71 this.timeout = timeout; 72 } 73 74 84 protected CacheItem createItem(int hashCode, Object key, 85 Object value, int size) { 86 return new LruCacheItem(hashCode, key, value, size); 87 } 88 89 96 protected CacheItem trimLru(long currentTime) { 97 98 LruCacheItem trimItem = tail; 99 100 if (tail != head) { 101 tail = trimItem.lPrev; 102 if (tail == null) { 103 _logger.log(Level.WARNING, 104 "[" + cacheName + "]: trimLru(), resetting head and tail"); 105 tail = head = null; 107 } else { 108 tail.lNext = null; 109 } 110 } else { 111 tail = head = null; 112 } 113 114 if (trimItem != null) { 115 trimItem.isTrimmed = true; 116 trimItem.lPrev = null; 117 trimCount++; 118 listSize--; 119 } 120 121 return trimItem; 122 } 123 124 135 protected CacheItem itemAdded(CacheItem item) { 136 CacheItem overflow = null; 137 LruCacheItem lc = (LruCacheItem) item; 138 139 lc.lastAccessed = System.currentTimeMillis(); 141 142 synchronized (this) { 144 if (head != null) { 145 head.lPrev = lc; 146 lc.lNext = head; 147 lc.lPrev = null; 148 head = lc; 149 } 150 else { 151 head = tail = lc; 152 lc.lPrev = lc.lNext = null; 153 } 154 155 listSize++; 156 157 if ( isThresholdReached() ) { 158 overflow = trimLru(lc.lastAccessed); 159 } 160 } 161 162 return overflow; 163 } 164 165 171 protected void itemAccessed(CacheItem item) { 172 LruCacheItem lc = (LruCacheItem) item; 173 174 synchronized (this) { 175 176 if (lc.isTrimmed) 178 return; 179 180 lc.lastAccessed = System.currentTimeMillis(); 182 183 LruCacheItem prev = lc.lPrev; 184 LruCacheItem next = lc.lNext; 185 186 if (prev != null) { 188 lc.lPrev = null; 190 lc.lNext = head; 191 head.lPrev = lc; 192 head = lc; 193 194 prev.lNext = next; 196 if (next != null) 197 next.lPrev = prev; 198 else 199 tail = prev; 200 } 201 } 202 } 203 204 205 211 protected void itemRefreshed(CacheItem item, int oldSize) { 212 itemAccessed(item); 213 } 214 215 221 protected void itemRemoved(CacheItem item) { 222 LruCacheItem l = (LruCacheItem) item; 223 224 synchronized (this) { 226 LruCacheItem prev = l.lPrev; 227 LruCacheItem next = l.lNext; 228 229 if (l.isTrimmed) 231 return; 232 233 if (prev != null) 235 prev.lNext = next; 236 else 237 head = next; 238 239 if (next != null) 240 next.lPrev = prev; 241 else 242 tail = prev; 243 244 l.lPrev = l.lNext = null; 245 listSize--; 246 } 247 } 248 249 258 public void trimExpiredEntries(int maxCount) { 259 260 int count = 0; 261 LruCacheItem item; 262 long currentTime = System.currentTimeMillis(); 263 ArrayList list = new ArrayList (); 264 265 synchronized (this) { 266 for (item = tail; item != null && count < maxCount; 269 item = item.lPrev) { 270 271 if ( (timeout != NO_TIMEOUT) && 272 ((item.lastAccessed + timeout) <= currentTime) ) { 273 item.isTrimmed = true; 274 list.add(item); 275 276 count++; 277 } else { 278 break; 279 } 280 } 281 282 if (item != tail) { 284 if (item != null) 285 item.lNext = null; 286 else 287 head = null; 288 289 tail = item; 290 } 291 listSize -= count; 292 trimCount += count; 293 } 294 295 for (int index=list.size()-1; index >= 0; index--) { 297 trimItem((LruCacheItem) list.get(index)); 298 } 299 } 300 301 304 305 311 public Object getStatByName(String key) { 312 Object stat = super.getStatByName(key); 313 314 if (stat == null && key != null) { 315 if (key.equals(Constants.STAT_LRUCACHE_LIST_LENGTH)) 316 stat = new Integer (listSize); 317 else if (key.equals(Constants.STAT_LRUCACHE_TRIM_COUNT)) 318 stat = new Integer (trimCount); 319 } 320 return stat; 321 } 322 323 public Map getStats() { 324 Map stats = super.getStats(); 325 stats.put(Constants.STAT_LRUCACHE_LIST_LENGTH, new Integer (listSize)); 326 stats.put(Constants.STAT_LRUCACHE_TRIM_COUNT, new Integer (trimCount)); 327 328 return stats; 329 } 330 331 public void setCacheName(String name) { 332 this.cacheName = name; 333 } 334 335 336 protected static class LruCacheItem extends CacheItem { 337 338 protected LruCacheItem lNext; 340 protected LruCacheItem lPrev; 341 protected boolean isTrimmed; 342 protected long lastAccessed; 343 344 protected LruCacheItem(int hashCode, Object key, Object value, 345 int size) { 346 super(hashCode, key, value, size); 347 } 348 } 349 350 } 351 | Popular Tags |