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

org.babyfish.jimmer.sql.cache.chain.ParameterizedChainCacheImpl Maven / Gradle / Ivy

There is a newer version: 0.9.19
Show newest version
package org.babyfish.jimmer.sql.cache.chain;

import org.babyfish.jimmer.sql.cache.Cache;
import org.babyfish.jimmer.sql.cache.CacheEnvironment;
import org.babyfish.jimmer.sql.cache.CacheLoader;
import org.babyfish.jimmer.sql.runtime.ExecutionException;
import org.jetbrains.annotations.NotNull;

import java.util.*;

class ParameterizedChainCacheImpl extends ChainCacheImpl implements Cache.Parameterized {

    public ParameterizedChainCacheImpl(List> binders) {
        super(binders);
        boolean hasParameterizedBinder = false;
        for (Object binder : binders) {
            boolean isParameterizedBinder =
                    binder instanceof LoadingBinder.Parameterized ||
                            binder instanceof SimpleBinder.Parameterized;
            if (hasParameterizedBinder && !isParameterizedBinder) {
                throw new IllegalArgumentException(
                        "Parameterized binder must be after other binders"
                );
            }
            hasParameterizedBinder = isParameterizedBinder;
        }
        if (!hasParameterizedBinder) {
            throw new IllegalArgumentException("No parameterized binders");
        }
    }

    @Override
    @NotNull
    public Map getAll(
            @NotNull Collection keys,
            @NotNull SortedMap parameterMap,
            @NotNull CacheEnvironment env
    ) {
        return usingCacheLoading(
                env.getLoader(), () -> ((ParameterizedNode)node).loadAll(keys, parameterMap)
        );
    }

    @SuppressWarnings("unchecked")
    @Override
    protected Node createNode(Object binder, Node next) {
        if (binder instanceof LoadingBinder.Parameterized) {
            return new ParameterizedLoadingNode(
                    (LoadingBinder.Parameterized) binder,
                    (ParameterizedNode) next
            );
        }
        if (binder instanceof SimpleBinder.Parameterized) {
            return new ParameterizedSimpleNode(
                    (SimpleBinder.Parameterized) binder,
                    next
            );
        }
        return super.createNode(binder, next);
    }

    @Override
    protected TailNode createTailNode() {
        return new TailNode<>();
    }

    protected interface ParameterizedNode extends Node, CacheChain.Parameterized {}

    private static class TailNode extends ChainCacheImpl.TailNode implements ParameterizedNode {

        @Override
        public @NotNull Map loadAll(@NotNull Collection keys, @NotNull SortedMap parameterMap) {
            CacheLoader loader = currentCacheLoader();
            return loader.loadAll(keys);
        }
    }

    private static class ParameterizedLoadingNode implements ParameterizedNode {

        private final LoadingBinder.Parameterized binder;

        private final ParameterizedNode next;

        ParameterizedLoadingNode(LoadingBinder.Parameterized binder, ParameterizedNode next) {
            this.binder = binder;
            this.next = next;
            binder.initialize(next);
        }

        @NotNull
        @Override
        public Map loadAll(@NotNull Collection keys) {
            return binder.getAll(keys);
        }

        @Override
        @NotNull
        public Map loadAll(
                @NotNull Collection keys,
                @NotNull SortedMap parameterMap
        ) {
            return binder.getAll(keys, parameterMap);
        }

        @Override
        public void deleteAll(@NotNull Collection keys, Object reason) {
            next.deleteAll(keys, reason);
            binder.deleteAll(keys, reason);
        }
    }

    protected static class ParameterizedSimpleNode extends SimpleNode implements ParameterizedNode {

        protected ParameterizedSimpleNode(SimpleBinder.Parameterized binder, Node next) {
            super(binder, next);
        }

        @Override
        public @NotNull Map loadAll(
                @NotNull Collection keys,
                @NotNull SortedMap parameterMap
        ) {
            SimpleBinder.Parameterized parameterizedBinder =
                    (SimpleBinder.Parameterized) binder;
            Map map = parameterizedBinder.getAll(keys, parameterMap);
            if (map.size() < keys.size()) {
                if (binder instanceof LockedBinder) {
                    Set missedKeys = missedKeys(keys, map);
                    LockedBinder lockedBinder = (LockedBinder) binder;
                    try {
                        lockedBinder.locker().locking(
                                ((LockedBinder) binder).unwrap(),
                                missedKeys,
                                lockedBinder.waitDuration(),
                                lockedBinder.leaseDuration(),
                                lock -> {
                                    loadAllFromNext(missedKeys, parameterMap, map,false);
                                }
                        );
                    } catch (ExecutionException ex) {
                        throw ex;
                    } catch (Exception ex) {
                        throw new ExecutionException(
                                "Failed to load missed data and update cache",
                                ex
                        );
                    }
                } else {
                    loadAllFromNext(missedKeys(keys, map), parameterMap, map, true);
                }
            }
            return map;
        }

        private static  Set missedKeys(Collection keys, Map loadedMap) {
            Set missedKeys = new LinkedHashSet<>();
            for (K key : keys) {
                if (!loadedMap.containsKey(key)) {
                    missedKeys.add(key);
                }
            }
            return missedKeys;
        }

        private void loadAllFromNext(
                Set missedKeys,
                SortedMap parameterMap,
                Map loadedMap,
                boolean updateBinder
        ) {
            Map mapFromNext = next.loadAll(missedKeys);
            if (mapFromNext.size() < missedKeys.size()) {
                mapFromNext = new HashMap<>(mapFromNext);
                if (updateBinder) {
                    for (K missedKey : missedKeys) {
                        if (!mapFromNext.containsKey(missedKey)) {
                            mapFromNext.put(missedKey, null);
                        }
                    }
                }
            }
            if (updateBinder) {
                ((SimpleBinder.Parameterized)binder).setAll(mapFromNext, parameterMap);
            }
            loadedMap.putAll(mapFromNext);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy