/*
* 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());
}
}
}