| 1 5 35 package com.opensymphony.oscache.base.algorithm; 36 37 38 39 import com.opensymphony.oscache.base.CacheEntry; 40 import com.opensymphony.oscache.base.persistence.CachePersistenceException; 41 import com.opensymphony.oscache.base.persistence.PersistenceListener; 42 43 import org.apache.commons.logging.Log; 44 import org.apache.commons.logging.LogFactory; 45 46 import java.io.IOException ; 47 import java.io.Serializable ; 48 49 import java.util.*; 50 51 153 public abstract class AbstractConcurrentReadCache extends AbstractMap implements Map, Cloneable , Serializable { 154 158 public static int DEFAULT_INITIAL_CAPACITY = 32; 159 160 166 private static final int MINIMUM_CAPACITY = 4; 167 168 174 private static final int MAXIMUM_CAPACITY = 1 << 30; 175 176 180 public static final float DEFAULT_LOAD_FACTOR = 0.75f; 181 182 protected static final String NULL = "_nul!~"; 184 protected static Log log = LogFactory.getLog(AbstractConcurrentReadCache.class); 185 186 209 210 215 protected final Boolean barrierLock = new Boolean (true); 216 217 220 protected transient Object lastWrite; 221 222 225 protected transient Entry[] table; 226 227 230 protected transient int count; 231 232 235 protected transient PersistenceListener persistenceListener = null; 236 237 240 protected boolean memoryCaching = true; 241 242 245 protected boolean unlimitedDiskCache = false; 246 247 252 protected float loadFactor; 253 254 257 protected final int DEFAULT_MAX_ENTRIES = 100; 258 259 262 protected final int UNLIMITED = 2147483646; 263 protected transient Collection values = null; 264 265 271 protected HashMap groups = new HashMap(); 272 protected transient Set entrySet = null; 273 274 protected transient Set keySet = null; 276 277 280 protected int maxEntries = DEFAULT_MAX_ENTRIES; 281 282 288 protected int threshold; 289 290 293 private boolean overflowPersistence = false; 294 295 305 public AbstractConcurrentReadCache(int initialCapacity, float loadFactor) { 306 if (loadFactor <= 0) { 307 throw new IllegalArgumentException ("Illegal Load factor: " + loadFactor); 308 } 309 310 this.loadFactor = loadFactor; 311 312 int cap = p2capacity(initialCapacity); 313 table = new Entry[cap]; 314 threshold = (int) (cap * loadFactor); 315 } 316 317 326 public AbstractConcurrentReadCache(int initialCapacity) { 327 this(initialCapacity, DEFAULT_LOAD_FACTOR); 328 } 329 330 333 public AbstractConcurrentReadCache() { 334 this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); 335 } 336 337 342 public AbstractConcurrentReadCache(Map t) { 343 this(Math.max(2 * t.size(), 11), DEFAULT_LOAD_FACTOR); 344 putAll(t); 345 } 346 347 352 public synchronized boolean isEmpty() { 353 return count == 0; 354 } 355 356 364 public Set getGroup(String groupName) { 365 if (log.isDebugEnabled()) { 366 log.debug("getGroup called (group=" + groupName + ")"); 367 } 368 369 Set groupEntries = null; 370 371 if (memoryCaching && (groups != null)) { 372 groupEntries = (Set) getGroupForReading(groupName); 373 } 374 375 if (groupEntries == null) { 376 groupEntries = persistRetrieveGroup(groupName); 378 } 379 380 return groupEntries; 381 } 382 383 386 public void setMaxEntries(int newLimit) { 387 if (newLimit > 0) { 388 maxEntries = newLimit; 389 390 synchronized (this) { 392 while (size() > maxEntries) { 393 remove(removeItem(), false, false); 394 } 395 } 396 } else { 397 throw new IllegalArgumentException ("Cache maximum number of entries must be at least 1"); 399 } 400 } 401 402 405 public int getMaxEntries() { 406 return maxEntries; 407 } 408 409 412 public void setMemoryCaching(boolean memoryCaching) { 413 this.memoryCaching = memoryCaching; 414 } 415 416 419 public boolean isMemoryCaching() { 420 return memoryCaching; 421 } 422 423 426 public void setPersistenceListener(PersistenceListener listener) { 427 this.persistenceListener = listener; 428 } 429 430 433 public PersistenceListener getPersistenceListener() { 434 return persistenceListener; 435 } 436 437 440 public void setUnlimitedDiskCache(boolean unlimitedDiskCache) { 441 this.unlimitedDiskCache = unlimitedDiskCache; 442 } 443 444 447 public boolean isUnlimitedDiskCache() { 448 return unlimitedDiskCache; 449 } 450 451 456 public boolean isOverflowPersistence() { 457 return this.overflowPersistence; 458 } 459 460 465 public void setOverflowPersistence(boolean overflowPersistence) { 466 this.overflowPersistence = overflowPersistence; 467 } 468 469 472 public synchronized int capacity() { 473 return table.length; 474 } 475 476 479 public synchronized void clear() { 480 Entry[] tab = table; 481 482 for (int i = 0; i < tab.length; ++i) { 483 for (Entry e = tab[i]; e != null; e = e.next) { 485 e.value = null; 486 487 488 itemRemoved(e.key); 489 490 491 } 492 493 tab[i] = null; 494 } 495 496 persistClear(); 498 499 count = 0; 500 recordModification(tab); 501 } 502 503 510 public synchronized Object clone() { 511 try { 512 AbstractConcurrentReadCache t = (AbstractConcurrentReadCache) super.clone(); 513 t.keySet = null; 514 t.entrySet = null; 515 t.values = null; 516 517 Entry[] tab = table; 518 t.table = new Entry[tab.length]; 519 520 Entry[] ttab = t.table; 521 522 for (int i = 0; i < tab.length; ++i) { 523 Entry first = tab[i]; 524 525 if (first != null) { 526 ttab[i] = (Entry) (first.clone()); 527 } 528 } 529 530 return t; 531 } catch (CloneNotSupportedException e) { 532 throw new InternalError (); 534 } 535 } 536 537 555 public boolean contains(Object value) { 556 return containsValue(value); 557 } 558 559 570 public boolean containsKey(Object key) { 571 return get(key) != null; 572 573 574 575 577 578 } 579 580 591 public boolean containsValue(Object value) { 592 if (value == null) { 593 throw new NullPointerException (); 594 } 595 596 Entry[] tab = getTableForReading(); 597 598 for (int i = 0; i < tab.length; ++i) { 599 for (Entry e = tab[i]; e != null; e = e.next) { 600 Object v = e.value; 601 602 if ((v != null) && value.equals(v)) { 603 return true; 604 } 605 } 606 } 607 608 return false; 609 } 610 611 622 public Enumeration elements() { 623 return new ValueIterator(); 624 } 625 626 638 public Set entrySet() { 639 Set es = entrySet; 640 641 if (es != null) { 642 return es; 643 } else { 644 return entrySet = new AbstractSet() { 645 public Iterator iterator() { 646 return new HashIterator(); 647 } 648 649 public boolean contains(Object o) { 650 if (!(o instanceof Map.Entry)) { 651 return false; 652 } 653 654 Map.Entry entry = (Map.Entry) o; 655 Object key = entry.getKey(); 656 Object v = AbstractConcurrentReadCache.this.get(key); 657 658 return (v != null) && v.equals(entry.getValue()); 659 } 660 661 public boolean remove(Object o) { 662 if (!(o instanceof Map.Entry)) { 663 return false; 664 } 665 666 return AbstractConcurrentReadCache.this.findAndRemoveEntry((Map.Entry) o); 667 } 668 669 public int size() { 670 return AbstractConcurrentReadCache.this.size(); 671 } 672 673 public void clear() { 674 AbstractConcurrentReadCache.this.clear(); 675 } 676 }; 677 } 678 } 679 680 691 public Object get(Object key) { 692 if (log.isDebugEnabled()) { 693 log.debug("get called (key=" + key + ")"); 694 } 695 696 int hash = hash(key); 698 699 707 Entry[] tab = table; 708 int index = hash & (tab.length - 1); 709 Entry first = tab[index]; 710 Entry e = first; 711 712 for (;;) { 713 if (e == null) { 714 tab = getTableForReading(); 717 718 if (first == tab[index]) { 719 720 721 723 724 Object value = persistRetrieve(key); 726 727 if (value != null) { 728 put(key, value, false); 730 } 731 732 return value; 733 734 735 } else { 736 e = first = tab[index = hash & (tab.length - 1)]; 738 } 739 } 740 else if ((key == e.key) || ((e.hash == hash) && key.equals(e.key))) { 742 Object value = e.value; 743 744 if (value != null) { 745 746 747 749 if (NULL.equals(value)) { 750 value = persistRetrieve(e.key); 752 753 if (value != null) { 754 itemRetrieved(key); 755 } 756 757 return value; } else { 759 itemRetrieved(key); 760 761 return value; 762 } 763 764 765 } 766 767 synchronized (this) { 772 tab = table; 773 } 774 775 e = first = tab[index = hash & (tab.length - 1)]; 776 } else { 777 e = e.next; 778 } 779 } 780 } 781 782 793 public Set keySet() { 794 Set ks = keySet; 795 796 if (ks != null) { 797 return ks; 798 } else { 799 return keySet = new AbstractSet() { 800 public Iterator iterator() { 801 return new KeyIterator(); 802 } 803 804 public int size() { 805 return AbstractConcurrentReadCache.this.size(); 806 } 807 808 public boolean contains(Object o) { 809 return AbstractConcurrentReadCache.this.containsKey(o); 810 } 811 812 public boolean remove(Object o) { 813 return AbstractConcurrentReadCache.this.remove(o) != null; 814 } 815 816 public void clear() { 817 AbstractConcurrentReadCache.this.clear(); 818 } 819 }; 820 } 821 } 822 823 832 public Enumeration keys() { 833 return new KeyIterator(); 834 } 835 836 839 public float loadFactor() { 840 return loadFactor; 841 } 842 843 860 861 public Object put(Object key, Object value) { 862 return put(key, value, true); 864 } 865 866 874 public synchronized void putAll(Map t) { 875 for (Iterator it = t.entrySet().iterator(); it.hasNext();) { 876 Map.Entry entry = (Map.Entry) it.next(); 877 Object key = entry.getKey(); 878 Object value = entry.getValue(); 879 put(key, value); 880 } 881 } 882 883 893 894 public Object remove(Object key) { 895 return remove(key, true, false); 896 } 897 898 905 public Object removeForce(Object key) { 906 return remove(key, true, true); 907 } 908 909 914 public synchronized int size() { 915 return count; 916 } 917 918 929 public Collection values() { 930 Collection vs = values; 931 932 if (vs != null) { 933 return vs; 934 } else { 935 return values = new AbstractCollection() { 936 public Iterator iterator() { 937 return new ValueIterator(); 938 } 939 940 public int size() { 941 return AbstractConcurrentReadCache.this.size(); 942 } 943 944 public boolean contains(Object  |