All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.babyfish.jimmer.sql.cache.caffeine.CaffeineValueBinder Maven / Gradle / Ivy

The newest version!
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 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
            );
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy