|
|
|
@ -224,23 +224,23 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public V get(Object key) { |
|
|
|
public V get(Object key) { |
|
|
|
Reference<K, V> reference = getReference(key, Restructure.WHEN_NECESSARY); |
|
|
|
Reference<K, V> reference = getReference(key, Restructure.WHEN_NECESSARY); |
|
|
|
Entry<K, V> entry = (reference == null ? null : reference.get()); |
|
|
|
Entry<K, V> entry = (reference != null ? reference.get() : null); |
|
|
|
return (entry != null ? entry.getValue() : null); |
|
|
|
return (entry != null ? entry.getValue() : null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public boolean containsKey(Object key) { |
|
|
|
public boolean containsKey(Object key) { |
|
|
|
Reference<K, V> reference = getReference(key, Restructure.WHEN_NECESSARY); |
|
|
|
Reference<K, V> reference = getReference(key, Restructure.WHEN_NECESSARY); |
|
|
|
Entry<K, V> entry = (reference == null ? null : reference.get()); |
|
|
|
Entry<K, V> entry = (reference != null ? reference.get() : null); |
|
|
|
return (entry != null && ObjectUtils.nullSafeEquals(entry.getKey(), key)); |
|
|
|
return (entry != null && ObjectUtils.nullSafeEquals(entry.getKey(), key)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Returns a {@link Reference} to the {@link Entry} for the specified {@code key} or |
|
|
|
* Return a {@link Reference} to the {@link Entry} for the specified {@code key}, |
|
|
|
* {@code null} if not found. |
|
|
|
* or {@code null} if not found. |
|
|
|
* @param key the key (can be {@code null}) |
|
|
|
* @param key the key (can be {@code null}) |
|
|
|
* @param restructure types of restructure allowed during this call |
|
|
|
* @param restructure types of restructure allowed during this call |
|
|
|
* @return the reference or {@code null} |
|
|
|
* @return the reference, or {@code null} if not found |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
protected final Reference<K, V> getReference(Object key, Restructure restructure) { |
|
|
|
protected final Reference<K, V> getReference(Object key, Restructure restructure) { |
|
|
|
int hash = getHash(key); |
|
|
|
int hash = getHash(key); |
|
|
|
@ -400,14 +400,10 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static enum ReferenceType { |
|
|
|
public static enum ReferenceType { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** Use {@link SoftReference}s */ |
|
|
|
* Use {@link SoftReference}s. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
SOFT, |
|
|
|
SOFT, |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** Use {@link WeakReference}s */ |
|
|
|
* Use {@link WeakReference}s. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
WEAK |
|
|
|
WEAK |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -462,8 +458,8 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Apply an update operation to this segment. The segment will be locked |
|
|
|
* Apply an update operation to this segment. |
|
|
|
* during update. |
|
|
|
* The segment will be locked during the update. |
|
|
|
* @param hash the hash of the key |
|
|
|
* @param hash the hash of the key |
|
|
|
* @param key the key |
|
|
|
* @param key the key |
|
|
|
* @param task the update operation |
|
|
|
* @param task the update operation |
|
|
|
@ -474,7 +470,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
if (task.hasOption(TaskOption.RESTRUCTURE_BEFORE)) { |
|
|
|
if (task.hasOption(TaskOption.RESTRUCTURE_BEFORE)) { |
|
|
|
restructureIfNecessary(resize); |
|
|
|
restructureIfNecessary(resize); |
|
|
|
} |
|
|
|
} |
|
|
|
if (task.hasOption(TaskOption.SKIP_IF_EMPTY) && (this.count == 0)) { |
|
|
|
if (task.hasOption(TaskOption.SKIP_IF_EMPTY) && this.count == 0) { |
|
|
|
return task.execute(null, null, null); |
|
|
|
return task.execute(null, null, null); |
|
|
|
} |
|
|
|
} |
|
|
|
lock(); |
|
|
|
lock(); |
|
|
|
@ -482,12 +478,12 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
final int index = getIndex(hash, this.references); |
|
|
|
final int index = getIndex(hash, this.references); |
|
|
|
final Reference<K, V> head = this.references[index]; |
|
|
|
final Reference<K, V> head = this.references[index]; |
|
|
|
Reference<K, V> reference = findInChain(head, key, hash); |
|
|
|
Reference<K, V> reference = findInChain(head, key, hash); |
|
|
|
Entry<K, V> entry = (reference == null ? null : reference.get()); |
|
|
|
Entry<K, V> entry = (reference != null ? reference.get() : null); |
|
|
|
Entries entries = new Entries() { |
|
|
|
Entries entries = new Entries() { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void add(V value) { |
|
|
|
public void add(V value) { |
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
Entry<K, V> newEntry = new Entry<K, V>((K)key, value); |
|
|
|
Entry<K, V> newEntry = new Entry<K, V>((K) key, value); |
|
|
|
Reference<K, V> newReference = Segment.this.referenceManager.createReference(newEntry, hash, head); |
|
|
|
Reference<K, V> newReference = Segment.this.referenceManager.createReference(newEntry, hash, head); |
|
|
|
Segment.this.references[index] = newReference; |
|
|
|
Segment.this.references[index] = newReference; |
|
|
|
Segment.this.count++; |
|
|
|
Segment.this.count++; |
|
|
|
@ -514,7 +510,8 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
try { |
|
|
|
try { |
|
|
|
setReferences(createReferenceArray(this.initialSize)); |
|
|
|
setReferences(createReferenceArray(this.initialSize)); |
|
|
|
this.count = 0; |
|
|
|
this.count = 0; |
|
|
|
} finally { |
|
|
|
} |
|
|
|
|
|
|
|
finally { |
|
|
|
unlock(); |
|
|
|
unlock(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -545,16 +542,16 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
|
|
|
|
|
|
|
|
// Recalculate taking into account count inside lock and items that
|
|
|
|
// Recalculate taking into account count inside lock and items that
|
|
|
|
// will be purged
|
|
|
|
// will be purged
|
|
|
|
needsResize = ((countAfterRestructure > 0) && (countAfterRestructure >= this.resizeThreshold)); |
|
|
|
needsResize = (countAfterRestructure > 0 && countAfterRestructure >= this.resizeThreshold); |
|
|
|
boolean resizing = false; |
|
|
|
boolean resizing = false; |
|
|
|
int restructureSize = this.references.length; |
|
|
|
int restructureSize = this.references.length; |
|
|
|
if (allowResize && needsResize && (restructureSize < MAXIMUM_SEGMENT_SIZE)) { |
|
|
|
if (allowResize && needsResize && restructureSize < MAXIMUM_SEGMENT_SIZE) { |
|
|
|
restructureSize <<= 1; |
|
|
|
restructureSize <<= 1; |
|
|
|
resizing = true; |
|
|
|
resizing = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Either create a new table or reuse the existing one
|
|
|
|
// Either create a new table or reuse the existing one
|
|
|
|
Reference<K, V>[] restructured = (resizing ? createReferenceArray(restructureSize) : this.references); |
|
|
|
Reference<K, V>[] restructured = (resizing ? createReferenceArray(restructureSize) : this.references); |
|
|
|
|
|
|
|
|
|
|
|
// Restructure
|
|
|
|
// Restructure
|
|
|
|
for (int i = 0; i < this.references.length; i++) { |
|
|
|
for (int i = 0; i < this.references.length; i++) { |
|
|
|
@ -578,7 +575,8 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
setReferences(restructured); |
|
|
|
setReferences(restructured); |
|
|
|
} |
|
|
|
} |
|
|
|
this.count = Math.max(countAfterRestructure, 0); |
|
|
|
this.count = Math.max(countAfterRestructure, 0); |
|
|
|
} finally { |
|
|
|
} |
|
|
|
|
|
|
|
finally { |
|
|
|
unlock(); |
|
|
|
unlock(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -606,7 +604,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private int getIndex(int hash, Reference<K, V>[] references) { |
|
|
|
private int getIndex(int hash, Reference<K, V>[] references) { |
|
|
|
return hash & (references.length - 1); |
|
|
|
return (hash & (references.length - 1)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -700,27 +698,26 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public String toString() { |
|
|
|
public String toString() { |
|
|
|
return this.key + "=" + this.value; |
|
|
|
return (this.key + "=" + this.value); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
@SuppressWarnings("rawtypes") |
|
|
|
@SuppressWarnings("rawtypes") |
|
|
|
public final boolean equals(Object o) { |
|
|
|
public final boolean equals(Object other) { |
|
|
|
if (o == this) { |
|
|
|
if (this == other) { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
if (o != null && o instanceof Map.Entry) { |
|
|
|
if (!(other instanceof Map.Entry)) { |
|
|
|
Map.Entry other = (Map.Entry) o; |
|
|
|
return false; |
|
|
|
return ObjectUtils.nullSafeEquals(getKey(), other.getKey()) |
|
|
|
|
|
|
|
&& ObjectUtils.nullSafeEquals(getValue(), other.getValue()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
Map.Entry otherEntry = (Map.Entry) other; |
|
|
|
|
|
|
|
return (ObjectUtils.nullSafeEquals(getKey(), otherEntry.getKey()) && |
|
|
|
|
|
|
|
ObjectUtils.nullSafeEquals(getValue(), otherEntry.getValue())); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public final int hashCode() { |
|
|
|
public final int hashCode() { |
|
|
|
return ObjectUtils.nullSafeHashCode(this.key) |
|
|
|
return (ObjectUtils.nullSafeHashCode(this.key) ^ ObjectUtils.nullSafeHashCode(this.value)); |
|
|
|
^ ObjectUtils.nullSafeHashCode(this.value); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -802,7 +799,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
if (o != null && o instanceof Map.Entry<?, ?>) { |
|
|
|
if (o != null && o instanceof Map.Entry<?, ?>) { |
|
|
|
Map.Entry<?, ?> entry = (java.util.Map.Entry<?, ?>) o; |
|
|
|
Map.Entry<?, ?> entry = (java.util.Map.Entry<?, ?>) o; |
|
|
|
Reference<K, V> reference = ConcurrentReferenceHashMap.this.getReference(entry.getKey(), Restructure.NEVER); |
|
|
|
Reference<K, V> reference = ConcurrentReferenceHashMap.this.getReference(entry.getKey(), Restructure.NEVER); |
|
|
|
Entry<K, V> other = (reference == null ? null : reference.get()); |
|
|
|
Entry<K, V> other = (reference != null ? reference.get() : null); |
|
|
|
if (other != null) { |
|
|
|
if (other != null) { |
|
|
|
return ObjectUtils.nullSafeEquals(entry.getValue(), other.getValue()); |
|
|
|
return ObjectUtils.nullSafeEquals(entry.getValue(), other.getValue()); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -855,7 +852,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public boolean hasNext() { |
|
|
|
public boolean hasNext() { |
|
|
|
getNextIfNecessary(); |
|
|
|
getNextIfNecessary(); |
|
|
|
return this.next != null; |
|
|
|
return (this.next != null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
@ -987,7 +984,6 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
enqueue(); |
|
|
|
enqueue(); |
|
|
|
clear(); |
|
|
|
clear(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1021,7 +1017,6 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen |
|
|
|
enqueue(); |
|
|
|
enqueue(); |
|
|
|
clear(); |
|
|
|
clear(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|