Skip to content

Commit

Permalink
perf[LazyCache]: remove cache reason
Browse files Browse the repository at this point in the history
  • Loading branch information
jaysunxiao committed Mar 25, 2024
1 parent 66d5735 commit 5ca7731
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 25 deletions.
89 changes: 67 additions & 22 deletions orm/src/main/java/com/zfoo/orm/util/LazyCache.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.zfoo.orm.util;

import com.zfoo.protocol.model.Pair;
import com.zfoo.scheduler.util.TimeUtils;

import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -14,22 +15,49 @@
*/
public class LazyCache<K, V> {

private static class ValueCache<V> {
private static class CacheValue<V> {
public volatile V value;
public volatile long expireTime;
}

public static enum RemovalCause {
/**
* The entry was manually removed by the user. This can result from the user invoking any of the
* following methods on the cache or map view.
* remove()
*/
EXPLICIT,

/**
* The entry itself was not actually removed, but its value was replaced by the user. This can
* result from the user invoking any of the following methods on the cache or map view.
* put()
*/
REPLACED,


/**
* The entry's expiration timestamp has passed.
*/
EXPIRED,

/**
* The entry was evicted due to size constraints.
*/
SIZE;
}

private AtomicLong expireCheckTimeAtomic;
private volatile long minExpireTime;

private int maximumSize;
private long expireAfterAccessMillis;
private long expireCheckInterval;
private int maximumSize;
private ConcurrentMap<K, ValueCache<V>> cacheMap;
private BiConsumer<K, V> removeCallback = (k, v) -> {
private AtomicLong expireCheckTimeAtomic;
private volatile long minExpireTime;
private ConcurrentMap<K, CacheValue<V>> cacheMap;
private BiConsumer<Pair<K, V>, RemovalCause> removeCallback = (pair, removalCause) -> {
};

public LazyCache(int maximumSize, long expireAfterAccessMillis, long expireCheckIntervalMillis, BiConsumer<K, V> removeCallback) {
public LazyCache(int maximumSize, long expireAfterAccessMillis, long expireCheckIntervalMillis, BiConsumer<Pair<K, V>, RemovalCause> removeCallback) {
this.maximumSize = maximumSize;
this.expireAfterAccessMillis = expireAfterAccessMillis;
this.expireCheckInterval = expireCheckIntervalMillis;
Expand All @@ -44,40 +72,57 @@ public LazyCache(int maximumSize, long expireAfterAccessMillis, long expireCheck
* If the cache previously contained a value associated with the key, the old value is replaced by the new value.
*/
public void put(K key, V value) {
var valueCache = new ValueCache<V>();
valueCache.value = value;
valueCache.expireTime = TimeUtils.now();
cacheMap.put(key, valueCache);
var cacheValue = new CacheValue<V>();
cacheValue.value = value;
cacheValue.expireTime = TimeUtils.now();
var oldCacheValue = cacheMap.put(key, cacheValue);
if (oldCacheValue != null) {
removeCallback.accept(new Pair<>(key, oldCacheValue.value), RemovalCause.REPLACED);
}
checkMaximumSize();
checkExpire();
}

public V get(K key) {
checkExpire();

var valueCache = cacheMap.get(key);
if (valueCache == null) {
var cacheValue = cacheMap.get(key);
if (cacheValue == null) {
return null;
}
if (valueCache.expireTime < TimeUtils.now()) {
remove(key);
if (cacheValue.expireTime < TimeUtils.now()) {
remove(key, RemovalCause.EXPIRED);
return null;
}
valueCache.expireTime = TimeUtils.now() + expireAfterAccessMillis;
return valueCache.value;
cacheValue.expireTime = TimeUtils.now() + expireAfterAccessMillis;
return cacheValue.value;
}


public void remove(K key) {
remove(key, RemovalCause.EXPLICIT);
}

public void remove(K key, RemovalCause removalCause) {
if (key == null) {
return;
}
var valueCache = cacheMap.remove(key);
if (valueCache != null) {
removeCallback.accept(key, valueCache.value);
var cacheValue = cacheMap.remove(key);
if (cacheValue != null) {
removeCallback.accept(new Pair<>(key, cacheValue.value), removalCause);
}
}

public void forEach(BiConsumer<K, V> biConsumer) {
for (var entry : cacheMap.entrySet()) {
biConsumer.accept(entry.getKey(), entry.getValue().value);
}
}

public int size() {
return cacheMap.size();
}


// -----------------------------------------------------------------------------------------------------------------
private void checkMaximumSize() {
Expand All @@ -93,7 +138,7 @@ private void checkMaximumSize() {
}
}
this.minExpireTime = minTimestamp;
remove(minKey);
remove(minKey, RemovalCause.SIZE);
checkMaximumSize();
}

Expand All @@ -107,7 +152,7 @@ private void checkExpire() {
for (var entry : cacheMap.entrySet()) {
var expireTime = entry.getValue().expireTime;
if (expireTime < now) {
remove(entry.getKey());
remove(entry.getKey(), RemovalCause.EXPIRED);
}
if (expireTime < minTimestamp) {
minTimestamp = expireTime;
Expand Down
7 changes: 4 additions & 3 deletions orm/src/test/java/com/zfoo/orm/cache/LazyCacheTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.zfoo.orm.cache;

import com.zfoo.orm.util.LazyCache;
import com.zfoo.protocol.model.Pair;
import com.zfoo.protocol.util.StringUtils;
import com.zfoo.protocol.util.ThreadUtils;
import com.zfoo.scheduler.util.TimeUtils;
Expand All @@ -15,10 +16,10 @@
@Ignore
public class LazyCacheTest {

private static final BiConsumer<Integer, String> myRemoveCallback = new BiConsumer<Integer, String>() {
private static final BiConsumer<Pair<Integer, String>, LazyCache.RemovalCause> myRemoveCallback = new BiConsumer<Pair<Integer, String>, LazyCache.RemovalCause>() {
@Override
public void accept(Integer key, String value) {
System.out.println(StringUtils.format("remove key:[{}] value:[{}]", key, value));
public void accept(Pair<Integer, String> pair, LazyCache.RemovalCause removalCause) {
System.out.println(StringUtils.format("remove key:[{}] value:[{}] removalCause:[{}]", pair.getKey(), pair.getValue(), removalCause));
}
};

Expand Down

0 comments on commit 5ca7731

Please sign in to comment.