LocalManualCache(@Nonnull CacheBuilder<? super K, ? super V> builder) { this(new LocalCache(builder, null)); }
@Override public void cleanUp() { localCache.cleanUp(); }
@Override public void invalidateAll() { localCache.clear(); }
boolean usesAccessQueue() { return expiresAfterAccess() || evictsBySize(); }
boolean expires() { return expiresAfterWrite() || expiresAfterAccess(); }
AbstractCacheSet(ConcurrentMap<?, ?> map) { this.map = map; }
Segment(@Nonnull LocalCache<K, V> map, int initialCapacity, long maxSegmentWeight) { this.map = map; this.maxSegmentWeight = maxSegmentWeight; initTable(newEntryArray(initialCapacity)); keyReferenceQueue = map.usesKeyReferences() ? new ReferenceQueue<K>() : null; valueReferenceQueue = map.usesValueReferences() ? new ReferenceQueue<V>() : null; recencyQueue = map.usesAccessQueue() ? new ConcurrentLinkedQueue<ReferenceEntry<K, V>>() : LocalCache.<ReferenceEntry<K, V>>discardingQueue(); writeQueue = map.usesWriteQueue() ? new WriteQueue<K, V>() : LocalCache.<ReferenceEntry<K, V>>discardingQueue(); accessQueue = map.usesAccessQueue() ? new AccessQueue<K, V>() : LocalCache.<ReferenceEntry<K, V>>discardingQueue(); }
@Override @SuppressWarnings("unchecked") public boolean remove(Object o) { ReferenceEntry<K, V> e = (ReferenceEntry) o; ReferenceEntry<K, V> previous = e.getPreviousInWriteQueue(); ReferenceEntry<K, V> next = e.getNextInWriteQueue(); connectWriteOrder(previous, next); nullifyWriteOrder(e); return next != NullEntry.INSTANCE; }
@Override @SuppressWarnings("unchecked") public boolean remove(Object o) { ReferenceEntry<K, V> e = (ReferenceEntry) o; ReferenceEntry<K, V> previous = e.getPreviousInAccessQueue(); ReferenceEntry<K, V> next = e.getNextInAccessQueue(); connectAccessOrder(previous, next); nullifyAccessOrder(e); return next != NullEntry.INSTANCE; }
boolean recordsAccess() { return expiresAfterAccess(); }
void initTable(@Nonnull AtomicReferenceArray<ReferenceEntry<K, V>> newTable) { this.threshold = newTable.length() * 3 / 4; // 0.75 if (!map.customWeigher() && this.threshold == maxSegmentWeight) { // prevent spurious expansion before eviction this.threshold++; } this.table = newTable; }
@Override public boolean offer(@Nonnull ReferenceEntry<K, V> entry) { // unlink connectAccessOrder(entry.getPreviousInAccessQueue(), entry.getNextInAccessQueue()); // add to tail connectAccessOrder(head.getPreviousInAccessQueue(), entry); connectAccessOrder(entry, head); return true; }
@Override public boolean offer(@Nonnull ReferenceEntry<K, V> entry) { // unlink connectWriteOrder(entry.getPreviousInWriteQueue(), entry.getNextInWriteQueue()); // add to tail connectWriteOrder(head.getPreviousInWriteQueue(), entry); connectWriteOrder(entry, head); return true; }
/** * Performs eviction if the segment is over capacity. Avoids flushing the entire cache if the * newest entry exceeds the maximum weight all on its own. * * @param newest the most recently added entry */ void evictEntries(@Nonnull ReferenceEntry<K, V> newest) { if (!map.evictsBySize()) { return; } drainRecencyQueue(); // If the newest entry by itself is too heavy for the segment, don't bother evicting // anything else, just that if (newest.getValueReference().getWeight() > maxSegmentWeight) { if (!removeEntry(newest, newest.getHash(), RemovalCause.SIZE)) { throw new AssertionError(); } } while (totalWeight > maxSegmentWeight) { ReferenceEntry<K, V> e = getNextEvictable(); if (!removeEntry(e, e.getHash(), RemovalCause.SIZE)) { throw new AssertionError(); } } }
<K, V> void copyWriteEntry(@Nonnull ReferenceEntry<K, V> original, @Nonnull ReferenceEntry<K, V> newEntry) { // TODO(fry): when we link values instead of entries this method can go // away, as can connectWriteOrder, nullifyWriteOrder. newEntry.setWriteTime(original.getWriteTime()); connectWriteOrder(original.getPreviousInWriteQueue(), newEntry); connectWriteOrder(newEntry, original.getNextInWriteQueue()); nullifyWriteOrder(original); } }
<K, V> void copyAccessEntry(@Nonnull ReferenceEntry<K, V> original, @Nonnull ReferenceEntry<K, V> newEntry) { // TODO(fry): when we link values instead of entries this method can go // away, as can connectAccessOrder, nullifyAccessOrder. newEntry.setAccessTime(original.getAccessTime()); connectAccessOrder(original.getPreviousInAccessQueue(), newEntry); connectAccessOrder(newEntry, original.getNextInAccessQueue()); nullifyAccessOrder(original); }
/** * Returns true if the entry has expired. */ boolean isExpired(@Nonnull ReferenceEntry<K, V> entry, long now) { Preconditions.checkNotNull(entry); if (expiresAfterAccess() && (now - entry.getAccessTime() >= expireAfterAccessNanos)) { return true; } if (expiresAfterWrite() && (now - entry.getWriteTime() >= expireAfterWriteNanos)) { return true; } return false; }
LocalLoadingCache(@Nonnull CacheBuilder<? super K, ? super V> builder, @Nonnull CacheLoader<? super K, V> loader) { super(new LocalCache<>(builder, Preconditions.checkNotNull(loader))); }