提交 66b7ede9 authored 作者: Thomas Mueller's avatar Thomas Mueller

LIRS cache: guard against bad hash functions.

上级 68956a78
...@@ -19,8 +19,7 @@ import java.util.Set; ...@@ -19,8 +19,7 @@ import java.util.Set;
* costly to acquire, for example file content. * costly to acquire, for example file content.
* <p> * <p>
* This implementation is not multi-threading save. Null keys or null values are * This implementation is not multi-threading save. Null keys or null values are
* not allowed. There is no guard against bad hash functions, so it is important * not allowed. The map fill factor is at most 75%.
* to the hash function of the key is good. The map fill factor is at most 75%.
* <p> * <p>
* Each entry is assigned a distinct memory size, and the cache will try to use * Each entry is assigned a distinct memory size, and the cache will try to use
* at most the specified amount of memory. The memory unit is not relevant, * at most the specified amount of memory. The memory unit is not relevant,
...@@ -269,7 +268,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> { ...@@ -269,7 +268,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
e.key = key; e.key = key;
e.value = value; e.value = value;
e.memory = memory; e.memory = memory;
int index = key.hashCode() & mask; int index = getIndex(key);
e.mapNext = entries[index]; e.mapNext = entries[index];
entries[index] = e; entries[index] = e;
usedMemory += memory; usedMemory += memory;
...@@ -283,6 +282,15 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> { ...@@ -283,6 +282,15 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
return old; return old;
} }
private int getIndex(Object key) {
int hash = key.hashCode();
// Doug Lea's supplemental secondaryHash function (inlined)
// to protect against hash codes that don't differ in low order bits
hash ^= (hash >>> 20) ^ (hash >>> 12);
hash ^= (hash >>> 7) ^ (hash >>> 4);
return hash & mask;
}
/** /**
* Remove an entry. Both resident and non-resident entries can be removed. * Remove an entry. Both resident and non-resident entries can be removed.
* *
...@@ -290,8 +298,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> { ...@@ -290,8 +298,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
* @return the old value, or null if there is no resident entry * @return the old value, or null if there is no resident entry
*/ */
public V remove(Object key) { public V remove(Object key) {
int hash = key.hashCode(); int index = getIndex(key);
int index = hash & mask;
Entry<K, V> e = entries[index]; Entry<K, V> e = entries[index];
if (e == null) { if (e == null) {
return null; return null;
...@@ -397,8 +404,8 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> { ...@@ -397,8 +404,8 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
* @return the entry (might be a non-resident) * @return the entry (might be a non-resident)
*/ */
private Entry<K, V> find(Object key) { private Entry<K, V> find(Object key) {
int hash = key.hashCode(); int index = getIndex(key);
Entry<K, V> e = entries[hash & mask]; Entry<K, V> e = entries[index];
while (e != null && !e.key.equals(key)) { while (e != null && !e.key.equals(key)) {
e = e.mapNext; e = e.mapNext;
} }
...@@ -484,7 +491,8 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> { ...@@ -484,7 +491,8 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
} }
/** /**
* Check whether there is a resident entry for the given key. * Check whether there is a resident entry for the given key. This method
* does not adjusts the internal state of the cache.
* *
* @param key the key (may not be null) * @param key the key (may not be null)
* @return true if there is a resident entry * @return true if there is a resident entry
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论