public ListenableFuture<V> loadFuture(K key, CacheLoader<? super K, V> loader) { try { stopwatch.start(); V previousValue = oldValue.get(); if (previousValue == null) { V newValue = loader.load(key);
static <K, V> Map<K, V> segmentTable(Segment<K, V> segment) { AtomicReferenceArray<? extends ReferenceEntry<K, V>> table = segment.table; Map<K, V> map = Maps.newLinkedHashMap(); for (int i = 0; i < table.length(); i++) { for (ReferenceEntry<K, V> entry = table.get(i); entry != null; entry = entry.getNext()) { K key = entry.getKey(); V value = entry.getValueReference().get(); if (key != null && value != null) { assertNull(map.put(key, value)); } } } return map; }
@GuardedBy("this") void removeCollectedEntry(ReferenceEntry<K, V> entry) { enqueueNotification( entry.getKey(), entry.getHash(), entry.getValueReference().get(), entry.getValueReference().getWeight(), RemovalCause.COLLECTED); writeQueue.remove(entry); accessQueue.remove(entry); }
@GuardedBy("this") void removeCollectedEntry(ReferenceEntry<K, V> entry) { enqueueNotification( entry.getKey(), entry.getHash(), entry.getValueReference().get(), entry.getValueReference().getWeight(), RemovalCause.COLLECTED); writeQueue.remove(entry); accessQueue.remove(entry); }
entryKey, hash, valueReference.get(), valueReference, RemovalCause.COLLECTED);
&& map.keyEquivalence.equivalent(key, entryKey)) { ValueReference<K, V> valueReference = e.getValueReference(); V entryValue = valueReference.get();
&& map.keyEquivalence.equivalent(key, entryKey)) { ValueReference<K, V> valueReference = e.getValueReference(); V entryValue = valueReference.get();
assertEquals(hashOne, entryOne.getHash()); assertNull(entryOne.getNext()); assertSame(valueOne, copyOne.getValueReference().get()); assertConnected(map, copyOne, entryTwo); assertEquals(hashTwo, copyTwo.getHash()); assertSame(copyOne, copyTwo.getNext()); assertSame(valueTwo, copyTwo.getValueReference().get()); assertConnected(map, copyOne, copyTwo);
assertSame(valueThree, newFirst.getValueReference().get()); assertEquals(hashThree, newFirst.getHash()); assertSame(entryOne, newFirst.getNext()); assertSame(valueTwo, newFirst.getValueReference().get()); assertEquals(hashTwo, newFirst.getHash()); newFirst = newFirst.getNext(); assertSame(keyThree, newFirst.getKey()); assertSame(valueThree, newFirst.getValueReference().get()); assertEquals(hashThree, newFirst.getHash()); assertNull(newFirst.getNext());
V value = e.getValueReference().get(); RemovalCause cause = (key == null || value == null) ? RemovalCause.COLLECTED : RemovalCause.EXPLICIT;
e.getKey(), hash, e.getValueReference().get(), e.getValueReference(), RemovalCause.COLLECTED);
public void testNewEntry() { for (CacheBuilder<Object, Object> builder : allEntryTypeMakers()) { LocalCache<Object, Object> map = makeLocalCache(builder); Object keyOne = new Object(); Object valueOne = new Object(); int hashOne = map.hash(keyOne); ReferenceEntry<Object, Object> entryOne = map.newEntry(keyOne, hashOne, null); ValueReference<Object, Object> valueRefOne = map.newValueReference(entryOne, valueOne, 1); assertSame(valueOne, valueRefOne.get()); entryOne.setValueReference(valueRefOne); assertSame(keyOne, entryOne.getKey()); assertEquals(hashOne, entryOne.getHash()); assertNull(entryOne.getNext()); assertSame(valueRefOne, entryOne.getValueReference()); Object keyTwo = new Object(); Object valueTwo = new Object(); int hashTwo = map.hash(keyTwo); ReferenceEntry<Object, Object> entryTwo = map.newEntry(keyTwo, hashTwo, entryOne); ValueReference<Object, Object> valueRefTwo = map.newValueReference(entryTwo, valueTwo, 1); assertSame(valueTwo, valueRefTwo.get()); entryTwo.setValueReference(valueRefTwo); assertSame(keyTwo, entryTwo.getKey()); assertEquals(hashTwo, entryTwo.getHash()); assertSame(entryOne, entryTwo.getNext()); assertSame(valueRefTwo, entryTwo.getValueReference()); } }
@VisibleForTesting @GuardedBy("this") boolean removeEntry(ReferenceEntry<K, V> entry, int hash, RemovalCause cause) { int newCount = this.count - 1; AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; int index = hash & (table.length() - 1); ReferenceEntry<K, V> first = table.get(index); for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { if (e == entry) { ++modCount; ReferenceEntry<K, V> newFirst = removeValueFromChain( first, e, e.getKey(), hash, e.getValueReference().get(), e.getValueReference(), cause); newCount = this.count - 1; table.set(index, newFirst); this.count = newCount; // write-volatile return true; } } return false; }
/** * Gets the value from an entry. Returns null if the entry is invalid, partially-collected, * loading, or expired. Unlike {@link Segment#getLiveValue} this method does not attempt to * cleanup stale entries. As such it should only be called outside of a segment context, such as * during iteration. */ @Nullable V getLiveValue(ReferenceEntry<K, V> entry, long now) { if (entry.getKey() == null) { return null; } V value = entry.getValueReference().get(); if (value == null) { return null; } if (isExpired(entry, now)) { return null; } return value; }
/** * Gets the value from an entry. Returns null if the entry is invalid, partially-collected, * loading, or expired. */ V getLiveValue(ReferenceEntry<K, V> entry, long now) { if (entry.getKey() == null) { tryDrainReferenceQueues(); return null; } V value = entry.getValueReference().get(); if (value == null) { tryDrainReferenceQueues(); return null; } if (map.isExpired(entry, now)) { tryExpireEntries(now); return null; } return value; }
@Nullable V get(Object key, int hash) { try { if (count != 0) { // read-volatile long now = map.ticker.read(); ReferenceEntry<K, V> e = getLiveEntry(key, hash, now); if (e == null) { return null; } V value = e.getValueReference().get(); if (value != null) { recordRead(e, now); return scheduleRefresh(e, e.getKey(), hash, value, now, map.defaultLoader); } tryDrainReferenceQueues(); } return null; } finally { postReadCleanup(); } }
/** * 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("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)); return newEntry; }
boolean containsKey(Object key, int hash) { try { if (count != 0) { // read-volatile long now = map.ticker.read(); ReferenceEntry<K, V> e = getLiveEntry(key, hash, now); if (e == null) { return false; } return e.getValueReference().get() != null; } return false; } finally { postReadCleanup(); } }
@Override public V get() { return oldValue.get(); }
private static <K, V> void assertSameEntries( List<ReferenceEntry<K, V>> expectedEntries, List<ReferenceEntry<K, V>> actualEntries) { int size = expectedEntries.size(); assertEquals(size, actualEntries.size()); for (int i = 0; i < size; i++) { ReferenceEntry<K, V> expectedEntry = expectedEntries.get(i); ReferenceEntry<K, V> actualEntry = actualEntries.get(i); assertSame(expectedEntry.getKey(), actualEntry.getKey()); assertSame(expectedEntry.getValueReference().get(), actualEntry.getValueReference().get()); } }