/*
 * 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 com.google.common.annotations.GwtCompatible;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;

This class provides a skeletal implementation of the Cache interface to minimize the effort required to implement this interface.

To implement a cache, the programmer needs only to extend this class and provide an implementation for the put and Cache.getIfPresent methods. getAllPresent is implemented in terms of Cache.getIfPresent; putAll is implemented in terms of put, invalidateAll(Iterable) is implemented in terms of invalidate. The method cleanUp is a no-op. All other methods throw an UnsupportedOperationException.

Author:Charles Fry
Since:10.0
/** * 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 {@link * UnsupportedOperationException}. * * @author Charles Fry * @since 10.0 */
@GwtCompatible public abstract class AbstractCache<K, V> implements Cache<K, V> {
Constructor for use by subclasses.
/** Constructor for use by subclasses. */
protected AbstractCache() {}
Since:11.0
/** @since 11.0 */
@Override public V get(K key, Callable<? extends V> valueLoader) throws ExecutionException { throw new UnsupportedOperationException(); }
{@inheritDoc}

This implementation of 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 keys to actually be of type K.

Since:11.0
/** * {@inheritDoc} * * <p>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}. * * @since 11.0 */
@Override public ImmutableMap<K, V> getAllPresent(Iterable<?> keys) { Map<K, V> result = Maps.newLinkedHashMap(); for (Object key : keys) { if (!result.containsKey(key)) { @SuppressWarnings("unchecked") K castKey = (K) key; V value = getIfPresent(key); if (value != null) { result.put(castKey, value); } } } return ImmutableMap.copyOf(result); }
Since:11.0
/** @since 11.0 */
@Override public void put(K key, V value) { throw new UnsupportedOperationException(); }
Since:12.0
/** @since 12.0 */
@Override public void putAll(Map<? extends K, ? extends V> m) { for (Entry<? extends K, ? extends V> entry : m.entrySet()) { put(entry.getKey(), entry.getValue()); } } @Override public void cleanUp() {} @Override public long size() { throw new UnsupportedOperationException(); } @Override public void invalidate(Object key) { throw new UnsupportedOperationException(); }
Since:11.0
/** @since 11.0 */
@Override public void invalidateAll(Iterable<?> keys) { for (Object key : keys) { invalidate(key); } } @Override public void invalidateAll() { throw new UnsupportedOperationException(); } @Override public CacheStats stats() { throw new UnsupportedOperationException(); } @Override public ConcurrentMap<K, V> asMap() { throw new UnsupportedOperationException(); }
Accumulates statistics during the operation of a Cache for presentation by Cache.stats. This is solely intended for consumption by Cache implementors.
Since:10.0
/** * 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. * * @since 10.0 */
public interface StatsCounter {
Records cache hits. This should be called when a cache request returns a cached value.
Params:
  • count – the number of hits to record
Since:11.0
/** * Records cache hits. This should be called when a cache request returns a cached value. * * @param count the number of hits to record * @since 11.0 */
void recordHits(int count);
Records cache misses. This should be called when a cache request returns a value that was not found in the cache. This method should be called by the loading thread, as well as by threads blocking on the load. Multiple concurrent calls to Cache lookup methods with the same key on an absent value should result in a single call to either recordLoadSuccess or recordLoadException and multiple calls to this method, despite all being served by the results of a single load operation.
Params:
  • count – the number of misses to record
Since:11.0
/** * Records cache misses. This should be called when a cache request returns a value that was not * found in the cache. This method should be called by the loading thread, as well as by threads * blocking on the load. Multiple concurrent calls to {@link Cache} lookup methods with the same * key on an absent value should result in a single call to either {@code recordLoadSuccess} or * {@code recordLoadException} and multiple calls to this method, despite all being served by * the results of a single load operation. * * @param count the number of misses to record * @since 11.0 */
void recordMisses(int count);
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 recordMisses, this method should only be called by the loading thread.
Params:
  • loadTime – the number of nanoseconds the cache spent computing or retrieving the new value
/** * 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. * * @param loadTime the number of nanoseconds the cache spent computing or retrieving the new * value */
void recordLoadSuccess(long loadTime);
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 recordMisses, this method should only be called by the loading thread.
Params:
  • loadTime – the number of nanoseconds the cache spent computing or retrieving the new value prior to an exception being thrown
/** * 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. * * @param loadTime the number of nanoseconds the cache spent computing or retrieving the new * value prior to an exception being thrown */
void recordLoadException(long loadTime);
Records the eviction of an entry from the cache. This should only been called when an entry is evicted due to the cache's eviction strategy, and not as a result of manual invalidations.
/** * Records the eviction of an entry from the cache. This should only been called when an entry * is evicted due to the cache's eviction strategy, and not as a result of manual {@linkplain * Cache#invalidate invalidations}. */
void recordEviction();
Returns a snapshot of this counter's values. Note that this may be an inconsistent view, as it may be interleaved with update operations.
/** * Returns a snapshot of this counter's values. Note that this may be an inconsistent view, as * it may be interleaved with update operations. */
CacheStats snapshot(); }
A thread-safe StatsCounter implementation for use by Cache implementors.
Since:10.0
/** * A thread-safe {@link StatsCounter} implementation for use by {@link Cache} implementors. * * @since 10.0 */
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.
/** Constructs an instance with all counts initialized to zero. */
public SimpleStatsCounter() {}
Since:11.0
/** @since 11.0 */
@Override public void recordHits(int count) { hitCount.add(count); }
Since:11.0
/** @since 11.0 */
@Override public void recordMisses(int count) { missCount.add(count); } @Override public void recordLoadSuccess(long loadTime) { loadSuccessCount.increment(); totalLoadTime.add(loadTime); } @Override public void recordLoadException(long loadTime) { loadExceptionCount.increment(); totalLoadTime.add(loadTime); } @Override public void recordEviction() { evictionCount.increment(); } @Override public CacheStats snapshot() { return new CacheStats( hitCount.sum(), missCount.sum(), loadSuccessCount.sum(), loadExceptionCount.sum(), totalLoadTime.sum(), evictionCount.sum()); }
Increments all counters by the values in other.
/** Increments all counters by the values in {@code other}. */
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()); } } }