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 30 import java.util.Map ; 31 import java.util.HashMap ; 32 import java.util.ArrayList ; 33 import java.util.Properties ; 34 import java.util.ResourceBundle ; 35 36 import java.util.logging.*; 37 import com.sun.logging.*; 38 39 44 public class FIFOEJBObjectCache 45 extends LruCache 46 implements EJBObjectCache 47 { 48 protected int maxCacheSize; 49 protected String name; 50 protected EJBObjectCacheListener listener; 51 52 protected Object refCountLock = new Object (); 53 protected int totalRefCount = 0; 54 protected static boolean _printRefCount = false; 55 56 57 private static Logger _logger; 58 static { 59 _logger=LogDomains.getLogger(LogDomains.EJB_LOGGER); 60 61 try { 62 Properties props = System.getProperties(); 63 _printRefCount = (Boolean.valueOf(props.getProperty 64 ("cache.printrefcount"))).booleanValue(); 65 } catch (Exception ex) { 66 _logger.log(Level.FINE, "Cache PrintRefCount property ex", ex); 67 } 68 } 69 70 73 public FIFOEJBObjectCache(String name) { 74 this.name = name; 75 } 76 77 80 public FIFOEJBObjectCache(String name, long timeout) { 81 super(timeout); 82 this.name = name; 83 } 84 85 public void init(int maxEntries, int numberOfVictimsToSelect, long timeout, 86 float loadFactor, Properties props) 87 { 88 super.init(maxEntries, loadFactor, props); 89 super.timeout = timeout; 90 this.maxCacheSize = maxEntries; 91 _logger.log(Level.FINE, name + ": FIFOEJBObject cache created...."); 92 } 93 94 public void setEJBObjectCacheListener(EJBObjectCacheListener listener) { 95 this.listener = listener; 96 } 97 98 public Object get(Object key) { 99 int hashCode = hash(key); 100 101 return internalGet(hashCode, key, false); 102 } 103 104 105 public Object get(Object key, boolean incrementRefCount) { 106 int hashCode = hash(key); 107 108 return internalGet(hashCode, key, incrementRefCount); 109 } 110 111 public Object put(Object key, Object value) { 112 int hashCode = hash(key); 113 114 return internalPut(hashCode, key, value, -1, false); 115 } 116 117 public Object put(Object key, Object value, boolean incrementRefCount) { 118 int hashCode = hash(key); 119 120 return internalPut(hashCode, key, value, -1, incrementRefCount); 121 } 122 123 124 public Object remove(Object key) { 125 return internalRemove(key, true); 126 } 127 128 public Object remove(Object key, boolean decrementRefCount) { 129 return internalRemove(key, decrementRefCount); 130 } 131 132 protected boolean isThresholdReached() { 133 return listSize > maxCacheSize; 134 } 135 136 protected void itemAccessed(CacheItem item) { } 137 138 protected void itemRemoved(CacheItem item) { 139 LruCacheItem l = (LruCacheItem) item; 140 141 synchronized (this) { 143 if (l.isTrimmed) { 145 return; 146 } 147 148 LruCacheItem prev = l.lPrev; 149 LruCacheItem next = l.lNext; 150 151 l.isTrimmed = true; 152 153 if (prev != null) 155 prev.lNext = next; 156 else 157 head = next; 158 159 if (next != null) 160 next.lPrev = prev; 161 else 162 tail = prev; 163 164 l.lNext = l.lPrev = null; 165 166 listSize--; 167 } 168 } 169 170 protected Object internalGet(int hashCode, Object key, 171 boolean incrementRefCount) { 172 173 int index = getIndex(hashCode); 174 Object value = null; 175 CacheItem item = null; 176 177 synchronized (bucketLocks[index]) { 178 item = buckets[index]; 179 180 for (; item != null; item = item.next) { 181 if ( (hashCode == item.hashCode) && eq(key, item.key) ) { 182 break; 183 } 184 } 185 186 if (item != null) { 188 value = item.getValue(); 189 if (incrementRefCount) { 190 EJBObjectCacheItem eoItem = (EJBObjectCacheItem) item; 191 eoItem.refCount++; 192 if (_printRefCount) { 193 incrementReferenceCount(); 194 } 195 if (! eoItem.isTrimmed) { 196 itemRemoved(eoItem); 197 } 198 } 199 } 200 } 201 202 if (item != null) 203 incrementHitCount(); 204 else 205 incrementMissCount(); 206 207 return value; 208 } 209 210 protected Object internalPut(int hashCode, Object key, Object value, 211 int size, boolean incrementRefCount) 212 { 213 214 int index = getIndex(hashCode); 215 216 CacheItem item, oldItem = null, overflow = null; 217 EJBObjectCacheItem newItem = null; 218 Object oldValue = null; 219 int oldSize = 0; 220 221 synchronized (bucketLocks[index]) { 223 for (item = buckets[index]; item != null; item = item.next) { 224 if ((hashCode == item.hashCode) && eq(key, item.key)) { 225 oldItem = item; 226 break; 227 } 228 } 229 230 if (oldItem == null) { 232 newItem = (EJBObjectCacheItem) 233 createItem(hashCode, key, value, size); 234 newItem.isTrimmed = incrementRefCount; 235 236 newItem.next = buckets[index]; 238 buckets[index] = newItem; 239 240 if (incrementRefCount) { 241 newItem.refCount++; 242 if (_printRefCount) { 243 incrementReferenceCount(); 244 } 245 } else { 246 overflow = itemAdded(newItem); 247 } 248 } else { 249 oldValue = oldItem.getValue(); 250 if (incrementRefCount) { 251 EJBObjectCacheItem oldEJBO = (EJBObjectCacheItem) oldItem; 252 oldEJBO.refCount++; 253 if (_printRefCount) { 254 incrementReferenceCount(); 255 } 256 } 257 } 258 } 259 260 if (newItem != null) { 261 incrementEntryCount(); 262 if ((overflow != null) && (listener != null)) { 264 listener.handleOverflow(overflow.key); 265 } 266 } 267 268 return oldValue; 269 } 270 271 272 public void print() { 273 System.out.println("EJBObjectCache:: size: " + getEntryCount() + 274 "; listSize: " + listSize); 275 for (LruCacheItem run = head; run!=null; run=run.lNext) { 276 System.out.print("("+run.key+", "+run.value+") "); 277 } 278 System.out.println(); 279 } 280 281 protected Object internalRemove(Object key, boolean decrementRefCount) { 282 283 int hashCode = hash(key); 284 int index = getIndex(hashCode); 285 286 CacheItem prev = null, item = null; 287 288 synchronized (bucketLocks[index]) { 289 for (item = buckets[index]; item != null; item = item.next) { 290 if (hashCode == item.hashCode && key.equals(item.key)) { 291 292 EJBObjectCacheItem eoItem = (EJBObjectCacheItem) item; 293 if (decrementRefCount) { 294 if (eoItem.refCount > 0) { 295 eoItem.refCount--; 296 if (_printRefCount) { 297 decrementReferenceCount(); 298 } 299 } 300 } 301 302 if (eoItem.refCount > 0) { 303 return null; 304 } 305 306 if (prev == null) { 307 buckets[index] = item.next; 308 } else { 309 prev.next = item.next; 310 } 311 item.next = null; 312 313 itemRemoved(item); 314 315 break; 316 317 } 318 prev = item; 319 } 320 } 321 322 if (item != null) { 323 decrementEntryCount(); 324 incrementRemovalCount(); 325 incrementHitCount(); 326 return item.value; 327 } else { 328 incrementMissCount(); 329 return null; 330 } 331 332 } 333 334 338 339 protected CacheItem createItem(int hashCode, Object key, Object value, 340 int size) { 341 return new EJBObjectCacheItem(hashCode, key, value, size); 342 } 343 344 protected static class EJBObjectCacheItem 345 extends LruCacheItem { 346 protected int refCount; 347 348 protected EJBObjectCacheItem(int hashCode, Object key, Object value, 349 int size) { 350 super(hashCode, key, value, size); 351 } 352 } 353 354 public Map getStats() { 355 Map map = new HashMap (); 356 StringBuffer sbuf = new StringBuffer (); 357 358 sbuf.append("(totalRef=").append(totalRefCount).append("; "); 359 360 sbuf.append("listSize=").append(listSize) 361 .append("; curSize/totSize=").append(getEntryCount()) 362 .append("/").append(maxEntries) 363 .append("; trim=").append(trimCount) 364 .append("; remove=").append(removalCount) 365 .append("; hit/miss=").append(hitCount).append("/").append(missCount) 366 .append(")"); 367 map.put("["+name+"]", sbuf.toString()); 368 return map; 369 } 370 371 public void trimExpiredEntries(int maxCount) { 372 373 int count = 0; 374 LruCacheItem item, lastItem = null; 375 long currentTime = System.currentTimeMillis(); 376 377 synchronized (this) { 378 for (item = tail; item != null && count < maxCount; 380 item = item.lPrev) { 381 382 if ((timeout != NO_TIMEOUT) && 383 (item.lastAccessed + timeout) <= currentTime) { 384 item.isTrimmed = true; 385 lastItem = item; 386 387 count++; 388 } else { 389 break; 390 } 391 } 392 393 if (item != tail) { 395 lastItem.lPrev = null; 396 397 if (item != null) 398 item.lNext = null; 399 else 400 head = null; 401 402 lastItem = tail; tail = item; 404 } 405 listSize -= count; 406 trimCount += count; 407 } 408 409 if (count > 0) { 410 411 ArrayList localVictims = new ArrayList (count); 412 for (item = lastItem; item != null; item = item.lPrev) { 414 localVictims.add(item.key); 415 } 416 417 if (listener != null) { 418 listener.handleBatchOverflow(localVictims); 419 } 420 } 421 } 422 423 protected void incrementReferenceCount() { 424 synchronized (refCountLock) { 425 totalRefCount++; 426 } 427 } 428 429 protected void decrementReferenceCount() { 430 synchronized (refCountLock) { 431 totalRefCount--; 432 } 433 } 434 435 protected void decrementReferenceCount(int count) { 436 synchronized (refCountLock) { 437 totalRefCount -= count; 438 } 439 } 440 441 442 static void unitTest_1() 443 throws Exception { 444 445 FIFOEJBObjectCache cache = new FIFOEJBObjectCache("UnitTestCache"); 446 cache.init(512, 0, 0, (float)1.0, null); 447 448 int maxCount = 14; 449 ArrayList keys = new ArrayList (); 450 for (int i=0; i<maxCount; i++) { 451 keys.add("K_"+i); 452 } 453 454 for (int i=0; i<maxCount; i++) { 455 String key = (String ) keys.get(i); 456 System.out.println("**** put(" + key + ", " + key + ", i" + 457 ((i%2) == 0) + ")"); 458 cache.put(key, key, ((i%2)==0)); 459 } 460 461 System.out.println("*** Only odd numbered keys must be printed ***"); 462 cache.print(); 463 System.out.println("************************************************"); 464 465 for (int i=0; i<maxCount; i++) { 466 String key = (String ) keys.get(i); 467 cache.get(key, ((i%2)==1)); 468 } 469 470 System.out.println("**** NONE SHOULD BE PRINTED ****"); 471 cache.print(); 472 System.out.println("************************************************"); 473 474 cache.put("K__15", "K__15", true); 475 cache.put("K__16", "K__15", true); 476 cache.get("K__16", true); cache.put("K__17", "K__17"); 479 System.out.println("**** Only K__17 must be printed ****"); 480 cache.print(); 481 System.out.println("************************************************"); 482 483 for (int i=0; i<maxCount; i++) { 484 String key = (String ) keys.get(i); 485 if (cache.remove(key) == null) { 486 throw new RuntimeException ("Remove must have returned null!!"); 487 } 488 } 489 490 Object k15 = cache.remove("K__15"); 491 Object k16_1 = cache.remove("K__16"); 492 Object k16_2 = cache.remove("K__16"); 493 Object k17 = cache.remove("K__17"); 494 495 if (k15 == null) { 496 System.out.println("** FAILED for K_15"); 497 } 498 499 if (k16_1 != null) { 500 System.out.println("** FAILED for K_16_1"); 501 } 502 503 if (k16_2 == null) { 504 System.out.println("** FAILED for K_16_2"); 505 } 506 507 if (k17 == null) { 508 System.out.println("** FAILED for K_17"); 509 } 510 511 for (int i=0; i<maxCount; i+=2) { 513 String key = (String ) keys.get(i); 514 cache.put(key, key, (i%4)==0); 515 } 516 cache.print(); 517 518 519 for (int i=0; i<maxCount; i+=2) { 521 String key = (String ) keys.get(i); 522 cache.get(key, true); 523 } 524 cache.print(); 525 526 for (int i=1; i<maxCount; i+=2) { 528 String key = (String ) keys.get(i); 529 cache.put(key, key, (i%9)==0); 530 } 531 cache.print(); 532 } 533 534 public static void main(String [] args) 535 throws Exception 536 { 537 unitTest_1(); 538 } 539 540 } 541 | Popular Tags |