hazelcast cashing map

This commit is contained in:
ialbert 2024-07-18 12:02:29 +03:00
parent 7652e28ae9
commit e6e4449b7f
12 changed files with 304 additions and 3 deletions

View file

@ -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<T extends SpcexObjectBase, K> extends ImdgHazelcast<T> {
private final CashV2<Long, T> idCash;
public ImdgHazelcastCashingV2(CashV2<Long, T> idCash) {
this.idCash = idCash;
}
@Override
public T getSingleObjectByID(Long paramLong) {
if (idCash == null) {
return super.getSingleObjectByID(paramLong);
}
Optional<T> 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<?, T> casted = (ImdgPredicateHazelcastCashing<?, T>) predicate;
Optional<T> obj = casted.getOrFind(() -> super.getSingleObjectByPredicate(predicate));
return obj.orElse(null);
}
@Override
public T getFirstObjectByPredicate(ImdgPredicate predicate) {
if (!predicate.isCashing()) {
return super.getFirstObjectByPredicate(predicate);
}
ImdgPredicateHazelcastCashing<?, T> casted = (ImdgPredicateHazelcastCashing<?, T>) predicate;
Optional<T> obj = casted.getOrFind(() -> super.getFirstObjectByPredicate(predicate));
return obj.orElse(null);
}
}

View file

@ -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<K, T> extends ImdgPredicateHazelcast {
private final CashV2<K, T> cash;
private final K key;
public ImdgPredicateHazelcastCashing(Predicate hazelcastPredicate,
CashV2<K, T> 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<T> getOrFind(Supplier<T> supplier) {
K key = key();
return cash.getOrFind(key, supplier);
}
}

View file

@ -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 <K, V> ImdgPredicate cashed(ImdgPredicate prdct, CashV2<K, V> cash, K key) {
Predicate rawPredicate = ((ImdgPredicateHazelcast) prdct).getRawPredicate();
return new ImdgPredicateHazelcastCashing<>(rawPredicate, cash, key);
}
}

View file

@ -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 <T extends SpcexObjectBase> Imdg<T> getCashingImdg(String key, Class<T> clazz, CashV2<Long, T> idCash) {
ImdgHazelcast<T> 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) {

View file

@ -33,6 +33,14 @@
<groupId>ru.spcex.platform</groupId>
<artifactId>platform-utils</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>

View file

@ -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 {
*/
<T extends SpcexObjectBase> Imdg<T> getImdg(String key, Class<T> clazz);
/**
* idCash can be null
*/
default <T extends SpcexObjectBase> Imdg<T> getCashingImdg(String key, Class<T> clazz, CashV2<Long, T> idCash) {
return getImdg(key, clazz);
}
ImdgId getImdgIdGenerator();
ImdgTransaction newTransaction();

View file

@ -1,4 +1,5 @@
package ru.spcex.platform.imdg.api.predicate;
public interface ImdgPredicate {
default boolean isCashing() {return false;}
}

View file

@ -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 <K, V> ImdgPredicate cashed(ImdgPredicate prdct, CashV2<K, V> cash, K key) {
return prdct;
}
}

View file

@ -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<CashV2<?, ?>> 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);
}
}

View file

@ -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<K, T> {
private final Logger log = LoggerFactory.getLogger(getClass());
private long hitRate = 0;
private long missRate = 0;
private final Map<K, T> 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<T> get(K key) {
T obj = cash.get(key);
if (obj != null) hitRate++;
else missRate++;
return Optional.ofNullable(obj);
}
protected Optional<T> getOrFind(K key, Supplier<T> supplier) {
Optional<T> 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<T> getOrFindO(K key, Supplier<Optional<T>> supplier) {
Optional<T> fromCash = get(key);
if (fromCash.isEmpty()) {
Optional<T> 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;
}
}

View file

@ -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<T extends SpcexObjectBase> extends CashV2<Long, T> {
public CashV2ById() {
}
public CashV2ById(String name) {
super(name);
}
@Override
public Optional<T> getOrFind(Long key, Supplier<T> supplier) {
return super.getOrFind(key, supplier);
}
@Override
public Optional<T> get(Long key) {
return super.get(key);
}
@Override
protected Long extractKey(T obj) {
return obj.getId();
}
}

View file

@ -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<T> extends CashV2<String, T> {
private final Function<T, String> codeExtractor;
public CashV2ByString(Function<T, String> codeExtractor) {
this.codeExtractor = codeExtractor;
}
public CashV2ByString(String name, Function<T, String> codeExtractor) {
super(name);
this.codeExtractor = codeExtractor;
}
@Override
public Optional<T> getOrFind(String key, Supplier<T> supplier) {
return super.getOrFind(key, supplier);
}
@Override
public Optional<T> get(String key) {
return super.get(key);
}
@Override
protected String extractKey(T obj) {
return codeExtractor.apply(obj);
}
}