1 19 package org.netbeans.mdr.persistence.btreeimpl.btreestorage; 20 21 import java.lang.ref.*; 22 import java.io.*; 23 import java.text.*; 24 import java.util.*; 25 26 import org.netbeans.mdr.persistence.*; 27 28 53 54 public class MDRCache { 55 private static final ArrayList instances = new ArrayList(); 56 57 58 private final FacilityCache hashOnId; 59 60 61 private final Map hardRef; 62 63 64 private HashMap newOnes; 65 66 67 private HashMap dirty; 68 69 70 private HashMap deleted; 71 72 73 OverflowHandler handler; 74 75 76 private static final int threshhold = Integer.getInteger( 77 "org.netbeans.mdr.persistence.btreeimpl.btreestorage.MDRCache.threshhold", 78 BtreeDatabase.MDR_CACHE_THRESHHOLD).intValue() * 2; 79 80 private static final boolean CACHE_DEBUG = Boolean.getBoolean("perf.mdr.MDRCache"); 81 82 private static int size = 0; 83 84 private static StringBuffer DEBUG_INFO = Boolean.getBoolean("debug.mdr.MDRCache") ? new StringBuffer (20000) : null; 85 86 private static boolean alreadyChecking = false; 87 private static final Object LOCK = new Object (); 88 89 private int localThreshhold; 90 private int lastLocalSize = 0; 91 92 public static final int M_DELETED = 1; 93 public static final int M_DIRTY = 2; 94 public static final int M_NEW = 4; 95 96 97 private static int hits; 98 private static int misses; 99 101 106 public MDRCache(int size, OverflowHandler hndlr, int limit, Map hardRef) { 107 this(size, hardRef); 108 handler = hndlr; 109 localThreshhold = limit; 110 } 111 112 private static class CacheClass implements Map { 113 private final Object inner[]; 114 private int size, cursor; 115 116 public CacheClass(int size) { 117 inner = new Object [size]; 118 } 119 120 public Set keySet() { 121 throw new UnsupportedOperationException (); 122 } 123 124 public Set entrySet() { 125 throw new UnsupportedOperationException (); 126 } 127 128 public void putAll(Map t) { 129 throw new UnsupportedOperationException (); 130 } 131 132 public boolean isEmpty() { 133 return size == 0; 134 } 135 136 public boolean containsKey(Object key) { 137 throw new UnsupportedOperationException (); 138 } 139 140 public boolean containsValue(Object value) { 141 throw new UnsupportedOperationException (); 142 } 143 144 public Collection values() { 145 throw new UnsupportedOperationException (); 146 } 147 148 public Object put(Object key, Object value) { 149 if (value != inner[cursor]) { 150 cursor++; 151 if (size < inner.length) { 152 size++; 153 } 154 if (cursor >= inner.length) { 155 cursor = 0; 156 } 157 inner[cursor] = value; 158 } 159 return null; 160 } 161 162 public void clear() { 163 Arrays.fill(inner, null); 164 size = cursor = 0; 165 } 166 167 public int size() { 168 return size; 169 } 170 171 public Object get(Object key) { 172 throw new UnsupportedOperationException (); 173 } 174 175 public Object remove(Object key) { 176 throw new UnsupportedOperationException (); 177 } 178 } 179 180 182 public MDRCache(final int size, Map hardRef) { 183 hashOnId = new FacilityCache(); 184 if (hardRef == null) { 185 hardRef = new CacheClass(size); 190 } 191 this.hardRef = hardRef; 192 deleted = new HashMap(); 193 dirty = new HashMap(); 194 newOnes = new HashMap(); 195 synchronized (MDRCache.class) { 196 instances.add(this); 197 } 198 } 199 200 public void shutDown() { 201 synchronized (MDRCache.class) { 202 instances.remove(this); 203 } 204 } 205 206 209 public synchronized int getModStatus() { 210 return (deleted.isEmpty() ? 0 : M_DELETED) + (dirty.isEmpty() ? 0 : M_DIRTY) + (newOnes.isEmpty() ? 0 : M_NEW); 211 } 212 213 214 218 public synchronized void put(Object m, Object o) throws StorageException { 219 if (hashOnId.get(m) == null) { 220 hashOnId.put(m, o); 221 } 222 makeHardRef(m, o); 223 } 228 229 232 public synchronized Object get(Object m) { 233 Object o = hashOnId.get(m); 234 if (o != null) { 235 makeHardRef(m, o); 236 } 237 238 if (CACHE_DEBUG) { 239 synchronized (MDRCache.class) { 240 if (o != null) { 241 hits++; 242 } else { 243 misses++; 244 } 245 if ((hits + misses) % 20000 == 0) { 246 showStats(System.err); 247 } 248 } 249 } 250 return o; 251 } 252 253 257 public synchronized void replace(Object m, Object o) throws StorageException { 258 removeFromCache(m); 259 put(m, o); 260 } 261 262 266 public synchronized void remove(Object m) { 267 if (!removeFromCache(m)) { 268 deleted.put(m, m); 269 } 270 } 271 272 275 private boolean removeFromCache(Object m) { 276 hashOnId.remove(m); 277 boolean wasNew = (newOnes.remove(m) != null); 278 dirty.remove(m); 279 280 return wasNew; 281 } 282 283 284 286 public synchronized void clear() { 287 hardRef.clear(); 288 System.gc(); 289 } 290 291 292 private void makeHardRef(Object m, Object o) { 293 hardRef.put(m, o); 294 } 295 296 public void updateSize() { 297 int allChanged = newOnes.size() + dirty.size(); 298 int sizeDelta = allChanged - lastLocalSize; 299 lastLocalSize = allChanged; 300 synchronized (MDRCache.class) { 301 size += sizeDelta; 302 } 303 } 304 305 307 private void checkThreshhold() throws StorageException { 308 try { 309 synchronized (LOCK) { 310 if (alreadyChecking) return; 311 alreadyChecking = true; 312 } 313 int allChanged = newOnes.size() + dirty.size(); 314 int sizeDelta = allChanged - lastLocalSize; 315 lastLocalSize = allChanged; 316 synchronized (MDRCache.class) { 317 size += sizeDelta; 318 if (size >= threshhold) { 319 if (DEBUG_INFO != null) DEBUG_INFO.append("Global threshhold reached at: " + size); 320 int newSize = 0; 321 for (Iterator it = instances.iterator(); it.hasNext();) { 322 MDRCache cache = (MDRCache) it.next(); 323 if (DEBUG_INFO != null) DEBUG_INFO.append("\nInstance: " + cache.handler.toString()); 324 allChanged = cache.newOnes.size() + cache.dirty.size(); 325 if (allChanged > 10) { 326 if (DEBUG_INFO != null) { 327 DEBUG_INFO.append("\nnewOnes: " + cache.newOnes.keySet().toString()); 328 DEBUG_INFO.append("\ndirty: " + cache.dirty.keySet().toString()); 329 DEBUG_INFO.append("\ndeleted: " + cache.deleted.keySet().toString()); 330 } 331 cache.handler.cacheThreshholdReached(cache, allChanged); 332 allChanged = cache.newOnes.size() + cache.dirty.size(); 333 } 334 cache.lastLocalSize = allChanged; 335 newSize += allChanged; 336 } 337 size = newSize; 338 return; 339 } 340 } 341 if (allChanged >= localThreshhold) { 342 if (DEBUG_INFO != null) DEBUG_INFO.append("\nLocal threshhold reached for: " + handler.toString()); 343 handler.cacheThreshholdReached(this, allChanged); 344 } 345 } catch (StorageException e) { 346 if (DEBUG_INFO != null) { 347 System.err.println("Debug info:"); 348 System.err.println(DEBUG_INFO.toString()); 349 } 350 throw e; 351 } finally { 352 synchronized (LOCK) { 353 alreadyChecking = false; 354 } 355 if (DEBUG_INFO != null) DEBUG_INFO.delete(0, DEBUG_INFO.length()); 356 } 357 } 358 359 360 private void badKey(Object key) throws StorageException { 361 throw new StorageBadRequestException( 362 MessageFormat.format( 363 "No object with ID {0}", new Object [] {key})); 364 } 365 366 370 public synchronized void setNew(Object key) throws StorageException{ 371 Object o = get(key); 372 if (o == null) { 373 badKey(key); 374 } 375 newOnes.put(key, o); 376 if (handler != null) 377 checkThreshhold(); 378 } 379 380 383 public synchronized boolean isNew(Object key) { 384 return newOnes.get(key) != null; 385 } 386 387 390 public synchronized Iterator iterateActive() { 391 return hashOnId.keySet().iterator(); 392 } 393 394 397 public synchronized Iterator iterateDeleted() { 398 return deleted.keySet().iterator(); 399 } 400 401 404 public synchronized Iterator iterateNew() { 405 return newOnes.keySet().iterator(); 406 } 407 408 411 public int numberNew() { 412 return newOnes.size(); 413 } 414 415 418 public int numberDeleted() { 419 return deleted.size(); 420 } 421 422 425 public synchronized boolean isDeleted(Object key) { 426 return deleted.get(key) != null; 427 } 428 429 433 public synchronized void setDirty(Object key) throws StorageException{ 434 Object o = get(key); 435 if (o == null) { 436 badKey(key); 437 } 438 if (newOnes.get(key) == null) { 439 dirty.put(key, o); 440 if (handler != null) 441 checkThreshhold(); 442 } 443 } 444 445 private static final Comparator mofidComparator = new Comparator() { 446 public int compare(Object o1, Object o2) { 447 MOFID id1=(MOFID) o1; 448 MOFID id2=(MOFID) o2; 449 450 return (int)(id1.getSerialNumber() - id2.getSerialNumber()); 451 } 452 }; 453 454 457 public synchronized Collection getNew() { 458 Map result = new TreeMap(mofidComparator); 459 result.putAll(newOnes); 460 newOnes.clear(); 461 return result.entrySet(); 462 } 463 464 467 public synchronized Collection getDirty() { 468 HashMap result = new HashMap(dirty); 469 dirty.clear(); 470 return result.entrySet(); 471 } 472 473 476 public synchronized Collection getDeleted() { 477 ArrayList result = new ArrayList(deleted.values()); 478 deleted.clear(); 479 return result; 480 } 481 482 485 public synchronized void clearLists() { 486 dirty.clear(); 487 newOnes.clear(); 488 deleted.clear(); 489 } 490 491 494 public void showStats(PrintStream strm) { 495 showStats(new PrintWriter(strm)); 496 } 497 498 501 public void showStats(PrintWriter strm) { 502 strm.println( 503 "MDRCache hits: " + hits + " misses: " + misses + 504 " hit rate: " + 100. * (float)hits / (float)(hits + misses)); 505 strm.flush(); 507 } 508 509 515 public interface OverflowHandler { 516 517 521 void cacheThreshholdReached(MDRCache cache, int size) 522 throws StorageException; 523 } 524 525 private static class FacilityCache extends HashMap { 526 private final ReferenceQueue queue = new ReferenceQueue(); 527 private boolean cleaningUp = false; 528 529 private static class CacheReference extends WeakReference { 530 private Object key; 531 532 public CacheReference(Object key, Object object, ReferenceQueue q) { 533 super(object, q); 534 this.key = key; 535 } 536 537 public Object getKey() { 538 return key; 539 } 540 } 541 542 private void cleanUp() { 543 assert !cleaningUp; 544 CacheReference reference; 545 cleaningUp = true; 546 try { 547 while ((reference = (CacheReference) queue.poll()) != null) { 548 Object key = reference.getKey(); 549 java.lang.ref.Reference currentRef = (java.lang.ref.Reference ) super.remove(key); 550 if (currentRef != null && currentRef != reference && currentRef.get() != null) { 551 super.put(key, currentRef); 552 } 553 } 554 } finally { 555 cleaningUp = false; 556 } 557 } 558 559 public Object put(Object key, Object value) { 560 cleanUp(); 561 Object result = super.put(key, new CacheReference(key, value, queue)); 562 assert result == null || ((CacheReference) result).get() == null : "replacing non-null reference"; 563 return null; 564 } 565 566 public Object remove(Object key) { 567 cleanUp(); 568 Object result = super.remove(key); 569 return result == null ? null : ((CacheReference) result).get(); 570 } 571 572 public Object get(Object key) { 573 cleanUp(); 574 Object result = super.get(key); 575 return result == null ? null : ((CacheReference) result).get(); 576 } 577 } 578 } 579 | Popular Tags |