1ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/* 2ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Copyright (C) 2011 The Android Open Source Project 3ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 4ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Licensed under the Apache License, Version 2.0 (the "License"); 5ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * you may not use this file except in compliance with the License. 6ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * You may obtain a copy of the License at 7ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 8ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * http://www.apache.org/licenses/LICENSE-2.0 9ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 10ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Unless required by applicable law or agreed to in writing, software 11ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * distributed under the License is distributed on an "AS IS" BASIS, 12ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * See the License for the specific language governing permissions and 14ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * limitations under the License. 15ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 16ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 17ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpackage com.android.dialer.util; 18ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 19ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.util.LruCache; 20ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport java.util.concurrent.atomic.AtomicInteger; 21ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport javax.annotation.concurrent.Immutable; 22ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport javax.annotation.concurrent.ThreadSafe; 23ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 24ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/** 25ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * An LRU cache in which all items can be marked as expired at a given time and it is possible to 26ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * query whether a particular cached value is expired or not. 27ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 28ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>A typical use case for this is caching of values which are expensive to compute but which are 29ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * still useful when out of date. 30ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 31ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>Consider a cache for contact information: 32ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 33ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <pre>{@code 34ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * private ExpirableCache<String, Contact> mContactCache; 35ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * }</pre> 36ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 37ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * which stores the contact information for a given phone number. 38ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 39ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>When we need to store contact information for a given phone number, we can look up the info in 40ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * the cache: 41ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 42ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <pre>{@code 43ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * CachedValue<Contact> cachedContact = mContactCache.getCachedValue(phoneNumber); 44ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * }</pre> 45ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 46ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * We might also want to fetch the contact information again if the item is expired. 47ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 48ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <pre> 49ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * if (cachedContact.isExpired()) { 50ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * fetchContactForNumber(phoneNumber, 51ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * new FetchListener() { 52ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @Override 53ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * public void onFetched(Contact contact) { 54ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * mContactCache.put(phoneNumber, contact); 55ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * } 56ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * }); 57ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * }</pre> 58ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 59ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * and insert it back into the cache when the fetch completes. 60ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 61ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>At a certain point we want to expire the content of the cache because we know the content may 62ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * no longer be up-to-date, for instance, when resuming the activity this is shown into: 63ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 64ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <pre> 65ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @Override 66ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * protected onResume() { 67ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * // We were paused for some time, the cached value might no longer be up to date. 68ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * mContactCache.expireAll(); 69ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * super.onResume(); 70ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * } 71ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * </pre> 72ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 73ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * The values will be still available from the cache, but they will be expired. 74ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 75ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>If interested only in the value itself, not whether it is expired or not, one should use the 76ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * {@link #getPossiblyExpired(Object)} method. If interested only in non-expired values, one should 77ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * use the {@link #get(Object)} method instead. 78ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 79ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>This class wraps around an {@link LruCache} instance: it follows the {@link LruCache} behavior 80ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * for evicting items when the cache is full. It is possible to supply your own subclass of LruCache 81ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * by using the {@link #create(LruCache)} method, which can define a custom expiration policy. Since 82ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * the underlying cache maps keys to cached values it can determine which items are expired and 83ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * which are not, allowing for an implementation that evicts expired items before non expired ones. 84ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 85ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>This class is thread-safe. 86ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 87ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param <K> the type of the keys 88ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param <V> the type of the values 89ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 90ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian@ThreadSafe 91ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpublic class ExpirableCache<K, V> { 92ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 93ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 94ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * The current generation of items added to the cache. 95ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 96ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>Items in the cache can belong to a previous generation, but in that case they would be 97ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * expired. 98ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 99ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @see ExpirableCache.CachedValue#isExpired() 100ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 101183cb71663320f16149d83eeebaff7795a4b55f2linyuh private final AtomicInteger generation; 102ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** The underlying cache used to stored the cached values. */ 103183cb71663320f16149d83eeebaff7795a4b55f2linyuh private LruCache<K, CachedValue<V>> cache; 104ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 105ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private ExpirableCache(LruCache<K, CachedValue<V>> cache) { 106183cb71663320f16149d83eeebaff7795a4b55f2linyuh this.cache = cache; 107183cb71663320f16149d83eeebaff7795a4b55f2linyuh generation = new AtomicInteger(0); 108ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 109ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 110ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 111ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Creates a new {@link ExpirableCache} that wraps the given {@link LruCache}. 112ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 113ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>The created cache takes ownership of the cache passed in as an argument. 114ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 115ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param <K> the type of the keys 116ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param <V> the type of the values 117ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param cache the cache to store the value in 118ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @return the newly created expirable cache 119ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @throws IllegalArgumentException if the cache is not empty 120ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 121ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static <K, V> ExpirableCache<K, V> create(LruCache<K, CachedValue<V>> cache) { 122ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return new ExpirableCache<K, V>(cache); 123ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 124ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 125ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 126ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Creates a new {@link ExpirableCache} with the given maximum size. 127ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 128ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param <K> the type of the keys 129ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param <V> the type of the values 130ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @return the newly created expirable cache 131ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 132ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static <K, V> ExpirableCache<K, V> create(int maxSize) { 133ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return create(new LruCache<K, CachedValue<V>>(maxSize)); 134ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 135ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 136ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 137ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Returns the cached value for the given key, or null if no value exists. 138ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 139ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>The cached value gives access both to the value associated with the key and whether it is 140ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * expired or not. 141ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 142ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>If not interested in whether the value is expired, use {@link #getPossiblyExpired(Object)} 143ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * instead. 144ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 145ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>If only wants values that are not expired, use {@link #get(Object)} instead. 146ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 147ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param key the key to look up 148ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 149ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public CachedValue<V> getCachedValue(K key) { 150183cb71663320f16149d83eeebaff7795a4b55f2linyuh return cache.get(key); 151ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 152ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 153ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 154ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Returns the value for the given key, or null if no value exists. 155ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 156ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>When using this method, it is not possible to determine whether the value is expired or not. 157ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Use {@link #getCachedValue(Object)} to achieve that instead. However, if using {@link 158ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * #getCachedValue(Object)} to determine if an item is expired, one should use the item within the 159ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * {@link CachedValue} and not call {@link #getPossiblyExpired(Object)} to get the value 160ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * afterwards, since that is not guaranteed to return the same value or that the newly returned 161ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * value is in the same state. 162ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 163ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param key the key to look up 164ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 165ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public V getPossiblyExpired(K key) { 166ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian CachedValue<V> cachedValue = getCachedValue(key); 167ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return cachedValue == null ? null : cachedValue.getValue(); 168ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 169ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 170ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 171ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Returns the value for the given key only if it is not expired, or null if no value exists or is 172ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * expired. 173ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 174ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>This method will return null if either there is no value associated with this key or if the 175ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * associated value is expired. 176ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 177ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param key the key to look up 178ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 179ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public V get(K key) { 180ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian CachedValue<V> cachedValue = getCachedValue(key); 181ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return cachedValue == null || cachedValue.isExpired() ? null : cachedValue.getValue(); 182ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 183ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 184ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 185ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Puts an item in the cache. 186ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 187ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>Newly added item will not be expired until {@link #expireAll()} is next called. 188ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 189ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param key the key to look up 190ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param value the value to associate with the key 191ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 192ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void put(K key, V value) { 193183cb71663320f16149d83eeebaff7795a4b55f2linyuh cache.put(key, newCachedValue(value)); 194ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 195ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 196ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 197ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Mark all items currently in the cache as expired. 198ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 199ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>Newly added items after this call will be marked as not expired. 200ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 201ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>Expiring the items in the cache does not imply they will be evicted. 202ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 203ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void expireAll() { 204183cb71663320f16149d83eeebaff7795a4b55f2linyuh generation.incrementAndGet(); 205ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 206ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 207ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 208ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Creates a new {@link CachedValue} instance to be stored in this cache. 209ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 210ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>Implementation of {@link LruCache#create(K)} can use this method to create a new entry. 211ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 212ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public CachedValue<V> newCachedValue(V value) { 213183cb71663320f16149d83eeebaff7795a4b55f2linyuh return new GenerationalCachedValue<V>(value, generation); 214ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 215ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 216ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 217ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * A cached value stored inside the cache. 218ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 219ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>It provides access to the value stored in the cache but also allows to check whether the 220ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * value is expired. 221ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 222ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param <V> the type of value stored in the cache 223ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 224ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public interface CachedValue<V> { 225ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 226ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Returns the value stored in the cache for a given key. */ 227ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian V getValue(); 228ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 229ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 230ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Checks whether the value, while still being present in the cache, is expired. 231ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 232ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @return true if the value is expired 233ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 234ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian boolean isExpired(); 235ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 236ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 237ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Cached values storing the generation at which they were added. */ 238ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Immutable 239ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static class GenerationalCachedValue<V> implements ExpirableCache.CachedValue<V> { 240ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 241ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** The value stored in the cache. */ 242183cb71663320f16149d83eeebaff7795a4b55f2linyuh public final V value; 243ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** The generation at which the value was added to the cache. */ 244183cb71663320f16149d83eeebaff7795a4b55f2linyuh private final int generation; 245ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** The atomic integer storing the current generation of the cache it belongs to. */ 246183cb71663320f16149d83eeebaff7795a4b55f2linyuh private final AtomicInteger cacheGeneration; 247ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 248ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 249ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @param cacheGeneration the atomic integer storing the generation of the cache in which this 250ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * value will be stored 251ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 252ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public GenerationalCachedValue(V value, AtomicInteger cacheGeneration) { 253183cb71663320f16149d83eeebaff7795a4b55f2linyuh this.value = value; 254183cb71663320f16149d83eeebaff7795a4b55f2linyuh this.cacheGeneration = cacheGeneration; 255ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Snapshot the current generation. 256183cb71663320f16149d83eeebaff7795a4b55f2linyuh generation = this.cacheGeneration.get(); 257ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 258ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 259ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 260ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public V getValue() { 261183cb71663320f16149d83eeebaff7795a4b55f2linyuh return value; 262ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 263ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 264ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 265ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public boolean isExpired() { 266183cb71663320f16149d83eeebaff7795a4b55f2linyuh return generation != cacheGeneration.get(); 267ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 268ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 269ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian} 270