A cache storage that implements a two-level Most Recently Used cache. In the first level, items are strongly referenced up to the specified maximum. When the maximum is exceeded, the least recently used item is moved into the second level cache, where they are softly referenced, up to another specif
| 89 | * @author Attila Szegedi |
| 90 | */ |
| 91 | public class MruCacheStorage implements CacheStorage |
| 92 | { |
| 93 | private final MruEntry strongHead = new MruEntry(); |
| 94 | private final MruEntry softHead = new MruEntry(); |
| 95 | { |
| 96 | softHead.linkAfter(strongHead); |
| 97 | } |
| 98 | private final Map map = new HashMap(); |
| 99 | private final ReferenceQueue refQueue = new ReferenceQueue(); |
| 100 | private final int maxStrongSize; |
| 101 | private final int maxSoftSize; |
| 102 | private int strongSize = 0; |
| 103 | private int softSize = 0; |
| 104 | |
| 105 | /** |
| 106 | * Creates a new MRU cache storage with specified maximum cache sizes. Each |
| 107 | * cache size can vary between 0 and {@link Integer#MAX_VALUE}. |
| 108 | * @param maxStrongSize the maximum number of strongly referenced templates |
| 109 | * @param maxSoftSize the maximum number of softly referenced templates |
| 110 | */ |
| 111 | public MruCacheStorage(int maxStrongSize, int maxSoftSize) { |
| 112 | if(maxStrongSize < 0) throw new IllegalArgumentException("maxStrongSize < 0"); |
| 113 | if(maxSoftSize < 0) throw new IllegalArgumentException("maxSoftSize < 0"); |
| 114 | this.maxStrongSize = maxStrongSize; |
| 115 | this.maxSoftSize = maxSoftSize; |
| 116 | } |
| 117 | |
| 118 | public Object get(Object key) { |
| 119 | removeClearedReferences(); |
| 120 | MruEntry entry = (MruEntry)map.get(key); |
| 121 | if(entry == null) { |
| 122 | return null; |
| 123 | } |
| 124 | relinkEntryAfterStrongHead(entry, null); |
| 125 | Object value = entry.getValue(); |
| 126 | if(value instanceof MruReference) { |
| 127 | // This can only happen with maxStrongSize == 0 |
| 128 | return ((MruReference)value).get(); |
| 129 | } |
| 130 | return value; |
| 131 | } |
| 132 | |
| 133 | public void put(Object key, Object value) { |
| 134 | removeClearedReferences(); |
| 135 | MruEntry entry = (MruEntry)map.get(key); |
| 136 | if(entry == null) { |
| 137 | entry = new MruEntry(key, value); |
| 138 | map.put(key, entry); |
| 139 | linkAfterStrongHead(entry); |
| 140 | } |
| 141 | else { |
| 142 | relinkEntryAfterStrongHead(entry, value); |
| 143 | } |
| 144 | |
| 145 | } |
| 146 | |
| 147 | public void remove(Object key) { |
| 148 | removeClearedReferences(); |
nothing calls this directly
no test coverage detected
searching dependent graphs…