package it.cavallium.dbengine.database.collections; import static it.cavallium.dbengine.database.collections.DatabaseMapDictionaryDeep.EMPTY_BYTES; import com.google.common.primitives.Ints; import it.cavallium.dbengine.client.CompositeSnapshot; import it.cavallium.dbengine.database.LLDictionary; import it.cavallium.dbengine.database.collections.Joiner.ValueGetter; import it.cavallium.dbengine.database.collections.JoinerBlocking.ValueGetterBlocking; import it.cavallium.dbengine.database.serialization.Serializer; import it.cavallium.dbengine.database.serialization.SerializerFixedBinaryLength; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.function.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @SuppressWarnings("unused") public class DatabaseMapDictionaryHashed implements DatabaseStageMap> { private final DatabaseMapDictionary> subDictionary; private final Function keySuffixHashFunction; private final Function> valueMapper; protected DatabaseMapDictionaryHashed(LLDictionary dictionary, byte[] prefixKey, Serializer keySuffixSerializer, Serializer valueSerializer, Function keySuffixHashFunction, SerializerFixedBinaryLength keySuffixHashSerializer) { ValueWithHashSerializer valueWithHashSerializer = new ValueWithHashSerializer<>(keySuffixSerializer, valueSerializer ); this.valueMapper = ValueMapper::new; this.subDictionary = DatabaseMapDictionary.tail(dictionary, prefixKey, keySuffixHashSerializer, valueWithHashSerializer ); this.keySuffixHashFunction = keySuffixHashFunction; } private static class ValueWithHashSerializer implements Serializer, byte[]> { private final Serializer keySuffixSerializer; private final Serializer valueSerializer; private ValueWithHashSerializer(Serializer keySuffixSerializer, Serializer valueSerializer) { this.keySuffixSerializer = keySuffixSerializer; this.valueSerializer = valueSerializer; } @Override public @NotNull Entry deserialize(byte @NotNull [] serialized) { int keySuffixLength = Ints.fromBytes(serialized[0], serialized[1], serialized[2], serialized[3]); T keySuffix = keySuffixSerializer.deserialize(Arrays.copyOfRange(serialized, Integer.BYTES, Integer.BYTES + keySuffixLength )); U value = valueSerializer.deserialize(Arrays.copyOfRange(serialized, Integer.BYTES + keySuffixLength, serialized.length )); return Map.entry(keySuffix, value); } @Override public byte @NotNull [] serialize(@NotNull Entry deserialized) { byte[] keySuffix = keySuffixSerializer.serialize(deserialized.getKey()); byte[] value = valueSerializer.serialize(deserialized.getValue()); byte[] result = new byte[Integer.BYTES + keySuffix.length + value.length]; byte[] keySuffixLen = Ints.toByteArray(keySuffix.length); System.arraycopy(keySuffixLen, 0, result, 0, Integer.BYTES); System.arraycopy(keySuffix, 0, result, Integer.BYTES, keySuffix.length); System.arraycopy(value, 0, result, Integer.BYTES + keySuffix.length, value.length); return result; } } private static class ValueMapper implements Serializer> { private final T key; public ValueMapper(T key) { this.key = key; } @Override public @NotNull U deserialize(@NotNull Entry serialized) { return serialized.getValue(); } @Override public @NotNull Entry serialize(@NotNull U deserialized) { return Map.entry(key, deserialized); } } public static DatabaseMapDictionaryHashed simple(LLDictionary dictionary, Serializer keySerializer, Serializer valueSerializer, Function keyHashFunction, SerializerFixedBinaryLength keyHashSerializer) { return new DatabaseMapDictionaryHashed<>(dictionary, EMPTY_BYTES, keySerializer, valueSerializer, keyHashFunction, keyHashSerializer ); } public static DatabaseMapDictionaryHashed tail(LLDictionary dictionary, byte[] prefixKey, Serializer keySuffixSerializer, Serializer valueSerializer, Function keySuffixHashFunction, SerializerFixedBinaryLength keySuffixHashSerializer) { return new DatabaseMapDictionaryHashed<>(dictionary, prefixKey, keySuffixSerializer, valueSerializer, keySuffixHashFunction, keySuffixHashSerializer ); } private Map> serializeMap(Map map) { var newMap = new HashMap>(map.size()); map.forEach((key, value) -> newMap.put(keySuffixHashFunction.apply(key), Map.entry(key, value))); return newMap; } private Map deserializeMap(Map> map) { var newMap = new HashMap(map.size()); map.forEach((key, value) -> newMap.put(value.getKey(), value.getValue())); return newMap; } @Override public Mono> get(@Nullable CompositeSnapshot snapshot) { return subDictionary.get(snapshot).map(this::deserializeMap); } @Override public Mono> getOrDefault(@Nullable CompositeSnapshot snapshot, Mono> defaultValue) { return this.get(snapshot).switchIfEmpty(defaultValue); } @Override public Mono set(Map map) { return Mono.fromSupplier(() -> this.serializeMap(map)).flatMap(subDictionary::set); } @Override public Mono setAndGetStatus(Map map) { return Mono.fromSupplier(() -> this.serializeMap(map)).flatMap(subDictionary::setAndGetStatus); } @Override public Mono update(Function>, Optional>> updater) { return subDictionary.update(old -> updater.apply(old.map(this::deserializeMap)).map(this::serializeMap)); } @Override public Mono clearAndGetStatus() { return subDictionary.clearAndGetStatus(); } @Override public Mono close() { return subDictionary.close(); } @Override public Mono isEmpty(@Nullable CompositeSnapshot snapshot) { return subDictionary.isEmpty(snapshot); } @Override public DatabaseStageEntry> entry() { return this; } @Override public Mono> at(@Nullable CompositeSnapshot snapshot, T key) { return subDictionary .at(snapshot, keySuffixHashFunction.apply(key)) .map(entry -> new DatabaseSingleMapped<>(entry, valueMapper.apply(key))); } @Override public Mono getValue(@Nullable CompositeSnapshot snapshot, T key, boolean existsAlmostCertainly) { return subDictionary .getValue(snapshot, keySuffixHashFunction.apply(key), existsAlmostCertainly) .map(Entry::getValue); } @Override public Mono getValue(@Nullable CompositeSnapshot snapshot, T key) { return subDictionary.getValue(snapshot, keySuffixHashFunction.apply(key)).map(Entry::getValue); } @Override public Mono getValueOrDefault(@Nullable CompositeSnapshot snapshot, T key, Mono defaultValue) { return subDictionary .getValueOrDefault(snapshot, keySuffixHashFunction.apply(key), defaultValue.map(v -> Map.entry(key, v))) .map(Entry::getValue); } @Override public Mono putValue(T key, U value) { return subDictionary.putValue(keySuffixHashFunction.apply(key), Map.entry(key, value)); } @Override public Mono updateValue(T key, boolean existsAlmostCertainly, Function, Optional> updater) { return subDictionary.updateValue(keySuffixHashFunction.apply(key), existsAlmostCertainly, old -> updater.apply(old.map(Entry::getValue)).map(newV -> Map.entry(key, newV)) ); } @Override public Mono updateValue(T key, Function, Optional> updater) { return subDictionary.updateValue(keySuffixHashFunction.apply(key), old -> updater.apply(old.map(Entry::getValue)).map(newV -> Map.entry(key, newV)) ); } @Override public Mono putValueAndGetPrevious(T key, U value) { return subDictionary .putValueAndGetPrevious(keySuffixHashFunction.apply(key), Map.entry(key, value)) .map(Entry::getValue); } @Override public Mono putValueAndGetStatus(T key, U value) { return subDictionary .putValueAndGetStatus(keySuffixHashFunction.apply(key), Map.entry(key, value)); } @Override public Mono remove(T key) { return subDictionary.remove(keySuffixHashFunction.apply(key)); } @Override public Mono removeAndGetPrevious(T key) { return subDictionary.removeAndGetPrevious(keySuffixHashFunction.apply(key)).map(Entry::getValue); } @Override public Mono removeAndGetStatus(T key) { return subDictionary.removeAndGetStatus(keySuffixHashFunction.apply(key)); } @Override public Flux> getMulti(@Nullable CompositeSnapshot snapshot, Flux keys, boolean existsAlmostCertainly) { return subDictionary .getMulti(snapshot, keys.map(keySuffixHashFunction), existsAlmostCertainly) .map(Entry::getValue); } @Override public Flux> getMulti(@Nullable CompositeSnapshot snapshot, Flux keys) { return subDictionary .getMulti(snapshot, keys.map(keySuffixHashFunction)) .map(Entry::getValue); } @Override public Mono putMulti(Flux> entries) { return subDictionary .putMulti(entries.map(entry -> Map.entry(keySuffixHashFunction.apply(entry.getKey()), Map.entry(entry.getKey(), entry.getValue()) ))); } @Override public Flux>> getAllStages(@Nullable CompositeSnapshot snapshot) { return subDictionary .getAllStages(snapshot) .flatMap(hashEntry -> hashEntry .getValue() .get(snapshot) .map(entry -> Map.entry(entry.getKey(), new DatabaseSingleMapped<>(hashEntry.getValue(), valueMapper.apply(entry.getKey())) )) ); } @Override public Flux> getAllValues(@Nullable CompositeSnapshot snapshot) { return subDictionary.getAllValues(snapshot).map(Entry::getValue); } @Override public Mono setAllValues(Flux> entries) { return subDictionary .setAllValues(entries.map(entry -> Map.entry(keySuffixHashFunction.apply(entry.getKey()), entry))); } @Override public Flux> setAllValuesAndGetPrevious(Flux> entries) { return subDictionary .setAllValuesAndGetPrevious(entries.map(entry -> Map.entry(keySuffixHashFunction.apply(entry.getKey()), entry))) .map(Entry::getValue); } @Override public Mono clear() { return subDictionary.clear(); } @Override public Mono replaceAllValues(boolean canKeysChange, Function, Mono>> entriesReplacer) { return subDictionary.replaceAllValues(canKeysChange, entry -> entriesReplacer .apply(entry.getValue()) .map(result -> Map.entry(keySuffixHashFunction.apply(result.getKey()), result)) ); } @Override public Mono replaceAll(Function>, Mono> entriesReplacer) { return subDictionary.replaceAll(hashEntry -> hashEntry .getValue() .get(null) .flatMap(entry -> entriesReplacer.apply(Map.entry(entry.getKey(), new DatabaseSingleMapped<>(hashEntry.getValue(), valueMapper.apply(entry.getKey())) )))); } @Override public Mono> setAndGetPrevious(Map value) { return Mono .fromSupplier(() -> this.serializeMap(value)) .flatMap(subDictionary::setAndGetPrevious) .map(this::deserializeMap); } @Override public Mono update(Function>, Optional>> updater, boolean existsAlmostCertainly) { return subDictionary .update(item -> updater.apply(item.map(this::deserializeMap)).map(this::serializeMap), existsAlmostCertainly); } @Override public Mono> clearAndGetPrevious() { return subDictionary .clearAndGetPrevious() .map(this::deserializeMap); } @Override public Mono> get(@Nullable CompositeSnapshot snapshot, boolean existsAlmostCertainly) { return subDictionary .get(snapshot, existsAlmostCertainly) .map(this::deserializeMap); } @Override public Mono leavesCount(@Nullable CompositeSnapshot snapshot, boolean fast) { return subDictionary.leavesCount(snapshot, fast); } @Override public ValueGetterBlocking getDbValueGetter(@Nullable CompositeSnapshot snapshot) { ValueGetterBlocking> getter = subDictionary.getDbValueGetter(snapshot); return key -> getter.get(keySuffixHashFunction.apply(key)).getValue(); } @Override public ValueGetter getAsyncDbValueGetter(@Nullable CompositeSnapshot snapshot) { ValueGetter> getter = subDictionary.getAsyncDbValueGetter(snapshot); return key -> getter.get(keySuffixHashFunction.apply(key)).map(Entry::getValue); } }