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 o) { 945 return AbstractConcurrentReadCache.this.containsValue(o); 946 } 947 948 public void clear() { 949 AbstractConcurrentReadCache.this.clear(); 950 } 951 }; 952 } 953 } 954 955 963 protected synchronized final Set getGroupForReading(String groupName) { 964 Set group = (Set) getGroupsForReading().get(groupName); 965 if (group == null) return null; 966 return new HashSet(group); 967 } 968 969 975 protected final Map getGroupsForReading() { 976 synchronized (barrierLock) { 977 return groups; 978 } 979 } 980 981 986 protected final Entry[] getTableForReading() { 987 synchronized (barrierLock) { 988 return table; 989 } 990 } 991 992 997 protected final void recordModification(Object x) { 998 synchronized (barrierLock) { 999 lastWrite = x; 1000 } 1001 } 1002 1003 1006 protected synchronized boolean findAndRemoveEntry(Map.Entry entry) { 1007 Object key = entry.getKey(); 1008 Object v = get(key); 1009 1010 if ((v != null) && v.equals(entry.getValue())) { 1011 remove(key); 1012 1013 return true; 1014 } else { 1015 return false; 1016 } 1017 } 1018 1019 1023 protected void persistRemove(Object key) { 1024 if (log.isDebugEnabled()) { 1025 log.debug("PersistRemove called (key=" + key + ")"); 1026 } 1027 1028 if (persistenceListener != null) { 1029 try { 1030 persistenceListener.remove((String ) key); 1031 } catch (CachePersistenceException e) { 1032 log.error("[oscache] Exception removing cache entry with key '" + key + "' from persistence", e); 1033 } 1034 } 1035 } 1036 1037 1041 protected void persistRemoveGroup(String groupName) { 1042 if (log.isDebugEnabled()) { 1043 log.debug("persistRemoveGroup called (groupName=" + groupName + ")"); 1044 } 1045 1046 if (persistenceListener != null) { 1047 try { 1048 persistenceListener.removeGroup(groupName); 1049 } catch (CachePersistenceException e) { 1050 log.error("[oscache] Exception removing group " + groupName, e); 1051 } 1052 } 1053 } 1054 1055 1059 protected Object persistRetrieve(Object key) { 1060 if (log.isDebugEnabled()) { 1061 log.debug("persistRetrieve called (key=" + key + ")"); 1062 } 1063 1064 Object entry = null; 1065 1066 if (persistenceListener != null) { 1067 try { 1068 entry = persistenceListener.retrieve((String ) key); 1069 } catch (CachePersistenceException e) { 1070 1075 } 1076 } 1077 1078 return entry; 1079 } 1080 1081 1085 protected Set persistRetrieveGroup(String groupName) { 1086 if (log.isDebugEnabled()) { 1087 log.debug("persistRetrieveGroup called (groupName=" + groupName + ")"); 1088 } 1089 1090 if (persistenceListener != null) { 1091 try { 1092 return persistenceListener.retrieveGroup(groupName); 1093 } catch (CachePersistenceException e) { 1094 log.error("[oscache] Exception retrieving group " + groupName, e); 1095 } 1096 } 1097 1098 return null; 1099 } 1100 1101 1106 protected void persistStore(Object key, Object obj) { 1107 if (log.isDebugEnabled()) { 1108 log.debug("persistStore called (key=" + key + ")"); 1109 } 1110 1111 if (persistenceListener != null) { 1112 try { 1113 persistenceListener.store((String ) key, obj); 1114 } catch (CachePersistenceException e) { 1115 log.error("[oscache] Exception persisting " + key, e); 1116 } 1117 } 1118 } 1119 1120 1125 protected void persistStoreGroup(String groupName, Set group) { 1126 if (log.isDebugEnabled()) { 1127 log.debug("persistStoreGroup called (groupName=" + groupName + ")"); 1128 } 1129 1130 if (persistenceListener != null) { 1131 try { 1132 if ((group == null) || group.isEmpty()) { 1133 persistenceListener.removeGroup(groupName); 1134 } else { 1135 persistenceListener.storeGroup(groupName, group); 1136 } 1137 } catch (CachePersistenceException e) { 1138 log.error("[oscache] Exception persisting group " + groupName, e); 1139 } 1140 } 1141 } 1142 1143 1146 protected void persistClear() { 1147 if (log.isDebugEnabled()) { 1148 log.debug("persistClear called"); 1149 ; 1150 } 1151 1152 if (persistenceListener != null) { 1153 try { 1154 persistenceListener.clear(); 1155 } catch (CachePersistenceException e) { 1156 log.error("[oscache] Exception clearing persistent cache", e); 1157 } 1158 } 1159 } 1160 1161 1166 protected abstract void itemPut(Object key); 1167 1168 1173 protected abstract void itemRetrieved(Object key); 1174 1175 1180 protected abstract void itemRemoved(Object key); 1181 1182 1188 protected abstract Object removeItem(); 1189 1190 1195 private synchronized void readObject(java.io.ObjectInputStream s) throws IOException , ClassNotFoundException { 1196 s.defaultReadObject(); 1198 1199 int numBuckets = s.readInt(); 1201 table = new Entry[numBuckets]; 1202 1203 int size = s.readInt(); 1205 1206 for (int i = 0; i < size; i++) { 1208 Object key = s.readObject(); 1209 Object value = s.readObject(); 1210 put(key, value); 1211 } 1212 } 1213 1214 1219 protected void rehash() { 1220 Entry[] oldMap = table; 1221 int oldCapacity = oldMap.length; 1222 1223 if (oldCapacity >= MAXIMUM_CAPACITY) { 1224 return; 1225 } 1226 1227 int newCapacity = oldCapacity << 1; 1228 Entry[] newMap = new Entry[newCapacity]; 1229 threshold = (int) (newCapacity * loadFactor); 1230 1231 1242 for (int i = 0; i < oldCapacity; ++i) { 1243 Entry l = null; 1244 Entry h = null; 1245 Entry e = oldMap[i]; 1246 1247 while (e != null) { 1248 int hash = e.hash; 1249 Entry next = e.next; 1250 1251 if ((hash & oldCapacity) == 0) { 1252 if (l == null) { 1254 if ((next == null) || ((next.next == null) && ((next.hash & oldCapacity) == 0))) { 1256 l = e; 1257 1258 break; 1259 } 1260 } 1261 1262 l = new Entry(hash, e.key, e.value, l); 1263 } else { 1264 if (h == null) { 1266 if ((next == null) || ((next.next == null) && ((next.hash & oldCapacity) != 0))) { 1267 h = e; 1268 1269 break; 1270 } 1271 } 1272 1273 h = new Entry(hash, e.key, e.value, h); 1274 } 1275 1276 e = next; 1277 } 1278 1279 newMap[i] = l; 1280 newMap[oldCapacity + i] = h; 1281 } 1282 1283 table = newMap; 1284 recordModification(newMap); 1285 } 1286 1287 1291 1292 1293 1295 protected Object sput(Object key, Object value, int hash, boolean persist) { 1296 1297 Entry[] tab = table; 1298 int index = hash & (tab.length - 1); 1299 Entry first = tab[index]; 1300 Entry e = first; 1301 1302 for (;;) { 1303 if (e == null) { 1304 1305 1306 Entry newEntry; 1309 1310 if (memoryCaching) { 1311 newEntry = new Entry(hash, key, value, first); 1312 } else { 1313 newEntry = new Entry(hash, key, NULL, first); 1314 } 1315 1316 itemPut(key); 1317 1318 if (persist && !overflowPersistence) { 1320 persistStore(key, value); 1321 } 1322 1323 if (value instanceof CacheEntry) { 1325 updateGroups(null, (CacheEntry) value, persist); 1326 } 1327 1328 1329 tab[index] = newEntry; 1330 1331 if (++count >= threshold) { 1332 rehash(); 1333 } else { 1334 recordModification(newEntry); 1335 } 1336 1337 return null; 1338 } else if ((key == e.key) || ((e.hash == hash) && key.equals(e.key))) { 1339 Object oldValue = e.value; 1340 1341 1342 1343 1345 if (memoryCaching) { 1346 e.value = value; 1347 } 1348 1349 if (persist && overflowPersistence) { 1351 persistRemove(key); 1352 } else if (persist) { 1353 persistStore(key, value); 1354 } 1355 1356 updateGroups(oldValue, value, persist); 1357 1358 itemPut(key); 1359 1360 1361 return oldValue; 1362 } else { 1363 e = e.next; 1364 } 1365 } 1366 } 1367 1368 1372 1373 1374 1376 protected Object sremove(Object key, int hash, boolean invokeAlgorithm) { 1377 1378 Entry[] tab = table; 1379 int index = hash & (tab.length - 1); 1380 Entry first = tab[index]; 1381 Entry e = first; 1382 1383 for (;;) { 1384 if (e == null) { 1385 return null; 1386 } else if ((key == e.key) || ((e.hash == hash) && key.equals(e.key))) { 1387 Object oldValue = e.value; 1388 if (persistenceListener != null && (oldValue == NULL)) { 1389 oldValue = persistRetrieve(key); 1390 } 1391 1392 e.value = null; 1393 count--; 1394 1395 1396 if (!unlimitedDiskCache && !overflowPersistence) { 1397 persistRemove(e.key); 1398 if (oldValue instanceof CacheEntry) { 1400 CacheEntry oldEntry = (CacheEntry)oldValue; 1401 removeGroupMappings(oldEntry.getKey(), 1402 oldEntry.getGroups(), true); 1403 } 1404 } else { 1405 if (oldValue instanceof CacheEntry) { 1407 CacheEntry oldEntry = (CacheEntry)oldValue; 1408 removeGroupMappings(oldEntry.getKey(), 1409 oldEntry.getGroups(), false); 1410 } 1411 } 1412 1413 if (overflowPersistence && ((size() + 1) >= maxEntries)) { 1414 persistStore(key, oldValue); 1415 if (oldValue instanceof CacheEntry) { 1417 CacheEntry oldEntry = (CacheEntry)oldValue; 1418 addGroupMappings(oldEntry.getKey(), oldEntry.getGroups(), true, false); 1419 } 1420 } 1421 1422 if (invokeAlgorithm) { 1423 itemRemoved(key); 1424 } 1425 1426 1427 Entry head = e.next; 1428 1429 for (Entry p = first; p != e; p = p.next) { 1430 head = new Entry(p.hash, p.key, p.value, head); 1431 } 1432 1433 tab[index] = head; 1434 recordModification(head); 1435 1436 return oldValue; 1437 } else { 1438 e = e.next; 1439 } 1440 } 1441 } 1442 1443 1455 private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { 1456 s.defaultWriteObject(); 1458 1459 s.writeInt(table.length); 1461 1462 s.writeInt(count); 1464 1465 for (int index = table.length - 1; index >= 0; index--) { 1467 Entry entry = table[index]; 1468 1469 while (entry != null) { 1470 s.writeObject(entry.key); 1471 s.writeObject(entry.value); 1472 entry = entry.next; 1473 } 1474 } 1475 } 1476 1477 1483 private static int hash(Object x) { 1484 int h = x.hashCode(); 1485 1486 return ((h << 7) - h + (h >>> 9) + (h >>> 17)); 1490 } 1491 1492 1506 private void addGroupMappings(String key, Set newGroups, boolean persist, boolean memory) { 1507 for (Iterator it = newGroups.iterator(); it.hasNext();) { 1509 String groupName = (String ) it.next(); 1510 1511 if (memoryCaching && memory) { 1513 if (groups == null) { 1514 groups = new HashMap(); 1515 } 1516 1517 Set memoryGroup = (Set) groups.get(groupName); 1518 1519 if (memoryGroup == null) { 1520 memoryGroup = new HashSet(); 1521 groups.put(groupName, memoryGroup); 1522 } 1523 1524 memoryGroup.add(key); 1525 } 1526 1527 if (persist) { 1529 Set persistentGroup = persistRetrieveGroup(groupName); 1530 1531 if (persistentGroup == null) { 1532 persistentGroup = new HashSet(); 1533 } 1534 1535 persistentGroup.add(key); 1536 persistStoreGroup(groupName, persistentGroup); 1537 } 1538 } 1539 } 1540 1541 1542 1546 private int p2capacity(int initialCapacity) { 1547 int cap = initialCapacity; 1548 1549 int result; 1551 1552 if ((cap > MAXIMUM_CAPACITY) || (cap < 0)) { 1553 result = MAXIMUM_CAPACITY; 1554 } else { 1555 result = MINIMUM_CAPACITY; 1556 1557 while (result < cap) { 1558 result <<= 1; 1559 } 1560 } 1561 1562 return result; 1563 } 1564 1565 1567 private Object put(Object key, Object value, boolean persist) { 1568 1569 if (value == null) { 1570 throw new NullPointerException (); 1571 } 1572 1573 int hash = hash(key); 1574 Entry[] tab = table; 1575 int index = hash & (tab.length - 1); 1576 Entry first = tab[index]; 1577 Entry e = first; 1578 1579 for (;;) { 1580 if (e == null) { 1581 synchronized (this) { 1582 tab = table; 1583 1584 1585 1586 1588 1595 1596 if (size() >= maxEntries) { 1598 remove(removeItem(), false, false); 1599 } 1600 1601 if (first == tab[index]) { 1602 Entry newEntry = null; 1604 1605 if (memoryCaching) { 1606 newEntry = new Entry(hash, key, value, first); 1607 } else { 1608 newEntry = new Entry(hash, key, NULL, first); 1609 } 1610 1611 tab[index] = newEntry; 1612 itemPut(key); 1613 1614 if (persist && !overflowPersistence) { 1616 persistStore(key, value); 1617 } 1618 1619 if (value instanceof CacheEntry) { 1621 updateGroups(null, (CacheEntry) value, persist); 1622 } 1623 1624 if (++count >= threshold) { 1625 rehash(); 1626 } else { 1627 recordModification(newEntry); 1628 } 1629 1630 return newEntry; 1631 1632 1633 } else { 1634 1636 1637 1638 1640 return sput(key, value, hash, persist); 1641 1642 1643 } 1644 } 1645 } else if ((key == e.key) || ((e.hash == hash) && key.equals(e.key))) { 1646 synchronized (this) { 1649 tab = table; 1650 1651 Object oldValue = e.value; 1652 1653 if (persist && (oldValue == NULL)) { 1655 oldValue = persistRetrieve(key); 1656 } 1657 1658 if ((first == tab[index]) && (oldValue != null)) { 1659 1660 1661 1664 if (memoryCaching) { 1665 e.value = value; 1666 } 1667 1668 if (persist && overflowPersistence) { 1670 persistRemove(key); 1671 } else if (persist) { 1672 persistStore(key, value); 1673 } 1674 1675 updateGroups(oldValue, value, persist); 1676 itemPut(key); 1677 1678 return oldValue; 1679 1680 1681 } else { 1682 1684 1685 1686 1688 return sput(key, value, hash, persist); 1689 1690 1691 } 1692 } 1693 } else { 1694 e = e.next; 1695 } 1696 } 1697 } 1698 1699 private synchronized Object remove(Object key, boolean invokeAlgorithm, boolean forcePersist) 1700 1702 1703 { 1704 1715 1716 1717 if (key == null) { 1718 return null; 1719 } 1720 1721 1722 int hash = hash(key); 1723 Entry[] tab = table; 1724 int index = hash & (tab.length - 1); 1725 Entry first = tab[index]; 1726 Entry e = first; 1727 1728 for (;;) { 1729 if (e == null) { 1730 tab = getTableForReading(); 1731 1732 if (first == tab[index]) { 1733 return null; 1734 } else { 1735 1737 1738 1739 1741 return sremove(key, hash, invokeAlgorithm); 1742 1743 1744 } 1745 } else if ((key == e.key) || ((e.hash == hash) && key.equals(e.key))) { 1746 synchronized (this) { 1747 tab = table; 1748 1749 Object oldValue = e.value; 1750 if (persistenceListener != null && (oldValue == NULL)) { 1751 oldValue = persistRetrieve(key); 1752 } 1753 1754 if ((first != tab[index]) || (oldValue == null)) { 1756 1757 1758 1760 return sremove(key, hash, invokeAlgorithm); 1761 } 1762 1763 1764 e.value = null; 1765 count--; 1766 1767 1768 if (forcePersist || (!unlimitedDiskCache && !overflowPersistence)) { 1769 persistRemove(e.key); 1770 if (oldValue instanceof CacheEntry) { 1772 CacheEntry oldEntry = (CacheEntry)oldValue; 1773 removeGroupMappings(oldEntry.getKey(), 1774 oldEntry.getGroups(), true); 1775 } 1776 } else { 1777 if (oldValue instanceof CacheEntry) { 1779 CacheEntry oldEntry = (CacheEntry)oldValue; 1780 removeGroupMappings(oldEntry.getKey(), 1781 oldEntry.getGroups(), false); 1782 } 1783 } 1784 1785 if (!forcePersist && overflowPersistence && ((size() + 1) >= maxEntries)) { 1786 persistStore(key, oldValue); 1787 if (oldValue instanceof CacheEntry) { 1789 CacheEntry oldEntry = (CacheEntry)oldValue; 1790 addGroupMappings(oldEntry.getKey(), oldEntry.getGroups(), true, false); 1791 } 1792 } 1793 1794 if (invokeAlgorithm) { 1795 itemRemoved(key); 1796 } 1797 1798 1799 Entry head = e.next; 1800 1801 for (Entry p = first; p != e; p = p.next) { 1802 head = new Entry(p.hash, p.key, p.value, head); 1803 } 1804 1805 tab[index] = head; 1806 recordModification(head); 1807 1808 return oldValue; 1809 } 1810 } else { 1811 e = e.next; 1812 } 1813 } 1814 } 1815 1816 1829 private void removeGroupMappings(String key, Set oldGroups, boolean persist) { 1830 if (oldGroups == null) { 1831 return; 1832 } 1833 1834 for (Iterator it = oldGroups.iterator(); it.hasNext();) { 1835 String groupName = (String ) it.next(); 1836 1837 if (memoryCaching && (this.groups != null)) { 1839 Set memoryGroup = (Set) groups.get(groupName); 1840 1841 if (memoryGroup != null) { 1842 memoryGroup.remove(key); 1843 1844 if (memoryGroup.isEmpty()) { 1845 groups.remove(groupName); 1846 } 1847 } 1848 } 1849 1850 if (persist) { 1852 Set persistentGroup = persistRetrieveGroup(groupName); 1853 1854 if (persistentGroup != null) { 1855 persistentGroup.remove(key); 1856 1857 if (persistentGroup.isEmpty()) { 1858 persistRemoveGroup(groupName); 1859 } else { 1860 persistStoreGroup(groupName, persistentGroup); 1861 } 1862 } 1863 } 1864 } 1865 } 1866 1867 1876 private void updateGroups(Object oldValue, Object newValue, boolean persist) { 1877 boolean oldIsCE = oldValue instanceof CacheEntry; 1879 boolean newIsCE = newValue instanceof CacheEntry; 1880 1881 if (newIsCE && oldIsCE) { 1882 updateGroups((CacheEntry) oldValue, (CacheEntry) newValue, persist); 1883 } else if (newIsCE) { 1884 updateGroups(null, (CacheEntry) newValue, persist); 1885 } else if (oldIsCE) { 1886 updateGroups((CacheEntry) oldValue, null, persist); 1887 } 1888 } 1889 1890 1899 private void updateGroups(CacheEntry oldValue, CacheEntry newValue, boolean persist) { 1900 Set oldGroups = null; 1901 Set newGroups = null; 1902 1903 if (oldValue != null) { 1904 oldGroups = oldValue.getGroups(); 1905 } 1906 1907 if (newValue != null) { 1908 newGroups = newValue.getGroups(); 1909 } 1910 1911 if (oldGroups != null) { 1913 Set removeFromGroups = new HashSet(); 1914 1915 for (Iterator it = oldGroups.iterator(); it.hasNext();) { 1916 String groupName = (String ) it.next(); 1917 1918 if ((newGroups == null) || !newGroups.contains(groupName)) { 1919 removeFromGroups.add(groupName); 1921 } 1922 } 1923 1924 removeGroupMappings(oldValue.getKey(), removeFromGroups, persist); 1925 } 1926 1927 if (newGroups != null) { 1929 Set addToGroups = new HashSet(); 1930 1931 for (Iterator it = newGroups.iterator(); it.hasNext();) { 1932 String groupName = (String ) it.next(); 1933 1934 if ((oldGroups == null) || !oldGroups.contains(groupName)) { 1935 addToGroups.add(groupName); 1937 } 1938 } 1939 1940 addGroupMappings(newValue.getKey(), addToGroups, persist, true); 1941 } 1942 } 1943 1944 1947 protected static class Entry implements Map.Entry { 1948 protected final Entry next; 1949 protected final Object key; 1950 1951 1957 protected final int hash; 1958 protected volatile Object value; 1959 1960 Entry(int hash, Object key, Object value, Entry next) { 1961 this.hash = hash; 1962 this.key = key; 1963 this.next = next; 1964 this.value = value; 1965 } 1966 1967 public Object getKey() { 1969 return key; 1970 } 1971 1972 1993 public Object setValue(Object value) { 1994 if (value == null) { 1995 throw new NullPointerException (); 1996 } 1997 1998 Object oldValue = this.value; 1999 this.value = value; 2000 2001 return oldValue; 2002 } 2003 2004 2017 public Object getValue() { 2018 return value; 2019 } 2020 2021 public boolean equals(Object o) { 2022 if (!(o instanceof Map.Entry)) { 2023 return false; 2024 } 2025 2026 Map.Entry e = (Map.Entry) o; 2027 2028 if (!key.equals(e.getKey())) { 2029 return false; 2030 } 2031 2032 Object v = value; 2033 2034 return (v == null) ? (e.getValue() == null) : v.equals(e.getValue()); 2035 } 2036 2037 public int hashCode() { 2038 Object v = value; 2039 2040 return hash ^ ((v == null) ? 0 : v.hashCode()); 2041 } 2042 2043 public String toString() { 2044 return key + "=" + value; 2045 } 2046 2047 protected Object clone() { 2048 return new Entry(hash, key, value, ((next == null) ? null : (Entry) next.clone())); 2049 } 2050 } 2051 2052 protected class HashIterator implements Iterator, Enumeration { 2053 protected final Entry[] tab; protected Entry entry = null; protected Entry lastReturned = null; protected Object currentKey; protected Object currentValue; protected int index; 2060 protected HashIterator() { 2061 tab = AbstractConcurrentReadCache.this.getTableForReading(); 2062 index = tab.length - 1; 2063 } 2064 2065 public boolean hasMoreElements() { 2066 return hasNext(); 2067 } 2068 2069 public boolean hasNext() { 2070 2077 for (;;) { 2078 if (entry != null) { 2079 Object v = entry.value; 2080 2081 if (v != null) { 2082 currentKey = entry.key; 2083 currentValue = v; 2084 2085 return true; 2086 } else { 2087 entry = entry.next; 2088 } 2089 } 2090 2091 while ((entry == null) && (index >= 0)) { 2092 entry = tab[index--]; 2093 } 2094 2095 if (entry == null) { 2096 currentKey = currentValue = null; 2097 2098 return false; 2099 } 2100 } 2101 } 2102 2103 public Object next() { 2104 if ((currentKey == null) && !hasNext()) { 2105 throw new NoSuchElementException(); 2106 } 2107 2108 Object result = returnValueOfNext(); 2109 lastReturned = entry; 2110 currentKey = currentValue = null; 2111 entry = entry.next; 2112 2113 return result; 2114 } 2115 2116 public Object nextElement() { 2117 return next(); 2118 } 2119 2120 public void remove() { 2121 if (lastReturned == null) { 2122 throw new IllegalStateException (); 2123 } 2124 2125 AbstractConcurrentReadCache.this.remove(lastReturned.key); 2126 } 2127 2128 protected Object returnValueOfNext() { 2129 return entry; 2130 } 2131 } 2132 2133 protected class KeyIterator extends HashIterator { 2134 protected Object returnValueOfNext() { 2135 return currentKey; 2136 } 2137 } 2138 2139 protected class ValueIterator extends HashIterator { 2140 protected Object returnValueOfNext() { 2141 return currentValue; 2142 } 2143 } 2144} 2145 | Popular Tags |