tech.ydb.yoj.repository.db.cache.FirstLevelCache Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of yoj-repository Show documentation
Show all versions of yoj-repository Show documentation
Core YOJ (YDB ORM for Java) abstractions and APIs for domain entities, repositories, transactions etc.
package tech.ydb.yoj.repository.db.cache;
import com.google.common.collect.Maps;
import lombok.NonNull;
import tech.ydb.yoj.repository.db.Entity;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
public interface FirstLevelCache {
> E get(@NonNull Entity.Id id, @NonNull Function, E> loader);
> Optional peek(@NonNull Entity.Id id);
/**
* Returns a immutable copy of the entities of {@code entityType} type that are in the
* transaction L1 cache.
*/
> List snapshot(@NonNull Class entityType);
/**
* Returns a unmodifiable map containing the entities of {@code entityType} type that are in the
* transaction L1 cache. The returned map is a unmodifiable live view of transaction L1 cache;
* changes to second affect the first. To avoid an {@link ConcurrentModificationException} exception
* when iterating and simultaneous modification of the transaction L1 cache, you may need to make a copy.
*/
> Map, E> entities(@NonNull Class entityType);
> void put(@NonNull E e);
> void putEmpty(@NonNull Entity.Id id);
> boolean containsKey(@NonNull Entity.Id id);
static FirstLevelCache empty() {
return new FirstLevelCache() {
@Override
public > E get(@NonNull Entity.Id id, Function, E> loader) {
return loader.apply(id);
}
@Override
public > Optional peek(@NonNull Entity.Id id) {
throw new NoSuchElementException();
}
@Override
public > List snapshot(@NonNull Class entityType) {
return List.of();
}
@Override
public > Map, E> entities(@NonNull Class entityType) {
return Map.of();
}
@Override
public > void put(@NonNull E e) {
}
@Override
public > void putEmpty(@NonNull Entity.Id id) {
}
@Override
public > boolean containsKey(Entity.@NonNull Id id) {
return false;
}
};
}
static FirstLevelCache create() {
class EntityCache> extends HashMap, Optional> {
}
return new FirstLevelCache() {
private final EntityCache> entityCache = new EntityCache<>();
@SuppressWarnings("unchecked")
private > EntityCache getEntityCache() {
return (EntityCache) entityCache;
}
@Override
public > Optional peek(@NonNull Entity.Id id) {
EntityCache cache = getEntityCache();
if (cache.containsKey(id)) {
return cache.get(id);
}
throw new NoSuchElementException();
}
@Override
public > E get(@NonNull Entity.Id id, @NonNull Function, E> loader) {
EntityCache cache = getEntityCache();
if (cache.containsKey(id)) {
return cache.get(id).orElse(null);
}
E entity = loader.apply(id);
cache.put(id, Optional.ofNullable(entity));
return entity;
}
@Override
public > List snapshot(@NonNull Class entityType) {
EntityCache cache = getEntityCache();
return cache.values().stream()
.flatMap(Optional::stream)
.filter(v -> entityType.equals(v.getId().getType()))
.collect(Collectors.toUnmodifiableList());
}
@Override
public > Map, E> entities(@NonNull Class entityType) {
EntityCache cache = getEntityCache();
return Collections.unmodifiableMap(Maps.transformValues(
Maps.filterEntries(cache, e -> entityType.equals(e.getKey().getType()) && e.getValue().isPresent()),
Optional::get
));
}
@Override
public > void put(@NonNull E e) {
EntityCache cache = getEntityCache();
cache.put(e.getId(), Optional.of(e));
}
@Override
public > void putEmpty(@NonNull Entity.Id id) {
EntityCache cache = getEntityCache();
cache.put(id, Optional.empty());
}
@Override
public > boolean containsKey(Entity.@NonNull Id id) {
return getEntityCache().containsKey(id);
}
};
}
}