org.babyfish.jimmer.sql.cache.caffeine.CaffeineValueBinder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jimmer-sql Show documentation
Show all versions of jimmer-sql Show documentation
A revolutionary ORM framework for both java and kotlin
package org.babyfish.jimmer.sql.cache.caffeine;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import org.babyfish.jimmer.lang.Ref;
import org.babyfish.jimmer.meta.ImmutableProp;
import org.babyfish.jimmer.meta.ImmutableType;
import org.babyfish.jimmer.sql.cache.CacheTracker;
import org.babyfish.jimmer.sql.cache.chain.CacheChain;
import org.babyfish.jimmer.sql.cache.chain.LoadingBinder;
import org.babyfish.jimmer.sql.cache.spi.AbstractTrackingConsumerBinder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;
public class CaffeineValueBinder extends AbstractTrackingConsumerBinder implements LoadingBinder {
private static final Logger LOGGER = LoggerFactory.getLogger(CaffeineValueBinder.class);
private final int maximumSize;
private final Duration duration;
// Caffeine does not support null value, use `Ref` as a wrapper
private LoadingCache> loadingCache;
protected CaffeineValueBinder(
@Nullable ImmutableType type,
@Nullable ImmutableProp prop,
@Nullable CacheTracker tracker,
int maximumSize,
@NotNull Duration duration
) {
super(type, prop, tracker);
this.maximumSize = maximumSize;
this.duration = duration;
}
@Override
public void initialize(CacheChain chain) {
loadingCache = Caffeine
.newBuilder()
.maximumSize(maximumSize)
.expireAfterWrite(duration)
.build(
new CacheLoader>() {
@Override
public Ref load(K key) {
Map map = chain.loadAll(Collections.singleton(key));
V value = map.get(key);
if (value != null || map.containsKey(key)) {
return Ref.of(value);
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public Map> loadAll(Iterable extends K> keys) {
Map map = chain.loadAll((Collection) keys);
return map
.entrySet()
.stream()
.collect(
Collectors.toMap(
Map.Entry::getKey,
e -> Ref.of(e.getValue())
)
);
}
}
);
}
@Override
public Map getAll(Collection keys) {
Map> map = loadingCache.getAll(keys);
Map convertedMap = new HashMap<>((map.size() * 4 + 2) / 3);
for (Map.Entry> e : map.entrySet()) {
convertedMap.put(e.getKey(), e.getValue().getValue());
}
return convertedMap;
}
@Override
public void deleteAllImpl(Collection keys) {
loadingCache.invalidateAll(keys);
}
@Override
protected void invalidateAll() {
loadingCache.invalidateAll();
}
@Override
protected boolean matched(@Nullable Object reason) {
return "caffeine".equals(reason);
}
@NotNull
public static Builder forObject(ImmutableType type) {
return new Builder<>(type, null);
}
@NotNull
public static Builder forProp(ImmutableProp prop) {
return new Builder<>(null, prop);
}
public static class Builder {
private final ImmutableType type;
private final ImmutableProp prop;
private CacheTracker tracker;
private int maximumSize = 100;
private Duration duration = Duration.ofMinutes(1);
public Builder(ImmutableType type, ImmutableProp prop) {
this.type = type;
this.prop = prop;
}
public Builder subscribe(CacheTracker tracker) {
this.tracker = tracker;
return this;
}
public Builder maximumSize(int maximumSize) {
this.maximumSize = maximumSize;
return this;
}
public Builder duration(Duration duration) {
this.duration = duration;
return this;
}
public CaffeineValueBinder build() {
return new CaffeineValueBinder<>(
type,
prop,
tracker,
maximumSize,
duration
);
}
}
}