/** * This method is a convenience for testing. Code should call {@link Segment#newEntry} directly. */ @Nonnull ReferenceEntry<K, V> newEntry(@Nonnull K key, int hash, ReferenceEntry<K, V> next) { Segment<K, V> segment = segmentFor(hash); segment.lock(); try { return segment.newEntry(key, hash, next); } finally { segment.unlock(); } }
void clear() { if (count != 0) { // read-volatile lock(); try { AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table; for (int i = 0; i < table.length(); ++i) { for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) { // Loading references aren't actually in the map yet. if (e.getValueReference().isActive()) { enqueueNotification(e, RemovalCause.EXPLICIT); } } } for (int i = 0; i < table.length(); ++i) { table.set(i, null); } clearReferenceQueues(); writeQueue.clear(); accessQueue.clear(); readCount.set(0); ++modCount; count = 0; // write-volatile } finally { unlock(); postWriteCleanup(); } } }
void runLockedCleanup(long now) { if (tryLock()) { try { drainReferenceQueues(); expireEntries(now); // calls drainRecencyQueue readCount.set(0); } finally { unlock(); } } }
unlock(); postWriteCleanup();
return null; } finally { unlock(); postWriteCleanup();
return true; } finally { unlock(); postWriteCleanup();
return loadingValueReference; } finally { unlock(); postWriteCleanup();
unlock(); postWriteCleanup();
unlock(); postWriteCleanup();
unlock(); postWriteCleanup();
unlock(); postWriteCleanup();
unlock(); if (!isHeldByCurrentThread()) { // don't cleanup inside of put postWriteCleanup();
/** * Removes an entry whose key has been garbage collected. */ boolean reclaimKey(ReferenceEntry<K, V> entry, int hash) { lock(); try { int newCount = 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(), RemovalCause.COLLECTED); newCount = this.count - 1; table.set(index, newFirst); this.count = newCount; // write-volatile return true; } } return false; } finally { unlock(); postWriteCleanup(); } }
boolean removeLoadingValue(K key, int hash, @Nonnull 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(); } }
/** * Cleanup expired entries when the lock is available. */ void tryExpireEntries(long now) { if (tryLock()) { try { expireEntries(now); } finally { unlock(); // don't call postWriteCleanup as we're in a read } } }
/** * Cleanup collected entries when the lock is available. */ void tryDrainReferenceQueues() { if (tryLock()) { try { drainReferenceQueues(); } finally { unlock(); } } }