abstract class AbstractCacheSet<T> extends AbstractSet<T> { @Weak final ConcurrentMap<?, ?> map; AbstractCacheSet(ConcurrentMap<?, ?> map) { this.map = map; } @Override public int size() { return map.size(); } @Override public boolean isEmpty() { return map.isEmpty(); } @Override public void clear() { map.clear(); } // super.toArray() may misbehave if size() is inaccurate, at least on old versions of Android. // https://code.google.com/p/android/issues/detail?id=36519 / http://r.android.com/47508 @Override public Object[] toArray() { return toArrayList(this).toArray(); } @Override public <E> E[] toArray(E[] a) { return toArrayList(this).toArray(a); } }
@GuardedBy("this") @Nullable ReferenceEntry<K, V> removeEntryFromChain( ReferenceEntry<K, V> first, ReferenceEntry<K, V> entry) { int newCount = count; ReferenceEntry<K, V> newFirst = entry.getNext(); for (ReferenceEntry<K, V> e = first; e != entry; e = e.getNext()) { ReferenceEntry<K, V> next = copyEntry(e, newFirst); if (next != null) { newFirst = next; } else { removeCollectedEntry(e); newCount--; } } this.count = newCount; return newFirst; }
private static <K, V> int countLiveEntries(LocalCache<K, V> map, long now) { int result = 0; for (Segment<K, V> segment : map.segments) { AtomicReferenceArray<ReferenceEntry<K, V>> table = segment.table; for (int i = 0; i < table.length(); i++) { for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) { if (map.isLive(e, now)) { result++; } } } } return result; }
/** * This method is a convenience for testing. Code should call {@link LocalCache#containsValue} * directly. */ @VisibleForTesting boolean containsValue(Object value) { try { if (count != 0) { // read-volatile long now = map.ticker.read(); AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; int length = table.length(); for (int i = 0; i < length; ++i) { for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) { V entryValue = getLiveValue(e, now); if (entryValue == null) { continue; } if (map.valueEquivalence.equivalent(value, entryValue)) { return true; } } } } return false; } finally { postReadCleanup(); } }
for (ReferenceEntry<K, V> e = table.get(j); e != null; e = e.getNext()) { V v = segment.getLiveValue(e, now); if (v != null && valueEquivalence.equivalent(value, v)) {
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; }
@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; }
@Nullable ReferenceEntry<K, V> getEntry(Object key, int hash) { for (ReferenceEntry<K, V> e = getFirst(hash); e != null; e = e.getNext()) { if (e.getHash() != hash) { continue; } K entryKey = e.getKey(); if (entryKey == null) { tryDrainReferenceQueues(); continue; } if (map.keyEquivalence.equivalent(key, entryKey)) { return e; } } return null; }
for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) {
ReferenceEntry<K, V> first = table.get(index); for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { if (e == entry) { ++modCount;
boolean removeLoadingValue(K key, int hash, LoadingValueReference<K, V> valueReference) { lock(); try { 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()) { K entryKey = e.getKey(); if (e.getHash() == hash && entryKey != null && map.keyEquivalence.equivalent(key, entryKey)) { ValueReference<K, V> v = e.getValueReference(); if (v == valueReference) { if (valueReference.isActive()) { e.setValueReference(valueReference.getOldValue()); } else { ReferenceEntry<K, V> newFirst = removeEntryFromChain(first, e); table.set(index, newFirst); } return true; } return false; } } return false; } finally { unlock(); postWriteCleanup(); } }
ReferenceEntry<K, V> first = table.get(index); for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { K entryKey = e.getKey(); if (e.getHash() == hash
ReferenceEntry<K, V> first = table.get(index); for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { K entryKey = e.getKey(); if (e.getHash() == hash
ReferenceEntry<K, V> first = table.get(index); for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { K entryKey = e.getKey(); if (e.getHash() == hash
for (e = first; e != null; e = e.getNext()) { K entryKey = e.getKey(); if (e.getHash() == hash
ReferenceEntry<K, V> first = table.get(index); for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { K entryKey = e.getKey(); if (e.getHash() == hash
ReferenceEntry<K, V> first = table.get(index); for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) { K entryKey = e.getKey(); if (e.getHash() == hash
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()); } }
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());
assertSame(keyOne, entryOne.getKey()); assertEquals(hashOne, entryOne.getHash()); assertNull(entryOne.getNext()); assertSame(valueOne, copyOne.getValueReference().get()); assertConnected(map, copyOne, entryTwo); assertSame(keyTwo, copyTwo.getKey()); assertEquals(hashTwo, copyTwo.getHash()); assertSame(copyOne, copyTwo.getNext()); assertSame(valueTwo, copyTwo.getValueReference().get()); assertConnected(map, copyOne, copyTwo);