This is an automated email from the ASF dual-hosted git repository.
dengliming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new 5e190b07db refactor(common): remove unused memory-safe cache (#7377)
5e190b07db is described below
commit 5e190b07dbbea6117ab9380e631b31dc76e1072e
Author: Eymen Onar <[email protected]>
AuthorDate: Sat Oct 3 07:02:15 2026 +0300
refactor(common): remove unused memory-safe cache (#7377)
Signed-off-by: Eymen <[email protected]>
Co-authored-by: Eymen <[email protected]>
---
RELEASE-NOTES.md | 1 +
.../common/cache/MemorySafeWindowTinyLFUMap.java | 190 ---------------------
.../apache/shenyu/common/constant/Constants.java | 5 -
.../cache/MemorySafeWindowTinyLFUMapTest.java | 85 ---------
4 files changed, 1 insertion(+), 280 deletions(-)
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index aede17dfee..73bf4efaff 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -30,6 +30,7 @@
to disable their deadline as well, and review route, retry and caller
deadlines.
The client factory now retains its connection-handler configuration, so
configured
read, write and idle handlers are installed on new connections.
+- Remove the unused `MemorySafeWindowTinyLFUMap` cache implementation.
## [v2.7.0]- 2024-12-23
diff --git
a/shenyu-common/src/main/java/org/apache/shenyu/common/cache/MemorySafeWindowTinyLFUMap.java
b/shenyu-common/src/main/java/org/apache/shenyu/common/cache/MemorySafeWindowTinyLFUMap.java
deleted file mode 100644
index 1500ae2277..0000000000
---
a/shenyu-common/src/main/java/org/apache/shenyu/common/cache/MemorySafeWindowTinyLFUMap.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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.shenyu.common.cache;
-
-import com.github.benmanes.caffeine.cache.Cache;
-import com.github.benmanes.caffeine.cache.Caffeine;
-import org.apache.shenyu.common.concurrent.MemoryLimitCalculator;
-import org.apache.shenyu.common.concurrent.ShenyuThreadFactory;
-import org.apache.shenyu.common.constant.Constants;
-import org.checkerframework.checker.nullness.qual.NonNull;
-
-import javax.annotation.concurrent.ThreadSafe;
-import java.io.Serializable;
-import java.lang.ref.WeakReference;
-import java.util.AbstractMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * The differences between this class and {@link MemorySafeLRUMap}
- * is that this class is thread safe, and it use WindowTinyLFU algorithm
- * provided by caffeine which is better than LRU algorithm.
- */
-@ThreadSafe
-public class MemorySafeWindowTinyLFUMap<K, V> extends AbstractMap<K, V>
implements Serializable {
-
- private static final long serialVersionUID = -3288161459386389022L;
-
- private static final AtomicBoolean GLOBAL = new AtomicBoolean(false);
-
- private static final Set<WeakReference<MemorySafeWindowTinyLFUMap<?, ?>>>
ALL = new CopyOnWriteArraySet<>();
-
- private final int maxFreeMemory;
-
- private final Cache<K, V> cache;
-
- public MemorySafeWindowTinyLFUMap(final int maxFreeMemory,
- final int initialSize) {
- this(maxFreeMemory, initialSize, Long.MAX_VALUE,
Constants.LRU_MAP_MAXSIZE);
- }
-
- public MemorySafeWindowTinyLFUMap(final int maxFreeMemory,
- final int initialSize,
- final long expireAfterWrite,
- final long maximumSize) {
- this.maxFreeMemory = maxFreeMemory;
- //see https://github.com/ben-manes/caffeine/issues/776
- this.cache = Caffeine.newBuilder()
- .expireAfterWrite(expireAfterWrite, TimeUnit.MILLISECONDS)
- .maximumSize(maximumSize)
- .initialCapacity(initialSize)
- .build();
- }
-
- @Override
- public V get(final Object key) {
- return cache.getIfPresent(key);
- }
-
- @Override
- public V put(final K key, final V value) {
- checkAndScheduleRefresh(this);
- final V previous = cache.getIfPresent(key);
- cache.put(key, value);
- return previous;
- }
-
- @Override
- public V remove(final Object key) {
- final V previous = cache.getIfPresent(key);
- cache.invalidate(key);
- cache.cleanUp();
- return previous;
- }
-
- @Override
- public Set<Entry<K, V>> entrySet() {
- return cache.asMap().entrySet();
- }
-
- /**
- * clean invalidated cache now.
- */
- public void cleanUp() {
- while (isFull()) {
- invalidate();
- }
- }
-
- /**
- * invalidate coldest cache now.
- */
- public void invalidate() {
- cache.policy().eviction().ifPresent(eviction -> {
- final Map<@NonNull K, @NonNull V> coldest = eviction.coldest(1);
- if (coldest.size() == 0) {
- return;
- }
- Optional.ofNullable(coldest.entrySet().iterator().next())
- .ifPresent(entry -> cache.invalidate(entry.getKey()));
- });
- }
-
- /**
- * whether to full.
- *
- * @return true if it's full
- */
- public boolean isFull() {
- // when free memory less than certain value, consider it's full
- return cache.estimatedSize() > 0 &&
MemoryLimitCalculator.maxAvailable() < maxFreeMemory;
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof MemorySafeWindowTinyLFUMap)) {
- return false;
- }
- if (!super.equals(o)) {
- return false;
- }
- MemorySafeWindowTinyLFUMap<?, ?> that = (MemorySafeWindowTinyLFUMap<?,
?>) o;
- return maxFreeMemory == that.maxFreeMemory && Objects.equals(cache,
that.cache);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(super.hashCode(), maxFreeMemory, cache);
- }
-
- private static void checkAndScheduleRefresh(final
MemorySafeWindowTinyLFUMap<?, ?> map) {
- ALL.add(new WeakReference<>(map));
- if (!GLOBAL.get()) {
- refresh();
- if (GLOBAL.compareAndSet(false, true)) {
- ScheduledExecutorService scheduledExecutorService =
- new ScheduledThreadPoolExecutor(1,
ShenyuThreadFactory.create("Shenyu-Memory-Safe-Lru-Map", false));
- // check every 50 ms to improve performance
-
scheduledExecutorService.scheduleWithFixedDelay(MemorySafeWindowTinyLFUMap::refresh,
50, 50, TimeUnit.MILLISECONDS);
- Runtime.getRuntime().addShutdownHook(new Thread(() -> {
- GLOBAL.set(false);
- scheduledExecutorService.shutdown();
- }));
- }
- }
- }
-
- private static void refresh() {
- // try to clear weak reference
- for (WeakReference<MemorySafeWindowTinyLFUMap<?, ?>> weakReference :
ALL) {
- MemorySafeWindowTinyLFUMap<?, ?> cacheMap = weakReference.get();
- if (Objects.isNull(cacheMap)) {
- ALL.remove(weakReference);
- }
- }
- // if jvm memory is full, try to release memory from caffine
- boolean anyFull =
ALL.stream().map(WeakReference::get).filter(Objects::nonNull)
- .anyMatch(MemorySafeWindowTinyLFUMap::isFull);
- while (anyFull) {
-
ALL.stream().map(WeakReference::get).filter(Objects::nonNull).forEach(MemorySafeWindowTinyLFUMap::invalidate);
- anyFull =
ALL.stream().map(WeakReference::get).filter(Objects::nonNull)
- .anyMatch(MemorySafeWindowTinyLFUMap::isFull);
- }
- }
-}
diff --git
a/shenyu-common/src/main/java/org/apache/shenyu/common/constant/Constants.java
b/shenyu-common/src/main/java/org/apache/shenyu/common/constant/Constants.java
index cb96014e49..b4654e8e8a 100644
---
a/shenyu-common/src/main/java/org/apache/shenyu/common/constant/Constants.java
+++
b/shenyu-common/src/main/java/org/apache/shenyu/common/constant/Constants.java
@@ -821,11 +821,6 @@ public interface Constants {
*/
String DEFAULT_CLUSTER = "failover";
- /**
- * cache data max size, means map size.
- */
- Long LRU_MAP_MAXSIZE = 65536L;
-
/**
* namespace,sush as nacos .
*/
diff --git
a/shenyu-common/src/test/java/org/apache/shenyu/common/cache/MemorySafeWindowTinyLFUMapTest.java
b/shenyu-common/src/test/java/org/apache/shenyu/common/cache/MemorySafeWindowTinyLFUMapTest.java
deleted file mode 100644
index caa9da4274..0000000000
---
a/shenyu-common/src/test/java/org/apache/shenyu/common/cache/MemorySafeWindowTinyLFUMapTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.shenyu.common.cache;
-
-import org.apache.shenyu.common.utils.ReflectUtils;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.lang.ref.WeakReference;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Test cases for MemorySafeWindowTinyLFUMap.
- */
-public class MemorySafeWindowTinyLFUMapTest {
-
- @Test
- public void testPut() {
- MemorySafeWindowTinyLFUMap<String, String> lru = new
MemorySafeWindowTinyLFUMap<>(1 << 10, 16);
- lru.put("1", "1");
- Assert.assertEquals(1, lru.size());
- lru.put("2", "2");
- lru.put("3", "3");
- Assert.assertEquals(3, lru.size());
- }
-
- @Test
- public void testWindowTinyLFU() {
- MemorySafeWindowTinyLFUMap<Integer, Integer> cache = new
MemorySafeWindowTinyLFUMap<>(1, 1024) {
-
- private static final long serialVersionUID = 8897028073615563875L;
-
- @Override
- public synchronized boolean isFull() {
- //just for test
- return size() > 1;
- }
-
- @Override
- public synchronized void cleanUp() {
- super.cleanUp();
- }
- };
- cache.put(1, 1);
- Assert.assertEquals(1, cache.size());
- cache.put(2, 2);
- cache.put(3, 3);
- cache.invalidate();
- cache.cleanUp();
- Assert.assertEquals(1, cache.size());
- final Map.Entry<Integer, Integer> entry =
cache.entrySet().iterator().next();
- final Integer key = entry.getKey();
- final Integer value = entry.getValue();
- Assert.assertEquals(3, (int) key);
- Assert.assertEquals(3, (int) value);
- }
-
- @Test
- public void testWindowTinyLFUOutOufMemoryException() {
- final int mb = 1024 * 1024;
- for (int i = 0; i < 1000; i++) {
- MemorySafeWindowTinyLFUMap<String, Byte[]> instance = new
MemorySafeWindowTinyLFUMap<>(1, 1024);
- instance.put(String.valueOf(1), new Byte[mb]);
- }
- Set<WeakReference<MemorySafeWindowTinyLFUMap<?, ?>>> all =
- (Set<WeakReference<MemorySafeWindowTinyLFUMap<?, ?>>>)
ReflectUtils.getFieldValue(new MemorySafeWindowTinyLFUMap(1, 1024), "ALL");
- Assert.assertNotEquals(1000, all.size());
- }
-}