This is an automated email from the ASF dual-hosted git repository.
zrlw pushed a commit to branch 3.3
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.3 by this push:
new e9aa740d2e Fix LRUCache and LRU2Cache to trim entries when max
capacity is reduced (#16053)
e9aa740d2e is described below
commit e9aa740d2e5ca21752a418e71c4349a8d60d8125
Author: Surya Srinivasan <[email protected]>
AuthorDate: Wed Jan 28 10:41:45 2026 +0530
Fix LRUCache and LRU2Cache to trim entries when max capacity is reduced
(#16053)
* Fix LRUCache and LRU2Cache to trim entries when max capacity is reduced
* Add unit tests for trimming when max capacity is reduced
---------
Co-authored-by: Surya Srinivasan <[email protected]>
Co-authored-by: heliang666s <[email protected]>
---
.../org/apache/dubbo/common/utils/LRU2Cache.java | 33 ++++++++++++-
.../org/apache/dubbo/common/utils/LRUCache.java | 20 +++++++-
.../apache/dubbo/common/utils/LRU2CacheTest.java | 55 ++++++++++++++++++++++
.../apache/dubbo/common/utils/LRUCacheTest.java | 48 +++++++++++++++++++
4 files changed, 153 insertions(+), 3 deletions(-)
diff --git
a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRU2Cache.java
b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRU2Cache.java
index b17674ffc0..9f52c0b9ed 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRU2Cache.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRU2Cache.java
@@ -16,7 +16,9 @@
*/
package org.apache.dubbo.common.utils;
+import java.util.Iterator;
import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
@@ -142,8 +144,24 @@ public class LRU2Cache<K, V> extends LinkedHashMap<K, V> {
}
public void setMaxCapacity(int maxCapacity) {
- preCache.setMaxCapacity(maxCapacity);
- this.maxCapacity = maxCapacity;
+ lock.lock();
+ try {
+ this.maxCapacity = maxCapacity;
+ preCache.setMaxCapacity(maxCapacity);
+ trimMainCache();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private void trimMainCache() {
+ while (super.size() > maxCapacity) {
+ Iterator<Map.Entry<K, V>> it = super.entrySet().iterator();
+ if (it.hasNext()) {
+ it.next();
+ it.remove();
+ }
+ }
}
static class PreCache<K, V> extends LinkedHashMap<K, V> {
@@ -166,6 +184,17 @@ public class LRU2Cache<K, V> extends LinkedHashMap<K, V> {
public void setMaxCapacity(int maxCapacity) {
this.maxCapacity = maxCapacity;
+ trimToSize();
+ }
+
+ private void trimToSize() {
+ while (super.size() > maxCapacity) {
+ Iterator<Map.Entry<K, V>> it = super.entrySet().iterator();
+ if (it.hasNext()) {
+ it.next();
+ it.remove();
+ }
+ }
}
}
}
diff --git
a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRUCache.java
b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRUCache.java
index c776dd21fb..6fe8de9b94 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRUCache.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LRUCache.java
@@ -16,7 +16,9 @@
*/
package org.apache.dubbo.common.utils;
+import java.util.Iterator;
import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
@@ -148,6 +150,22 @@ public class LRUCache<K, V> extends LinkedHashMap<K, V> {
}
public void setMaxCapacity(int maxCapacity) {
- this.maxCapacity = maxCapacity;
+ lock.lock();
+ try {
+ this.maxCapacity = maxCapacity;
+ trimToSize();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private void trimToSize() {
+ while (super.size() > maxCapacity) {
+ Iterator<Map.Entry<K, V>> it = super.entrySet().iterator();
+ if (it.hasNext()) {
+ it.next();
+ it.remove();
+ }
+ }
}
}
diff --git
a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LRU2CacheTest.java
b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LRU2CacheTest.java
index 04fe0f94ed..96b47e0173 100644
---
a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LRU2CacheTest.java
+++
b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LRU2CacheTest.java
@@ -67,4 +67,59 @@ class LRU2CacheTest {
cache.setMaxCapacity(10);
assertThat(cache.getMaxCapacity(), equalTo(10));
}
+
+ @Test
+ void testTrimWhenCapacityReduced() {
+ LRU2Cache<String, Integer> cache = new LRU2Cache<>(5);
+
+ cache.put("1", 1);
+ cache.put("2", 2);
+ cache.put("3", 3);
+ cache.put("4", 4);
+ cache.put("5", 5);
+
+ // trigger LRU2 flow (do not assume size)
+ cache.get("1");
+ cache.get("1");
+ cache.get("2");
+ cache.get("2");
+ cache.get("3");
+ cache.get("3");
+ cache.get("4");
+ cache.get("4");
+ cache.get("5");
+ cache.get("5");
+
+ // Reduce capacity
+ cache.setMaxCapacity(3);
+
+ // Only guarantee we care about:
+ assertTrue(cache.size() <= 3);
+
+ // Old entries should be gone
+ assertFalse(cache.containsKey("1"));
+ assertFalse(cache.containsKey("2"));
+ }
+
+ @Test
+ void testPreCacheTrimWhenCapacityReduced() {
+ LRU2Cache<String, Integer> cache = new LRU2Cache<>(5);
+
+ cache.put("1", 1);
+ cache.put("2", 2);
+ cache.put("3", 3);
+ cache.put("4", 4);
+ cache.put("5", 5);
+
+ cache.setMaxCapacity(2);
+
+ // Access entries to promote them through LRU2 flow
+ cache.get("1");
+ cache.get("2");
+ cache.get("3");
+ cache.get("4");
+ cache.get("5");
+
+ assertTrue(cache.size() <= 2);
+ }
}
diff --git
a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LRUCacheTest.java
b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LRUCacheTest.java
new file mode 100644
index 0000000000..992c6e90b6
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LRUCacheTest.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.dubbo.common.utils;
+
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+class LRUCacheTest {
+
+ @Test
+ void testTrimWhenCapacityReduced() {
+ LRUCache<String, Integer> cache = new LRUCache<>(5);
+
+ cache.put("1", 1);
+ cache.put("2", 2);
+ cache.put("3", 3);
+ cache.put("4", 4);
+ cache.put("5", 5);
+
+ assertThat(cache.size(), equalTo(5));
+
+ // Reduce capacity and verify immediate trimming
+ cache.setMaxCapacity(3);
+
+ assertThat(cache.size(), equalTo(3));
+
+ // Oldest entries should be evicted
+ assertFalse(cache.containsKey("1"));
+ assertFalse(cache.containsKey("2"));
+ }
+}