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.CustomConcurrentHashMap Maven / Gradle / Ivy
/*
* Copyright (C) 2009 Google Inc.
*
* 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 com.google.common.base.Equivalence;
import com.google.common.base.Equivalences;
import com.google.common.base.FinalizableReferenceQueue;
import com.google.common.base.FinalizableSoftReference;
import com.google.common.base.FinalizableWeakReference;
import com.google.common.primitives.Ints;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
/**
* The concurrent hash map implementation built by {@link MapMaker}.
*
* This implementation is heavily derived from revision 1.96 of
* ConcurrentHashMap.java .
*
* @author Bob Lee
* @author Doug Lea ({@code ConcurrentHashMap})
*/
class CustomConcurrentHashMap extends AbstractMap
implements ConcurrentMap, Serializable {
/*
* TODO: Select a permanent name for this class. The name matters because
* we expose it in the serialized state and will be stuck w/ it forever.
*/
/*
* The basic strategy is to subdivide the table among Segments,
* each of which itself is a concurrently readable hash table.
*/
/* ---------------- 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 <=
* 1<<30 to ensure that entries are indexable using ints.
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 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 size and containsValue methods before
* resorting to locking. This is used to avoid unbounded retries if tables
* undergo continuous modification which would make it impossible to obtain
* an accurate result.
*
* TODO: Talk to Doug about the possiblity of defining size() and
* containsValue() in terms of weakly consistent iteration.
*/
static final int RETRIES_BEFORE_LOCK = 2;
/* ---------------- 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;
/** Strategy for comparing keys. */
final Equivalence keyEquivalence;
/** Strategy for comparing values. */
final Equivalence valueEquivalence;
/** Strategy for referencing keys. */
final Strength keyStrength;
/** Strategy for referencing values. */
final Strength valueStrength;
/** How long the map retains values in ns. */
final long expirationNanos;
/** True if expiration is enabled. */
final boolean expires;
/**
* The maximum size of this map. MapMaker.UNSET_MAXIMUM_SIZE if there is no
* maximum.
*/
final int maximumSize;
/** True if size-based eviction is enabled. */
final boolean evicts;
/** The concurrency level. */
final int concurrencyLevel;
/** Factory used to create new entries. */
final transient EntryFactory entryFactory;
/**
* Creates a new, empty map with the specified strategy, initial capacity
* and concurrency level.
*/
CustomConcurrentHashMap(MapMaker builder) {
keyStrength = builder.getKeyStrength();
valueStrength = builder.getValueStrength();
keyEquivalence = builder.getKeyEquivalence();
valueEquivalence = builder.getValueEquivalence();
expirationNanos = builder.getExpirationNanos();
maximumSize = builder.maximumSize;
evicts = maximumSize != MapMaker.UNSET_MAXIMUM_SIZE;
expires = expirationNanos > 0;
entryFactory = EntryFactory.getFactory(keyStrength, expires, evicts);
concurrencyLevel = filterConcurrencyLevel(builder.getConcurrencyLevel());
// TODO: Handle initialCapacity > maximumSize.
int initialCapacity = builder.getInitialCapacity();
if (initialCapacity > MAXIMUM_CAPACITY) {
initialCapacity = MAXIMUM_CAPACITY;
}
// Find power-of-two sizes best matching arguments
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;
}
if (evicts) {
// Ensure sum of segment max sizes = overall max size
int maximumSegmentSize = maximumSize / segmentCount + 1;
int remainder = maximumSize % segmentCount;
for (int i = 0; i < this.segments.length; ++i) {
if (i == remainder) {
maximumSegmentSize--;
}
this.segments[i] = new Segment(segmentSize, maximumSegmentSize);
}
} else {
for (int i = 0; i < this.segments.length; ++i) {
this.segments[i] = new Segment(segmentSize,
MapMaker.UNSET_MAXIMUM_SIZE);
}
}
}
/**
* Returns the given concurrency level or MAX_SEGMENTS if the given level
* is > MAX_SEGMENTS.
*/
static int filterConcurrencyLevel(int concurrenyLevel) {
return Math.min(concurrenyLevel, MAX_SEGMENTS);
}
enum Strength {
/*
* TODO: If we strongly reference the value and aren't computing, we
* needn't wrap the value. This could save ~8 bytes per entry.
*/
STRONG {
@Override ValueReference referenceValue(
ReferenceEntry entry, V value) {
return new StrongValueReference(value);
}
@Override Equivalence defaultEquivalence() {
return Equivalences.equals();
}
},
SOFT {
@Override ValueReference referenceValue(
ReferenceEntry entry, V value) {
return new SoftValueReference(value, entry);
}
@Override Equivalence defaultEquivalence() {
return Equivalences.identity();
}
},
WEAK {
@Override ValueReference referenceValue(
ReferenceEntry entry, V value) {
return new WeakValueReference(value, entry);
}
@Override Equivalence defaultEquivalence() {
return Equivalences.identity();
}
};
/**
* Creates a reference for the given value according to this value
* strength.
*/
abstract ValueReference referenceValue(
ReferenceEntry entry, V value);
/**
* 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();
}
/**
* Creates new entries.
*/
enum EntryFactory {
// TODO: Generate all of these combos at build time.
STRONG {
@Override ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
return new StrongEntry(map, key, hash, next);
}
},
STRONG_EXPIRABLE {
@Override ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
return new StrongExpirableEntry(map, key, hash, next);
}
@Override ReferenceEntry copyEntry(
CustomConcurrentHashMap map,
ReferenceEntry original, ReferenceEntry newNext) {
ReferenceEntry newEntry = super.copyEntry(map, original, newNext);
copyExpirableEntry(original, newEntry);
return newEntry;
}
},
STRONG_EVICTABLE {
@Override ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
return new StrongEvictableEntry(map, key, hash, next);
}
@Override ReferenceEntry copyEntry(
CustomConcurrentHashMap map,
ReferenceEntry original, ReferenceEntry newNext) {
ReferenceEntry newEntry = super.copyEntry(map, original, newNext);
copyEvictableEntry(original, newEntry);
return newEntry;
}
},
STRONG_EXPIRABLE_EVICTABLE {
@Override ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
return new StrongExpirableEvictableEntry(map, key, hash, next);
}
@Override ReferenceEntry copyEntry(
CustomConcurrentHashMap map,
ReferenceEntry original, ReferenceEntry newNext) {
ReferenceEntry newEntry = super.copyEntry(map, original, newNext);
copyExpirableEntry(original, newEntry);
copyEvictableEntry(original, newEntry);
return newEntry;
}
},
SOFT {
@Override ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
return new SoftEntry(map, key, hash, next);
}
},
SOFT_EXPIRABLE {
@Override ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
return new SoftExpirableEntry(map, key, hash, next);
}
@Override ReferenceEntry copyEntry(
CustomConcurrentHashMap map,
ReferenceEntry original, ReferenceEntry newNext) {
ReferenceEntry newEntry = super.copyEntry(map, original, newNext);
copyExpirableEntry(original, newEntry);
return newEntry;
}
},
SOFT_EVICTABLE {
@Override ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
return new SoftEvictableEntry(map, key, hash, next);
}
@Override ReferenceEntry copyEntry(
CustomConcurrentHashMap map,
ReferenceEntry original, ReferenceEntry newNext) {
ReferenceEntry newEntry = super.copyEntry(map, original, newNext);
copyEvictableEntry(original, newEntry);
return newEntry;
}
},
SOFT_EXPIRABLE_EVICTABLE {
@Override ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
return new SoftExpirableEvictableEntry(map, key, hash, next);
}
@Override ReferenceEntry copyEntry(
CustomConcurrentHashMap map,
ReferenceEntry original, ReferenceEntry newNext) {
ReferenceEntry newEntry = super.copyEntry(map, original, newNext);
copyExpirableEntry(original, newEntry);
copyEvictableEntry(original, newEntry);
return newEntry;
}
},
WEAK {
@Override ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
return new WeakEntry(map, key, hash, next);
}
},
WEAK_EXPIRABLE {
@Override ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
return new WeakExpirableEntry(map, key, hash, next);
}
@Override ReferenceEntry copyEntry(
CustomConcurrentHashMap map,
ReferenceEntry original, ReferenceEntry newNext) {
ReferenceEntry newEntry = super.copyEntry(map, original, newNext);
copyExpirableEntry(original, newEntry);
return newEntry;
}
},
WEAK_EVICTABLE {
@Override ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
return new WeakEvictableEntry(map, key, hash, next);
}
@Override ReferenceEntry copyEntry(
CustomConcurrentHashMap map,
ReferenceEntry original, ReferenceEntry newNext) {
ReferenceEntry newEntry = super.copyEntry(map, original, newNext);
copyEvictableEntry(original, newEntry);
return newEntry;
}
},
WEAK_EXPIRABLE_EVICTABLE {
@Override ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
return new WeakExpirableEvictableEntry(map, key, hash, next);
}
@Override ReferenceEntry copyEntry(
CustomConcurrentHashMap map,
ReferenceEntry original, ReferenceEntry newNext) {
ReferenceEntry newEntry = super.copyEntry(map, original, newNext);
copyExpirableEntry(original, newEntry);
copyEvictableEntry(original, newEntry);
return newEntry;
}
};
/**
* Masks used to compute indices in the following table.
*/
static final int EXPIRABLE_MASK = 1;
static final int EVICTABLE_MASK = 2;
/**
* Look-up table for factories. First dimension is the reference type.
* The second dimension is the result of OR-ing the feature masks.
*/
static final EntryFactory[][] FACTORIES = {
{ STRONG, STRONG_EXPIRABLE, STRONG_EVICTABLE, STRONG_EXPIRABLE_EVICTABLE },
{ SOFT, SOFT_EXPIRABLE, SOFT_EVICTABLE, SOFT_EXPIRABLE_EVICTABLE },
{ WEAK, WEAK_EXPIRABLE, WEAK_EVICTABLE, WEAK_EXPIRABLE_EVICTABLE }
};
static EntryFactory getFactory(Strength keyStrength,
boolean expires, boolean evicts) {
int flags = (expires ? EXPIRABLE_MASK : 0)
| (evicts ? EVICTABLE_MASK : 0);
return FACTORIES[keyStrength.ordinal()][flags];
}
/**
* Creates a new entry.
*
* @param map to create the entry for
* @param key of the entry
* @param hash of the key
* @param next entry in the same bucket
*/
abstract ReferenceEntry newEntry(
CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next);
/**
* Copies an entry, assigning it a new {@code next} entry.
*
* @param original the entry to copy
* @param newNext entry in the same bucket
*/
@GuardedBy("Segment.this")
ReferenceEntry copyEntry(
CustomConcurrentHashMap map,
ReferenceEntry original, ReferenceEntry newNext) {
return newEntry(map, original.getKey(), original.getHash(), newNext);
}
@GuardedBy("Segment.this")
void copyExpirableEntry(
ReferenceEntry original, ReferenceEntry newEntry) {
Expirable originalExpirable = (Expirable) original;
Expirable newExpirable = (Expirable) newEntry;
newExpirable.setWriteTime(originalExpirable.getWriteTime());
connectExpirable(originalExpirable.getPreviousExpirable(), newExpirable);
connectExpirable(newExpirable, originalExpirable.getNextExpirable());
nullifyExpirable(originalExpirable);
}
void copyEvictableEntry(
ReferenceEntry original, ReferenceEntry newEntry) {
Evictable originalEvictable = (Evictable) original;
Evictable newEvictable = (Evictable) newEntry;
newEvictable.setLastUsage(originalEvictable.getLastUsage());
}
}
/** A reference to a value. */
interface ValueReference {
/**
* Gets the value. Does not block or throw exceptions.
*/
V get();
/** Creates a copy of this reference for the given entry. */
ValueReference copyFor(ReferenceEntry entry);
/**
* Waits for a value that may still be computing. Unlike get(),
* this method can block (in the case of FutureValueReference) or
* throw an exception.
*/
V waitForValue() throws InterruptedException;
}
/**
* Placeholder. Indicates that the value hasn't been set yet.
*/
static final ValueReference UNSET
= new ValueReference() {
public Object get() {
return null;
}
public ValueReference copyFor(
ReferenceEntry entry) {
throw new AssertionError();
}
public Object waitForValue() {
throw new AssertionError();
}
};
/**
* Singleton placeholder that indicates a value is being computed.
*/
@SuppressWarnings("unchecked")
// Safe because impl never uses a parameter or returns any non-null value
private static ValueReference unset() {
return (ValueReference) UNSET;
}
/** Wrapper class ensures that queue isn't created until it's used. */
private static class QueueHolder {
static final FinalizableReferenceQueue queue
= new FinalizableReferenceQueue();
}
/**
* An entry in a reference map.
*/
interface ReferenceEntry {
/**
* Gets the value reference from this entry.
*/
ValueReference getValueReference();
/**
* Sets the value reference for this entry.
*/
void setValueReference(ValueReference valueReference);
/**
* Removes this entry from the map if its value reference hasn't
* changed. Used to clean up after values. The value reference can
* just call this method on the entry so it doesn't have to keep
* its own reference to the map.
*/
void valueReclaimed();
/** Gets the next entry in the chain. */
ReferenceEntry getNext();
/** Gets the entry's hash. */
int getHash();
/** Gets the key for this entry. */
K getKey();
}
/**
* Implemented by entries that are expirable. Expirable entries are
* maintained in a doubly-linked list. New entries are added at the tail
* of the list at write time; stale entries are expired from the head
* of the list.
*/
interface Expirable {
/** Gets the entry write time in ns. */
long getWriteTime();
/** Sets the entry write time in ns. */
void setWriteTime(long writeTime);
/** Gets the next entry in the recency list. */
Expirable getNextExpirable();
/** Sets the next entry in the recency list. */
void setNextExpirable(Expirable next);
/** Gets the previous entry in the recency list. */
Expirable getPreviousExpirable();
/** Sets the previous entry in the recency list. */
void setPreviousExpirable(Expirable previous);
}
private enum NullExpirable implements Expirable {
INSTANCE;
@Override
public long getWriteTime() {
return 0;
}
@Override
public void setWriteTime(long writeTime) {}
@Override
public Expirable getNextExpirable() {
return this;
}
@Override
public void setNextExpirable(Expirable next) {}
@Override
public Expirable getPreviousExpirable() {
return this;
}
@Override
public void setPreviousExpirable(Expirable previous) {}
}
/** Implemented by entries that support eviction. */
interface Evictable {
/** Sets the last usage timestamp. */
void setLastUsage(int timestamp);
/** Gets the last usage timestamp. */
int getLastUsage();
}
/*
* Note: All of this duplicate code sucks, but it saves a lot of memory.
* If only Java had mixins! To maintain this code, make a change for
* the strong reference type. Then, cut and paste, and replace "Strong"
* with "Soft" or "Weak" within the pasted text. The primary difference
* is that strong entries store the key reference directly while soft
* and weak entries delegate to their respective superclasses.
*
* TODO: Generate this code.
*/
/**
* Used for strongly-referenced keys.
*/
private static class StrongEntry implements ReferenceEntry {
final K key;
StrongEntry(CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
this.map = map;
this.key = key;
this.hash = hash;
this.next = next;
}
public K getKey() {
return this.key;
}
// The code below is exactly the same for each entry type.
final CustomConcurrentHashMap map;
final int hash;
final ReferenceEntry next;
volatile ValueReference valueReference = unset();
public ValueReference getValueReference() {
return valueReference;
}
public void setValueReference(
ValueReference valueReference) {
this.valueReference = valueReference;
}
public void valueReclaimed() {
map.reclaimValue(this);
}
public int getHash() {
return hash;
}
public ReferenceEntry getNext() {
return next;
}
}
private static class StrongExpirableEntry extends StrongEntry
implements Expirable {
StrongExpirableEntry(CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
super(map, key, hash, next);
}
// The code below is exactly the same for each expirable entry type.
volatile long writeTime = Long.MAX_VALUE;
public long getWriteTime() {
return writeTime;
}
public void setWriteTime(long writeTime) {
this.writeTime = writeTime;
}
@GuardedBy("Segment.this")
Expirable next = NullExpirable.INSTANCE;
public Expirable getNextExpirable() {
return next;
}
public void setNextExpirable(Expirable next) {
this.next = next;
}
@GuardedBy("Segment.this")
Expirable previous = NullExpirable.INSTANCE;
public Expirable getPreviousExpirable() {
return previous;
}
public void setPreviousExpirable(Expirable previous) {
this.previous = previous;
}
}
private static class StrongEvictableEntry extends StrongEntry
implements Evictable {
StrongEvictableEntry(CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
super(map, key, hash, next);
}
// The code below is exactly the same for each evictable entry type.
volatile int lastUsage;
public int getLastUsage() {
return lastUsage;
}
public void setLastUsage(int lastUsage) {
this.lastUsage = lastUsage;
}
}
private static class StrongExpirableEvictableEntry
extends StrongEntry implements Expirable, Evictable {
StrongExpirableEvictableEntry(CustomConcurrentHashMap map, K key,
int hash, ReferenceEntry next) {
super(map, key, hash, next);
}
// The code below is exactly the same for each expirable entry type.
volatile long writeTime = Long.MAX_VALUE;
public long getWriteTime() {
return writeTime;
}
public void setWriteTime(long writeTime) {
this.writeTime = writeTime;
}
@GuardedBy("Segment.this")
Expirable next = NullExpirable.INSTANCE;
public Expirable getNextExpirable() {
return next;
}
public void setNextExpirable(Expirable next) {
this.next = next;
}
@GuardedBy("Segment.this")
Expirable previous = NullExpirable.INSTANCE;
public Expirable getPreviousExpirable() {
return previous;
}
public void setPreviousExpirable(Expirable previous) {
this.previous = previous;
}
// The code below is exactly the same for each evictable entry type.
volatile int lastUsage;
public int getLastUsage() {
return lastUsage;
}
public void setLastUsage(int lastUsage) {
this.lastUsage = lastUsage;
}
}
/**
* Used for softly-referenced keys.
*/
private static class SoftEntry extends FinalizableSoftReference
implements ReferenceEntry {
SoftEntry(CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
super(key, QueueHolder.queue);
this.map = map;
this.hash = hash;
this.next = next;
}
public K getKey() {
return get();
}
public void finalizeReferent() {
map.removeEntry(this);
}
// The code below is exactly the same for each entry type.
final CustomConcurrentHashMap map;
final int hash;
final ReferenceEntry next;
volatile ValueReference valueReference = unset();
public ValueReference getValueReference() {
return valueReference;
}
public void setValueReference(
ValueReference valueReference) {
this.valueReference = valueReference;
}
public void valueReclaimed() {
map.reclaimValue(this);
}
public int getHash() {
return hash;
}
public ReferenceEntry getNext() {
return next;
}
}
private static class SoftExpirableEntry extends SoftEntry
implements Expirable {
SoftExpirableEntry(CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
super(map, key, hash, next);
}
// The code below is exactly the same for each expirable entry type.
volatile long writeTime = Long.MAX_VALUE;
public long getWriteTime() {
return writeTime;
}
public void setWriteTime(long writeTime) {
this.writeTime = writeTime;
}
@GuardedBy("Segment.this")
Expirable next = NullExpirable.INSTANCE;
public Expirable getNextExpirable() {
return next;
}
public void setNextExpirable(Expirable next) {
this.next = next;
}
@GuardedBy("Segment.this")
Expirable previous = NullExpirable.INSTANCE;
public Expirable getPreviousExpirable() {
return previous;
}
public void setPreviousExpirable(Expirable previous) {
this.previous = previous;
}
}
private static class SoftEvictableEntry extends SoftEntry
implements Evictable {
SoftEvictableEntry(CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
super(map, key, hash, next);
}
// The code below is exactly the same for each evictable entry type.
volatile int lastUsage;
public int getLastUsage() {
return lastUsage;
}
public void setLastUsage(int lastUsage) {
this.lastUsage = lastUsage;
}
}
private static class SoftExpirableEvictableEntry
extends SoftEntry implements Expirable, Evictable {
SoftExpirableEvictableEntry(CustomConcurrentHashMap map, K key,
int hash, ReferenceEntry next) {
super(map, key, hash, next);
}
// The code below is exactly the same for each expirable entry type.
volatile long writeTime = Long.MAX_VALUE;
public long getWriteTime() {
return writeTime;
}
public void setWriteTime(long writeTime) {
this.writeTime = writeTime;
}
@GuardedBy("Segment.this")
Expirable next = NullExpirable.INSTANCE;
public Expirable getNextExpirable() {
return next;
}
public void setNextExpirable(Expirable next) {
this.next = next;
}
@GuardedBy("Segment.this")
Expirable previous = NullExpirable.INSTANCE;
public Expirable getPreviousExpirable() {
return previous;
}
public void setPreviousExpirable(Expirable previous) {
this.previous = previous;
}
// The code below is exactly the same for each evictable entry type.
volatile int lastUsage;
public int getLastUsage() {
return lastUsage;
}
public void setLastUsage(int lastUsage) {
this.lastUsage = lastUsage;
}
}
/**
* Used for weakly-referenced keys.
*/
private static class WeakEntry extends FinalizableWeakReference
implements ReferenceEntry {
WeakEntry(CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
super(key, QueueHolder.queue);
this.map = map;
this.hash = hash;
this.next = next;
}
public K getKey() {
return get();
}
public void finalizeReferent() {
map.removeEntry(this);
}
// The code below is exactly the same for each entry type.
final CustomConcurrentHashMap map;
final int hash;
final ReferenceEntry next;
volatile ValueReference valueReference = unset();
public ValueReference getValueReference() {
return valueReference;
}
public void setValueReference(
ValueReference valueReference) {
this.valueReference = valueReference;
}
public void valueReclaimed() {
map.reclaimValue(this);
}
public int getHash() {
return hash;
}
public ReferenceEntry getNext() {
return next;
}
}
private static class WeakExpirableEntry extends WeakEntry
implements Expirable {
WeakExpirableEntry(CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
super(map, key, hash, next);
}
// The code below is exactly the same for each expirable entry type.
volatile long writeTime = Long.MAX_VALUE;
public long getWriteTime() {
return writeTime;
}
public void setWriteTime(long writeTime) {
this.writeTime = writeTime;
}
@GuardedBy("Segment.this")
Expirable next = NullExpirable.INSTANCE;
public Expirable getNextExpirable() {
return next;
}
public void setNextExpirable(Expirable next) {
this.next = next;
}
@GuardedBy("Segment.this")
Expirable previous = NullExpirable.INSTANCE;
public Expirable getPreviousExpirable() {
return previous;
}
public void setPreviousExpirable(Expirable previous) {
this.previous = previous;
}
}
private static class WeakEvictableEntry extends WeakEntry
implements Evictable {
WeakEvictableEntry(CustomConcurrentHashMap map, K key, int hash,
ReferenceEntry next) {
super(map, key, hash, next);
}
// The code below is exactly the same for each evictable entry type.
volatile int lastUsage;
public int getLastUsage() {
return lastUsage;
}
public void setLastUsage(int lastUsage) {
this.lastUsage = lastUsage;
}
}
private static class WeakExpirableEvictableEntry
extends WeakEntry implements Expirable, Evictable {
WeakExpirableEvictableEntry(CustomConcurrentHashMap map, K key,
int hash, ReferenceEntry next) {
super(map, key, hash, next);
}
// The code below is exactly the same for each expirable entry type.
volatile long writeTime = Long.MAX_VALUE;
public long getWriteTime() {
return writeTime;
}
public void setWriteTime(long writeTime) {
this.writeTime = writeTime;
}
@GuardedBy("Segment.this")
Expirable next = NullExpirable.INSTANCE;
public Expirable getNextExpirable() {
return next;
}
public void setNextExpirable(Expirable next) {
this.next = next;
}
@GuardedBy("Segment.this")
Expirable previous = NullExpirable.INSTANCE;
public Expirable getPreviousExpirable() {
return previous;
}
public void setPreviousExpirable(Expirable previous) {
this.previous = previous;
}
// The code below is exactly the same for each evictable entry type.
volatile int lastUsage;
public int getLastUsage() {
return lastUsage;
}
public void setLastUsage(int lastUsage) {
this.lastUsage = lastUsage;
}
}
/** References a weak value. */
private static class WeakValueReference
extends FinalizableWeakReference
implements ValueReference {
final ReferenceEntry entry;
WeakValueReference(V referent, ReferenceEntry entry) {
super(referent, QueueHolder.queue);
this.entry = entry;
}
public void finalizeReferent() {
entry.valueReclaimed();
}
public ValueReference copyFor(
ReferenceEntry entry) {
return new WeakValueReference(get(), entry);
}
public V waitForValue() {
return get();
}
}
/** References a soft value. */
private static class SoftValueReference
extends FinalizableSoftReference
implements ValueReference {
final ReferenceEntry entry;
SoftValueReference(V referent, ReferenceEntry entry) {
super(referent, QueueHolder.queue);
this.entry = entry;
}
public void finalizeReferent() {
entry.valueReclaimed();
}
public ValueReference copyFor(
ReferenceEntry entry) {
return new SoftValueReference(get(), entry);
}
public V waitForValue() {
return get();
}
}
/** References a strong value. */
private static class StrongValueReference