diff options
Diffstat (limited to 'guava/src/com/google/common/cache/LocalCache.java')
-rw-r--r-- | guava/src/com/google/common/cache/LocalCache.java | 369 |
1 files changed, 170 insertions, 199 deletions
diff --git a/guava/src/com/google/common/cache/LocalCache.java b/guava/src/com/google/common/cache/LocalCache.java index d7c5bd7..4973429 100644 --- a/guava/src/com/google/common/cache/LocalCache.java +++ b/guava/src/com/google/common/cache/LocalCache.java @@ -23,10 +23,9 @@ import static com.google.common.cache.CacheBuilder.UNSET_INT; import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly; import static java.util.concurrent.TimeUnit.NANOSECONDS; -import com.google.common.annotations.GwtCompatible; -import com.google.common.annotations.GwtIncompatible; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Equivalence; +import com.google.common.base.Equivalences; import com.google.common.base.Stopwatch; import com.google.common.base.Ticker; import com.google.common.cache.AbstractCache.SimpleStatsCounter; @@ -35,7 +34,7 @@ import com.google.common.cache.CacheBuilder.NullListener; import com.google.common.cache.CacheBuilder.OneWeigher; import com.google.common.cache.CacheLoader.InvalidCacheLoadException; import com.google.common.cache.CacheLoader.UnsupportedLoadingOperationException; -import com.google.common.collect.AbstractSequentialIterator; +import com.google.common.collect.AbstractLinkedIterator; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterators; import com.google.common.collect.Maps; @@ -48,7 +47,6 @@ import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.UncheckedExecutionException; -import com.google.common.util.concurrent.Uninterruptibles; import java.io.IOException; import java.io.ObjectInputStream; @@ -57,6 +55,7 @@ import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; +import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractQueue; import java.util.AbstractSet; @@ -90,7 +89,6 @@ import javax.annotation.concurrent.GuardedBy; * @author Bob Lee ({@code com.google.common.collect.MapMaker}) * @author Doug Lea ({@code ConcurrentHashMap}) */ -@GwtCompatible(emulated = true) class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> { /* @@ -232,8 +230,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> /** * Creates a new, empty map with the specified strategy, initial capacity and concurrency level. */ - LocalCache( - CacheBuilder<? super K, ? super V> builder, @Nullable CacheLoader<? super K, V> loader) { + LocalCache(CacheBuilder<? super K, ? super V> builder, CacheLoader<? super K, V> loader) { concurrencyLevel = Math.min(builder.getConcurrencyLevel(), MAX_SEGMENTS); keyStrength = builder.getKeyStrength(); @@ -263,15 +260,13 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> initialCapacity = Math.min(initialCapacity, (int) maxWeight); } - // Find the lowest power-of-two segmentCount that exceeds concurrencyLevel, unless - // maximumSize/Weight is specified in which case ensure that each segment gets at least 10 - // entries. The special casing for size-based eviction is only necessary because that eviction - // happens per segment instead of globally, so too many segments compared to the maximum size - // will result in random eviction behavior. + // Find power-of-two sizes best matching arguments. Constraints: + // (segmentCount <= maxWeight) + // && (concurrencyLevel > maxWeight || segmentCount > concurrencyLevel) int segmentShift = 0; int segmentCount = 1; while (segmentCount < concurrencyLevel - && (!evictsBySize() || segmentCount * 20 <= maxWeight)) { + && (!evictsBySize() || customWeigher() || segmentCount * 2 <= maxWeight)) { ++segmentShift; segmentCount <<= 1; } @@ -386,7 +381,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> @Override Equivalence<Object> defaultEquivalence() { - return Equivalence.equals(); + return Equivalences.equals(); } }, @@ -402,7 +397,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> @Override Equivalence<Object> defaultEquivalence() { - return Equivalence.identity(); + return Equivalences.identity(); } }, @@ -418,7 +413,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> @Override Equivalence<Object> defaultEquivalence() { - return Equivalence.identity(); + return Equivalences.identity(); } }; @@ -652,11 +647,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> /** * Creates a copy of this reference for the given entry. - * - * <p>{@code value} may be null only for a loading reference. */ - ValueReference<K, V> copyFor( - ReferenceQueue<V> queue, @Nullable V value, ReferenceEntry<K, V> entry); + ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry); /** * Notifify pending loads that a new value was set. This is only relevant to loading @@ -701,8 +693,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } @Override - public ValueReference<Object, Object> copyFor(ReferenceQueue<Object> queue, - @Nullable Object value, ReferenceEntry<Object, Object> entry) { + public ValueReference<Object, Object> copyFor( + ReferenceQueue<Object> queue, ReferenceEntry<Object, Object> entry) { return this; } @@ -1664,8 +1656,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> @Override public ValueReference<K, V> copyFor( - ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) { - return new WeakValueReference<K, V>(queue, value, entry); + ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) { + return new WeakValueReference<K, V>(queue, get(), entry); } @Override @@ -1710,9 +1702,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> public void notifyNewValue(V newValue) {} @Override - public ValueReference<K, V> copyFor( - ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) { - return new SoftValueReference<K, V>(queue, value, entry); + public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) { + return new SoftValueReference<K, V>(queue, get(), entry); } @Override @@ -1757,8 +1748,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } @Override - public ValueReference<K, V> copyFor( - ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) { + public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) { return this; } @@ -1800,8 +1790,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> @Override public ValueReference<K, V> copyFor( - ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) { - return new WeightedWeakValueReference<K, V>(queue, value, entry, weight); + ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) { + return new WeightedWeakValueReference<K, V>(queue, get(), entry, weight); } } @@ -1822,9 +1812,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> return weight; } @Override - public ValueReference<K, V> copyFor( - ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) { - return new WeightedSoftValueReference<K, V>(queue, value, entry, weight); + public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) { + return new WeightedSoftValueReference<K, V>(queue, get(), entry, weight); } } @@ -1892,10 +1881,10 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> @VisibleForTesting ValueReference<K, V> newValueReference(ReferenceEntry<K, V> entry, V value, int weight) { int hash = entry.getHash(); - return valueStrength.referenceValue(segmentFor(hash), entry, checkNotNull(value), weight); + return valueStrength.referenceValue(segmentFor(hash), entry, value, weight); } - int hash(@Nullable Object key) { + int hash(Object key) { int h = keyEquivalence.hash(key); return rehash(h); } @@ -1964,13 +1953,12 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> * Returns true if the entry has expired. */ boolean isExpired(ReferenceEntry<K, V> entry, long now) { - checkNotNull(entry); if (expiresAfterAccess() - && (now - entry.getAccessTime() >= expireAfterAccessNanos)) { + && (now - entry.getAccessTime() > expireAfterAccessNanos)) { return true; } if (expiresAfterWrite() - && (now - entry.getWriteTime() >= expireAfterWriteNanos)) { + && (now - entry.getWriteTime() > expireAfterWriteNanos)) { return true; } return false; @@ -2150,7 +2138,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> StatsCounter statsCounter) { this.map = map; this.maxSegmentWeight = maxSegmentWeight; - this.statsCounter = checkNotNull(statsCounter); + this.statsCounter = statsCounter; initTable(newEntryArray(initialCapacity)); keyReferenceQueue = map.usesKeyReferences() @@ -2187,29 +2175,14 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> @GuardedBy("Segment.this") ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) { - return map.entryFactory.newEntry(this, checkNotNull(key), hash, next); + return map.entryFactory.newEntry(this, key, hash, next); } - /** - * Copies {@code original} into a new entry chained to {@code newNext}. Returns the new entry, - * or {@code null} if {@code original} was already garbage collected. - */ @GuardedBy("Segment.this") ReferenceEntry<K, V> copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) { - if (original.getKey() == null) { - // key collected - return null; - } - ValueReference<K, V> valueReference = original.getValueReference(); - V value = valueReference.get(); - if ((value == null) && valueReference.isActive()) { - // value collected - return null; - } - ReferenceEntry<K, V> newEntry = map.entryFactory.copyEntry(this, original, newNext); - newEntry.setValueReference(valueReference.copyFor(this.valueReferenceQueue, value, newEntry)); + newEntry.setValueReference(valueReference.copyFor(this.valueReferenceQueue, newEntry)); return newEntry; } @@ -2232,8 +2205,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> // loading V get(K key, int hash, CacheLoader<? super K, V> loader) throws ExecutionException { - checkNotNull(key); - checkNotNull(loader); try { if (count != 0) { // read-volatile // don't call getLiveEntry, which would ignore loading values @@ -2424,9 +2395,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> V scheduleRefresh(ReferenceEntry<K, V> entry, K key, int hash, V oldValue, long now, CacheLoader<? super K, V> loader) { - if (map.refreshes() && (now - entry.getWriteTime() > map.refreshNanos) - && !entry.getValueReference().isLoading()) { - V newValue = refresh(key, hash, loader, true); + if (map.refreshes() && (now - entry.getWriteTime() > map.refreshNanos)) { + V newValue = refresh(key, hash, loader); if (newValue != null) { return newValue; } @@ -2441,9 +2411,9 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> * refresh. */ @Nullable - V refresh(K key, int hash, CacheLoader<? super K, V> loader, boolean checkTime) { + V refresh(K key, int hash, CacheLoader<? super K, V> loader) { final LoadingValueReference<K, V> loadingValueReference = - insertLoadingValueReference(key, hash, checkTime); + insertLoadingValueReference(key, hash); if (loadingValueReference == null) { return null; } @@ -2451,7 +2421,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> ListenableFuture<V> result = loadAsync(key, hash, loadingValueReference, loader); if (result.isDone()) { try { - return Uninterruptibles.getUninterruptibly(result); + return result.get(); } catch (Throwable t) { // don't let refresh exceptions propagate; error was already logged } @@ -2464,8 +2434,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> * is already loading. */ @Nullable - LoadingValueReference<K, V> insertLoadingValueReference(final K key, final int hash, - boolean checkTime) { + LoadingValueReference<K, V> insertLoadingValueReference(final K key, final int hash) { ReferenceEntry<K, V> e = null; lock(); try { @@ -2484,11 +2453,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> // We found an existing entry. ValueReference<K, V> valueReference = e.getValueReference(); - if (valueReference.isLoading() - || (checkTime && (now - e.getWriteTime() < map.refreshNanos))) { + if (valueReference.isLoading()) { // refresh is a no-op if loading is pending - // if checkTime, we want to check *after* acquiring the lock if refresh still needs - // to be scheduled return null; } @@ -3008,14 +2974,14 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> // Clone nodes leading up to the tail. for (ReferenceEntry<K, V> e = head; e != tail; e = e.getNext()) { - int newIndex = e.getHash() & newMask; - ReferenceEntry<K, V> newNext = newTable.get(newIndex); - ReferenceEntry<K, V> newFirst = copyEntry(e, newNext); - if (newFirst != null) { - newTable.set(newIndex, newFirst); - } else { + if (isCollected(e)) { removeCollectedEntry(e); newCount--; + } else { + int newIndex = e.getHash() & newMask; + ReferenceEntry<K, V> newNext = newTable.get(newIndex); + ReferenceEntry<K, V> newFirst = copyEntry(e, newNext); + newTable.set(newIndex, newFirst); } } } @@ -3177,11 +3143,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> preWriteCleanup(now); int newCount = this.count + 1; - if (newCount > this.threshold) { // ensure capacity - expand(); - newCount = this.count + 1; - } - AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; int index = hash & (table.length() - 1); ReferenceEntry<K, V> first = table.get(index); @@ -3192,10 +3153,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> && map.keyEquivalence.equivalent(key, entryKey)) { ValueReference<K, V> valueReference = e.getValueReference(); V entryValue = valueReference.get(); - // replace the old LoadingValueReference if it's live, otherwise - // perform a putIfAbsent - if (oldValueReference == valueReference - || (entryValue == null && valueReference != UNSET)) { + if (entryValue == null || oldValueReference == valueReference) { ++modCount; if (oldValueReference.isActive()) { RemovalCause cause = @@ -3328,12 +3286,11 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> int newCount = count; ReferenceEntry<K, V> newFirst = entry.getNext(); for (ReferenceEntry<K, V> e = first; e != entry; e = e.getNext()) { - ReferenceEntry<K, V> next = copyEntry(e, newFirst); - if (next != null) { - newFirst = next; - } else { + if (isCollected(e)) { removeCollectedEntry(e); newCount--; + } else { + newFirst = copyEntry(e, newFirst); } } this.count = newCount; @@ -3470,6 +3427,18 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } /** + * Returns true if the entry has been partially collected, meaning that either the key is null, + * or the value is active but null. + */ + boolean isCollected(ReferenceEntry<K, V> entry) { + if (entry.getKey() == null) { + return true; + } + ValueReference<K, V> valueReference = entry.getValueReference(); + return (valueReference.get() == null) && valueReference.isActive(); + } + + /** * Performs routine cleanup following a read. Normally cleanup happens during writes. If cleanup * is not observed after a sufficient number of reads, try cleaning up from the read thread. */ @@ -3604,15 +3573,12 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> return newValue != null ? newValue : Futures.<V>immediateFuture(null); } } catch (Throwable t) { - if (t instanceof InterruptedException) { - Thread.currentThread().interrupt(); - } return setException(t) ? futureValue : fullyFailedFuture(t); } } public long elapsedNanos() { - return stopwatch.elapsed(NANOSECONDS); + return stopwatch.elapsedTime(NANOSECONDS); } @Override @@ -3635,8 +3601,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } @Override - public ValueReference<K, V> copyFor( - ReferenceQueue<V> queue, @Nullable V value, ReferenceEntry<K, V> entry) { + public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) { return this; } } @@ -3770,7 +3735,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> @Override public Iterator<ReferenceEntry<K, V>> iterator() { - return new AbstractSequentialIterator<ReferenceEntry<K, V>>(peek()) { + return new AbstractLinkedIterator<ReferenceEntry<K, V>>(peek()) { @Override protected ReferenceEntry<K, V> computeNext(ReferenceEntry<K, V> previous) { ReferenceEntry<K, V> next = previous.getNextInWriteQueue(); @@ -3907,7 +3872,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> @Override public Iterator<ReferenceEntry<K, V>> iterator() { - return new AbstractSequentialIterator<ReferenceEntry<K, V>>(peek()) { + return new AbstractLinkedIterator<ReferenceEntry<K, V>>(peek()) { @Override protected ReferenceEntry<K, V> computeNext(ReferenceEntry<K, V> previous) { ReferenceEntry<K, V> next = previous.getNextInAccessQueue(); @@ -4004,20 +3969,17 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> return get(key, defaultLoader); } - ImmutableMap<K, V> getAllPresent(Iterable<?> keys) { + ImmutableMap<K, V> getAllPresent(Iterable<? extends K> keys) { int hits = 0; int misses = 0; Map<K, V> result = Maps.newLinkedHashMap(); - for (Object key : keys) { + for (K key : keys) { V value = get(key); if (value == null) { misses++; } else { - // TODO(fry): store entry key instead of query key - @SuppressWarnings("unchecked") - K castKey = (K) key; - result.put(castKey, value); + result.put(key, value); hits++; } } @@ -4026,7 +3988,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> return ImmutableMap.copyOf(result); } - ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException { + ImmutableMap<K, V> getAll(Iterable<? extends K> keys) + throws ExecutionException { int hits = 0; int misses = 0; @@ -4078,8 +4041,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> @Nullable Map<K, V> loadAll(Set<? extends K> keys, CacheLoader<? super K, V> loader) throws ExecutionException { - checkNotNull(loader); - checkNotNull(keys); Stopwatch stopwatch = new Stopwatch().start(); Map<K, V> result; boolean success = false; @@ -4091,9 +4052,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } catch (UnsupportedLoadingOperationException e) { success = true; throw e; - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new ExecutionException(e); } catch (RuntimeException e) { throw new UncheckedExecutionException(e); } catch (Exception e) { @@ -4102,12 +4060,12 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> throw new ExecutionError(e); } finally { if (!success) { - globalStatsCounter.recordLoadException(stopwatch.elapsed(NANOSECONDS)); + globalStatsCounter.recordLoadException(stopwatch.elapsedTime(NANOSECONDS)); } } if (result == null) { - globalStatsCounter.recordLoadException(stopwatch.elapsed(NANOSECONDS)); + globalStatsCounter.recordLoadException(stopwatch.elapsedTime(NANOSECONDS)); throw new InvalidCacheLoadException(loader + " returned null map from loadAll"); } @@ -4126,12 +4084,12 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } if (nullsPresent) { - globalStatsCounter.recordLoadException(stopwatch.elapsed(NANOSECONDS)); + globalStatsCounter.recordLoadException(stopwatch.elapsedTime(NANOSECONDS)); throw new InvalidCacheLoadException(loader + " returned null keys or values from loadAll"); } // TODO(fry): record count of loaded entries - globalStatsCounter.recordLoadSuccess(stopwatch.elapsed(NANOSECONDS)); + globalStatsCounter.recordLoadSuccess(stopwatch.elapsedTime(NANOSECONDS)); return result; } @@ -4148,9 +4106,21 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> return segmentFor(hash).getEntry(key, hash); } + /** + * Returns the live internal entry for the specified key. + */ + ReferenceEntry<K, V> getLiveEntry(@Nullable Object key) { + // does not impact recency ordering + if (key == null) { + return null; + } + int hash = hash(key); + return segmentFor(hash).getLiveEntry(key, hash, ticker.read()); + } + void refresh(K key) { int hash = hash(checkNotNull(key)); - segmentFor(hash).refresh(key, hash, defaultLoader, false); + segmentFor(hash).refresh(key, hash, defaultLoader); } @Override @@ -4284,7 +4254,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> public Set<K> keySet() { // does not impact recency ordering Set<K> ks = keySet; - return (ks != null) ? ks : (keySet = new KeySet(this)); + return (ks != null) ? ks : (keySet = new KeySet()); } Collection<V> values; @@ -4293,22 +4263,21 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> public Collection<V> values() { // does not impact recency ordering Collection<V> vs = values; - return (vs != null) ? vs : (values = new Values(this)); + return (vs != null) ? vs : (values = new Values()); } Set<Entry<K, V>> entrySet; @Override - @GwtIncompatible("Not supported.") public Set<Entry<K, V>> entrySet() { // does not impact recency ordering Set<Entry<K, V>> es = entrySet; - return (es != null) ? es : (entrySet = new EntrySet(this)); + return (es != null) ? es : (entrySet = new EntrySet()); } // Iterator Support - abstract class HashIterator<T> implements Iterator<T> { + abstract class HashIterator { int nextSegmentIndex; int nextTableIndex; @@ -4324,9 +4293,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> advance(); } - @Override - public abstract T next(); - final void advance() { nextExternal = null; @@ -4399,7 +4365,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } } - @Override public boolean hasNext() { return nextExternal != null; } @@ -4413,7 +4378,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> return lastReturned; } - @Override public void remove() { checkState(lastReturned != null); LocalCache.this.remove(lastReturned.getKey()); @@ -4421,7 +4385,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } } - final class KeyIterator extends HashIterator<K> { + final class KeyIterator extends HashIterator implements Iterator<K> { @Override public K next() { @@ -4429,7 +4393,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } } - final class ValueIterator extends HashIterator<V> { + final class ValueIterator extends HashIterator implements Iterator<V> { @Override public V next() { @@ -4489,7 +4453,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } } - final class EntryIterator extends HashIterator<Entry<K, V>> { + final class EntryIterator extends HashIterator implements Iterator<Entry<K, V>> { @Override public Entry<K, V> next() { @@ -4497,73 +4461,68 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } } - abstract class AbstractCacheSet<T> extends AbstractSet<T> { - final ConcurrentMap<?, ?> map; + final class KeySet extends AbstractSet<K> { - AbstractCacheSet(ConcurrentMap<?, ?> map) { - this.map = map; + @Override + public Iterator<K> iterator() { + return new KeyIterator(); } @Override public int size() { - return map.size(); + return LocalCache.this.size(); } @Override public boolean isEmpty() { - return map.isEmpty(); + return LocalCache.this.isEmpty(); } @Override - public void clear() { - map.clear(); + public boolean contains(Object o) { + return LocalCache.this.containsKey(o); } - } - final class KeySet extends AbstractCacheSet<K> { - - KeySet(ConcurrentMap<?, ?> map) { - super(map); + @Override + public boolean remove(Object o) { + return LocalCache.this.remove(o) != null; } @Override - public Iterator<K> iterator() { - return new KeyIterator(); + public void clear() { + LocalCache.this.clear(); } + } + + final class Values extends AbstractCollection<V> { @Override - public boolean contains(Object o) { - return map.containsKey(o); + public Iterator<V> iterator() { + return new ValueIterator(); } @Override - public boolean remove(Object o) { - return map.remove(o) != null; + public int size() { + return LocalCache.this.size(); } - } - - final class Values extends AbstractCacheSet<V> { - Values(ConcurrentMap<?, ?> map) { - super(map); + @Override + public boolean isEmpty() { + return LocalCache.this.isEmpty(); } @Override - public Iterator<V> iterator() { - return new ValueIterator(); + public boolean contains(Object o) { + return LocalCache.this.containsValue(o); } @Override - public boolean contains(Object o) { - return map.containsValue(o); + public void clear() { + LocalCache.this.clear(); } } - final class EntrySet extends AbstractCacheSet<Entry<K, V>> { - - EntrySet(ConcurrentMap<?, ?> map) { - super(map); - } + final class EntrySet extends AbstractSet<Entry<K, V>> { @Override public Iterator<Entry<K, V>> iterator() { @@ -4594,6 +4553,21 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> Object key = e.getKey(); return key != null && LocalCache.this.remove(key, e.getValue()); } + + @Override + public int size() { + return LocalCache.this.size(); + } + + @Override + public boolean isEmpty() { + return LocalCache.this.isEmpty(); + } + + @Override + public void clear() { + LocalCache.this.clear(); + } } // Serialization Support @@ -4663,15 +4637,15 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> this.loader = loader; } - CacheBuilder<K, V> recreateCacheBuilder() { - CacheBuilder<K, V> builder = CacheBuilder.newBuilder() + CacheBuilder<Object, Object> recreateCacheBuilder() { + CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder() .setKeyStrength(keyStrength) .setValueStrength(valueStrength) .keyEquivalence(keyEquivalence) .valueEquivalence(valueEquivalence) - .concurrencyLevel(concurrencyLevel) - .removalListener(removalListener); + .concurrencyLevel(concurrencyLevel); builder.strictParsing = false; + builder.removalListener(removalListener); if (expireAfterWriteNanos > 0) { builder.expireAfterWrite(expireAfterWriteNanos, TimeUnit.NANOSECONDS); } @@ -4696,7 +4670,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); - CacheBuilder<K, V> builder = recreateCacheBuilder(); + CacheBuilder<Object, Object> builder = recreateCacheBuilder(); this.delegate = builder.build(); } @@ -4730,7 +4704,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); - CacheBuilder<K, V> builder = recreateCacheBuilder(); + CacheBuilder<Object, Object> builder = recreateCacheBuilder(); this.autoDelegate = builder.build(loader); } @@ -4768,18 +4742,19 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> final LocalCache<K, V> localCache; LocalManualCache(CacheBuilder<? super K, ? super V> builder) { - this(new LocalCache<K, V>(builder, null)); + this(builder, null); } - private LocalManualCache(LocalCache<K, V> localCache) { - this.localCache = localCache; + protected LocalManualCache(CacheBuilder<? super K, ? super V> builder, + CacheLoader<? super K, V> loader) { + this.localCache = new LocalCache<K, V>(builder, loader); } // Cache methods @Override @Nullable - public V getIfPresent(Object key) { + public V getIfPresent(K key) { return localCache.getIfPresent(key); } @@ -4795,7 +4770,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } @Override - public ImmutableMap<K, V> getAllPresent(Iterable<?> keys) { + public ImmutableMap<K, V> getAllPresent(Iterable<? extends K> keys) { return localCache.getAllPresent(keys); } @@ -4805,11 +4780,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> } @Override - public void putAll(Map<? extends K, ? extends V> m) { - localCache.putAll(m); - } - - @Override public void invalidate(Object key) { checkNotNull(key); localCache.remove(key); @@ -4850,6 +4820,27 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> localCache.cleanUp(); } + /* + * These methods have been moved to LoadingCache, but they temporarily + * remain in Cache in Guava. + */ + + public V get(K key) throws ExecutionException { + return localCache.getOrLoad(key); + } + + public V getUnchecked(K key) { + try { + return get(key); + } catch (ExecutionException e) { + throw new UncheckedExecutionException(e.getCause()); + } + } + + public final V apply(K key) { + return getUnchecked(key); + } + // Serialization Support private static final long serialVersionUID = 1; @@ -4864,24 +4855,10 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> LocalLoadingCache(CacheBuilder<? super K, ? super V> builder, CacheLoader<? super K, V> loader) { - super(new LocalCache<K, V>(builder, checkNotNull(loader))); + super(builder, checkNotNull(loader)); } - // LoadingCache methods - - @Override - public V get(K key) throws ExecutionException { - return localCache.getOrLoad(key); - } - - @Override - public V getUnchecked(K key) { - try { - return get(key); - } catch (ExecutionException e) { - throw new UncheckedExecutionException(e.getCause()); - } - } + // Cache methods @Override public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException { @@ -4893,16 +4870,10 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> localCache.refresh(key); } - @Override - public final V apply(K key) { - return getUnchecked(key); - } - // Serialization Support private static final long serialVersionUID = 1; - @Override Object writeReplace() { return new LoadingSerializationProxy<K, V>(localCache); } |