Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.google.common.collect.MapMakerInternalMap Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including
all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and
Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
/*
* Copyright (C) 2009 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.CollectPreconditions.checkRemove;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Equivalence;
import com.google.common.collect.MapMaker.Dummy;
import com.google.common.primitives.Ints;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.concurrent.GuardedBy;
import com.google.j2objc.annotations.Weak;
import com.google.j2objc.annotations.WeakOuter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.concurrent.locks.ReentrantLock;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* The concurrent hash map implementation built by {@link MapMaker}.
*
* This implementation is heavily derived from revision 1.96 of ConcurrentHashMap.java .
*
* @param the type of the keys in the map
* @param the type of the values in the map
* @param the type of the {@link InternalEntry} entry implementation used internally
* @param the type of the {@link Segment} entry implementation used internally
* @author Bob Lee
* @author Charles Fry
* @author Doug Lea ({@code ConcurrentHashMap})
*/
// TODO(kak): Consider removing @CanIgnoreReturnValue from this class.
@GwtIncompatible
@SuppressWarnings({
"GuardedBy", // TODO(b/35466881): Fix or suppress.
"nullness", // too much trouble for the payoff
})
// TODO(cpovirk): Annotate for nullness.
class MapMakerInternalMap<
K,
V,
E extends MapMakerInternalMap.InternalEntry,
S extends MapMakerInternalMap.Segment>
extends AbstractMap implements ConcurrentMap, Serializable {
/*
* The basic strategy is to subdivide the table among Segments, each of which itself is a
* concurrently readable hash table. The map supports non-blocking reads and concurrent writes
* across different segments.
*
* The page replacement algorithm's data structures are kept casually consistent with the map. The
* ordering of writes to a segment is sequentially consistent. An update to the map and recording
* of reads may not be immediately reflected on the algorithm's data structures. These structures
* are guarded by a lock and operations are applied in batches to avoid lock contention. The
* penalty of applying the batches is spread across threads so that the amortized cost is slightly
* higher than performing just the operation without enforcing the capacity constraint.
*
* This implementation uses a per-segment queue to record a memento of the additions, removals,
* and accesses that were performed on the map. The queue is drained on writes and when it exceeds
* its capacity threshold.
*
* The Least Recently Used page replacement algorithm was chosen due to its simplicity, high hit
* rate, and ability to be implemented with O(1) time complexity. The initial LRU implementation
* operates per-segment rather than globally for increased implementation simplicity. We expect
* the cache hit rate to be similar to that of a global LRU algorithm.
*/
// Constants
/**
* The maximum capacity, used if a higher value is implicitly specified by either of the
* constructors with arguments. MUST be a power of two no greater than {@code 1<<30} to ensure
* that entries are indexable using ints.
*/
static final int MAXIMUM_CAPACITY = Ints.MAX_POWER_OF_TWO;
/** The maximum number of segments to allow; used to bound constructor arguments. */
static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
/** Number of (unsynchronized) retries in the containsValue method. */
static final int CONTAINS_VALUE_RETRIES = 3;
/**
* Number of cache access operations that can be buffered per segment before the cache's recency
* ordering information is updated. This is used to avoid lock contention by recording a memento
* of reads and delaying a lock acquisition until the threshold is crossed or a mutation occurs.
*
* This must be a (2^n)-1 as it is used as a mask.
*/
static final int DRAIN_THRESHOLD = 0x3F;
/**
* Maximum number of entries to be drained in a single cleanup run. This applies independently to
* the cleanup queue and both reference queues.
*/
// TODO(fry): empirically optimize this
static final int DRAIN_MAX = 16;
static final long CLEANUP_EXECUTOR_DELAY_SECS = 60;
// Fields
/**
* Mask value for indexing into segments. The upper bits of a key's hash code are used to choose
* the segment.
*/
final transient int segmentMask;
/**
* Shift value for indexing within segments. Helps prevent entries that end up in the same segment
* from also ending up in the same bucket.
*/
final transient int segmentShift;
/** The segments, each of which is a specialized hash table. */
final transient Segment[] segments;
/** The concurrency level. */
final int concurrencyLevel;
/** Strategy for comparing keys. */
final Equivalence keyEquivalence;
/** Strategy for handling entries and segments in a type-safe and efficient manner. */
final transient InternalEntryHelper entryHelper;
/**
* Creates a new, empty map with the specified strategy, initial capacity and concurrency level.
*/
private MapMakerInternalMap(MapMaker builder, InternalEntryHelper entryHelper) {
concurrencyLevel = Math.min(builder.getConcurrencyLevel(), MAX_SEGMENTS);
keyEquivalence = builder.getKeyEquivalence();
this.entryHelper = entryHelper;
int initialCapacity = Math.min(builder.getInitialCapacity(), MAXIMUM_CAPACITY);
// Find power-of-two sizes best matching arguments. Constraints:
// (segmentCount > concurrencyLevel)
int segmentShift = 0;
int segmentCount = 1;
while (segmentCount < concurrencyLevel) {
++segmentShift;
segmentCount <<= 1;
}
this.segmentShift = 32 - segmentShift;
segmentMask = segmentCount - 1;
this.segments = newSegmentArray(segmentCount);
int segmentCapacity = initialCapacity / segmentCount;
if (segmentCapacity * segmentCount < initialCapacity) {
++segmentCapacity;
}
int segmentSize = 1;
while (segmentSize < segmentCapacity) {
segmentSize <<= 1;
}
for (int i = 0; i < this.segments.length; ++i) {
this.segments[i] = createSegment(segmentSize, MapMaker.UNSET_INT);
}
}
/** Returns a fresh {@link MapMakerInternalMap} as specified by the given {@code builder}. */
static MapMakerInternalMap, ?> create(
MapMaker builder) {
if (builder.getKeyStrength() == Strength.STRONG
&& builder.getValueStrength() == Strength.STRONG) {
return new MapMakerInternalMap<>(builder, StrongKeyStrongValueEntry.Helper.instance());
}
if (builder.getKeyStrength() == Strength.STRONG
&& builder.getValueStrength() == Strength.WEAK) {
return new MapMakerInternalMap<>(builder, StrongKeyWeakValueEntry.Helper.instance());
}
if (builder.getKeyStrength() == Strength.WEAK
&& builder.getValueStrength() == Strength.STRONG) {
return new MapMakerInternalMap<>(builder, WeakKeyStrongValueEntry.Helper.instance());
}
if (builder.getKeyStrength() == Strength.WEAK && builder.getValueStrength() == Strength.WEAK) {
return new MapMakerInternalMap<>(builder, WeakKeyWeakValueEntry.Helper.instance());
}
throw new AssertionError();
}
/**
* Returns a fresh {@link MapMakerInternalMap} with {@link MapMaker.Dummy} values but otherwise as
* specified by the given {@code builder}. The returned {@link MapMakerInternalMap} will be
* optimized to saved memory. Since {@link MapMaker.Dummy} is a singleton, we don't need to store
* any values at all. Because of this optimization, {@code build.getValueStrength()} must be
* {@link Strength#STRONG}.
*
* This method is intended to only be used by the internal implementation of {@link Interners},
* since a map of dummy values is the exact use case there.
*/
static
MapMakerInternalMap, ?> createWithDummyValues(
MapMaker builder) {
if (builder.getKeyStrength() == Strength.STRONG
&& builder.getValueStrength() == Strength.STRONG) {
return new MapMakerInternalMap<>(builder, StrongKeyDummyValueEntry.Helper.instance());
}
if (builder.getKeyStrength() == Strength.WEAK
&& builder.getValueStrength() == Strength.STRONG) {
return new MapMakerInternalMap<>(builder, WeakKeyDummyValueEntry.Helper.instance());
}
if (builder.getValueStrength() == Strength.WEAK) {
throw new IllegalArgumentException("Map cannot have both weak and dummy values");
}
throw new AssertionError();
}
enum Strength {
STRONG {
@Override
Equivalence defaultEquivalence() {
return Equivalence.equals();
}
},
WEAK {
@Override
Equivalence defaultEquivalence() {
return Equivalence.identity();
}
};
/**
* Returns the default equivalence strategy used to compare and hash keys or values referenced
* at this strength. This strategy will be used unless the user explicitly specifies an
* alternate strategy.
*/
abstract Equivalence defaultEquivalence();
}
/**
* A helper object for operating on {@link InternalEntry} instances in a type-safe and efficient
* manner.
*
* For each of the four combinations of strong/weak key and strong/weak value, there are
* corresponding {@link InternalEntry}, {@link Segment}, and {@link InternalEntryHelper}
* implementations.
*
* @param the type of the key in each entry
* @param the type of the value in each entry
* @param the type of the {@link InternalEntry} entry implementation
* @param the type of the {@link Segment} entry implementation
*/
interface InternalEntryHelper<
K, V, E extends InternalEntry, S extends Segment> {
/** The strength of the key type in each entry. */
Strength keyStrength();
/** The strength of the value type in each entry. */
Strength valueStrength();
/** Returns a freshly created segment, typed at the {@code S} type. */
S newSegment(MapMakerInternalMap map, int initialCapacity, int maxSegmentSize);
/**
* Returns a freshly created entry, typed at the {@code E} type, for the given {@code segment}.
*/
E newEntry(S segment, K key, int hash, @Nullable E next);
/**
* Returns a freshly created entry, typed at the {@code E} type, for the given {@code segment},
* that is a copy of the given {@code entry}.
*/
E copy(S segment, E entry, @Nullable E newNext);
/**
* Sets the value of the given {@code entry} in the given {@code segment} to be the given {@code
* value}
*/
void setValue(S segment, E entry, V value);
}
/**
* An entry in a hash table of a {@link Segment}.
*
* Entries in the map can be in the following states:
*
*
Valid: - Live: valid key/value are set
*
*
Invalid: - Collected: key/value was partially collected, but not yet cleaned up
*/
interface InternalEntry> {
/** Gets the next entry in the chain. */
E getNext();
/** Gets the entry's hash. */
int getHash();
/** Gets the key for this entry. */
K getKey();
/** Gets the value for the entry. */
V getValue();
}
/*
* Note: the following classes have a lot of duplicate code. It sucks, but it saves a lot of
* memory. If only Java had mixins!
*/
/** Base class for {@link InternalEntry} implementations for strong keys. */
abstract static class AbstractStrongKeyEntry>
implements InternalEntry {
final K key;
final int hash;
final @Nullable E next;
AbstractStrongKeyEntry(K key, int hash, @Nullable E next) {
this.key = key;
this.hash = hash;
this.next = next;
}
@Override
public K getKey() {
return this.key;
}
@Override
public int getHash() {
return hash;
}
@Override
public E getNext() {
return next;
}
}
/** Marker interface for {@link InternalEntry} implementations for strong values. */
interface StrongValueEntry>
extends InternalEntry {}
/** Marker interface for {@link InternalEntry} implementations for weak values. */
interface WeakValueEntry> extends InternalEntry {
/** Gets the weak value reference held by entry. */
WeakValueReference getValueReference();
/**
* Clears the weak value reference held by the entry. Should be used when the entry's value is
* overwritten.
*/
void clearValue();
}
@SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value
static >
WeakValueReference unsetWeakValueReference() {
return (WeakValueReference) UNSET_WEAK_VALUE_REFERENCE;
}
/** Concrete implementation of {@link InternalEntry} for strong keys and strong values. */
static final class StrongKeyStrongValueEntry
extends AbstractStrongKeyEntry>
implements StrongValueEntry> {
private volatile @Nullable V value = null;
StrongKeyStrongValueEntry(K key, int hash, @Nullable StrongKeyStrongValueEntry next) {
super(key, hash, next);
}
@Override
public @Nullable V getValue() {
return value;
}
void setValue(V value) {
this.value = value;
}
StrongKeyStrongValueEntry copy(StrongKeyStrongValueEntry newNext) {
StrongKeyStrongValueEntry newEntry =
new StrongKeyStrongValueEntry<>(this.key, this.hash, newNext);
newEntry.value = this.value;
return newEntry;
}
/** Concrete implementation of {@link InternalEntryHelper} for strong keys and strong values. */
static final class Helper
implements InternalEntryHelper<
K, V, StrongKeyStrongValueEntry, StrongKeyStrongValueSegment> {
private static final Helper, ?> INSTANCE = new Helper<>();
@SuppressWarnings("unchecked")
static Helper instance() {
return (Helper) INSTANCE;
}
@Override
public Strength keyStrength() {
return Strength.STRONG;
}
@Override
public Strength valueStrength() {
return Strength.STRONG;
}
@Override
public StrongKeyStrongValueSegment newSegment(
MapMakerInternalMap<
K, V, StrongKeyStrongValueEntry, StrongKeyStrongValueSegment>
map,
int initialCapacity,
int maxSegmentSize) {
return new StrongKeyStrongValueSegment<>(map, initialCapacity, maxSegmentSize);
}
@Override
public StrongKeyStrongValueEntry copy(
StrongKeyStrongValueSegment segment,
StrongKeyStrongValueEntry entry,
@Nullable StrongKeyStrongValueEntry newNext) {
return entry.copy(newNext);
}
@Override
public void setValue(
StrongKeyStrongValueSegment segment,
StrongKeyStrongValueEntry entry,
V value) {
entry.setValue(value);
}
@Override
public StrongKeyStrongValueEntry newEntry(
StrongKeyStrongValueSegment segment,
K key,
int hash,
@Nullable StrongKeyStrongValueEntry next) {
return new StrongKeyStrongValueEntry<>(key, hash, next);
}
}
}
/** Concrete implementation of {@link InternalEntry} for strong keys and weak values. */
static final class StrongKeyWeakValueEntry
extends AbstractStrongKeyEntry>
implements WeakValueEntry> {
private volatile WeakValueReference> valueReference =
unsetWeakValueReference();
StrongKeyWeakValueEntry(K key, int hash, @Nullable StrongKeyWeakValueEntry next) {
super(key, hash, next);
}
@Override
public V getValue() {
return valueReference.get();
}
@Override
public void clearValue() {
valueReference.clear();
}
void setValue(V value, ReferenceQueue queueForValues) {
WeakValueReference> previous = this.valueReference;
this.valueReference = new WeakValueReferenceImpl<>(queueForValues, value, this);
previous.clear();
}
StrongKeyWeakValueEntry copy(
ReferenceQueue queueForValues, StrongKeyWeakValueEntry newNext) {
StrongKeyWeakValueEntry newEntry = new StrongKeyWeakValueEntry<>(key, hash, newNext);
newEntry.valueReference = valueReference.copyFor(queueForValues, newEntry);
return newEntry;
}
@Override
public WeakValueReference> getValueReference() {
return valueReference;
}
/** Concrete implementation of {@link InternalEntryHelper} for strong keys and weak values. */
static final class Helper
implements InternalEntryHelper<
K, V, StrongKeyWeakValueEntry, StrongKeyWeakValueSegment> {
private static final Helper, ?> INSTANCE = new Helper<>();
@SuppressWarnings("unchecked")
static Helper instance() {
return (Helper) INSTANCE;
}
@Override
public Strength keyStrength() {
return Strength.STRONG;
}
@Override
public Strength valueStrength() {
return Strength.WEAK;
}
@Override
public StrongKeyWeakValueSegment newSegment(
MapMakerInternalMap, StrongKeyWeakValueSegment>
map,
int initialCapacity,
int maxSegmentSize) {
return new StrongKeyWeakValueSegment<>(map, initialCapacity, maxSegmentSize);
}
@Override
public StrongKeyWeakValueEntry copy(
StrongKeyWeakValueSegment segment,
StrongKeyWeakValueEntry entry,
@Nullable StrongKeyWeakValueEntry newNext) {
if (Segment.isCollected(entry)) {
return null;
}
return entry.copy(segment.queueForValues, newNext);
}
@Override
public void setValue(
StrongKeyWeakValueSegment segment, StrongKeyWeakValueEntry entry, V value) {
entry.setValue(value, segment.queueForValues);
}
@Override
public StrongKeyWeakValueEntry newEntry(
StrongKeyWeakValueSegment segment,
K key,
int hash,
@Nullable StrongKeyWeakValueEntry next) {
return new StrongKeyWeakValueEntry<>(key, hash, next);
}
}
}
/** Concrete implementation of {@link InternalEntry} for strong keys and {@link Dummy} values. */
static final class StrongKeyDummyValueEntry
extends AbstractStrongKeyEntry>
implements StrongValueEntry> {
StrongKeyDummyValueEntry(K key, int hash, @Nullable StrongKeyDummyValueEntry next) {
super(key, hash, next);
}
@Override
public Dummy getValue() {
return Dummy.VALUE;
}
void setValue(Dummy value) {}
StrongKeyDummyValueEntry copy(StrongKeyDummyValueEntry newNext) {
return new StrongKeyDummyValueEntry(this.key, this.hash, newNext);
}
/**
* Concrete implementation of {@link InternalEntryHelper} for strong keys and {@link Dummy}
* values.
*/
static final class Helper
implements InternalEntryHelper<
K, Dummy, StrongKeyDummyValueEntry, StrongKeyDummyValueSegment> {
private static final Helper> INSTANCE = new Helper<>();
@SuppressWarnings("unchecked")
static Helper instance() {
return (Helper) INSTANCE;
}
@Override
public Strength keyStrength() {
return Strength.STRONG;
}
@Override
public Strength valueStrength() {
return Strength.STRONG;
}
@Override
public StrongKeyDummyValueSegment newSegment(
MapMakerInternalMap, StrongKeyDummyValueSegment>
map,
int initialCapacity,
int maxSegmentSize) {
return new StrongKeyDummyValueSegment(map, initialCapacity, maxSegmentSize);
}
@Override
public StrongKeyDummyValueEntry copy(
StrongKeyDummyValueSegment segment,
StrongKeyDummyValueEntry entry,
@Nullable StrongKeyDummyValueEntry newNext) {
return entry.copy(newNext);
}
@Override
public void setValue(
StrongKeyDummyValueSegment segment, StrongKeyDummyValueEntry entry, Dummy value) {}
@Override
public StrongKeyDummyValueEntry newEntry(
StrongKeyDummyValueSegment segment,
K key,
int hash,
@Nullable StrongKeyDummyValueEntry next) {
return new StrongKeyDummyValueEntry(key, hash, next);
}
}
}
/** Base class for {@link InternalEntry} implementations for weak keys. */
abstract static class AbstractWeakKeyEntry>
extends WeakReference implements InternalEntry {
final int hash;
final @Nullable E next;
AbstractWeakKeyEntry(ReferenceQueue queue, K key, int hash, @Nullable E next) {
super(key, queue);
this.hash = hash;
this.next = next;
}
@Override
public K getKey() {
return get();
}
@Override
public int getHash() {
return hash;
}
@Override
public E getNext() {
return next;
}
}
/** Concrete implementation of {@link InternalEntry} for weak keys and {@link Dummy} values. */
static final class WeakKeyDummyValueEntry
extends AbstractWeakKeyEntry>
implements StrongValueEntry> {
WeakKeyDummyValueEntry(
ReferenceQueue queue, K key, int hash, @Nullable WeakKeyDummyValueEntry next) {
super(queue, key, hash, next);
}
@Override
public Dummy getValue() {
return Dummy.VALUE;
}
void setValue(Dummy value) {}
WeakKeyDummyValueEntry copy(
ReferenceQueue queueForKeys, WeakKeyDummyValueEntry newNext) {
return new WeakKeyDummyValueEntry(queueForKeys, getKey(), this.hash, newNext);
}
/**
* Concrete implementation of {@link InternalEntryHelper} for weak keys and {@link Dummy}
* values.
*/
static final class Helper
implements InternalEntryHelper<
K, Dummy, WeakKeyDummyValueEntry, WeakKeyDummyValueSegment> {
private static final Helper> INSTANCE = new Helper<>();
@SuppressWarnings("unchecked")
static Helper instance() {
return (Helper) INSTANCE;
}
@Override
public Strength keyStrength() {
return Strength.WEAK;
}
@Override
public Strength valueStrength() {
return Strength.STRONG;
}
@Override
public WeakKeyDummyValueSegment newSegment(
MapMakerInternalMap, WeakKeyDummyValueSegment> map,
int initialCapacity,
int maxSegmentSize) {
return new WeakKeyDummyValueSegment(map, initialCapacity, maxSegmentSize);
}
@Override
public WeakKeyDummyValueEntry copy(
WeakKeyDummyValueSegment segment,
WeakKeyDummyValueEntry entry,
@Nullable WeakKeyDummyValueEntry newNext) {
if (entry.getKey() == null) {
// key collected
return null;
}
return entry.copy(segment.queueForKeys, newNext);
}
@Override
public void setValue(
WeakKeyDummyValueSegment segment, WeakKeyDummyValueEntry entry, Dummy value) {}
@Override
public WeakKeyDummyValueEntry newEntry(
WeakKeyDummyValueSegment segment,
K key,
int hash,
@Nullable WeakKeyDummyValueEntry next) {
return new WeakKeyDummyValueEntry(segment.queueForKeys, key, hash, next);
}
}
}
/** Concrete implementation of {@link InternalEntry} for weak keys and strong values. */
static final class WeakKeyStrongValueEntry
extends AbstractWeakKeyEntry>
implements StrongValueEntry> {
private volatile @Nullable V value = null;
WeakKeyStrongValueEntry(
ReferenceQueue queue, K key, int hash, @Nullable WeakKeyStrongValueEntry next) {
super(queue, key, hash, next);
}
@Override
public @Nullable V getValue() {
return value;
}
void setValue(V value) {
this.value = value;
}
WeakKeyStrongValueEntry copy(
ReferenceQueue queueForKeys, WeakKeyStrongValueEntry newNext) {
WeakKeyStrongValueEntry newEntry =
new WeakKeyStrongValueEntry<>(queueForKeys, getKey(), this.hash, newNext);
newEntry.setValue(value);
return newEntry;
}
/** Concrete implementation of {@link InternalEntryHelper} for weak keys and strong values. */
static final class Helper
implements InternalEntryHelper<
K, V, WeakKeyStrongValueEntry, WeakKeyStrongValueSegment> {
private static final Helper, ?> INSTANCE = new Helper<>();
@SuppressWarnings("unchecked")
static Helper instance() {
return (Helper) INSTANCE;
}
@Override
public Strength keyStrength() {
return Strength.WEAK;
}
@Override
public Strength valueStrength() {
return Strength.STRONG;
}
@Override
public WeakKeyStrongValueSegment newSegment(
MapMakerInternalMap, WeakKeyStrongValueSegment>
map,
int initialCapacity,
int maxSegmentSize) {
return new WeakKeyStrongValueSegment<>(map, initialCapacity, maxSegmentSize);
}
@Override
public WeakKeyStrongValueEntry copy(
WeakKeyStrongValueSegment segment,
WeakKeyStrongValueEntry entry,
@Nullable WeakKeyStrongValueEntry newNext) {
if (entry.getKey() == null) {
// key collected
return null;
}
return entry.copy(segment.queueForKeys, newNext);
}
@Override
public void setValue(
WeakKeyStrongValueSegment segment, WeakKeyStrongValueEntry entry, V value) {
entry.setValue(value);
}
@Override
public WeakKeyStrongValueEntry newEntry(
WeakKeyStrongValueSegment segment,
K key,
int hash,
@Nullable WeakKeyStrongValueEntry next) {
return new WeakKeyStrongValueEntry<>(segment.queueForKeys, key, hash, next);
}
}
}
/** Concrete implementation of {@link InternalEntry} for weak keys and weak values. */
static final class WeakKeyWeakValueEntry
extends AbstractWeakKeyEntry>
implements WeakValueEntry> {
private volatile WeakValueReference> valueReference =
unsetWeakValueReference();
WeakKeyWeakValueEntry(
ReferenceQueue queue, K key, int hash, @Nullable WeakKeyWeakValueEntry next) {
super(queue, key, hash, next);
}
@Override
public V getValue() {
return valueReference.get();
}
WeakKeyWeakValueEntry copy(
ReferenceQueue queueForKeys,
ReferenceQueue queueForValues,
WeakKeyWeakValueEntry newNext) {
WeakKeyWeakValueEntry newEntry =
new WeakKeyWeakValueEntry<>(queueForKeys, getKey(), this.hash, newNext);
newEntry.valueReference = valueReference.copyFor(queueForValues, newEntry);
return newEntry;
}
@Override
public void clearValue() {
valueReference.clear();
}
void setValue(V value, ReferenceQueue queueForValues) {
WeakValueReference> previous = this.valueReference;
this.valueReference = new WeakValueReferenceImpl<>(queueForValues, value, this);
previous.clear();
}
@Override
public WeakValueReference> getValueReference() {
return valueReference;
}
/** Concrete implementation of {@link InternalEntryHelper} for weak keys and weak values. */
static final class Helper
implements InternalEntryHelper<
K, V, WeakKeyWeakValueEntry, WeakKeyWeakValueSegment> {
private static final Helper, ?> INSTANCE = new Helper<>();
@SuppressWarnings("unchecked")
static Helper instance() {
return (Helper) INSTANCE;
}
@Override
public Strength keyStrength() {
return Strength.WEAK;
}
@Override
public Strength valueStrength() {
return Strength.WEAK;
}
@Override
public WeakKeyWeakValueSegment newSegment(
MapMakerInternalMap, WeakKeyWeakValueSegment> map,
int initialCapacity,
int maxSegmentSize) {
return new WeakKeyWeakValueSegment<>(map, initialCapacity, maxSegmentSize);
}
@Override
public WeakKeyWeakValueEntry copy(
WeakKeyWeakValueSegment segment,
WeakKeyWeakValueEntry entry,
@Nullable WeakKeyWeakValueEntry newNext) {
if (entry.getKey() == null) {
// key collected
return null;
}
if (Segment.isCollected(entry)) {
return null;
}
return entry.copy(segment.queueForKeys, segment.queueForValues, newNext);
}
@Override
public void setValue(
WeakKeyWeakValueSegment segment, WeakKeyWeakValueEntry entry, V value) {
entry.setValue(value, segment.queueForValues);
}
@Override
public WeakKeyWeakValueEntry newEntry(
WeakKeyWeakValueSegment segment,
K key,
int hash,
@Nullable WeakKeyWeakValueEntry next) {
return new WeakKeyWeakValueEntry<>(segment.queueForKeys, key, hash, next);
}
}
}
/** A weakly referenced value that also has a reference to its containing entry. */
interface WeakValueReference> {
/**
* Returns the current value being referenced, or {@code null} if there is none (e.g. because
* either it got collected, or {@link #clear} was called, or it wasn't set in the first place).
*/
@Nullable
V get();
/** Returns the entry which contains this {@link WeakValueReference}. */
E getEntry();
/** Unsets the referenced value. Subsequent calls to {@link #get} will return {@code null}. */
void clear();
/**
* Returns a freshly created {@link WeakValueReference} for the given {@code entry} (and on the
* given {@code queue} with the same value as this {@link WeakValueReference}.
*/
WeakValueReference copyFor(ReferenceQueue queue, E entry);
}
/**
* A dummy implementation of {@link InternalEntry}, solely for use in the type signature of {@link
* #UNSET_WEAK_VALUE_REFERENCE} below.
*/
static final class DummyInternalEntry
implements InternalEntry {
private DummyInternalEntry() {
throw new AssertionError();
}
@Override
public DummyInternalEntry getNext() {
throw new AssertionError();
}
@Override
public int getHash() {
throw new AssertionError();
}
@Override
public Object getKey() {
throw new AssertionError();
}
@Override
public Object getValue() {
throw new AssertionError();
}
}
/**
* A singleton {@link WeakValueReference} used to denote an unset value in a entry with weak
* values.
*/
static final WeakValueReference UNSET_WEAK_VALUE_REFERENCE =
new WeakValueReference() {
@Override
public DummyInternalEntry getEntry() {
return null;
}
@Override
public void clear() {}
@Override
public Object get() {
return null;
}
@Override
public WeakValueReference copyFor(
ReferenceQueue queue, DummyInternalEntry entry) {
return this;
}
};
/** Concrete implementation of {@link WeakValueReference}. */
static final class WeakValueReferenceImpl>
extends WeakReference implements WeakValueReference {
@Weak final E entry;
WeakValueReferenceImpl(ReferenceQueue queue, V referent, E entry) {
super(referent, queue);
this.entry = entry;
}
@Override
public E getEntry() {
return entry;
}
@Override
public WeakValueReference copyFor(ReferenceQueue queue, E entry) {
return new WeakValueReferenceImpl<>(queue, get(), entry);
}
}
/**
* Applies a supplemental hash function to a given hash code, which defends against poor quality
* hash functions. This is critical when the concurrent hash map uses power-of-two length hash
* tables, that otherwise encounter collisions for hash codes that do not differ in lower or upper
* bits.
*
* @param h hash code
*/
static int rehash(int h) {
// Spread bits to regularize both segment and index locations,
// using variant of single-word Wang/Jenkins hash.
// TODO(kevinb): use Hashing/move this to Hashing?
h += (h << 15) ^ 0xffffcd7d;
h ^= (h >>> 10);
h += (h << 3);
h ^= (h >>> 6);
h += (h << 2) + (h << 14);
return h ^ (h >>> 16);
}
/**
* This method is a convenience for testing. Code should call {@link Segment#copyEntry} directly.
*/
// Guarded By Segment.this
@VisibleForTesting
E copyEntry(E original, E newNext) {
int hash = original.getHash();
return segmentFor(hash).copyEntry(original, newNext);
}
int hash(Object key) {
int h = keyEquivalence.hash(key);
return rehash(h);
}
void reclaimValue(WeakValueReference valueReference) {
E entry = valueReference.getEntry();
int hash = entry.getHash();
segmentFor(hash).reclaimValue(entry.getKey(), hash, valueReference);
}
void reclaimKey(E entry) {
int hash = entry.getHash();
segmentFor(hash).reclaimKey(entry, hash);
}
/**
* This method is a convenience for testing. Code should call {@link Segment#getLiveValue}
* instead.
*/
@VisibleForTesting
boolean isLiveForTesting(InternalEntry entry) {
return segmentFor(entry.getHash()).getLiveValueForTesting(entry) != null;
}
/**
* Returns the segment that should be used for a key with the given hash.
*
* @param hash the hash code for the key
* @return the segment
*/
Segment segmentFor(int hash) {
// TODO(fry): Lazily create segments?
return segments[(hash >>> segmentShift) & segmentMask];
}
Segment createSegment(int initialCapacity, int maxSegmentSize) {
return entryHelper.newSegment(this, initialCapacity, maxSegmentSize);
}
/**
* Gets the value from an entry. Returns {@code null} if the entry is invalid, partially-collected
* or computing.
*/
V getLiveValue(E entry) {
if (entry.getKey() == null) {
return null;
}
return entry.getValue();
}
@SuppressWarnings("unchecked")
final Segment[] newSegmentArray(int ssize) {
return new Segment[ssize];
}
// Inner Classes
/**
* Segments are specialized versions of hash tables. This subclass inherits from ReentrantLock
* opportunistically, just to simplify some locking and avoid separate construction.
*/
@SuppressWarnings("serial") // This class is never serialized.
abstract static class Segment<
K, V, E extends InternalEntry, S extends Segment>
extends ReentrantLock {
/*
* Segments maintain a table of entry lists that are ALWAYS kept in a consistent state, so can
* be read without locking. Next fields of nodes are immutable (final). All list additions are
* performed at the front of each bin. This makes it easy to check changes, and also fast to
* traverse. When nodes would otherwise be changed, new nodes are created to replace them. This
* works well for hash tables since the bin lists tend to be short. (The average length is less
* than two.)
*
* Read operations can thus proceed without locking, but rely on selected uses of volatiles to
* ensure that completed write operations performed by other threads are noticed. For most
* purposes, the "count" field, tracking the number of elements, serves as that volatile
* variable ensuring visibility. This is convenient because this field needs to be read in many
* read operations anyway:
*
* - All (unsynchronized) read operations must first read the "count" field, and should not
* look at table entries if it is 0.
*
* - All (synchronized) write operations should write to the "count" field after structurally
* changing any bin. The operations must not take any action that could even momentarily
* cause a concurrent read operation to see inconsistent data. This is made easier by the
* nature of the read operations in Map. For example, no operation can reveal that the table
* has grown but the threshold has not yet been updated, so there are no atomicity requirements
* for this with respect to reads.
*
* As a guide, all critical volatile reads and writes to the count field are marked in code
* comments.
*/
@Weak final MapMakerInternalMap map;
/**
* The number of live elements in this segment's region. This does not include unset elements
* which are awaiting cleanup.
*/
volatile int count;
/**
* Number of updates that alter the size of the table. This is used during bulk-read methods to
* make sure they see a consistent snapshot: If modCounts change during a traversal of segments
* computing size or checking containsValue, then we might have an inconsistent view of state so
* (usually) must retry.
*/
int modCount;
/**
* The table is expanded when its size exceeds this threshold. (The value of this field is
* always {@code (int) (capacity * 0.75)}.)
*/
int threshold;
/** The per-segment table. */
volatile @Nullable AtomicReferenceArray table;
/** The maximum size of this map. MapMaker.UNSET_INT if there is no maximum. */
final int maxSegmentSize;
/**
* A counter of the number of reads since the last write, used to drain queues on a small
* fraction of read operations.
*/
final AtomicInteger readCount = new AtomicInteger();
Segment(MapMakerInternalMap map, int initialCapacity, int maxSegmentSize) {
this.map = map;
this.maxSegmentSize = maxSegmentSize;
initTable(newEntryArray(initialCapacity));
}
/**
* Returns {@code this} up-casted to the specific {@link Segment} implementation type {@code S}.
*
* This method exists so that the {@link Segment} code can be generic in terms of {@code S},
* the type of the concrete implementation.
*/
abstract S self();
/** Drains the reference queues used by this segment, if any. */
@GuardedBy("this")
void maybeDrainReferenceQueues() {}
/** Clears the reference queues used by this segment, if any. */
void maybeClearReferenceQueues() {}
/** Sets the value of the given {@code entry}. */
void setValue(E entry, V value) {
this.map.entryHelper.setValue(self(), entry, value);
}
/** Returns a copy of the given {@code entry}. */
E copyEntry(E original, E newNext) {
return this.map.entryHelper.copy(self(), original, newNext);
}
AtomicReferenceArray newEntryArray(int size) {
return new AtomicReferenceArray(size);
}
void initTable(AtomicReferenceArray newTable) {
this.threshold = newTable.length() * 3 / 4; // 0.75
if (this.threshold == maxSegmentSize) {
// prevent spurious expansion before eviction
this.threshold++;
}
this.table = newTable;
}
// Convenience methods for testing
/**
* Unsafe cast of the given entry to {@code E}, the type of the specific {@link InternalEntry}
* implementation type.
*
*