diff --git a/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/ImdgHazelcastCashingV2.java b/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/ImdgHazelcastCashingV2.java new file mode 100644 index 000000000..79e29c9a3 --- /dev/null +++ b/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/ImdgHazelcastCashingV2.java @@ -0,0 +1,42 @@ +package ru.spcex.platform.imdg.iml.hazelcast.adapter; + +import java.util.Optional; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.imdg.api.predicate.ImdgPredicate; + +public class ImdgHazelcastCashingV2 extends ImdgHazelcast { + private final CashV2 idCash; + + public ImdgHazelcastCashingV2(CashV2 idCash) { + this.idCash = idCash; + } + + @Override + public T getSingleObjectByID(Long paramLong) { + if (idCash == null) { + return super.getSingleObjectByID(paramLong); + } + Optional obj = idCash.getOrFind(paramLong, () -> super.getSingleObjectByID(paramLong)); + return obj.orElse(null); + } + + @Override + public T getSingleObjectByPredicate(ImdgPredicate predicate) { + if (!predicate.isCashing()) { + return super.getSingleObjectByPredicate(predicate); + } + ImdgPredicateHazelcastCashing casted = (ImdgPredicateHazelcastCashing) predicate; + Optional obj = casted.getOrFind(() -> super.getSingleObjectByPredicate(predicate)); + return obj.orElse(null); + } + + @Override + public T getFirstObjectByPredicate(ImdgPredicate predicate) { + if (!predicate.isCashing()) { + return super.getFirstObjectByPredicate(predicate); + } + ImdgPredicateHazelcastCashing casted = (ImdgPredicateHazelcastCashing) predicate; + Optional obj = casted.getOrFind(() -> super.getFirstObjectByPredicate(predicate)); + return obj.orElse(null); + } +} \ No newline at end of file diff --git a/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/ImdgPredicateHazelcastCashing.java b/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/ImdgPredicateHazelcastCashing.java new file mode 100644 index 000000000..fb13f64f9 --- /dev/null +++ b/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/ImdgPredicateHazelcastCashing.java @@ -0,0 +1,34 @@ +package ru.spcex.platform.imdg.iml.hazelcast.adapter; + +import java.util.Optional; +import java.util.function.Supplier; +import com.hazelcast.query.Predicate; +import ru.spcex.platform.imdg.iml.hazelcast.adapter.predicate.ImdgPredicateHazelcast; + +public class ImdgPredicateHazelcastCashing extends ImdgPredicateHazelcast { + + private final CashV2 cash; + private final K key; + + public ImdgPredicateHazelcastCashing(Predicate hazelcastPredicate, + CashV2 cash, + K key) { + super(hazelcastPredicate); //prdct.getRawPredicate() + this.cash = cash; + this.key = key; + } + + @Override + public boolean isCashing() { + return true; + } + + protected K key() { + return key; + } + + public Optional getOrFind(Supplier supplier) { + K key = key(); + return cash.getOrFind(key, supplier); + } +} diff --git a/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/predicate/ImdgPredicateBuilderHazelcast.java b/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/predicate/ImdgPredicateBuilderHazelcast.java index 12a1ff431..d4cc4a6c4 100644 --- a/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/predicate/ImdgPredicateBuilderHazelcast.java +++ b/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/predicate/ImdgPredicateBuilderHazelcast.java @@ -5,6 +5,8 @@ import com.hazelcast.query.Predicates; import com.hazelcast.query.SqlPredicate; import ru.spcex.platform.imdg.api.predicate.ImdgPredicate; import ru.spcex.platform.imdg.api.predicate.ImdgPredicateBuilder; +import ru.spcex.platform.imdg.iml.hazelcast.adapter.CashV2; +import ru.spcex.platform.imdg.iml.hazelcast.adapter.ImdgPredicateHazelcastCashing; public class ImdgPredicateBuilderHazelcast implements ImdgPredicateBuilder { protected static final ImdgPredicateBuilderHazelcast instance = new ImdgPredicateBuilderHazelcast(); @@ -117,4 +119,10 @@ public class ImdgPredicateBuilderHazelcast implements ImdgPredicateBuilder { public ImdgPredicate alwaysFalse() { return new ImdgPredicateHazelcast(Predicates.alwaysFalse()); } + + @Override + public ImdgPredicate cashed(ImdgPredicate prdct, CashV2 cash, K key) { + Predicate rawPredicate = ((ImdgPredicateHazelcast) prdct).getRawPredicate(); + return new ImdgPredicateHazelcastCashing<>(rawPredicate, cash, key); + } } diff --git a/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/service/HazelcastServiceBase.java b/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/service/HazelcastServiceBase.java index 4d3fc0bd3..3ae1ca517 100644 --- a/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/service/HazelcastServiceBase.java +++ b/platform-parent/platform-imdg-api-hazelcast-impl/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/service/HazelcastServiceBase.java @@ -1,5 +1,11 @@ package ru.spcex.platform.imdg.iml.hazelcast.service; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Date; +import java.util.concurrent.atomic.AtomicBoolean; import com.hazelcast.client.HazelcastClient; import com.hazelcast.client.config.ClientConfig; import com.hazelcast.core.HazelcastInstance; @@ -16,16 +22,15 @@ import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgId; import ru.spcex.platform.imdg.api.ImdgProvider; import ru.spcex.platform.imdg.api.ImdgTransaction; +import ru.spcex.platform.imdg.iml.hazelcast.adapter.CashV2; import ru.spcex.platform.imdg.iml.hazelcast.adapter.ImdgHazelcast; +import ru.spcex.platform.imdg.iml.hazelcast.adapter.ImdgHazelcastCashingV2; import ru.spcex.platform.imdg.iml.hazelcast.adapter.ImdgIdGeneratorHazelcast; import ru.spcex.platform.imdg.iml.hazelcast.adapter.ImdgTransactionProviderHazelcast; import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams; import ru.spcex.platform.imdg.iml.hazelcast.util.HazelcastHelper; import ru.spcex.platform.utils.log.ExceptionUtils; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; - public abstract class HazelcastServiceBase // implements IHazelcastService implements ImdgProvider @@ -242,6 +247,26 @@ public abstract class HazelcastServiceBase return imdg; } + @Override + public Imdg getCashingImdg(String key, Class clazz, CashV2 idCash) { + ImdgHazelcast imdg = new ImdgHazelcastCashingV2<>(idCash); + statusSubscribe(new IHazelcastClusterStatus() { + @Override + public void getAvailable(HazelcastInstance hazelcastNotInited) { + IdGenerator generator = hazelcastInstance.getIdGenerator(IMDGDistributedNames.MAP_SEQUENCE_NAME); + imdg.setMap(hazelcastInstance.getMap(key)); + imdg.setMapName(key); + imdg.setHzInstance(hazelcastInstance); + imdg.setIdGenerator(generator); + } + + @Override + public void getUnavailable(HazelcastInstance hazelcastNotInited) { + } + }); + return imdg; + } + @Override public synchronized void waitAvailable() { if (lockAvailable == null) { diff --git a/platform-parent/platform-imdg-api/pom.xml b/platform-parent/platform-imdg-api/pom.xml index 3f2517bfa..1f44563cb 100644 --- a/platform-parent/platform-imdg-api/pom.xml +++ b/platform-parent/platform-imdg-api/pom.xml @@ -33,6 +33,14 @@ ru.spcex.platform platform-utils + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + org.junit.jupiter diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/ImdgProvider.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/ImdgProvider.java index 4ff60bf67..1f21d8764 100644 --- a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/ImdgProvider.java +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/ImdgProvider.java @@ -1,6 +1,7 @@ package ru.spcex.platform.imdg.api; import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.imdg.iml.hazelcast.adapter.CashV2; public interface ImdgProvider { /** @@ -8,6 +9,13 @@ public interface ImdgProvider { */ Imdg getImdg(String key, Class clazz); + /** + * idCash can be null + */ + default Imdg getCashingImdg(String key, Class clazz, CashV2 idCash) { + return getImdg(key, clazz); + } + ImdgId getImdgIdGenerator(); ImdgTransaction newTransaction(); diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/predicate/ImdgPredicate.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/predicate/ImdgPredicate.java index 922245086..a74cef070 100644 --- a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/predicate/ImdgPredicate.java +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/predicate/ImdgPredicate.java @@ -1,4 +1,5 @@ package ru.spcex.platform.imdg.api.predicate; public interface ImdgPredicate { + default boolean isCashing() {return false;} } diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/predicate/ImdgPredicateBuilder.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/predicate/ImdgPredicateBuilder.java index 4bd78cb41..883f9aee1 100644 --- a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/predicate/ImdgPredicateBuilder.java +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/api/predicate/ImdgPredicateBuilder.java @@ -1,5 +1,7 @@ package ru.spcex.platform.imdg.api.predicate; +import ru.spcex.platform.imdg.iml.hazelcast.adapter.CashV2; + public interface ImdgPredicateBuilder { ImdgPredicate equals(String key, Object value); ImdgPredicate greatEqual(String key, Comparable value); @@ -23,4 +25,7 @@ public interface ImdgPredicateBuilder { ImdgPredicate alwaysTrue(); ImdgPredicate alwaysFalse(); + default ImdgPredicate cashed(ImdgPredicate prdct, CashV2 cash, K key) { + return prdct; + } } diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/CashCloser.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/CashCloser.java new file mode 100644 index 000000000..0be1485c7 --- /dev/null +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/CashCloser.java @@ -0,0 +1,24 @@ +package ru.spcex.platform.imdg.iml.hazelcast.adapter; + +import java.util.Collection; +import java.util.List; + +public class CashCloser implements AutoCloseable { + protected Collection> cashes; + + public CashCloser(CashV2... cashes) { + this.cashes = List.of(cashes); + } + + public CashCloser() {} + + public CashCloser add(CashV2 cash) { + this.cashes.add(cash); + return this; + } + + @Override + public void close() { + cashes.forEach(CashV2::clear); + } +} diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/CashV2.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/CashV2.java new file mode 100644 index 000000000..f446f0825 --- /dev/null +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/CashV2.java @@ -0,0 +1,82 @@ +package ru.spcex.platform.imdg.iml.hazelcast.adapter; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class CashV2 { + private final Logger log = LoggerFactory.getLogger(getClass()); + private long hitRate = 0; + private long missRate = 0; + private final Map cash; + private final String name; + + public CashV2() { + this.cash = new HashMap<>(); + this.name = null; + } + + public CashV2(String name) { + this.cash = new HashMap<>(); + this.name = name; + } + + public void clear() { + log.info("cash {}: size {}, hit rate {}, miss rate {}", + name != null ? name : "[unknown]", + cash.size(), + hitRate, + missRate); + this.hitRate = 0L; + this.missRate = 0L; + this.cash.clear(); + } + + public void store(T obj) { + if (obj == null || !needToStore(obj)) return; + K key = extractKey(obj); + cash.put(key, obj); + } + + protected Optional get(K key) { + T obj = cash.get(key); + if (obj != null) hitRate++; + else missRate++; + return Optional.ofNullable(obj); + } + + protected Optional getOrFind(K key, Supplier supplier) { + Optional by = get(key); + if (by.isEmpty()) { + T t = supplier.get(); + if (t != null && needToStore(t)) { + cash.put(key, t); + by = Optional.of(t); + } + } + return by; + } + + protected Optional getOrFindO(K key, Supplier> supplier) { + Optional fromCash = get(key); + if (fromCash.isEmpty()) { + Optional foundAnew = supplier.get(); + if (foundAnew.isPresent()) { + if (needToStore(foundAnew.get())) { + cash.put(key, foundAnew.get()); + } + fromCash = foundAnew; + } + } + return fromCash; + } + + protected abstract K extractKey(T obj); + + protected boolean needToStore(T obj) { + return true; + } +} diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/CashV2ById.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/CashV2ById.java new file mode 100644 index 000000000..a5d2c9e63 --- /dev/null +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/CashV2ById.java @@ -0,0 +1,30 @@ +package ru.spcex.platform.imdg.iml.hazelcast.adapter; + +import java.util.Optional; +import java.util.function.Supplier; +import ru.spcex.platform.classes.base.SpcexObjectBase; + +public class CashV2ById extends CashV2 { + + public CashV2ById() { + } + + public CashV2ById(String name) { + super(name); + } + + @Override + public Optional getOrFind(Long key, Supplier supplier) { + return super.getOrFind(key, supplier); + } + + @Override + public Optional get(Long key) { + return super.get(key); + } + + @Override + protected Long extractKey(T obj) { + return obj.getId(); + } +} diff --git a/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/CashV2ByString.java b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/CashV2ByString.java new file mode 100644 index 000000000..9dea9ab26 --- /dev/null +++ b/platform-parent/platform-imdg-api/src/main/java/ru/spcex/platform/imdg/iml/hazelcast/adapter/CashV2ByString.java @@ -0,0 +1,34 @@ +package ru.spcex.platform.imdg.iml.hazelcast.adapter; + +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; + +public class CashV2ByString extends CashV2 { + + private final Function codeExtractor; + + public CashV2ByString(Function codeExtractor) { + this.codeExtractor = codeExtractor; + } + + public CashV2ByString(String name, Function codeExtractor) { + super(name); + this.codeExtractor = codeExtractor; + } + + @Override + public Optional getOrFind(String key, Supplier supplier) { + return super.getOrFind(key, supplier); + } + + @Override + public Optional get(String key) { + return super.get(key); + } + + @Override + protected String extractKey(T obj) { + return codeExtractor.apply(obj); + } +}