This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/master by this push:
new cd6b63d92d Revert "[LFUCache]Add frequency of key and delete the empty
cache queue (#7967)" (#10086)
cd6b63d92d is described below
commit cd6b63d92d21bd3cd568ab1216a9d7ab8cf58ca2
Author: zhaoguhong <[email protected]>
AuthorDate: Wed Jun 29 09:28:56 2022 +0800
Revert "[LFUCache]Add frequency of key and delete the empty cache queue
(#7967)" (#10086)
This reverts commit e8581fd7ff93fd8d579e24f0d45f131bff87cac9.
---
.../org/apache/dubbo/common/utils/LFUCache.java | 214 ++++-----------------
.../apache/dubbo/common/utils/LFUCacheTest.java | 30 ---
2 files changed, 35 insertions(+), 209 deletions(-)
diff --git
a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LFUCache.java
b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LFUCache.java
index e584dc4b96..8230bd6886 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LFUCache.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LFUCache.java
@@ -16,35 +16,26 @@
*/
package org.apache.dubbo.common.utils;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantLock;
public class LFUCache<K, V> {
private Map<K, CacheNode<K, V>> map;
- private Map<Long, CacheDeque<K, V>> freqTable;
+ private CacheDeque<K, V>[] freqTable;
private final int capacity;
private int evictionCount;
private int curSize = 0;
- private long removeFreqEntryTimeout;
- private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+ private final ReentrantLock lock = new ReentrantLock();
private static final int DEFAULT_INITIAL_CAPACITY = 1000;
private static final float DEFAULT_EVICTION_FACTOR = 0.75f;
- private static final long DEFAULT_REMOVE_FREQ_TABLE_TIME_OUT = 1800000L;
-
public LFUCache() {
- this(DEFAULT_INITIAL_CAPACITY, DEFAULT_EVICTION_FACTOR,
DEFAULT_REMOVE_FREQ_TABLE_TIME_OUT);
+ this(DEFAULT_INITIAL_CAPACITY, DEFAULT_EVICTION_FACTOR);
}
/**
@@ -69,36 +60,14 @@ public class LFUCache<K, V> {
this.capacity = maxCapacity;
this.evictionCount = (int) (capacity * evictionFactor);
this.map = new HashMap<>();
- this.freqTable = new TreeMap<>(Long::compareTo);
- freqTable.put(1L, new CacheDeque<>());
- }
-
- /**
- * Constructs and initializes cache with specified capacity and eviction
- * factor. Unacceptable parameter values followed with
- * {@link IllegalArgumentException}.
- *
- * @param maxCapacity cache max capacity
- * @param evictionFactor cache proceedEviction factor
- * @param removeFreqEntryTimeout cache queue remove timeout
- */
- @SuppressWarnings("unchecked")
- public LFUCache(final int maxCapacity, final float evictionFactor, final
long removeFreqEntryTimeout) {
- if (maxCapacity <= 0) {
- throw new IllegalArgumentException("Illegal initial capacity: " +
- maxCapacity);
+ this.freqTable = new CacheDeque[capacity + 1];
+ for (int i = 0; i <= capacity; i++) {
+ freqTable[i] = new CacheDeque<>();
}
- boolean factorInRange = evictionFactor <= 1 && evictionFactor > 0;
- if (!factorInRange || Float.isNaN(evictionFactor)) {
- throw new IllegalArgumentException("Illegal eviction factor value:"
- + evictionFactor);
+ for (int i = 0; i < capacity; i++) {
+ freqTable[i].nextDeque = freqTable[i + 1];
}
- this.capacity = maxCapacity;
- this.evictionCount = (int) (capacity * evictionFactor);
- this.removeFreqEntryTimeout = removeFreqEntryTimeout;
- this.map = new HashMap<>();
- this.freqTable = new TreeMap<>(Long::compareTo);
- freqTable.put(1L, new CacheDeque<>());
+ freqTable[capacity].nextDeque = freqTable[capacity];
}
public int getCapacity() {
@@ -107,31 +76,31 @@ public class LFUCache<K, V> {
public V put(final K key, final V value) {
CacheNode<K, V> node;
- lock.writeLock().lock();
+ lock.lock();
try {
node = map.get(key);
if (node != null) {
CacheNode.withdrawNode(node);
node.value = value;
- moveToNextFreqQueue(node.incrFreq(), node);
+ freqTable[0].addLastNode(node);
map.put(key, node);
} else {
- if (curSize + 1 > capacity) {
- proceedEviction();
- }
- node = freqTable.get(1L).addLast(key, value);
+ node = freqTable[0].addLast(key, value);
map.put(key, node);
curSize++;
+ if (curSize > capacity) {
+ proceedEviction();
+ }
}
} finally {
- lock.writeLock().unlock();
+ lock.unlock();
}
return node.value;
}
public V remove(final K key) {
CacheNode<K, V> node = null;
- lock.writeLock().lock();
+ lock.lock();
try {
if (map.containsKey(key)) {
node = map.remove(key);
@@ -141,96 +110,26 @@ public class LFUCache<K, V> {
curSize--;
}
} finally {
- lock.writeLock().unlock();
+ lock.unlock();
}
return (node != null) ? node.value : null;
}
public V get(final K key) {
CacheNode<K, V> node = null;
- lock.writeLock().lock();
+ lock.lock();
try {
if (map.containsKey(key)) {
node = map.get(key);
CacheNode.withdrawNode(node);
- moveToNextFreqQueue(node.incrFreq(), node);
+ node.owner.nextDeque.addLastNode(node);
}
} finally {
- lock.writeLock().unlock();
+ lock.unlock();
}
return (node != null) ? node.value : null;
}
- /**
- * Returns size of the freq table
- *
- * @return size
- */
- public int getFreqTableSize(){
- return freqTable.size();
- }
-
- /**
- * Returns freq of the element
- *
- * @return freq
- */
- public Long getFreq(final K key) {
- CacheNode<K, V> node = null;
- lock.readLock().lock();
- try {
- if (map.containsKey(key)) {
- node = map.get(key);
- return node.getFreq();
- }
- } finally {
- lock.readLock().unlock();
- }
- return null;
- }
-
- /**
- * Returns node list of this frequency
- *
- * @return node list
- */
- private List<CacheNode<K,V>> getFreqList(final Long freq){
- if(freq == null){
- return null;
- }
- lock.writeLock().lock();
- try {
- if (freqTable.containsKey(freq)) {
- if(freqTable.get(freq).nodeMap.size() > 0){
- return new
ArrayList<>(freqTable.get(freq).nodeMap.values());
- }
- }
- } finally {
- lock.writeLock().unlock();
- }
- return null;
- }
-
- /**
- * Returns node list's size of this frequency
- *
- * @return node list's size
- */
- public int getFreqListSize(final Long freq){
- if(freq == null){
- return 0;
- }
- lock.writeLock().lock();
- try {
- if (freqTable.containsKey(freq)) {
- return freqTable.get(freq).size.get();
- }
- } finally {
- lock.writeLock().unlock();
- }
- return 0;
- }
-
/**
* Evicts less frequently used elements corresponding to eviction factor,
* specified at instantiation step.
@@ -238,40 +137,24 @@ public class LFUCache<K, V> {
* @return number of evicted elements
*/
private int proceedEviction() {
- int targetSize = capacity - evictionCount - 1;
+ int targetSize = capacity - evictionCount;
int evictedElements = 0;
- Set<Long> freqKeys = freqTable.keySet();
- boolean evictionEnd = false;
- for (Long freq : freqKeys) {
- CacheDeque<K, V> q = freqTable.get(freq);
+
+ FREQ_TABLE_ITER_LOOP:
+ for (int i = 0; i <= capacity; i++) {
CacheNode<K, V> node;
- if(!evictionEnd) {
- while (!q.isEmpty()) {
- node = q.pollFirst();
- remove(node.key);
- evictedElements++;
- if (targetSize >= curSize) {
- evictionEnd = true;
- break;
- }
+ while (!freqTable[i].isEmpty()) {
+ node = freqTable[i].pollFirst();
+ remove(node.key);
+ if (targetSize >= curSize) {
+ break FREQ_TABLE_ITER_LOOP;
}
- }
- // If the queue is empty for a long time, delete the queue
- if (removeFreqEntryTimeout > 0 && freq > 1 && q.isEmpty() &&
(System.currentTimeMillis() - q.getLastReqTime()) >= removeFreqEntryTimeout) {
- freqTable.remove(freq);
+ evictedElements++;
}
}
return evictedElements;
}
- /**
- * Move the node to the next cache queue
- */
- private void moveToNextFreqQueue(long newFreq, CacheNode<K, V> node){
- freqTable.putIfAbsent(newFreq, new CacheDeque<>());
- freqTable.get(newFreq).addLastNode(node);
- }
-
/**
* Returns cache current size.
*
@@ -287,7 +170,6 @@ public class LFUCache<K, V> {
CacheNode<K, V> next;
K key;
V value;
- volatile AtomicLong freq = new AtomicLong(1);
CacheDeque<K, V> owner;
CacheNode() {
@@ -298,14 +180,6 @@ public class LFUCache<K, V> {
this.value = value;
}
- long incrFreq(){
- return freq.incrementAndGet();
- }
-
- long getFreq(){
- return freq.get();
- }
-
/**
* This method takes specified node and reattaches it neighbors nodes
* links to each other, so specified node will no longer tied with
them.
@@ -322,8 +196,6 @@ public class LFUCache<K, V> {
node.prev.next = node.next;
if (node.next != null) {
node.next.prev = node.prev;
- node.owner.nodeMap.remove(node.key);
- node.owner.size.decrementAndGet();
}
}
return node;
@@ -344,9 +216,8 @@ public class LFUCache<K, V> {
CacheNode<K, V> last;
CacheNode<K, V> first;
- Map<K, CacheNode<K, V>> nodeMap;
- long lastReqTime;
- volatile AtomicInteger size = new AtomicInteger(0);
+ CacheDeque<K, V> nextDeque;
+
/**
* Constructs list and initializes last and first pointers.
*/
@@ -355,7 +226,6 @@ public class LFUCache<K, V> {
first = new CacheNode<>();
last.next = first;
first.prev = last;
- nodeMap = new HashMap<>();
}
/**
@@ -373,8 +243,6 @@ public class LFUCache<K, V> {
node.prev = last;
node.next.prev = node;
last.next = node;
- this.setLastReqTime(System.currentTimeMillis());
- this.size.incrementAndGet();
return node;
}
@@ -384,9 +252,6 @@ public class LFUCache<K, V> {
node.prev = last;
node.next.prev = node;
last.next = node;
- this.setLastReqTime(System.currentTimeMillis());
- this.nodeMap.put(node.key, node);
- this.size.incrementAndGet();
return node;
}
@@ -403,8 +268,6 @@ public class LFUCache<K, V> {
first.prev.next = first;
node.prev = null;
node.next = null;
- this.nodeMap.remove(node.key);
- this.size.decrementAndGet();
}
return node;
}
@@ -418,13 +281,6 @@ public class LFUCache<K, V> {
return last.next == first;
}
- public CacheDeque<K, V> setLastReqTime(long lastReqTime) {
- this.lastReqTime = lastReqTime;
- return this;
- }
-
- public long getLastReqTime() {
- return lastReqTime;
- }
}
+
}
\ No newline at end of file
diff --git
a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LFUCacheTest.java
b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LFUCacheTest.java
index 8d86261ce3..d7a725089e 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LFUCacheTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LFUCacheTest.java
@@ -73,36 +73,6 @@ public class LFUCacheTest {
assertThat(cache.getCapacity(), equalTo(1000));
}
- @Test
- public void testGetFreq() throws Exception {
- LFUCache<String, Integer> cache = new LFUCache<>();
- cache.put("one", 1);
- cache.put("two", 2);
- cache.put("two", 2);
- assertThat(cache.getFreq("one"), equalTo(1L));
- assertThat(cache.getFreq("two"), equalTo(2L));
- }
-
- @Test
- public void testRemoveEmptyCacheQueue() throws Exception {
- LFUCache<String, Integer> cache = new LFUCache<>(2, 0.5f, 1000);
- cache.put("one", 1);
- cache.put("two", 2);
- assertThat(cache.getFreqTableSize(), equalTo(1));
- cache.put("two", 2);
- assertThat(cache.getFreqTableSize(), equalTo(2));
- cache.remove("two");
- cache.put("three",3);
- cache.put("four", 4);
- assertThat(cache.getSize(), equalTo(1));
- assertThat(cache.getFreqTableSize(), equalTo(2));
- Thread.sleep(1000);
- cache.put("five",5);
- cache.put("six", 6);
- assertThat(cache.getSize(), equalTo(1));
- assertThat(cache.getFreqTableSize(), equalTo(1));
- }
-
@Test
public void testErrorConstructArguments() throws IOException {
Assertions.assertThrows(IllegalArgumentException.class, () -> new
LFUCache<>(0, 0.8f));