diff options
Diffstat (limited to 'guava/src/com/google/common/cache')
20 files changed, 406 insertions, 1618 deletions
diff --git a/guava/src/com/google/common/cache/AbstractCache.java b/guava/src/com/google/common/cache/AbstractCache.java index a8af810..8ce941d 100644 --- a/guava/src/com/google/common/cache/AbstractCache.java +++ b/guava/src/com/google/common/cache/AbstractCache.java @@ -20,21 +20,22 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; +import com.google.common.util.concurrent.UncheckedExecutionException; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicLong; /** * This class provides a skeletal implementation of the {@code Cache} interface to minimize the * effort required to implement this interface. * * <p>To implement a cache, the programmer needs only to extend this class and provide an - * implementation for the {@link #put} and {@link #getIfPresent} methods. {@link #getAllPresent} is - * implemented in terms of {@link #getIfPresent}; {@link #putAll} is implemented in terms of - * {@link #put}, {@link #invalidateAll(Iterable)} is implemented in terms of {@link #invalidate}. - * The method {@link #cleanUp} is a no-op. All other methods throw an + * implementation for the {@link #getIfPresent} method. {@link #getAllPresent} is implemented in + * terms of {@code getIfPresent}; {@link #invalidateAll(Iterable)} is implemented in terms of + * {@link #invalidate}. The method {@link #cleanUp} is a no-op. All other methods throw an * {@link UnsupportedOperationException}. * * @author Charles Fry @@ -56,22 +57,14 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> { } /** - * This implementation of {@code getAllPresent} lacks any insight into the internal cache data - * structure, and is thus forced to return the query keys instead of the cached keys. This is only - * possible with an unsafe cast which requires {@code keys} to actually be of type {@code K}. - * - * {@inheritDoc} - * * @since 11.0 */ @Override - public ImmutableMap<K, V> getAllPresent(Iterable<?> keys) { + public ImmutableMap<K, V> getAllPresent(Iterable<? extends K> keys) { Map<K, V> result = Maps.newLinkedHashMap(); - for (Object key : keys) { + for (K key : keys) { if (!result.containsKey(key)) { - @SuppressWarnings("unchecked") - K castKey = (K) key; - result.put(castKey, getIfPresent(key)); + result.put(key, getIfPresent(key)); } } return ImmutableMap.copyOf(result); @@ -85,16 +78,6 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> { throw new UnsupportedOperationException(); } - /** - * @since 12.0 - */ - @Override - public void putAll(Map<? extends K, ? extends V> m) { - for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) { - put(entry.getKey(), entry.getValue()); - } - } - @Override public void cleanUp() {} @@ -133,6 +116,22 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> { throw new UnsupportedOperationException(); } + @Deprecated + @Override + public V getUnchecked(K key) { + try { + return get(key); + } catch (ExecutionException e) { + throw new UncheckedExecutionException(e.getCause()); + } + } + + @Deprecated + @Override + public V apply(K key) { + return getUnchecked(key); + } + /** * Accumulates statistics during the operation of a {@link Cache} for presentation by {@link * Cache#stats}. This is solely intended for consumption by {@code Cache} implementors. @@ -165,7 +164,7 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> { /** * Records the successful load of a new entry. This should be called when a cache request * causes an entry to be loaded, and the loading completes successfully. In contrast to - * {@link #recordMisses}, this method should only be called by the loading thread. + * {@link #recordConcurrentMiss}, this method should only be called by the loading thread. * * @param loadTime the number of nanoseconds the cache spent computing or retrieving the new * value @@ -175,7 +174,7 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> { /** * Records the failed load of a new entry. This should be called when a cache request causes * an entry to be loaded, but an exception is thrown while loading the entry. In contrast to - * {@link #recordMisses}, this method should only be called by the loading thread. + * {@link #recordConcurrentMiss}, this method should only be called by the loading thread. * * @param loadTime the number of nanoseconds the cache spent computing or retrieving the new * value prior to an exception being thrown @@ -202,25 +201,20 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> { * @since 10.0 */ @Beta - public static final class SimpleStatsCounter implements StatsCounter { - private final LongAddable hitCount = LongAddables.create(); - private final LongAddable missCount = LongAddables.create(); - private final LongAddable loadSuccessCount = LongAddables.create(); - private final LongAddable loadExceptionCount = LongAddables.create(); - private final LongAddable totalLoadTime = LongAddables.create(); - private final LongAddable evictionCount = LongAddables.create(); - - /** - * Constructs an instance with all counts initialized to zero. - */ - public SimpleStatsCounter() {} + public static class SimpleStatsCounter implements StatsCounter { + private final AtomicLong hitCount = new AtomicLong(); + private final AtomicLong missCount = new AtomicLong(); + private final AtomicLong loadSuccessCount = new AtomicLong(); + private final AtomicLong loadExceptionCount = new AtomicLong(); + private final AtomicLong totalLoadTime = new AtomicLong(); + private final AtomicLong evictionCount = new AtomicLong(); /** * @since 11.0 */ @Override public void recordHits(int count) { - hitCount.add(count); + hitCount.addAndGet(count); } /** @@ -228,35 +222,35 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> { */ @Override public void recordMisses(int count) { - missCount.add(count); + missCount.addAndGet(count); } @Override public void recordLoadSuccess(long loadTime) { - loadSuccessCount.increment(); - totalLoadTime.add(loadTime); + loadSuccessCount.incrementAndGet(); + totalLoadTime.addAndGet(loadTime); } @Override public void recordLoadException(long loadTime) { - loadExceptionCount.increment(); - totalLoadTime.add(loadTime); + loadExceptionCount.incrementAndGet(); + totalLoadTime.addAndGet(loadTime); } @Override public void recordEviction() { - evictionCount.increment(); + evictionCount.incrementAndGet(); } @Override public CacheStats snapshot() { return new CacheStats( - hitCount.sum(), - missCount.sum(), - loadSuccessCount.sum(), - loadExceptionCount.sum(), - totalLoadTime.sum(), - evictionCount.sum()); + hitCount.get(), + missCount.get(), + loadSuccessCount.get(), + loadExceptionCount.get(), + totalLoadTime.get(), + evictionCount.get()); } /** @@ -264,12 +258,12 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> { */ public void incrementBy(StatsCounter other) { CacheStats otherStats = other.snapshot(); - hitCount.add(otherStats.hitCount()); - missCount.add(otherStats.missCount()); - loadSuccessCount.add(otherStats.loadSuccessCount()); - loadExceptionCount.add(otherStats.loadExceptionCount()); - totalLoadTime.add(otherStats.totalLoadTime()); - evictionCount.add(otherStats.evictionCount()); + hitCount.addAndGet(otherStats.hitCount()); + missCount.addAndGet(otherStats.missCount()); + loadSuccessCount.addAndGet(otherStats.loadSuccessCount()); + loadExceptionCount.addAndGet(otherStats.loadExceptionCount()); + totalLoadTime.addAndGet(otherStats.totalLoadTime()); + evictionCount.addAndGet(otherStats.evictionCount()); } } } diff --git a/guava/src/com/google/common/cache/AbstractLoadingCache.java b/guava/src/com/google/common/cache/AbstractLoadingCache.java index 6a12c40..22ef81b 100644 --- a/guava/src/com/google/common/cache/AbstractLoadingCache.java +++ b/guava/src/com/google/common/cache/AbstractLoadingCache.java @@ -30,11 +30,10 @@ import java.util.concurrent.ExecutionException; * effort required to implement this interface. * * <p>To implement a cache, the programmer needs only to extend this class and provide an - * implementation for the {@link #get(Object)} and {@link #getIfPresent} methods. - * {@link #getUnchecked}, {@link #get(Object, Callable)}, and {@link #getAll} are implemented in - * terms of {@code get}; {@link #getAllPresent} is implemented in terms of {@code getIfPresent}; - * {@link #putAll} is implemented in terms of {@link #put}, {@link #invalidateAll(Iterable)} is - * implemented in terms of {@link #invalidate}. The method {@link #cleanUp} is a no-op. All other + * implementation for the {@link #get} and {@link #getIfPresent} methods. {@link #getUnchecked}, + * {@link #get(K, Callable)}, and {@link #getAll} are implemented in terms of {@code get}; + * {@link #getAllPresent} is implemented in terms of {@code get}; {@link #invalidateAll(Iterable)} + * is implemented in terms of {@link #invalidate}. The method {@link #cleanUp} is a no-op. All other * methods throw an {@link UnsupportedOperationException}. * * @author Charles Fry diff --git a/guava/src/com/google/common/cache/Cache.java b/guava/src/com/google/common/cache/Cache.java index cfe5764..f243adc 100644 --- a/guava/src/com/google/common/cache/Cache.java +++ b/guava/src/com/google/common/cache/Cache.java @@ -18,11 +18,11 @@ package com.google.common.cache; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; +import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.ExecutionError; import com.google.common.util.concurrent.UncheckedExecutionException; -import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; @@ -31,23 +31,24 @@ import javax.annotation.Nullable; /** * A semi-persistent mapping from keys to values. Cache entries are manually added using - * {@link #get(Object, Callable)} or {@link #put(Object, Object)}, and are stored in the cache until - * either evicted or manually invalidated. + * {@link #get(K, Callable)} or {@link #put(K, V)}, and are stored in the cache until either + * evicted or manually invalidated. + * + * <p><b>Note:</b> in release 12.0, all methods moved from {@code Cache} to {@link LoadingCache} + * will be deleted from {@code Cache}. As part of this transition {@code Cache} will no longer + * extend {@link Function}. * * <p>Implementations of this interface are expected to be thread-safe, and can be safely accessed * by multiple concurrent threads. * - * <p>Note that while this class is still annotated as {@link Beta}, the API is frozen from a - * consumer's standpoint. In other words existing methods are all considered {@code non-Beta} and - * won't be changed without going through an 18 month deprecation cycle; however new methods may be - * added at any time. + * <p>All methods other than {@link #getIfPresent} are optional. * * @author Charles Fry * @since 10.0 */ @Beta @GwtCompatible -public interface Cache<K, V> { +public interface Cache<K, V> extends Function<K, V> { /** * Returns the value associated with {@code key} in this cache, or {@code null} if there is no @@ -56,7 +57,7 @@ public interface Cache<K, V> { * @since 11.0 */ @Nullable - V getIfPresent(Object key); + V getIfPresent(K key); /** * Returns the value associated with {@code key} in this cache, obtaining that value from @@ -82,7 +83,7 @@ public interface Cache<K, V> { * * @since 11.0 */ - ImmutableMap<K, V> getAllPresent(Iterable<?> keys); + ImmutableMap<K, V> getAllPresent(Iterable<? extends K> keys); /** * Associates {@code value} with {@code key} in this cache. If the cache previously contained a @@ -96,16 +97,6 @@ public interface Cache<K, V> { void put(K key, V value); /** - * Copies all of the mappings from the specified map to the cache. The effect of this call is - * equivalent to that of calling {@code put(k, v)} on this map once for each mapping from key - * {@code k} to value {@code v} in the specified map. The behavior of this operation is undefined - * if the specified map is modified while the operation is in progress. - * - * @since 12.0 - */ - void putAll(Map<? extends K,? extends V> m); - - /** * Discards any cached value for key {@code key}. */ void invalidate(Object key); @@ -144,4 +135,55 @@ public interface Cache<K, V> { * performed -- if any -- is implementation-dependent. */ void cleanUp(); + + /** + * Returns the value associated with {@code key} in this cache, first loading that value if + * necessary. No observable state associated with this cache is modified until loading completes. + * + * @throws ExecutionException if a checked exception was thrown while loading the value + * @throws UncheckedExecutionException if an unchecked exception was thrown while loading the + * value + * @throws ExecutionError if an error was thrown while loading the value + * @deprecated This method has been split out into the {@link LoadingCache} interface, and will be + * removed from {@code Cache} in Guava release 12.0. Note that + * {@link CacheBuilder#build(CacheLoader)} now returns a {@code LoadingCache}, so this deprecation + * (migration) can be dealt with by simply changing the type of references to the results of + * {@link CacheBuilder#build(CacheLoader)}. + */ + @Deprecated V get(K key) throws ExecutionException; + + /** + * Returns the value associated with {@code key} in this cache, first loading that value if + * necessary. No observable state associated with this cache is modified until computation + * completes. Unlike {@link #get}, this method does not throw a checked exception, and thus should + * only be used in situations where checked exceptions are not thrown by the cache loader. + * + * <p><b>Warning:</b> this method silently converts checked exceptions to unchecked exceptions, + * and should not be used with cache loaders which throw checked exceptions. + * + * @throws UncheckedExecutionException if an exception was thrown while loading the value, + * regardless of whether the exception was checked or unchecked + * @throws ExecutionError if an error was thrown while loading the value + * @deprecated This method has been split out into the {@link LoadingCache} interface, and will be + * removed from {@code Cache} in Guava release 12.0. Note that + * {@link CacheBuilder#build(CacheLoader)} now returns a {@code LoadingCache}, so this deprecation + * (migration) can be dealt with by simply changing the type of references to the results of + * {@link CacheBuilder#build(CacheLoader)}. + */ + @Deprecated V getUnchecked(K key); + + /** + * Discouraged. Provided to satisfy the {@code Function} interface; use {@link #get} or + * {@link #getUnchecked} instead. + * + * @throws UncheckedExecutionException if an exception was thrown while loading the value, + * regardless of whether the exception was checked or unchecked + * @throws ExecutionError if an error was thrown while loading the value + * @deprecated This method has been split out into the {@link LoadingCache} interface, and will be + * removed from {@code Cache} in Guava release 12.0. Note that + * {@link CacheBuilder#build(CacheLoader)} now returns a {@code LoadingCache}, so this deprecation + * (migration) can be dealt with by simply changing the type of references to the results of + * {@link CacheBuilder#build(CacheLoader)}. + */ + @Deprecated V apply(K key); } diff --git a/guava/src/com/google/common/cache/CacheBuilder.java b/guava/src/com/google/common/cache/CacheBuilder.java index 105ff73..8eef200 100644 --- a/guava/src/com/google/common/cache/CacheBuilder.java +++ b/guava/src/com/google/common/cache/CacheBuilder.java @@ -26,6 +26,7 @@ import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; import com.google.common.base.Ascii; import com.google.common.base.Equivalence; +import com.google.common.base.Equivalences; import com.google.common.base.Objects; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; @@ -56,12 +57,8 @@ import javax.annotation.CheckReturnValue; * <li>values automatically wrapped in {@linkplain WeakReference weak} or * {@linkplain SoftReference soft} references * <li>notification of evicted (or otherwise removed) entries - * <li>accumulation of cache access statistics * </ul> * - * These features are all optional; caches can be created using all or none of them. By default - * cache instances created by {@code CacheBuilder} will not perform any type of eviction. - * * <p>Usage example: <pre> {@code * * LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder() @@ -75,19 +72,8 @@ import javax.annotation.CheckReturnValue; * } * });}</pre> * - * Or equivalently, <pre> {@code - * - * // In real life this would come from a command-line flag or config file - * String spec = "maximumSize=10000,expireAfterWrite=10m"; * - * LoadingCache<Key, Graph> graphs = CacheBuilder.from(spec) - * .removalListener(MY_LISTENER) - * .build( - * new CacheLoader<Key, Graph>() { - * public Graph load(Key key) throws AnyException { - * return createExpensiveGraph(key); - * } - * });}</pre> + * These features are all optional. * * <p>The returned cache is implemented as a hash table with similar performance characteristics to * {@link ConcurrentHashMap}. It implements all optional operations of the {@link LoadingCache} and @@ -139,16 +125,13 @@ import javax.annotation.CheckReturnValue; * retain all the configuration properties of the original cache. Note that the serialized form does * <i>not</i> include cache contents, but only configuration. * - * <p>See the Guava User Guide article on <a href= - * "http://code.google.com/p/guava-libraries/wiki/CachesExplained">caching</a> for a higher-level - * explanation. - * * @param <K> the base key type for all caches created by this builder * @param <V> the base value type for all caches created by this builder * @author Charles Fry * @author Kevin Bourrillion * @since 10.0 */ +@Beta @GwtCompatible(emulated = true) public final class CacheBuilder<K, V> { private static final int DEFAULT_INITIAL_CAPACITY = 16; @@ -180,10 +163,10 @@ public final class CacheBuilder<K, V> { }); static final CacheStats EMPTY_STATS = new CacheStats(0, 0, 0, 0, 0, 0); - static final Supplier<StatsCounter> CACHE_STATS_COUNTER = - new Supplier<StatsCounter>() { + static final Supplier<SimpleStatsCounter> CACHE_STATS_COUNTER = + new Supplier<SimpleStatsCounter>() { @Override - public StatsCounter get() { + public SimpleStatsCounter get() { return new SimpleStatsCounter(); } }; @@ -236,7 +219,7 @@ public final class CacheBuilder<K, V> { RemovalListener<? super K, ? super V> removalListener; Ticker ticker; - Supplier<? extends StatsCounter> statsCounterSupplier = NULL_STATS_COUNTER; + Supplier<? extends StatsCounter> statsCounterSupplier = CACHE_STATS_COUNTER; // TODO(fry): make constructor private and update tests to use newBuilder CacheBuilder() {} @@ -250,34 +233,8 @@ public final class CacheBuilder<K, V> { } /** - * Constructs a new {@code CacheBuilder} instance with the settings specified in {@code spec}. - * - * @since 12.0 - */ - @Beta - @GwtIncompatible("To be supported") - public static CacheBuilder<Object, Object> from(CacheBuilderSpec spec) { - return spec.toCacheBuilder() - .lenientParsing(); - } - - /** - * Constructs a new {@code CacheBuilder} instance with the settings specified in {@code spec}. - * This is especially useful for command-line configuration of a {@code CacheBuilder}. - * - * @param spec a String in the format specified by {@link CacheBuilderSpec} - * @since 12.0 - */ - @Beta - @GwtIncompatible("To be supported") - public static CacheBuilder<Object, Object> from(String spec) { - return from(CacheBuilderSpec.parse(spec)); - } - - /** * Enables lenient parsing. Useful for tests and spec parsing. */ - @GwtIncompatible("To be supported") CacheBuilder<K, V> lenientParsing() { strictParsing = false; return this; @@ -286,10 +243,9 @@ public final class CacheBuilder<K, V> { /** * Sets a custom {@code Equivalence} strategy for comparing keys. * - * <p>By default, the cache uses {@link Equivalence#identity} to determine key equality when - * {@link #weakKeys} is specified, and {@link Equivalence#equals()} otherwise. + * <p>By default, the cache uses {@link Equivalences#identity} to determine key equality when + * {@link #weakKeys} is specified, and {@link Equivalences#equals()} otherwise. */ - @GwtIncompatible("To be supported") CacheBuilder<K, V> keyEquivalence(Equivalence<Object> equivalence) { checkState(keyEquivalence == null, "key equivalence was already set to %s", keyEquivalence); keyEquivalence = checkNotNull(equivalence); @@ -303,11 +259,10 @@ public final class CacheBuilder<K, V> { /** * Sets a custom {@code Equivalence} strategy for comparing values. * - * <p>By default, the cache uses {@link Equivalence#identity} to determine value equality when - * {@link #weakValues} or {@link #softValues} is specified, and {@link Equivalence#equals()} + * <p>By default, the cache uses {@link Equivalences#identity} to determine value equality when + * {@link #weakValues} or {@link #softValues} is specified, and {@link Equivalences#equals()} * otherwise. */ - @GwtIncompatible("To be supported") CacheBuilder<K, V> valueEquivalence(Equivalence<Object> equivalence) { checkState(valueEquivalence == null, "value equivalence was already set to %s", valueEquivalence); @@ -350,23 +305,11 @@ public final class CacheBuilder<K, V> { * higher value than you need can waste space and time, and a significantly lower value can lead * to thread contention. But overestimates and underestimates within an order of magnitude do not * usually have much noticeable impact. A value of one permits only one thread to modify the cache - * at a time, but since read operations and cache loading computations can proceed concurrently, - * this still yields higher concurrency than full synchronization. - * - * <p> Defaults to 4. <b>Note:</b>The default may change in the future. If you care about this - * value, you should always choose it explicitly. - * - * <p>The current implementation uses the concurrency level to create a fixed number of hashtable - * segments, each governed by its own write lock. The segment lock is taken once for each explicit - * write, and twice for each cache loading computation (once prior to loading the new value, - * and once after loading completes). Much internal cache management is performed at the segment - * granularity. For example, access queues and write queues are kept per segment when they are - * required by the selected eviction algorithm. As such, when writing unit tests it is not - * uncommon to specify {@code concurrencyLevel(1)} in order to achieve more deterministic eviction - * behavior. + * at a time, but since read operations can proceed concurrently, this still yields higher + * concurrency than full synchronization. Defaults to 4. * - * <p>Note that future implementations may abandon segment locking in favor of more advanced - * concurrency controls. + * <p><b>Note:</b>The default may change in the future. If you care about this value, you should + * always choose it explicitly. * * @throws IllegalArgumentException if {@code concurrencyLevel} is nonpositive * @throws IllegalStateException if a concurrency level was already set @@ -392,11 +335,9 @@ public final class CacheBuilder<K, V> { * <p>When {@code size} is zero, elements will be evicted immediately after being loaded into the * cache. This can be useful in testing, or to disable caching temporarily without a code change. * - * <p>This feature cannot be used in conjunction with {@link #maximumWeight}. - * * @param size the maximum size of the cache * @throws IllegalArgumentException if {@code size} is negative - * @throws IllegalStateException if a maximum size or weight was already set + * @throws IllegalStateException if a maximum size was already set */ public CacheBuilder<K, V> maximumSize(long size) { checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s", @@ -423,17 +364,11 @@ public final class CacheBuilder<K, V> { * cache. This can be useful in testing, or to disable caching temporarily without a code * change. * - * <p>Note that weight is only used to determine whether the cache is over capacity; it has no - * effect on selecting which entry should be evicted next. - * - * <p>This feature cannot be used in conjunction with {@link #maximumSize}. - * - * @param weight the maximum total weight of entries the cache may contain - * @throws IllegalArgumentException if {@code weight} is negative - * @throws IllegalStateException if a maximum weight or size was already set + * @param weight the maximum weight the cache may contain + * @throws IllegalArgumentException if {@code size} is negative + * @throws IllegalStateException if a maximum size was already set * @since 11.0 */ - @GwtIncompatible("To be supported") public CacheBuilder<K, V> maximumWeight(long weight) { checkState(this.maximumWeight == UNSET_INT, "maximum weight was already set to %s", this.maximumWeight); @@ -472,7 +407,6 @@ public final class CacheBuilder<K, V> { * @throws IllegalStateException if a maximum size was already set * @since 11.0 */ - @GwtIncompatible("To be supported") public <K1 extends K, V1 extends V> CacheBuilder<K1, V1> weigher( Weigher<? super K1, ? super V1> weigher) { checkState(this.weigher == null); @@ -502,6 +436,15 @@ public final class CacheBuilder<K, V> { } /** + * Specifies that each key (not value) stored in the cache should be strongly referenced. + * + * @throws IllegalStateException if the key strength was already set + */ + CacheBuilder<K, V> strongKeys() { + return setKeyStrength(Strength.STRONG); + } + + /** * Specifies that each key (not value) stored in the cache should be wrapped in a {@link * WeakReference} (by default, strong references are used). * @@ -530,6 +473,15 @@ public final class CacheBuilder<K, V> { } /** + * Specifies that each value (not key) stored in the cache should be strongly referenced. + * + * @throws IllegalStateException if the value strength was already set + */ + CacheBuilder<K, V> strongValues() { + return setValueStrength(Strength.STRONG); + } + + /** * Specifies that each value (not key) stored in the cache should be wrapped in a * {@link WeakReference} (by default, strong references are used). * @@ -657,9 +609,8 @@ public final class CacheBuilder<K, V> { * {@link CacheLoader#reload}. * * <p>As the default implementation of {@link CacheLoader#reload} is synchronous, it is - * recommended that users of this method override {@link CacheLoader#reload} with an asynchronous - * implementation; otherwise refreshes will be performed during unrelated cache read and write - * operations. + * recommended that users of this method override {@link CacheLoader#reload} with an asynchrnous + * implementation; otherwise refreshes will block other cache operations. * * <p>Currently automatic refreshes are performed when the first stale request for an entry * occurs. The request triggering refresh will make a blocking call to {@link CacheLoader#reload} @@ -675,8 +626,7 @@ public final class CacheBuilder<K, V> { * @throws IllegalStateException if the refresh interval was already set * @since 11.0 */ - @Beta - @GwtIncompatible("To be supported (synchronously).") + @GwtIncompatible("To be supported") public CacheBuilder<K, V> refreshAfterWrite(long duration, TimeUnit unit) { checkNotNull(unit); checkState(refreshNanos == UNSET_INT, "refresh was already set to %s ns", refreshNanos); @@ -698,6 +648,7 @@ public final class CacheBuilder<K, V> { * * @throws IllegalStateException if a ticker was already set */ + @GwtIncompatible("To be supported") public CacheBuilder<K, V> ticker(Ticker ticker) { checkState(this.ticker == null); this.ticker = checkNotNull(ticker); @@ -712,27 +663,34 @@ public final class CacheBuilder<K, V> { } /** - * Specifies a listener instance that caches should notify each time an entry is removed for any - * {@linkplain RemovalCause reason}. Each cache created by this builder will invoke this listener - * as part of the routine maintenance described in the class documentation above. - * - * <p><b>Warning:</b> after invoking this method, do not continue to use <i>this</i> cache - * builder reference; instead use the reference this method <i>returns</i>. At runtime, these - * point to the same instance, but only the returned reference has the correct generic type - * information so as to ensure type safety. For best results, use the standard method-chaining - * idiom illustrated in the class documentation above, configuring a builder and building your - * cache in a single statement. Failure to heed this advice can result in a {@link - * ClassCastException} being thrown by a cache operation at some <i>undefined</i> point in the - * future. - * - * <p><b>Warning:</b> any exception thrown by {@code listener} will <i>not</i> be propagated to - * the {@code Cache} user, only logged via a {@link Logger}. - * - * @return the cache builder reference that should be used instead of {@code this} for any - * remaining configuration and cache building + * Specifies a listener instance, which all caches built using this {@code CacheBuilder} will + * notify each time an entry is removed from the cache by any means. + * + * <p>Each cache built by this {@code CacheBuilder} after this method is called invokes the + * supplied listener after removing an element for any reason (see removal causes in {@link + * RemovalCause}). It will invoke the listener as part of the routine maintenance described + * in the class javadoc. + * + * <p><b>Note:</b> <i>all exceptions thrown by {@code listener} will be logged (using + * {@link java.util.logging.Logger})and then swallowed</i>. + * + * <p><b>Important note:</b> Instead of returning <em>this</em> as a {@code CacheBuilder} + * instance, this method returns {@code CacheBuilder<K1, V1>}. From this point on, either the + * original reference or the returned reference may be used to complete configuration and build + * the cache, but only the "generic" one is type-safe. That is, it will properly prevent you from + * building caches whose key or value types are incompatible with the types accepted by the + * listener already provided; the {@code CacheBuilder} type cannot do this. For best results, + * simply use the standard method-chaining idiom, as illustrated in the documentation at top, + * configuring a {@code CacheBuilder} and building your {@link Cache} all in a single statement. + * + * <p><b>Warning:</b> if you ignore the above advice, and use this {@code CacheBuilder} to build + * a cache whose key or value type is incompatible with the listener, you will likely experience + * a {@link ClassCastException} at some <i>undefined</i> point in the future. + * * @throws IllegalStateException if a removal listener was already set */ @CheckReturnValue + @GwtIncompatible("To be supported") public <K1 extends K, V1 extends V> CacheBuilder<K1, V1> removalListener( RemovalListener<? super K1, ? super V1> listener) { checkState(this.removalListener == null); @@ -751,15 +709,11 @@ public final class CacheBuilder<K, V> { } /** - * Enable the accumulation of {@link CacheStats} during the operation of the cache. Without this - * {@link Cache#stats} will return zero for all statistics. Note that recording stats requires - * bookkeeping to be performed with each operation, and thus imposes a performance penalty on - * cache operation. - * - * @since 12.0 (previously, stats collection was automatic) + * Disable the accumulation of {@link CacheStats} during the operation of the cache. */ - public CacheBuilder<K, V> recordStats() { - statsCounterSupplier = CACHE_STATS_COUNTER; + CacheBuilder<K, V> disableStats() { + checkState(statsCounterSupplier == CACHE_STATS_COUNTER); + statsCounterSupplier = NULL_STATS_COUNTER; return this; } @@ -834,11 +788,12 @@ public final class CacheBuilder<K, V> { if (concurrencyLevel != UNSET_INT) { s.add("concurrencyLevel", concurrencyLevel); } - if (maximumSize != UNSET_INT) { - s.add("maximumSize", maximumSize); - } if (maximumWeight != UNSET_INT) { - s.add("maximumWeight", maximumWeight); + if (weigher == null) { + s.add("maximumSize", maximumWeight); + } else { + s.add("maximumWeight", maximumWeight); + } } if (expireAfterWriteNanos != UNSET_INT) { s.add("expireAfterWrite", expireAfterWriteNanos + "ns"); diff --git a/guava/src/com/google/common/cache/CacheBuilderSpec.java b/guava/src/com/google/common/cache/CacheBuilderSpec.java deleted file mode 100644 index 1e03335..0000000 --- a/guava/src/com/google/common/cache/CacheBuilderSpec.java +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Copyright (C) 2011 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.common.cache; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.annotations.Beta; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Objects; -import com.google.common.base.Splitter; -import com.google.common.cache.LocalCache.Strength; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -import javax.annotation.Nullable; - -/** - * A specification of a {@link CacheBuilder} configuration. - * - * <p>{@code CacheBuilderSpec} supports parsing configuration off of a string, which - * makes it especially useful for command-line configuration of a {@code CacheBuilder}. - * - * <p>The string syntax is a series of comma-separated keys or key-value pairs, - * each corresponding to a {@code CacheBuilder} method. - * <ul> - * <li>{@code concurrencyLevel=[integer]}: sets {@link CacheBuilder#concurrencyLevel}. - * <li>{@code initialCapacity=[integer]}: sets {@link CacheBuilder#initialCapacity}. - * <li>{@code maximumSize=[long]}: sets {@link CacheBuilder#maximumSize}. - * <li>{@code maximumWeight=[long]}: sets {@link CacheBuilder#maximumWeight}. - * <li>{@code expireAfterAccess=[duration]}: sets {@link CacheBuilder#expireAfterAccess}. - * <li>{@code expireAfterWrite=[duration]}: sets {@link CacheBuilder#expireAfterWrite}. - * <li>{@code refreshAfterWrite=[duration]}: sets {@link CacheBuilder#refreshAfterWrite}. - * <li>{@code weakKeys}: sets {@link CacheBuilder#weakKeys}. - * <li>{@code softValues}: sets {@link CacheBuilder#softValues}. - * <li>{@code weakValues}: sets {@link CacheBuilder#weakValues}. - * </ul> - * - * The set of supported keys will grow as {@code CacheBuilder} evolves, but existing keys - * will never be removed. - * - * <p>Durations are represented by an integer, followed by one of "d", "h", "m", - * or "s", representing days, hours, minutes, or seconds respectively. (There - * is currently no syntax to request expiration in milliseconds, microseconds, - * or nanoseconds.) - * - * <p>Whitespace before and after commas and equal signs is ignored. Keys may - * not be repeated; it is also illegal to use the following pairs of keys in - * a single value: - * <ul> - * <li>{@code maximumSize} and {@code maximumWeight} - * <li>{@code softValues} and {@code weakValues} - * </ul> - * - * <p>{@code CacheBuilderSpec} does not support configuring {@code CacheBuilder} methods - * with non-value parameters. These must be configured in code. - * - * <p>A new {@code CacheBuilder} can be instantiated from a {@code CacheBuilderSpec} using - * {@link CacheBuilder#from(CacheBuilderSpec)} or {@link CacheBuilder#from(String)}. - * - * @author Adam Winer - * @since 12.0 - */ -@Beta -public final class CacheBuilderSpec { - /** Parses a single value. */ - private interface ValueParser { - void parse(CacheBuilderSpec spec, String key, @Nullable String value); - } - - /** Splits each key-value pair. */ - private static final Splitter KEYS_SPLITTER = Splitter.on(',').trimResults(); - - /** Splits the key from the value. */ - private static final Splitter KEY_VALUE_SPLITTER = Splitter.on('=').trimResults(); - - /** Map of names to ValueParser. */ - private static final ImmutableMap<String, ValueParser> VALUE_PARSERS = - ImmutableMap.<String, ValueParser>builder() - .put("initialCapacity", new InitialCapacityParser()) - .put("maximumSize", new MaximumSizeParser()) - .put("maximumWeight", new MaximumWeightParser()) - .put("concurrencyLevel", new ConcurrencyLevelParser()) - .put("weakKeys", new KeyStrengthParser(Strength.WEAK)) - .put("softValues", new ValueStrengthParser(Strength.SOFT)) - .put("weakValues", new ValueStrengthParser(Strength.WEAK)) - .put("expireAfterAccess", new AccessDurationParser()) - .put("expireAfterWrite", new WriteDurationParser()) - .put("refreshAfterWrite", new RefreshDurationParser()) - .put("refreshInterval", new RefreshDurationParser()) - .build(); - - @VisibleForTesting Integer initialCapacity; - @VisibleForTesting Long maximumSize; - @VisibleForTesting Long maximumWeight; - @VisibleForTesting Integer concurrencyLevel; - @VisibleForTesting Strength keyStrength; - @VisibleForTesting Strength valueStrength; - @VisibleForTesting long writeExpirationDuration; - @VisibleForTesting TimeUnit writeExpirationTimeUnit; - @VisibleForTesting long accessExpirationDuration; - @VisibleForTesting TimeUnit accessExpirationTimeUnit; - @VisibleForTesting long refreshDuration; - @VisibleForTesting TimeUnit refreshTimeUnit; - /** Specification; used for toParseableString(). */ - private final String specification; - - private CacheBuilderSpec(String specification) { - this.specification = specification; - } - - /** - * Creates a CacheBuilderSpec from a string. - * - * @param cacheBuilderSpecification the string form - */ - public static CacheBuilderSpec parse(String cacheBuilderSpecification) { - CacheBuilderSpec spec = new CacheBuilderSpec(cacheBuilderSpecification); - if (!cacheBuilderSpecification.isEmpty()) { - for (String keyValuePair : KEYS_SPLITTER.split(cacheBuilderSpecification)) { - List<String> keyAndValue = ImmutableList.copyOf(KEY_VALUE_SPLITTER.split(keyValuePair)); - checkArgument(!keyAndValue.isEmpty(), "blank key-value pair"); - checkArgument(keyAndValue.size() <= 2, - "key-value pair %s with more than one equals sign", keyValuePair); - - // Find the ValueParser for the current key. - String key = keyAndValue.get(0); - ValueParser valueParser = VALUE_PARSERS.get(key); - checkArgument(valueParser != null, "unknown key %s", key); - - String value = keyAndValue.size() == 1 ? null : keyAndValue.get(1); - valueParser.parse(spec, key, value); - } - } - - return spec; - } - - /** - * Returns a CacheBuilderSpec that will prevent caching. - */ - public static CacheBuilderSpec disableCaching() { - // Maximum size of zero is one way to block caching - return CacheBuilderSpec.parse("maximumSize=0"); - } - - /** - * Returns a CacheBuilder configured according to this instance's specification. - */ - CacheBuilder<Object, Object> toCacheBuilder() { - CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder(); - if (initialCapacity != null) { - builder.initialCapacity(initialCapacity); - } - if (maximumSize != null) { - builder.maximumSize(maximumSize); - } - if (maximumWeight != null) { - builder.maximumWeight(maximumWeight); - } - if (concurrencyLevel != null) { - builder.concurrencyLevel(concurrencyLevel); - } - if (keyStrength != null) { - switch (keyStrength) { - case WEAK: - builder.weakKeys(); - break; - default: - throw new AssertionError(); - } - } - if (valueStrength != null) { - switch (valueStrength) { - case SOFT: - builder.softValues(); - break; - case WEAK: - builder.weakValues(); - break; - default: - throw new AssertionError(); - } - } - if (writeExpirationTimeUnit != null) { - builder.expireAfterWrite(writeExpirationDuration, writeExpirationTimeUnit); - } - if (accessExpirationTimeUnit != null) { - builder.expireAfterAccess(accessExpirationDuration, accessExpirationTimeUnit); - } - if (refreshTimeUnit != null) { - builder.refreshAfterWrite(refreshDuration, refreshTimeUnit); - } - - return builder; - } - - /** - * Returns a string that can be used to parse an equivalent - * {@code CacheBuilderSpec}. The order and form of this representation is - * not guaranteed, except that reparsing its output will produce - * a {@code CacheBuilderSpec} equal to this instance. - */ - public String toParsableString() { - return specification; - } - - /** - * Returns a string representation for this CacheBuilderSpec instance. - * The form of this representation is not guaranteed. - */ - @Override - public String toString() { - return Objects.toStringHelper(this).addValue(toParsableString()).toString(); - } - - @Override - public int hashCode() { - return Objects.hashCode( - initialCapacity, - maximumSize, - maximumWeight, - concurrencyLevel, - keyStrength, - valueStrength, - durationInNanos(writeExpirationDuration, writeExpirationTimeUnit), - durationInNanos(accessExpirationDuration, accessExpirationTimeUnit), - durationInNanos(refreshDuration, refreshTimeUnit)); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof CacheBuilderSpec)) { - return false; - } - CacheBuilderSpec that = (CacheBuilderSpec) obj; - return Objects.equal(initialCapacity, that.initialCapacity) - && Objects.equal(maximumSize, that.maximumSize) - && Objects.equal(maximumWeight, that.maximumWeight) - && Objects.equal(concurrencyLevel, that.concurrencyLevel) - && Objects.equal(keyStrength, that.keyStrength) - && Objects.equal(valueStrength, that.valueStrength) - && Objects.equal(durationInNanos(writeExpirationDuration, writeExpirationTimeUnit), - durationInNanos(that.writeExpirationDuration, that.writeExpirationTimeUnit)) - && Objects.equal(durationInNanos(accessExpirationDuration, accessExpirationTimeUnit), - durationInNanos(that.accessExpirationDuration, that.accessExpirationTimeUnit)) - && Objects.equal(durationInNanos(refreshDuration, refreshTimeUnit), - durationInNanos(that.refreshDuration, that.refreshTimeUnit)); - } - - /** - * Converts an expiration duration/unit pair into a single Long for hashing and equality. - * Uses nanos to match CacheBuilder implementation. - */ - @Nullable private static Long durationInNanos(long duration, @Nullable TimeUnit unit) { - return (unit == null) ? null : unit.toNanos(duration); - } - - /** Base class for parsing integers. */ - abstract static class IntegerParser implements ValueParser { - protected abstract void parseInteger(CacheBuilderSpec spec, int value); - - @Override - public void parse(CacheBuilderSpec spec, String key, String value) { - checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key); - try { - parseInteger(spec, Integer.parseInt(value)); - } catch (NumberFormatException e) { - throw new IllegalArgumentException( - String.format("key %s value set to %s, must be integer", key, value), e); - } - } - } - - /** Base class for parsing integers. */ - abstract static class LongParser implements ValueParser { - protected abstract void parseLong(CacheBuilderSpec spec, long value); - - @Override - public void parse(CacheBuilderSpec spec, String key, String value) { - checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key); - try { - parseLong(spec, Long.parseLong(value)); - } catch (NumberFormatException e) { - throw new IllegalArgumentException( - String.format("key %s value set to %s, must be integer", key, value), e); - } - } - } - - /** Parse initialCapacity */ - static class InitialCapacityParser extends IntegerParser { - @Override - protected void parseInteger(CacheBuilderSpec spec, int value) { - checkArgument(spec.initialCapacity == null, - "initial capacity was already set to ", spec.initialCapacity); - spec.initialCapacity = value; - } - } - - /** Parse maximumSize */ - static class MaximumSizeParser extends LongParser { - @Override - protected void parseLong(CacheBuilderSpec spec, long value) { - checkArgument(spec.maximumSize == null, - "maximum size was already set to ", spec.maximumSize); - checkArgument(spec.maximumWeight == null, - "maximum weight was already set to ", spec.maximumWeight); - spec.maximumSize = value; - } - } - - /** Parse maximumWeight */ - static class MaximumWeightParser extends LongParser { - @Override - protected void parseLong(CacheBuilderSpec spec, long value) { - checkArgument(spec.maximumWeight == null, - "maximum weight was already set to ", spec.maximumWeight); - checkArgument(spec.maximumSize == null, - "maximum size was already set to ", spec.maximumSize); - spec.maximumWeight = value; - } - } - - /** Parse concurrencyLevel */ - static class ConcurrencyLevelParser extends IntegerParser { - @Override - protected void parseInteger(CacheBuilderSpec spec, int value) { - checkArgument(spec.concurrencyLevel == null, - "concurrency level was already set to ", spec.concurrencyLevel); - spec.concurrencyLevel = value; - } - } - - /** Parse weakKeys */ - static class KeyStrengthParser implements ValueParser { - private final Strength strength; - - public KeyStrengthParser(Strength strength) { - this.strength = strength; - } - - @Override - public void parse(CacheBuilderSpec spec, String key, @Nullable String value) { - checkArgument(value == null, "key %s does not take values", key); - checkArgument(spec.keyStrength == null, "%s was already set to %s", key, spec.keyStrength); - spec.keyStrength = strength; - } - } - - /** Parse weakValues and softValues */ - static class ValueStrengthParser implements ValueParser { - private final Strength strength; - - public ValueStrengthParser(Strength strength) { - this.strength = strength; - } - - @Override - public void parse(CacheBuilderSpec spec, String key, @Nullable String value) { - checkArgument(value == null, "key %s does not take values", key); - checkArgument(spec.valueStrength == null, - "%s was already set to %s", key, spec.valueStrength); - - spec.valueStrength = strength; - } - } - - /** Base class for parsing times with durations */ - abstract static class DurationParser implements ValueParser { - protected abstract void parseDuration( - CacheBuilderSpec spec, - long duration, - TimeUnit unit); - - @Override - public void parse(CacheBuilderSpec spec, String key, String value) { - checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key); - try { - char lastChar = value.charAt(value.length() - 1); - TimeUnit timeUnit; - switch (lastChar) { - case 'd': - timeUnit = TimeUnit.DAYS; - break; - case 'h': - timeUnit = TimeUnit.HOURS; - break; - case 'm': - timeUnit = TimeUnit.MINUTES; - break; - case 's': - timeUnit = TimeUnit.SECONDS; - break; - default: - throw new IllegalArgumentException( - String.format("key %s invalid format. was %s, must end with one of [dDhHmMsS]", - key, value)); - } - - long duration = Long.parseLong(value.substring(0, value.length() - 1)); - parseDuration(spec, duration, timeUnit); - } catch (NumberFormatException e) { - throw new IllegalArgumentException( - String.format("key %s value set to %s, must be integer", key, value)); - } - } - } - - /** Parse expireAfterAccess */ - static class AccessDurationParser extends DurationParser { - @Override protected void parseDuration(CacheBuilderSpec spec, long duration, TimeUnit unit) { - checkArgument(spec.accessExpirationTimeUnit == null, "expireAfterAccess already set"); - spec.accessExpirationDuration = duration; - spec.accessExpirationTimeUnit = unit; - } - } - - /** Parse expireAfterWrite */ - static class WriteDurationParser extends DurationParser { - @Override protected void parseDuration(CacheBuilderSpec spec, long duration, TimeUnit unit) { - checkArgument(spec.writeExpirationTimeUnit == null, "expireAfterWrite already set"); - spec.writeExpirationDuration = duration; - spec.writeExpirationTimeUnit = unit; - } - } - - /** Parse refreshAfterWrite */ - static class RefreshDurationParser extends DurationParser { - @Override protected void parseDuration(CacheBuilderSpec spec, long duration, TimeUnit unit) { - checkArgument(spec.refreshTimeUnit == null, "refreshAfterWrite already set"); - spec.refreshDuration = duration; - spec.refreshTimeUnit = unit; - } - } -} diff --git a/guava/src/com/google/common/cache/CacheLoader.java b/guava/src/com/google/common/cache/CacheLoader.java index 2f014a3..21811e8 100644 --- a/guava/src/com/google/common/cache/CacheLoader.java +++ b/guava/src/com/google/common/cache/CacheLoader.java @@ -30,23 +30,15 @@ import java.io.Serializable; import java.util.Map; /** - * Computes or retrieves values, based on a key, for use in populating a {@link LoadingCache}. + * Computes or retrieves values, based on a key, for use in populating a {@code Cache}. * * <p>Most implementations will only need to implement {@link #load}. Other methods may be * overridden as desired. * - * <p>Usage example: <pre> {@code - * - * CacheLoader<Key, Graph> loader = new CacheLoader<Key, Graph>() { - * public Graph load(Key key) throws AnyException { - * return createExpensiveGraph(key); - * } - * }; - * LoadingCache<Key, Graph> cache = CacheBuilder.newBuilder().build(loader);}</pre> - * * @author Charles Fry * @since 10.0 */ +@Beta @GwtCompatible(emulated = true) public abstract class CacheLoader<K, V> { /** @@ -59,17 +51,13 @@ public abstract class CacheLoader<K, V> { * * @param key the non-null key whose value should be loaded * @return the value associated with {@code key}; <b>must not be null</b> - * @throws Exception if unable to load the result - * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is - * treated like any other {@code Exception} in all respects except that, when it is caught, - * the thread's interrupt status is set */ public abstract V load(K key) throws Exception; /** * Computes or retrieves a replacement value corresponding to an already-cached {@code key}. This * method is called when an existing cache entry is refreshed by - * {@link CacheBuilder#refreshAfterWrite}, or through a call to {@link LoadingCache#refresh}. + * {@link CacheBuilder#refreshAfterWrite}, or through a call to {@link Cache#refresh}. * * <p>This implementation synchronously delegates to {@link #load}. It is recommended that it be * overridden with an asynchronous implementation when using @@ -81,22 +69,16 @@ public abstract class CacheLoader<K, V> { * @param oldValue the non-null old value corresponding to {@code key} * @return the future new value associated with {@code key}; * <b>must not be null, must not return null</b> - * @throws Exception if unable to reload the result - * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is - * treated like any other {@code Exception} in all respects except that, when it is caught, - * the thread's interrupt status is set * @since 11.0 */ @GwtIncompatible("Futures") public ListenableFuture<V> reload(K key, V oldValue) throws Exception { - checkNotNull(key); - checkNotNull(oldValue); return Futures.immediateFuture(load(key)); } /** * Computes or retrieves the values corresponding to {@code keys}. This method is called by - * {@link LoadingCache#getAll}. + * {@link Cache#getAll}. * * <p>If the returned map doesn't contain all requested {@code keys} then the entries it does * contain will be cached, but {@code getAll} will throw an exception. If the returned map @@ -104,33 +86,22 @@ public abstract class CacheLoader<K, V> { * but only the entries for {@code keys} will be returned from {@code getAll}. * * <p>This method should be overriden when bulk retrieval is significantly more efficient than - * many individual lookups. Note that {@link LoadingCache#getAll} will defer to individual calls - * to {@link LoadingCache#get} if this method is not overriden. + * many individual lookups. Note that {@link Cache#getAll} will defer to individual calls to + * {@link Cache#get} if this method is not overriden. * * @param keys the unique, non-null keys whose values should be loaded * @return a map from each key in {@code keys} to the value associated with that key; * <b>may not contain null values</b> - * @throws Exception if unable to load the result - * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is - * treated like any other {@code Exception} in all respects except that, when it is caught, - * the thread's interrupt status is set * @since 11.0 */ public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception { - // This will be caught by getAll(), causing it to fall back to multiple calls to - // LoadingCache.get + // This will be caught by getAll(), causing it to fall back to multiple calls to Cache.get throw new UnsupportedLoadingOperationException(); } /** - * Returns a cache loader based on an <i>existing</i> function instance. Note that there's no need - * to create a <i>new</i> function just to pass it in here; just subclass {@code CacheLoader} and - * implement {@link #load load} instead. - * - * @param function the function to be used for loading values; must never return {@code null} - * @return a cache loader that loads values by passing each key to {@code function} + * Returns a {@code CacheLoader} which creates values by applying a {@code Function} to the key. */ - @Beta public static <K, V> CacheLoader<K, V> from(Function<K, V> function) { return new FunctionToCacheLoader<K, V>(function); } @@ -145,22 +116,16 @@ public abstract class CacheLoader<K, V> { @Override public V load(K key) { - return computingFunction.apply(checkNotNull(key)); + return computingFunction.apply(key); } private static final long serialVersionUID = 0; } /** - * Returns a cache loader based on an <i>existing</i> supplier instance. Note that there's no need - * to create a <i>new</i> supplier just to pass it in here; just subclass {@code CacheLoader} and - * implement {@link #load load} instead. - * - * @param supplier the supplier to be used for loading values; must never return {@code null} - * @return a cache loader that loads values by calling {@link Supplier#get}, irrespective of the - * key + * Returns a {@code CacheLoader} which obtains values from a {@code Supplier} (independent of the + * key). */ - @Beta public static <V> CacheLoader<Object, V> from(Supplier<V> supplier) { return new SupplierToCacheLoader<V>(supplier); } @@ -175,7 +140,6 @@ public abstract class CacheLoader<K, V> { @Override public V load(Object key) { - checkNotNull(key); return computingSupplier.get(); } diff --git a/guava/src/com/google/common/cache/CacheStats.java b/guava/src/com/google/common/cache/CacheStats.java index d8c9eb7..04d442c 100644 --- a/guava/src/com/google/common/cache/CacheStats.java +++ b/guava/src/com/google/common/cache/CacheStats.java @@ -22,8 +22,6 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import com.google.common.base.Objects; -import java.util.concurrent.Callable; - import javax.annotation.Nullable; /** @@ -46,14 +44,9 @@ import javax.annotation.Nullable; * </ul> * <li>When an entry is evicted from the cache, {@code evictionCount} is incremented. * <li>No stats are modified when a cache entry is invalidated or manually removed. - * <li>No stats are modified on a query to {@link Cache#getIfPresent}. * <li>No stats are modified by operations invoked on the {@linkplain Cache#asMap asMap} view of * the cache. * </ul> - * - * <p>A lookup is specifically defined as an invocation of one of the methods - * {@link LoadingCache#get(Object)}, {@link LoadingCache#getUnchecked(Object)}, - * {@link Cache#get(Object, Callable)}, or {@link LoadingCache#getAll(Iterable)}. * * @author Charles Fry * @since 10.0 diff --git a/guava/src/com/google/common/cache/ForwardingCache.java b/guava/src/com/google/common/cache/ForwardingCache.java index 44fe683..4404593 100644 --- a/guava/src/com/google/common/cache/ForwardingCache.java +++ b/guava/src/com/google/common/cache/ForwardingCache.java @@ -21,7 +21,6 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ForwardingObject; import com.google.common.collect.ImmutableMap; -import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; @@ -50,7 +49,7 @@ public abstract class ForwardingCache<K, V> extends ForwardingObject implements */ @Override @Nullable - public V getIfPresent(Object key) { + public V getIfPresent(K key) { return delegate().getIfPresent(key); } @@ -66,7 +65,7 @@ public abstract class ForwardingCache<K, V> extends ForwardingObject implements * @since 11.0 */ @Override - public ImmutableMap<K, V> getAllPresent(Iterable<?> keys) { + public ImmutableMap<K, V> getAllPresent(Iterable<? extends K> keys) { return delegate().getAllPresent(keys); } @@ -78,14 +77,6 @@ public abstract class ForwardingCache<K, V> extends ForwardingObject implements delegate().put(key, value); } - /** - * @since 12.0 - */ - @Override - public void putAll(Map<? extends K,? extends V> m) { - delegate().putAll(m); - } - @Override public void invalidate(Object key) { delegate().invalidate(key); @@ -124,6 +115,24 @@ public abstract class ForwardingCache<K, V> extends ForwardingObject implements delegate().cleanUp(); } + @Deprecated + @Override + public V get(K key) throws ExecutionException { + return delegate().get(key); + } + + @Deprecated + @Override + public V getUnchecked(K key) { + return delegate().getUnchecked(key); + } + + @Deprecated + @Override + public V apply(K key) { + return delegate().apply(key); + } + /** * A simplified version of {@link ForwardingCache} where subclasses can pass in an already * constructed {@link Cache} as the delegete. diff --git a/guava/src/com/google/common/cache/LoadingCache.java b/guava/src/com/google/common/cache/LoadingCache.java index 05b1312..471c31a 100644 --- a/guava/src/com/google/common/cache/LoadingCache.java +++ b/guava/src/com/google/common/cache/LoadingCache.java @@ -33,14 +33,11 @@ import java.util.concurrent.ExecutionException; * <p>Implementations of this interface are expected to be thread-safe, and can be safely accessed * by multiple concurrent threads. * + * <p>All methods other than {@link #get} and {@link #getUnchecked} are optional. + * * <p>When evaluated as a {@link Function}, a cache yields the same result as invoking * {@link #getUnchecked}. * - * <p>Note that while this class is still annotated as {@link Beta}, the API is frozen from a - * consumer's standpoint. In other words existing methods are all considered {@code non-Beta} and - * won't be changed without going through an 18 month deprecation cycle; however new methods may be - * added at any time. - * * @author Charles Fry * @since 11.0 */ @@ -141,8 +138,6 @@ public interface LoadingCache<K, V> extends Cache<K, V>, Function<K, V> { * * <p>Caches loaded by a {@link CacheLoader} will call {@link CacheLoader#reload} if the * cache currently contains a value for {@code key}, and {@link CacheLoader#load} otherwise. - * Loading is asynchronous only if {@link CacheLoader#reload} was overridden with an - * asynchronous implementation. * * <p>Returns without doing anything if another thread is currently loading the value for * {@code key}. If the cache loader associated with this cache performs refresh asynchronously 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); } diff --git a/guava/src/com/google/common/cache/LongAddable.java b/guava/src/com/google/common/cache/LongAddable.java deleted file mode 100644 index 48ddbfc..0000000 --- a/guava/src/com/google/common/cache/LongAddable.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2012 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.common.cache; - -import com.google.common.annotations.GwtCompatible; - -/** - * Abstract interface for objects that can concurrently add longs. - * - * @author Louis Wasserman - */ -@GwtCompatible -interface LongAddable { - void increment(); - - void add(long x); - - long sum(); -} diff --git a/guava/src/com/google/common/cache/LongAddables.java b/guava/src/com/google/common/cache/LongAddables.java deleted file mode 100644 index a110c6c..0000000 --- a/guava/src/com/google/common/cache/LongAddables.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2012 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.common.cache; - -import com.google.common.annotations.GwtCompatible; -import com.google.common.base.Supplier; - -import java.util.concurrent.atomic.AtomicLong; - -/** - * Source of {@link LongAddable} objects that deals with GWT, Unsafe, and all - * that. - * - * @author Louis Wasserman - */ -@GwtCompatible(emulated = true) -final class LongAddables { - private static final Supplier<LongAddable> SUPPLIER; - - static { - Supplier<LongAddable> supplier; - try { - new LongAdder(); - supplier = new Supplier<LongAddable>() { - @Override - public LongAddable get() { - return new LongAdder(); - } - }; - } catch (Throwable t) { // we really want to catch *everything* - supplier = new Supplier<LongAddable>() { - @Override - public LongAddable get() { - return new PureJavaLongAddable(); - } - }; - } - SUPPLIER = supplier; - } - - public static LongAddable create() { - return SUPPLIER.get(); - } - - private static final class PureJavaLongAddable extends AtomicLong implements LongAddable { - @Override - public void increment() { - getAndIncrement(); - } - - @Override - public void add(long x) { - getAndAdd(x); - } - - @Override - public long sum() { - return get(); - } - } -} diff --git a/guava/src/com/google/common/cache/LongAdder.java b/guava/src/com/google/common/cache/LongAdder.java deleted file mode 100644 index 5af81e1..0000000 --- a/guava/src/com/google/common/cache/LongAdder.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -/* - * Source: - * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/LongAdder.java?revision=1.8 - */ - -package com.google.common.cache; - -import com.google.common.annotations.GwtCompatible; - -import java.util.concurrent.atomic.AtomicLong; -import java.io.IOException; -import java.io.Serializable; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -/** - * One or more variables that together maintain an initially zero - * {@code long} sum. When updates (method {@link #add}) are contended - * across threads, the set of variables may grow dynamically to reduce - * contention. Method {@link #sum} (or, equivalently, {@link - * #longValue}) returns the current total combined across the - * variables maintaining the sum. - * - * <p> This class is usually preferable to {@link AtomicLong} when - * multiple threads update a common sum that is used for purposes such - * as collecting statistics, not for fine-grained synchronization - * control. Under low update contention, the two classes have similar - * characteristics. But under high contention, expected throughput of - * this class is significantly higher, at the expense of higher space - * consumption. - * - * <p>This class extends {@link Number}, but does <em>not</em> define - * methods such as {@code hashCode} and {@code compareTo} because - * instances are expected to be mutated, and so are not useful as - * collection keys. - * - * <p><em>jsr166e note: This class is targeted to be placed in - * java.util.concurrent.atomic<em> - * - * @since 1.8 - * @author Doug Lea - */ -@GwtCompatible(emulated = true) -final class LongAdder extends Striped64 implements Serializable, LongAddable { - private static final long serialVersionUID = 7249069246863182397L; - - /** - * Version of plus for use in retryUpdate - */ - final long fn(long v, long x) { return v + x; } - - /** - * Creates a new adder with initial sum of zero. - */ - public LongAdder() { - } - - /** - * Adds the given value. - * - * @param x the value to add - */ - public void add(long x) { - Cell[] as; long b, v; HashCode hc; Cell a; int n; - if ((as = cells) != null || !casBase(b = base, b + x)) { - boolean uncontended = true; - int h = (hc = threadHashCode.get()).code; - if (as == null || (n = as.length) < 1 || - (a = as[(n - 1) & h]) == null || - !(uncontended = a.cas(v = a.value, v + x))) - retryUpdate(x, hc, uncontended); - } - } - - /** - * Equivalent to {@code add(1)}. - */ - public void increment() { - add(1L); - } - - /** - * Equivalent to {@code add(-1)}. - */ - public void decrement() { - add(-1L); - } - - /** - * Returns the current sum. The returned value is <em>NOT</em> an - * atomic snapshot: Invocation in the absence of concurrent - * updates returns an accurate result, but concurrent updates that - * occur while the sum is being calculated might not be - * incorporated. - * - * @return the sum - */ - public long sum() { - long sum = base; - Cell[] as = cells; - if (as != null) { - int n = as.length; - for (int i = 0; i < n; ++i) { - Cell a = as[i]; - if (a != null) - sum += a.value; - } - } - return sum; - } - - /** - * Resets variables maintaining the sum to zero. This method may - * be a useful alternative to creating a new adder, but is only - * effective if there are no concurrent updates. Because this - * method is intrinsically racy, it should only be used when it is - * known that no threads are concurrently updating. - */ - public void reset() { - internalReset(0L); - } - - /** - * Equivalent in effect to {@link #sum} followed by {@link - * #reset}. This method may apply for example during quiescent - * points between multithreaded computations. If there are - * updates concurrent with this method, the returned value is - * <em>not</em> guaranteed to be the final value occurring before - * the reset. - * - * @return the sum - */ - public long sumThenReset() { - long sum = base; - Cell[] as = cells; - base = 0L; - if (as != null) { - int n = as.length; - for (int i = 0; i < n; ++i) { - Cell a = as[i]; - if (a != null) { - sum += a.value; - a.value = 0L; - } - } - } - return sum; - } - - /** - * Returns the String representation of the {@link #sum}. - * @return the String representation of the {@link #sum} - */ - public String toString() { - return Long.toString(sum()); - } - - /** - * Equivalent to {@link #sum}. - * - * @return the sum - */ - public long longValue() { - return sum(); - } - - /** - * Returns the {@link #sum} as an {@code int} after a narrowing - * primitive conversion. - */ - public int intValue() { - return (int)sum(); - } - - /** - * Returns the {@link #sum} as a {@code float} - * after a widening primitive conversion. - */ - public float floatValue() { - return (float)sum(); - } - - /** - * Returns the {@link #sum} as a {@code double} after a widening - * primitive conversion. - */ - public double doubleValue() { - return (double)sum(); - } - - private void writeObject(ObjectOutputStream s) - throws java.io.IOException { - s.defaultWriteObject(); - s.writeLong(sum()); - } - - private void readObject(ObjectInputStream s) - throws IOException, ClassNotFoundException { - s.defaultReadObject(); - busy = 0; - cells = null; - base = s.readLong(); - } - -} diff --git a/guava/src/com/google/common/cache/RemovalCause.java b/guava/src/com/google/common/cache/RemovalCause.java index 0be9b5b..6574b0e 100644 --- a/guava/src/com/google/common/cache/RemovalCause.java +++ b/guava/src/com/google/common/cache/RemovalCause.java @@ -17,7 +17,6 @@ package com.google.common.cache; import com.google.common.annotations.Beta; -import com.google.common.annotations.GwtCompatible; import java.util.Iterator; import java.util.Map; @@ -30,7 +29,6 @@ import java.util.concurrent.ConcurrentMap; * @since 10.0 */ @Beta -@GwtCompatible public enum RemovalCause { /** * The entry was manually removed by the user. This can result from the user invoking diff --git a/guava/src/com/google/common/cache/RemovalListener.java b/guava/src/com/google/common/cache/RemovalListener.java index 270a7c4..e9b6c2c 100644 --- a/guava/src/com/google/common/cache/RemovalListener.java +++ b/guava/src/com/google/common/cache/RemovalListener.java @@ -17,7 +17,6 @@ package com.google.common.cache; import com.google.common.annotations.Beta; -import com.google.common.annotations.GwtCompatible; /** * An object that can receive a notification when an entry is removed from a cache. The removal @@ -37,7 +36,6 @@ import com.google.common.annotations.GwtCompatible; * @since 10.0 */ @Beta -@GwtCompatible public interface RemovalListener<K, V> { /** * Notifies the listener that a removal occurred at some point in the past. diff --git a/guava/src/com/google/common/cache/RemovalListeners.java b/guava/src/com/google/common/cache/RemovalListeners.java index dbb9efc..18292fd 100644 --- a/guava/src/com/google/common/cache/RemovalListeners.java +++ b/guava/src/com/google/common/cache/RemovalListeners.java @@ -16,8 +16,6 @@ package com.google.common.cache; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.common.annotations.Beta; import java.util.concurrent.Executor; @@ -43,8 +41,6 @@ public final class RemovalListeners { */ public static <K, V> RemovalListener<K, V> asynchronous( final RemovalListener<K, V> listener, final Executor executor) { - checkNotNull(listener); - checkNotNull(executor); return new RemovalListener<K, V>() { @Override public void onRemoval(final RemovalNotification<K, V> notification) { diff --git a/guava/src/com/google/common/cache/RemovalNotification.java b/guava/src/com/google/common/cache/RemovalNotification.java index 2565dba..8e0066e 100644 --- a/guava/src/com/google/common/cache/RemovalNotification.java +++ b/guava/src/com/google/common/cache/RemovalNotification.java @@ -19,7 +19,6 @@ package com.google.common.cache; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.Beta; -import com.google.common.annotations.GwtCompatible; import com.google.common.base.Objects; import java.util.Map.Entry; @@ -38,7 +37,6 @@ import javax.annotation.Nullable; * @since 10.0 */ @Beta -@GwtCompatible public final class RemovalNotification<K, V> implements Entry<K, V> { @Nullable private final K key; @Nullable private final V value; diff --git a/guava/src/com/google/common/cache/Striped64.java b/guava/src/com/google/common/cache/Striped64.java deleted file mode 100644 index e045453..0000000 --- a/guava/src/com/google/common/cache/Striped64.java +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Written by Doug Lea with assistance from members of JCP JSR-166 - * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -/* - * Source: - * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/Striped64.java?revision=1.7 - */ - -package com.google.common.cache; - -import java.util.Random; - -/** - * A package-local class holding common representation and mechanics - * for classes supporting dynamic striping on 64bit values. The class - * extends Number so that concrete subclasses must publicly do so. - */ -abstract class Striped64 extends Number { - /* - * This class maintains a lazily-initialized table of atomically - * updated variables, plus an extra "base" field. The table size - * is a power of two. Indexing uses masked per-thread hash codes. - * Nearly all declarations in this class are package-private, - * accessed directly by subclasses. - * - * Table entries are of class Cell; a variant of AtomicLong padded - * to reduce cache contention on most processors. Padding is - * overkill for most Atomics because they are usually irregularly - * scattered in memory and thus don't interfere much with each - * other. But Atomic objects residing in arrays will tend to be - * placed adjacent to each other, and so will most often share - * cache lines (with a huge negative performance impact) without - * this precaution. - * - * In part because Cells are relatively large, we avoid creating - * them until they are needed. When there is no contention, all - * updates are made to the base field. Upon first contention (a - * failed CAS on base update), the table is initialized to size 2. - * The table size is doubled upon further contention until - * reaching the nearest power of two greater than or equal to the - * number of CPUS. Table slots remain empty (null) until they are - * needed. - * - * A single spinlock ("busy") is used for initializing and - * resizing the table, as well as populating slots with new Cells. - * There is no need for a blocking lock: When the lock is not - * available, threads try other slots (or the base). During these - * retries, there is increased contention and reduced locality, - * which is still better than alternatives. - * - * Per-thread hash codes are initialized to random values. - * Contention and/or table collisions are indicated by failed - * CASes when performing an update operation (see method - * retryUpdate). Upon a collision, if the table size is less than - * the capacity, it is doubled in size unless some other thread - * holds the lock. If a hashed slot is empty, and lock is - * available, a new Cell is created. Otherwise, if the slot - * exists, a CAS is tried. Retries proceed by "double hashing", - * using a secondary hash (Marsaglia XorShift) to try to find a - * free slot. - * - * The table size is capped because, when there are more threads - * than CPUs, supposing that each thread were bound to a CPU, - * there would exist a perfect hash function mapping threads to - * slots that eliminates collisions. When we reach capacity, we - * search for this mapping by randomly varying the hash codes of - * colliding threads. Because search is random, and collisions - * only become known via CAS failures, convergence can be slow, - * and because threads are typically not bound to CPUS forever, - * may not occur at all. However, despite these limitations, - * observed contention rates are typically low in these cases. - * - * It is possible for a Cell to become unused when threads that - * once hashed to it terminate, as well as in the case where - * doubling the table causes no thread to hash to it under - * expanded mask. We do not try to detect or remove such cells, - * under the assumption that for long-running instances, observed - * contention levels will recur, so the cells will eventually be - * needed again; and for short-lived ones, it does not matter. - */ - - /** - * Padded variant of AtomicLong supporting only raw accesses plus CAS. - * The value field is placed between pads, hoping that the JVM doesn't - * reorder them. - * - * JVM intrinsics note: It would be possible to use a release-only - * form of CAS here, if it were provided. - */ - static final class Cell { - volatile long p0, p1, p2, p3, p4, p5, p6; - volatile long value; - volatile long q0, q1, q2, q3, q4, q5, q6; - Cell(long x) { value = x; } - - final boolean cas(long cmp, long val) { - return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val); - } - - // Unsafe mechanics - private static final sun.misc.Unsafe UNSAFE; - private static final long valueOffset; - static { - try { - UNSAFE = getUnsafe(); - Class<?> ak = Cell.class; - valueOffset = UNSAFE.objectFieldOffset - (ak.getDeclaredField("value")); - } catch (Exception e) { - throw new Error(e); - } - } - - } - - /** - * Holder for the thread-local hash code. The code is initially - * random, but may be set to a different value upon collisions. - */ - static final class HashCode { - static final Random rng = new Random(); - int code; - HashCode() { - int h = rng.nextInt(); // Avoid zero to allow xorShift rehash - code = (h == 0) ? 1 : h; - } - } - - /** - * The corresponding ThreadLocal class - */ - static final class ThreadHashCode extends ThreadLocal<HashCode> { - public HashCode initialValue() { return new HashCode(); } - } - - /** - * Static per-thread hash codes. Shared across all instances to - * reduce ThreadLocal pollution and because adjustments due to - * collisions in one table are likely to be appropriate for - * others. - */ - static final ThreadHashCode threadHashCode = new ThreadHashCode(); - - /** Number of CPUS, to place bound on table size */ - static final int NCPU = Runtime.getRuntime().availableProcessors(); - - /** - * Table of cells. When non-null, size is a power of 2. - */ - transient volatile Cell[] cells; - - /** - * Base value, used mainly when there is no contention, but also as - * a fallback during table initialization races. Updated via CAS. - */ - transient volatile long base; - - /** - * Spinlock (locked via CAS) used when resizing and/or creating Cells. - */ - transient volatile int busy; - - /** - * Package-private default constructor - */ - Striped64() { - } - - /** - * CASes the base field. - */ - final boolean casBase(long cmp, long val) { - return UNSAFE.compareAndSwapLong(this, baseOffset, cmp, val); - } - - /** - * CASes the busy field from 0 to 1 to acquire lock. - */ - final boolean casBusy() { - return UNSAFE.compareAndSwapInt(this, busyOffset, 0, 1); - } - - /** - * Computes the function of current and new value. Subclasses - * should open-code this update function for most uses, but the - * virtualized form is needed within retryUpdate. - * - * @param currentValue the current value (of either base or a cell) - * @param newValue the argument from a user update call - * @return result of the update function - */ - abstract long fn(long currentValue, long newValue); - - /** - * Handles cases of updates involving initialization, resizing, - * creating new Cells, and/or contention. See above for - * explanation. This method suffers the usual non-modularity - * problems of optimistic retry code, relying on rechecked sets of - * reads. - * - * @param x the value - * @param hc the hash code holder - * @param wasUncontended false if CAS failed before call - */ - final void retryUpdate(long x, HashCode hc, boolean wasUncontended) { - int h = hc.code; - boolean collide = false; // True if last slot nonempty - for (;;) { - Cell[] as; Cell a; int n; long v; - if ((as = cells) != null && (n = as.length) > 0) { - if ((a = as[(n - 1) & h]) == null) { - if (busy == 0) { // Try to attach new Cell - Cell r = new Cell(x); // Optimistically create - if (busy == 0 && casBusy()) { - boolean created = false; - try { // Recheck under lock - Cell[] rs; int m, j; - if ((rs = cells) != null && - (m = rs.length) > 0 && - rs[j = (m - 1) & h] == null) { - rs[j] = r; - created = true; - } - } finally { - busy = 0; - } - if (created) - break; - continue; // Slot is now non-empty - } - } - collide = false; - } - else if (!wasUncontended) // CAS already known to fail - wasUncontended = true; // Continue after rehash - else if (a.cas(v = a.value, fn(v, x))) - break; - else if (n >= NCPU || cells != as) - collide = false; // At max size or stale - else if (!collide) - collide = true; - else if (busy == 0 && casBusy()) { - try { - if (cells == as) { // Expand table unless stale - Cell[] rs = new Cell[n << 1]; - for (int i = 0; i < n; ++i) - rs[i] = as[i]; - cells = rs; - } - } finally { - busy = 0; - } - collide = false; - continue; // Retry with expanded table - } - h ^= h << 13; // Rehash - h ^= h >>> 17; - h ^= h << 5; - } - else if (busy == 0 && cells == as && casBusy()) { - boolean init = false; - try { // Initialize table - if (cells == as) { - Cell[] rs = new Cell[2]; - rs[h & 1] = new Cell(x); - cells = rs; - init = true; - } - } finally { - busy = 0; - } - if (init) - break; - } - else if (casBase(v = base, fn(v, x))) - break; // Fall back on using base - } - hc.code = h; // Record index for next time - } - - /** - * Sets base and all cells to the given value. - */ - final void internalReset(long initialValue) { - Cell[] as = cells; - base = initialValue; - if (as != null) { - int n = as.length; - for (int i = 0; i < n; ++i) { - Cell a = as[i]; - if (a != null) - a.value = initialValue; - } - } - } - - // Unsafe mechanics - private static final sun.misc.Unsafe UNSAFE; - private static final long baseOffset; - private static final long busyOffset; - static { - try { - UNSAFE = getUnsafe(); - Class<?> sk = Striped64.class; - baseOffset = UNSAFE.objectFieldOffset - (sk.getDeclaredField("base")); - busyOffset = UNSAFE.objectFieldOffset - (sk.getDeclaredField("busy")); - } catch (Exception e) { - throw new Error(e); - } - } - - /** - * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. - * Replace with a simple call to Unsafe.getUnsafe when integrating - * into a jdk. - * - * @return a sun.misc.Unsafe - */ - private static sun.misc.Unsafe getUnsafe() { - try { - return sun.misc.Unsafe.getUnsafe(); - } catch (SecurityException tryReflectionInstead) {} - try { - return java.security.AccessController.doPrivileged - (new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() { - public sun.misc.Unsafe run() throws Exception { - Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class; - for (java.lang.reflect.Field f : k.getDeclaredFields()) { - f.setAccessible(true); - Object x = f.get(null); - if (k.isInstance(x)) - return k.cast(x); - } - throw new NoSuchFieldError("the Unsafe"); - }}); - } catch (java.security.PrivilegedActionException e) { - throw new RuntimeException("Could not initialize intrinsics", - e.getCause()); - } - } - -} diff --git a/guava/src/com/google/common/cache/Weigher.java b/guava/src/com/google/common/cache/Weigher.java index 5720cb8..bbb0a33 100644 --- a/guava/src/com/google/common/cache/Weigher.java +++ b/guava/src/com/google/common/cache/Weigher.java @@ -1,30 +1,30 @@ /* * Copyright (C) 2011 The Guava Authors * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package com.google.common.cache; import com.google.common.annotations.Beta; -import com.google.common.annotations.GwtCompatible; /** * Calculates the weights of cache entries. * - * @author Charles Fry + * @author fry@google.com (Charles Fry) * @since 11.0 */ @Beta -@GwtCompatible public interface Weigher<K, V> { /** @@ -34,4 +34,5 @@ public interface Weigher<K, V> { * @return the weight of the entry; must be non-negative */ int weigh(K key, V value); + } diff --git a/guava/src/com/google/common/cache/package-info.java b/guava/src/com/google/common/cache/package-info.java index ea0297b..1c5391c 100644 --- a/guava/src/com/google/common/cache/package-info.java +++ b/guava/src/com/google/common/cache/package-info.java @@ -22,9 +22,6 @@ * {@link com.google.common.cache.CacheBuilder}, with cache entries being loaded by * {@link com.google.common.cache.CacheLoader}. Statistics about cache performance are exposed using * {@link com.google.common.cache.CacheStats}. - * - * <p>See the Guava User Guide article on <a href= - * "http://code.google.com/p/guava-libraries/wiki/CachesExplained">caches</a>. * * <p>This package is a part of the open-source * <a href="http://guava-libraries.googlecode.com">Guava libraries</a>. @@ -35,4 +32,3 @@ package com.google.common.cache; import javax.annotation.ParametersAreNonnullByDefault; - |