Add checked serialization exception
This commit is contained in:
parent
4e71e42d32
commit
2a24570512
@ -1,6 +1,7 @@
|
||||
package it.cavallium.dbengine.client;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationException;
|
||||
import it.cavallium.dbengine.database.serialization.Serializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -16,7 +17,7 @@ public class MappedSerializer<A, B> implements Serializer<B, ByteBuf> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull B deserialize(@NotNull ByteBuf serialized) {
|
||||
public @NotNull B deserialize(@NotNull ByteBuf serialized) throws SerializationException {
|
||||
try {
|
||||
return keyMapper.map(serializer.deserialize(serialized.retain()));
|
||||
} finally {
|
||||
@ -25,7 +26,7 @@ public class MappedSerializer<A, B> implements Serializer<B, ByteBuf> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ByteBuf serialize(@NotNull B deserialized) {
|
||||
public @NotNull ByteBuf serialize(@NotNull B deserialized) throws SerializationException {
|
||||
return serializer.serialize(keyMapper.unmap(deserialized));
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package it.cavallium.dbengine.client;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationException;
|
||||
import it.cavallium.dbengine.database.serialization.SerializerFixedBinaryLength;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -16,7 +17,7 @@ public class MappedSerializerFixedLength<A, B> implements SerializerFixedBinaryL
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull B deserialize(@NotNull ByteBuf serialized) {
|
||||
public @NotNull B deserialize(@NotNull ByteBuf serialized) throws SerializationException {
|
||||
try {
|
||||
return keyMapper.map(fixedLengthSerializer.deserialize(serialized.retain()));
|
||||
} finally {
|
||||
@ -25,7 +26,7 @@ public class MappedSerializerFixedLength<A, B> implements SerializerFixedBinaryL
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ByteBuf serialize(@NotNull B deserialized) {
|
||||
public @NotNull ByteBuf serialize(@NotNull B deserialized) throws SerializationException {
|
||||
return fixedLengthSerializer.serialize(keyMapper.unmap(deserialized));
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@ package it.cavallium.dbengine.database;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import it.cavallium.dbengine.client.BadBlock;
|
||||
import it.cavallium.dbengine.database.serialization.BiSerializationFunction;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationFunction;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
@ -34,7 +36,7 @@ public interface LLDictionary extends LLKeyValueDatabaseStructure {
|
||||
Mono<UpdateMode> getUpdateMode();
|
||||
|
||||
default Mono<ByteBuf> update(Mono<ByteBuf> key,
|
||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||
SerializationFunction<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||
UpdateReturnMode updateReturnMode,
|
||||
boolean existsAlmostCertainly) {
|
||||
return this
|
||||
@ -43,17 +45,17 @@ public interface LLDictionary extends LLKeyValueDatabaseStructure {
|
||||
}
|
||||
|
||||
default Mono<ByteBuf> update(Mono<ByteBuf> key,
|
||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||
SerializationFunction<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||
UpdateReturnMode returnMode) {
|
||||
return update(key, updater, returnMode, false);
|
||||
}
|
||||
|
||||
Mono<Delta<ByteBuf>> updateAndGetDelta(Mono<ByteBuf> key,
|
||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||
SerializationFunction<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||
boolean existsAlmostCertainly);
|
||||
|
||||
default Mono<Delta<ByteBuf>> updateAndGetDelta(Mono<ByteBuf> key,
|
||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater) {
|
||||
SerializationFunction<@Nullable ByteBuf, @Nullable ByteBuf> updater) {
|
||||
return updateAndGetDelta(key, updater, false);
|
||||
}
|
||||
|
||||
@ -72,7 +74,7 @@ public interface LLDictionary extends LLKeyValueDatabaseStructure {
|
||||
Flux<Entry<ByteBuf, ByteBuf>> putMulti(Flux<Entry<ByteBuf, ByteBuf>> entries, boolean getOldValues);
|
||||
|
||||
<X> Flux<ExtraKeyOperationResult<ByteBuf, X>> updateMulti(Flux<Tuple2<ByteBuf, X>> entries,
|
||||
BiFunction<ByteBuf, X, ByteBuf> updateFunction);
|
||||
BiSerializationFunction<ByteBuf, X, ByteBuf> updateFunction);
|
||||
|
||||
Flux<Entry<ByteBuf, ByteBuf>> getRange(@Nullable LLSnapshot snapshot, Mono<LLRange> range, boolean existsAlmostCertainly);
|
||||
|
||||
|
@ -7,17 +7,22 @@ import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.CompositeByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.util.AbstractReferenceCounted;
|
||||
import io.netty.util.IllegalReferenceCountException;
|
||||
import io.netty.util.ReferenceCounted;
|
||||
import it.cavallium.dbengine.database.disk.ReleasableSlice;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationException;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationFunction;
|
||||
import it.cavallium.dbengine.lucene.RandomSortField;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.ToIntFunction;
|
||||
import org.apache.lucene.document.Document;
|
||||
@ -37,6 +42,8 @@ import org.apache.lucene.search.SortedNumericSortField;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.rocksdb.RocksDB;
|
||||
import org.warp.commonutils.functional.IOFunction;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ -94,16 +101,12 @@ public class LLUtils {
|
||||
}
|
||||
|
||||
public static ScoreMode toScoreMode(LLScoreMode scoreMode) {
|
||||
switch (scoreMode) {
|
||||
case COMPLETE:
|
||||
return ScoreMode.COMPLETE;
|
||||
case TOP_SCORES:
|
||||
return ScoreMode.TOP_SCORES;
|
||||
case COMPLETE_NO_SCORES:
|
||||
return ScoreMode.COMPLETE_NO_SCORES;
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected value: " + scoreMode);
|
||||
}
|
||||
return switch (scoreMode) {
|
||||
case COMPLETE -> ScoreMode.COMPLETE;
|
||||
case TOP_SCORES -> ScoreMode.TOP_SCORES;
|
||||
case COMPLETE_NO_SCORES -> ScoreMode.COMPLETE_NO_SCORES;
|
||||
default -> throw new IllegalStateException("Unexpected value: " + scoreMode);
|
||||
};
|
||||
}
|
||||
|
||||
public static Term toTerm(LLTerm term) {
|
||||
@ -143,25 +146,18 @@ public class LLUtils {
|
||||
}
|
||||
|
||||
private static IndexableField toField(LLItem item) {
|
||||
switch (item.getType()) {
|
||||
case IntPoint:
|
||||
return new IntPoint(item.getName(), Ints.fromByteArray(item.getData()));
|
||||
case LongPoint:
|
||||
return new LongPoint(item.getName(), Longs.fromByteArray(item.getData()));
|
||||
case FloatPoint:
|
||||
return new FloatPoint(item.getName(), ByteBuffer.wrap(item.getData()).getFloat());
|
||||
case TextField:
|
||||
return new TextField(item.getName(), item.stringValue(), Field.Store.NO);
|
||||
case TextFieldStored:
|
||||
return new TextField(item.getName(), item.stringValue(), Field.Store.YES);
|
||||
case SortedNumericDocValuesField:
|
||||
return new SortedNumericDocValuesField(item.getName(), Longs.fromByteArray(item.getData()));
|
||||
case StringField:
|
||||
return new StringField(item.getName(), item.stringValue(), Field.Store.NO);
|
||||
case StringFieldStored:
|
||||
return new StringField(item.getName(), item.stringValue(), Field.Store.YES);
|
||||
}
|
||||
throw new UnsupportedOperationException("Unsupported field type");
|
||||
return switch (item.getType()) {
|
||||
case IntPoint -> new IntPoint(item.getName(), Ints.fromByteArray(item.getData()));
|
||||
case LongPoint -> new LongPoint(item.getName(), Longs.fromByteArray(item.getData()));
|
||||
case FloatPoint -> new FloatPoint(item.getName(), ByteBuffer.wrap(item.getData()).getFloat());
|
||||
case TextField -> new TextField(item.getName(), item.stringValue(), Field.Store.NO);
|
||||
case TextFieldStored -> new TextField(item.getName(), item.stringValue(), Field.Store.YES);
|
||||
case SortedNumericDocValuesField -> new SortedNumericDocValuesField(item.getName(),
|
||||
Longs.fromByteArray(item.getData())
|
||||
);
|
||||
case StringField -> new StringField(item.getName(), item.stringValue(), Field.Store.NO);
|
||||
case StringFieldStored -> new StringField(item.getName(), item.stringValue(), Field.Store.YES);
|
||||
};
|
||||
}
|
||||
|
||||
public static it.cavallium.dbengine.database.LLKeyScore toKeyScore(LLKeyScore hit) {
|
||||
@ -442,48 +438,50 @@ public class LLUtils {
|
||||
public static <T> Mono<T> resolveDelta(Mono<Delta<T>> prev, UpdateReturnMode updateReturnMode) {
|
||||
return prev.handle((delta, sink) -> {
|
||||
switch (updateReturnMode) {
|
||||
case GET_NEW_VALUE:
|
||||
case GET_NEW_VALUE -> {
|
||||
var current = delta.current();
|
||||
if (current != null) {
|
||||
sink.next(current);
|
||||
} else {
|
||||
sink.complete();
|
||||
}
|
||||
break;
|
||||
case GET_OLD_VALUE:
|
||||
}
|
||||
case GET_OLD_VALUE -> {
|
||||
var previous = delta.previous();
|
||||
if (previous != null) {
|
||||
sink.next(previous);
|
||||
} else {
|
||||
sink.complete();
|
||||
}
|
||||
break;
|
||||
case NOTHING:
|
||||
sink.complete();
|
||||
break;
|
||||
default:
|
||||
sink.error(new IllegalStateException());
|
||||
}
|
||||
case NOTHING -> sink.complete();
|
||||
default -> sink.error(new IllegalStateException());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static <T, U> Mono<Delta<U>> mapDelta(Mono<Delta<T>> mono, Function<@NotNull T, @Nullable U> mapper) {
|
||||
return mono.map(delta -> {
|
||||
T prev = delta.previous();
|
||||
T curr = delta.current();
|
||||
U newPrev;
|
||||
U newCurr;
|
||||
if (prev != null) {
|
||||
newPrev = mapper.apply(prev);
|
||||
} else {
|
||||
newPrev = null;
|
||||
public static <T, U> Mono<Delta<U>> mapDelta(Mono<Delta<T>> mono,
|
||||
SerializationFunction<@NotNull T, @Nullable U> mapper) {
|
||||
return mono.handle((delta, sink) -> {
|
||||
try {
|
||||
T prev = delta.previous();
|
||||
T curr = delta.current();
|
||||
U newPrev;
|
||||
U newCurr;
|
||||
if (prev != null) {
|
||||
newPrev = mapper.apply(prev);
|
||||
} else {
|
||||
newPrev = null;
|
||||
}
|
||||
if (curr != null) {
|
||||
newCurr = mapper.apply(curr);
|
||||
} else {
|
||||
newCurr = null;
|
||||
}
|
||||
sink.next(new Delta<>(newPrev, newCurr));
|
||||
} catch (SerializationException ex) {
|
||||
sink.error(ex);
|
||||
}
|
||||
if (curr != null) {
|
||||
newCurr = mapper.apply(curr);
|
||||
} else {
|
||||
newCurr = null;
|
||||
}
|
||||
return new Delta<>(newPrev, newCurr);
|
||||
});
|
||||
}
|
||||
|
||||
@ -514,4 +512,44 @@ public class LLUtils {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> Mono<T> handleDiscard(Mono<T> mono) {
|
||||
return mono.doOnDiscard(Map.Entry.class, e -> {
|
||||
if (e.getKey() instanceof ByteBuf bb) {
|
||||
if (bb.refCnt() > 0) {
|
||||
bb.release();
|
||||
}
|
||||
}
|
||||
if (e.getValue() instanceof ByteBuf bb) {
|
||||
if (bb.refCnt() > 0) {
|
||||
bb.release();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> Flux<T> handleDiscard(Flux<T> mono) {
|
||||
return mono
|
||||
.doOnDiscard(ReferenceCounted.class, LLUtils::discardRefCounted)
|
||||
.doOnDiscard(Map.Entry.class, LLUtils::discardEntry);
|
||||
}
|
||||
|
||||
private static void discardEntry(Map.Entry<?, ?> e) {
|
||||
if (e.getKey() instanceof ByteBuf bb) {
|
||||
if (bb.refCnt() > 0) {
|
||||
bb.release();
|
||||
}
|
||||
}
|
||||
if (e.getValue() instanceof ByteBuf bb) {
|
||||
if (bb.refCnt() > 0) {
|
||||
bb.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void discardRefCounted(ReferenceCounted referenceCounted) {
|
||||
if (referenceCounted.refCnt() > 0) {
|
||||
referenceCounted.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,9 @@ import it.cavallium.dbengine.database.LLDictionaryResultType;
|
||||
import it.cavallium.dbengine.database.LLUtils;
|
||||
import it.cavallium.dbengine.database.UpdateMode;
|
||||
import it.cavallium.dbengine.database.UpdateReturnMode;
|
||||
import it.cavallium.dbengine.database.serialization.BiSerializationFunction;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationException;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationFunction;
|
||||
import it.cavallium.dbengine.database.serialization.Serializer;
|
||||
import it.cavallium.dbengine.database.serialization.SerializerFixedBinaryLength;
|
||||
import java.util.Collections;
|
||||
@ -23,6 +26,7 @@ import java.util.function.Function;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.SynchronousSink;
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
@ -64,28 +68,48 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
}
|
||||
}
|
||||
|
||||
private void deserializeValue(ByteBuf value, SynchronousSink<U> sink) {
|
||||
try {
|
||||
sink.next(valueSerializer.deserialize(value));
|
||||
} catch (SerializationException ex) {
|
||||
sink.error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Map<T, U>> get(@Nullable CompositeSnapshot snapshot, boolean existsAlmostCertainly) {
|
||||
return dictionary
|
||||
.getRange(resolveSnapshot(snapshot), rangeMono, existsAlmostCertainly)
|
||||
.collectMap(
|
||||
entry -> deserializeSuffix(stripPrefix(entry.getKey(), false)),
|
||||
entry -> valueSerializer.deserialize(entry.getValue()),
|
||||
HashMap::new)
|
||||
.<Entry<T, U>>handle((entry, sink) -> {
|
||||
try {
|
||||
var key = deserializeSuffix(stripPrefix(entry.getKey(), false));
|
||||
var value = valueSerializer.deserialize(entry.getValue());
|
||||
sink.next(Map.entry(key, value));
|
||||
} catch (SerializationException ex) {
|
||||
sink.error(ex);
|
||||
}
|
||||
})
|
||||
.collectMap(Entry::getKey, Entry::getValue, HashMap::new)
|
||||
.filter(map -> !map.isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Map<T, U>> setAndGetPrevious(Map<T, U> value) {
|
||||
return Mono.usingWhen(
|
||||
Mono.just(true),
|
||||
b -> get(null, false),
|
||||
b -> dictionary.setRange(rangeMono, Flux
|
||||
return this
|
||||
.get(null, false)
|
||||
.concatWith(dictionary.setRange(rangeMono, Flux
|
||||
.fromIterable(Collections.unmodifiableMap(value).entrySet())
|
||||
.map(entry -> Map.entry(this.toKey(serializeSuffix(entry.getKey())),
|
||||
valueSerializer.serialize(entry.getValue())))
|
||||
)
|
||||
);
|
||||
.handle((entry, sink) -> {
|
||||
try {
|
||||
sink.next(Map.entry(this.toKey(serializeSuffix(entry.getKey())),
|
||||
valueSerializer.serialize(entry.getValue())));
|
||||
} catch (SerializationException e) {
|
||||
sink.error(e);
|
||||
}
|
||||
})
|
||||
).then(Mono.empty()))
|
||||
.singleOrEmpty()
|
||||
.transform(LLUtils::handleDiscard);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -107,7 +131,7 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
@Override
|
||||
public Mono<DatabaseStageEntry<U>> at(@Nullable CompositeSnapshot snapshot, T keySuffix) {
|
||||
return Mono
|
||||
.fromSupplier(() -> new DatabaseSingleMapped<>(
|
||||
.fromCallable(() -> new DatabaseSingleMapped<>(
|
||||
new DatabaseSingle<>(dictionary, toKey(serializeSuffix(keySuffix)), Serializer.noop())
|
||||
, valueSerializer)
|
||||
);
|
||||
@ -120,7 +144,7 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
() -> toKey(serializeSuffix(keySuffix)),
|
||||
keyBuf -> dictionary
|
||||
.get(resolveSnapshot(snapshot), LLUtils.lazyRetain(keyBuf), existsAlmostCertainly)
|
||||
.map(valueSerializer::deserialize),
|
||||
.handle(this::deserializeValue),
|
||||
ReferenceCounted::release
|
||||
);
|
||||
}
|
||||
@ -158,13 +182,13 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
public Mono<U> updateValue(T keySuffix,
|
||||
UpdateReturnMode updateReturnMode,
|
||||
boolean existsAlmostCertainly,
|
||||
Function<@Nullable U, @Nullable U> updater) {
|
||||
SerializationFunction<@Nullable U, @Nullable U> updater) {
|
||||
return Mono
|
||||
.using(
|
||||
() -> toKey(serializeSuffix(keySuffix)),
|
||||
keyBuf -> dictionary
|
||||
.update(LLUtils.lazyRetain(keyBuf), getSerializedUpdater(updater), updateReturnMode, existsAlmostCertainly)
|
||||
.map(valueSerializer::deserialize),
|
||||
.handle(this::deserializeValue),
|
||||
ReferenceCounted::release
|
||||
);
|
||||
}
|
||||
@ -172,7 +196,7 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
@Override
|
||||
public Mono<Delta<U>> updateValueAndGetDelta(T keySuffix,
|
||||
boolean existsAlmostCertainly,
|
||||
Function<@Nullable U, @Nullable U> updater) {
|
||||
SerializationFunction<@Nullable U, @Nullable U> updater) {
|
||||
return Mono
|
||||
.using(
|
||||
() -> toKey(serializeSuffix(keySuffix)),
|
||||
@ -183,10 +207,15 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
);
|
||||
}
|
||||
|
||||
public Function<@Nullable ByteBuf, @Nullable ByteBuf> getSerializedUpdater(Function<@Nullable U, @Nullable U> updater) {
|
||||
public SerializationFunction<@Nullable ByteBuf, @Nullable ByteBuf> getSerializedUpdater(SerializationFunction<@Nullable U, @Nullable U> updater) {
|
||||
return oldSerialized -> {
|
||||
try {
|
||||
var result = updater.apply(oldSerialized == null ? null : valueSerializer.deserialize(oldSerialized.retain()));
|
||||
U result;
|
||||
if (oldSerialized == null) {
|
||||
result = updater.apply(null);
|
||||
} else {
|
||||
result = updater.apply(valueSerializer.deserialize(oldSerialized.retain()));
|
||||
}
|
||||
if (result == null) {
|
||||
return null;
|
||||
} else {
|
||||
@ -200,10 +229,16 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
};
|
||||
}
|
||||
|
||||
public <X> BiFunction<@Nullable ByteBuf, X, @Nullable ByteBuf> getSerializedUpdater(BiFunction<@Nullable U, X, @Nullable U> updater) {
|
||||
public <X> BiSerializationFunction<@Nullable ByteBuf, X, @Nullable ByteBuf> getSerializedUpdater(
|
||||
BiSerializationFunction<@Nullable U, X, @Nullable U> updater) {
|
||||
return (oldSerialized, extra) -> {
|
||||
try {
|
||||
var result = updater.apply(oldSerialized == null ? null : valueSerializer.deserialize(oldSerialized.retain()), extra);
|
||||
U result;
|
||||
if (oldSerialized == null) {
|
||||
result = updater.apply(null, extra);
|
||||
} else {
|
||||
result = updater.apply(valueSerializer.deserialize(oldSerialized.retain()), extra);
|
||||
}
|
||||
if (result == null) {
|
||||
return null;
|
||||
} else {
|
||||
@ -231,7 +266,7 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
.put(LLUtils.lazyRetain(keyBuf),
|
||||
LLUtils.lazyRetain(valueBuf),
|
||||
LLDictionaryResultType.PREVIOUS_VALUE)
|
||||
.map(valueSerializer::deserialize),
|
||||
.handle(this::deserializeValue),
|
||||
ReferenceCounted::release
|
||||
),
|
||||
ReferenceCounted::release
|
||||
@ -255,7 +290,7 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
LLUtils.lazyRetain(valueBuf),
|
||||
LLDictionaryResultType.PREVIOUS_VALUE
|
||||
)
|
||||
.map(valueSerializer::deserialize)
|
||||
.handle(this::deserializeValue)
|
||||
.map(oldValue -> !Objects.equals(oldValue, value))
|
||||
.defaultIfEmpty(value != null),
|
||||
ReferenceCounted::release
|
||||
@ -286,7 +321,7 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
() -> toKey(serializeSuffix(keySuffix)),
|
||||
keyBuf -> dictionary
|
||||
.remove(LLUtils.lazyRetain(keyBuf), LLDictionaryResultType.PREVIOUS_VALUE)
|
||||
.map(valueSerializer::deserialize),
|
||||
.handle(this::deserializeValue),
|
||||
ReferenceCounted::release
|
||||
);
|
||||
}
|
||||
@ -316,11 +351,19 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
})), existsAlmostCertainly)
|
||||
.flatMapSequential(entry -> {
|
||||
entry.getT2().release();
|
||||
return Mono.fromCallable(() -> Map.entry(entry.getT1(), entry.getT3().map(valueSerializer::deserialize)));
|
||||
return Mono.fromCallable(() -> {
|
||||
Optional<U> valueOpt;
|
||||
if (entry.getT3().isPresent()) {
|
||||
valueOpt = Optional.of(valueSerializer.deserialize(entry.getT3().get()));
|
||||
} else {
|
||||
valueOpt = Optional.empty();
|
||||
}
|
||||
return Map.entry(entry.getT1(), valueOpt);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private Entry<ByteBuf, ByteBuf> serializeEntry(T key, U value) {
|
||||
private Entry<ByteBuf, ByteBuf> serializeEntry(T key, U value) throws SerializationException {
|
||||
ByteBuf serializedKey = toKey(serializeSuffix(key));
|
||||
try {
|
||||
ByteBuf serializedValue = valueSerializer.serialize(value);
|
||||
@ -355,7 +398,7 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
|
||||
@Override
|
||||
public <X> Flux<ExtraKeyOperationResult<T, X>> updateMulti(Flux<Tuple2<T, X>> entries,
|
||||
BiFunction<@Nullable U, X, @Nullable U> updater) {
|
||||
BiSerializationFunction<@Nullable U, X, @Nullable U> updater) {
|
||||
Flux<Tuple2<ByteBuf, X>> serializedEntries = entries
|
||||
.flatMap(entry -> Mono
|
||||
.fromCallable(() -> Tuples.of(serializeSuffix(entry.getT1()), entry.getT2()))
|
||||
@ -370,26 +413,34 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
});
|
||||
var serializedUpdater = getSerializedUpdater(updater);
|
||||
return dictionary.updateMulti(serializedEntries, serializedUpdater)
|
||||
.map(result -> new ExtraKeyOperationResult<>(deserializeSuffix(result.key()),
|
||||
result.extra(),
|
||||
result.changed()
|
||||
));
|
||||
.handle((result, sink) -> {
|
||||
try {
|
||||
sink.next(new ExtraKeyOperationResult<>(deserializeSuffix(result.key()),
|
||||
result.extra(),
|
||||
result.changed()
|
||||
));
|
||||
} catch (SerializationException ex) {
|
||||
sink.error(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Entry<T, DatabaseStageEntry<U>>> getAllStages(@Nullable CompositeSnapshot snapshot) {
|
||||
return dictionary
|
||||
.getRangeKeys(resolveSnapshot(snapshot), rangeMono)
|
||||
.map(key -> {
|
||||
.handle((key, sink) -> {
|
||||
ByteBuf keySuffixWithExt = stripPrefix(key.retain(), false);
|
||||
try {
|
||||
try {
|
||||
return Map.entry(deserializeSuffix(keySuffixWithExt.retainedSlice()),
|
||||
sink.next(Map.entry(deserializeSuffix(keySuffixWithExt.retainedSlice()),
|
||||
new DatabaseSingleMapped<>(new DatabaseSingle<>(dictionary,
|
||||
toKey(keySuffixWithExt.retainedSlice()),
|
||||
Serializer.noop()
|
||||
), valueSerializer)
|
||||
);
|
||||
));
|
||||
} catch (SerializationException ex) {
|
||||
sink.error(ex);
|
||||
} finally {
|
||||
keySuffixWithExt.release();
|
||||
}
|
||||
@ -403,10 +454,16 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
public Flux<Entry<T, U>> getAllValues(@Nullable CompositeSnapshot snapshot) {
|
||||
return dictionary
|
||||
.getRange(resolveSnapshot(snapshot), rangeMono)
|
||||
.map(serializedEntry -> Map.entry(
|
||||
deserializeSuffix(stripPrefix(serializedEntry.getKey(), false)),
|
||||
valueSerializer.deserialize(serializedEntry.getValue())
|
||||
))
|
||||
.<Entry<T, U>>handle((serializedEntry, sink) -> {
|
||||
try {
|
||||
sink.next(Map.entry(
|
||||
deserializeSuffix(stripPrefix(serializedEntry.getKey(), false)),
|
||||
valueSerializer.deserialize(serializedEntry.getValue())
|
||||
));
|
||||
} catch (SerializationException e) {
|
||||
sink.error(e);
|
||||
}
|
||||
})
|
||||
.doOnDiscard(Entry.class, uncastedEntry -> {
|
||||
if (uncastedEntry.getKey() instanceof ByteBuf byteBuf) {
|
||||
byteBuf.release();
|
||||
@ -419,17 +476,18 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
|
||||
|
||||
@Override
|
||||
public Flux<Entry<T, U>> setAllValuesAndGetPrevious(Flux<Entry<T, U>> entries) {
|
||||
return Flux
|
||||
.usingWhen(
|
||||
Mono.just(true),
|
||||
b -> getAllValues(null),
|
||||
b -> dictionary
|
||||
.setRange(rangeMono,
|
||||
entries.map(entry -> Map.entry(toKey(serializeSuffix(entry.getKey())),
|
||||
valueSerializer.serialize(entry.getValue())
|
||||
))
|
||||
)
|
||||
);
|
||||
return Flux.usingWhen(
|
||||
Mono.just(true),
|
||||
b -> getAllValues(null),
|
||||
b -> dictionary.setRange(rangeMono, entries.handle((entry, sink) -> {
|
||||
try {
|
||||
ByteBuf serializedValue = valueSerializer.serialize(entry.getValue());
|
||||
sink.next(Map.entry(toKey(serializeSuffix(entry.getKey())), serializedValue));
|
||||
} catch (SerializationException e) {
|
||||
sink.error(e);
|
||||
}
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -13,6 +13,7 @@ import it.cavallium.dbengine.database.LLSnapshot;
|
||||
import it.cavallium.dbengine.database.LLUtils;
|
||||
import it.cavallium.dbengine.database.UpdateMode;
|
||||
import it.cavallium.dbengine.database.disk.LLLocalDictionary;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationException;
|
||||
import it.cavallium.dbengine.database.serialization.SerializerFixedBinaryLength;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@ -457,7 +458,14 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> implem
|
||||
LLUtils.lazyRetain(buffers.groupKeyWithoutExt),
|
||||
Flux.fromIterable(rangeKeys).map(ByteBuf::retain)
|
||||
)
|
||||
.map(us -> Map.entry(this.deserializeSuffix(buffers.groupSuffix.retain()), us))
|
||||
.<Entry<T, US>>handle((us, sink) -> {
|
||||
try {
|
||||
var deserializedSuffix = this.deserializeSuffix(buffers.groupSuffix.retain());
|
||||
sink.next(Map.entry(deserializedSuffix, us));
|
||||
} catch (SerializationException ex) {
|
||||
sink.error(ex);
|
||||
}
|
||||
})
|
||||
),
|
||||
buffers -> {
|
||||
buffers.groupSuffix.release();
|
||||
@ -494,7 +502,13 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> implem
|
||||
LLUtils.lazyRetain(groupKeyWithoutExt),
|
||||
Flux.empty()
|
||||
)
|
||||
.map(us -> Map.entry(this.deserializeSuffix(groupSuffix.retain()), us)),
|
||||
.<Entry<T, US>>handle((us, sink) -> {
|
||||
try {
|
||||
sink.next(Map.entry(this.deserializeSuffix(groupSuffix.retain()), us));
|
||||
} catch (SerializationException ex) {
|
||||
sink.error(ex);
|
||||
}
|
||||
}),
|
||||
ReferenceCounted::release
|
||||
)
|
||||
);
|
||||
@ -543,7 +557,7 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> implem
|
||||
}
|
||||
|
||||
//todo: temporary wrapper. convert the whole class to buffers
|
||||
protected T deserializeSuffix(ByteBuf keySuffix) {
|
||||
protected T deserializeSuffix(ByteBuf keySuffix) throws SerializationException {
|
||||
try {
|
||||
assert suffixKeyConsistency(keySuffix.readableBytes());
|
||||
var result = keySuffixSerializer.deserialize(keySuffix.retain());
|
||||
@ -555,7 +569,7 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> implem
|
||||
}
|
||||
|
||||
//todo: temporary wrapper. convert the whole class to buffers
|
||||
protected ByteBuf serializeSuffix(T keySuffix) {
|
||||
protected ByteBuf serializeSuffix(T keySuffix) throws SerializationException {
|
||||
ByteBuf suffixData = keySuffixSerializer.serialize(keySuffix);
|
||||
assert suffixKeyConsistency(suffixData.readableBytes());
|
||||
assert keyPrefix.refCnt() > 0;
|
||||
|
@ -11,11 +11,14 @@ import it.cavallium.dbengine.database.LLRange;
|
||||
import it.cavallium.dbengine.database.LLSnapshot;
|
||||
import it.cavallium.dbengine.database.LLUtils;
|
||||
import it.cavallium.dbengine.database.UpdateReturnMode;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationException;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationFunction;
|
||||
import it.cavallium.dbengine.database.serialization.Serializer;
|
||||
import java.util.function.Function;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.SynchronousSink;
|
||||
|
||||
public class DatabaseSingle<U> implements DatabaseStageEntry<U> {
|
||||
|
||||
@ -43,11 +46,19 @@ public class DatabaseSingle<U> implements DatabaseStageEntry<U> {
|
||||
}
|
||||
}
|
||||
|
||||
private void deserializeValue(ByteBuf value, SynchronousSink<U> sink) {
|
||||
try {
|
||||
sink.next(serializer.deserialize(value));
|
||||
} catch (SerializationException ex) {
|
||||
sink.error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<U> get(@Nullable CompositeSnapshot snapshot, boolean existsAlmostCertainly) {
|
||||
return dictionary
|
||||
.get(resolveSnapshot(snapshot), keyMono, existsAlmostCertainly)
|
||||
.map(serializer::deserialize);
|
||||
.handle(this::deserializeValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -56,13 +67,13 @@ public class DatabaseSingle<U> implements DatabaseStageEntry<U> {
|
||||
.using(() -> serializer.serialize(value),
|
||||
valueByteBuf -> dictionary
|
||||
.put(keyMono, LLUtils.lazyRetain(valueByteBuf), LLDictionaryResultType.PREVIOUS_VALUE)
|
||||
.map(serializer::deserialize),
|
||||
.handle(this::deserializeValue),
|
||||
ReferenceCounted::release
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<U> update(Function<@Nullable U, @Nullable U> updater,
|
||||
public Mono<U> update(SerializationFunction<@Nullable U, @Nullable U> updater,
|
||||
UpdateReturnMode updateReturnMode,
|
||||
boolean existsAlmostCertainly) {
|
||||
return dictionary
|
||||
@ -74,11 +85,11 @@ public class DatabaseSingle<U> implements DatabaseStageEntry<U> {
|
||||
return serializer.serialize(result);
|
||||
}
|
||||
}, updateReturnMode, existsAlmostCertainly)
|
||||
.map(serializer::deserialize);
|
||||
.handle(this::deserializeValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Delta<U>> updateAndGetDelta(Function<@Nullable U, @Nullable U> updater,
|
||||
public Mono<Delta<U>> updateAndGetDelta(SerializationFunction<@Nullable U, @Nullable U> updater,
|
||||
boolean existsAlmostCertainly) {
|
||||
return dictionary
|
||||
.updateAndGetDelta(keyMono, (oldValueSer) -> {
|
||||
@ -95,7 +106,7 @@ public class DatabaseSingle<U> implements DatabaseStageEntry<U> {
|
||||
public Mono<U> clearAndGetPrevious() {
|
||||
return dictionary
|
||||
.remove(keyMono, LLDictionaryResultType.PREVIOUS_VALUE)
|
||||
.map(serializer::deserialize);
|
||||
.handle(this::deserializeValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,6 +6,7 @@ import it.cavallium.dbengine.database.Column;
|
||||
import it.cavallium.dbengine.database.Delta;
|
||||
import it.cavallium.dbengine.database.LLUtils;
|
||||
import it.cavallium.dbengine.database.UpdateReturnMode;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationFunction;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArraySet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSets;
|
||||
import java.util.HashSet;
|
||||
@ -58,7 +59,7 @@ public class DatabaseSingleBucket<K, V, TH> implements DatabaseStageEntry<V> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<V> update(Function<@Nullable V, @Nullable V> updater,
|
||||
public Mono<V> update(SerializationFunction<@Nullable V, @Nullable V> updater,
|
||||
UpdateReturnMode updateReturnMode,
|
||||
boolean existsAlmostCertainly) {
|
||||
return bucketStage
|
||||
@ -76,7 +77,7 @@ public class DatabaseSingleBucket<K, V, TH> implements DatabaseStageEntry<V> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Delta<V>> updateAndGetDelta(Function<@Nullable V, @Nullable V> updater, boolean existsAlmostCertainly) {
|
||||
public Mono<Delta<V>> updateAndGetDelta(SerializationFunction<@Nullable V, @Nullable V> updater, boolean existsAlmostCertainly) {
|
||||
return bucketStage
|
||||
.updateAndGetDelta(oldBucket -> {
|
||||
V oldValue = extractValue(oldBucket);
|
||||
|
@ -1,15 +1,19 @@
|
||||
package it.cavallium.dbengine.database.collections;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import it.cavallium.dbengine.client.BadBlock;
|
||||
import it.cavallium.dbengine.client.CompositeSnapshot;
|
||||
import it.cavallium.dbengine.database.Delta;
|
||||
import it.cavallium.dbengine.database.LLUtils;
|
||||
import it.cavallium.dbengine.database.UpdateReturnMode;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationException;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationFunction;
|
||||
import it.cavallium.dbengine.database.serialization.Serializer;
|
||||
import java.util.function.Function;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.SynchronousSink;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class DatabaseSingleMapped<A, B> implements DatabaseStageEntry<A> {
|
||||
@ -22,33 +26,49 @@ public class DatabaseSingleMapped<A, B> implements DatabaseStageEntry<A> {
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
private void deserializeSink(B value, SynchronousSink<A> sink) {
|
||||
try {
|
||||
sink.next(this.deserialize(value));
|
||||
} catch (SerializationException ex) {
|
||||
sink.error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<A> get(@Nullable CompositeSnapshot snapshot, boolean existsAlmostCertainly) {
|
||||
return serializedSingle.get(snapshot, existsAlmostCertainly).map(this::deserialize);
|
||||
return serializedSingle.get(snapshot, existsAlmostCertainly).handle(this::deserializeSink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<A> getOrDefault(@Nullable CompositeSnapshot snapshot, Mono<A> defaultValue) {
|
||||
return serializedSingle.get(snapshot).map(this::deserialize).switchIfEmpty(defaultValue);
|
||||
return serializedSingle.get(snapshot).handle(this::deserializeSink).switchIfEmpty(defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> set(A value) {
|
||||
return serializedSingle.set(serialize(value));
|
||||
return Mono
|
||||
.fromCallable(() -> serialize(value))
|
||||
.flatMap(serializedSingle::set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<A> setAndGetPrevious(A value) {
|
||||
return serializedSingle.setAndGetPrevious(serialize(value)).map(this::deserialize);
|
||||
return Mono
|
||||
.fromCallable(() -> serialize(value))
|
||||
.flatMap(serializedSingle::setAndGetPrevious)
|
||||
.handle(this::deserializeSink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Boolean> setAndGetChanged(A value) {
|
||||
return serializedSingle.setAndGetChanged(serialize(value)).single();
|
||||
return Mono
|
||||
.fromCallable(() -> serialize(value))
|
||||
.flatMap(serializedSingle::setAndGetChanged)
|
||||
.single();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<A> update(Function<@Nullable A, @Nullable A> updater,
|
||||
public Mono<A> update(SerializationFunction<@Nullable A, @Nullable A> updater,
|
||||
UpdateReturnMode updateReturnMode,
|
||||
boolean existsAlmostCertainly) {
|
||||
return serializedSingle.update(oldValue -> {
|
||||
@ -58,11 +78,11 @@ public class DatabaseSingleMapped<A, B> implements DatabaseStageEntry<A> {
|
||||
} else {
|
||||
return this.serialize(result);
|
||||
}
|
||||
}, updateReturnMode, existsAlmostCertainly).map(this::deserialize);
|
||||
}, updateReturnMode, existsAlmostCertainly).handle(this::deserializeSink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Delta<A>> updateAndGetDelta(Function<@Nullable A, @Nullable A> updater,
|
||||
public Mono<Delta<A>> updateAndGetDelta(SerializationFunction<@Nullable A, @Nullable A> updater,
|
||||
boolean existsAlmostCertainly) {
|
||||
return serializedSingle.updateAndGetDelta(oldValue -> {
|
||||
var result = updater.apply(oldValue == null ? null : this.deserialize(oldValue));
|
||||
@ -81,7 +101,7 @@ public class DatabaseSingleMapped<A, B> implements DatabaseStageEntry<A> {
|
||||
|
||||
@Override
|
||||
public Mono<A> clearAndGetPrevious() {
|
||||
return serializedSingle.clearAndGetPrevious().map(this::deserialize);
|
||||
return serializedSingle.clearAndGetPrevious().handle(this::deserializeSink);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -120,12 +140,12 @@ public class DatabaseSingleMapped<A, B> implements DatabaseStageEntry<A> {
|
||||
}
|
||||
|
||||
//todo: temporary wrapper. convert the whole class to buffers
|
||||
private A deserialize(B bytes) {
|
||||
private A deserialize(B bytes) throws SerializationException {
|
||||
return serializer.deserialize(bytes);
|
||||
}
|
||||
|
||||
//todo: temporary wrapper. convert the whole class to buffers
|
||||
private B serialize(A bytes) {
|
||||
private B serialize(A bytes) throws SerializationException {
|
||||
return serializer.serialize(bytes);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import it.cavallium.dbengine.client.CompositeSnapshot;
|
||||
import it.cavallium.dbengine.database.Delta;
|
||||
import it.cavallium.dbengine.database.LLUtils;
|
||||
import it.cavallium.dbengine.database.UpdateReturnMode;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationFunction;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -44,7 +45,7 @@ public interface DatabaseStage<T> extends DatabaseStageWithEntry<T> {
|
||||
.switchIfEmpty(Mono.fromSupplier(() -> value != null));
|
||||
}
|
||||
|
||||
default Mono<T> update(Function<@Nullable T, @Nullable T> updater,
|
||||
default Mono<T> update(SerializationFunction<@Nullable T, @Nullable T> updater,
|
||||
UpdateReturnMode updateReturnMode,
|
||||
boolean existsAlmostCertainly) {
|
||||
return this
|
||||
@ -52,14 +53,14 @@ public interface DatabaseStage<T> extends DatabaseStageWithEntry<T> {
|
||||
.transform(prev -> LLUtils.resolveDelta(prev, updateReturnMode));
|
||||
}
|
||||
|
||||
default Mono<T> update(Function<@Nullable T, @Nullable T> updater, UpdateReturnMode updateReturnMode) {
|
||||
default Mono<T> update(SerializationFunction<@Nullable T, @Nullable T> updater, UpdateReturnMode updateReturnMode) {
|
||||
return update(updater, updateReturnMode, false);
|
||||
}
|
||||
|
||||
Mono<Delta<T>> updateAndGetDelta(Function<@Nullable T, @Nullable T> updater,
|
||||
Mono<Delta<T>> updateAndGetDelta(SerializationFunction<@Nullable T, @Nullable T> updater,
|
||||
boolean existsAlmostCertainly);
|
||||
|
||||
default Mono<Delta<T>> updateAndGetDelta(Function<@Nullable T, @Nullable T> updater) {
|
||||
default Mono<Delta<T>> updateAndGetDelta(SerializationFunction<@Nullable T, @Nullable T> updater) {
|
||||
return updateAndGetDelta(updater, false);
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,9 @@ import it.cavallium.dbengine.database.KeyOperationResult;
|
||||
import it.cavallium.dbengine.database.LLUtils;
|
||||
import it.cavallium.dbengine.database.UpdateMode;
|
||||
import it.cavallium.dbengine.database.UpdateReturnMode;
|
||||
import it.cavallium.dbengine.database.serialization.BiSerializationFunction;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationException;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationFunction;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@ -58,7 +61,7 @@ public interface DatabaseStageMap<T, U, US extends DatabaseStage<U>> extends Dat
|
||||
default Mono<U> updateValue(T key,
|
||||
UpdateReturnMode updateReturnMode,
|
||||
boolean existsAlmostCertainly,
|
||||
Function<@Nullable U, @Nullable U> updater) {
|
||||
SerializationFunction<@Nullable U, @Nullable U> updater) {
|
||||
return Mono.usingWhen(
|
||||
this.at(null, key).single(),
|
||||
stage -> stage.update(updater, updateReturnMode, existsAlmostCertainly),
|
||||
@ -66,7 +69,8 @@ public interface DatabaseStageMap<T, U, US extends DatabaseStage<U>> extends Dat
|
||||
);
|
||||
}
|
||||
|
||||
default <X> Flux<ExtraKeyOperationResult<T, X>> updateMulti(Flux<Tuple2<T, X>> entries, BiFunction<@Nullable U, X, @Nullable U> updater) {
|
||||
default <X> Flux<ExtraKeyOperationResult<T, X>> updateMulti(Flux<Tuple2<T, X>> entries,
|
||||
BiSerializationFunction<@Nullable U, X, @Nullable U> updater) {
|
||||
return entries
|
||||
.flatMapSequential(entry -> this
|
||||
.updateValue(entry.getT1(), prevValue -> updater.apply(prevValue, entry.getT2()))
|
||||
@ -74,21 +78,21 @@ public interface DatabaseStageMap<T, U, US extends DatabaseStage<U>> extends Dat
|
||||
);
|
||||
}
|
||||
|
||||
default Mono<U> updateValue(T key, UpdateReturnMode updateReturnMode, Function<@Nullable U, @Nullable U> updater) {
|
||||
default Mono<U> updateValue(T key, UpdateReturnMode updateReturnMode, SerializationFunction<@Nullable U, @Nullable U> updater) {
|
||||
return updateValue(key, updateReturnMode, false, updater);
|
||||
}
|
||||
|
||||
default Mono<Boolean> updateValue(T key, Function<@Nullable U, @Nullable U> updater) {
|
||||
default Mono<Boolean> updateValue(T key, SerializationFunction<@Nullable U, @Nullable U> updater) {
|
||||
return updateValueAndGetDelta(key, false, updater).map(LLUtils::isDeltaChanged).single();
|
||||
}
|
||||
|
||||
default Mono<Boolean> updateValue(T key, boolean existsAlmostCertainly, Function<@Nullable U, @Nullable U> updater) {
|
||||
default Mono<Boolean> updateValue(T key, boolean existsAlmostCertainly, SerializationFunction<@Nullable U, @Nullable U> updater) {
|
||||
return updateValueAndGetDelta(key, existsAlmostCertainly, updater).map(LLUtils::isDeltaChanged).single();
|
||||
}
|
||||
|
||||
default Mono<Delta<U>> updateValueAndGetDelta(T key,
|
||||
boolean existsAlmostCertainly,
|
||||
Function<@Nullable U, @Nullable U> updater) {
|
||||
SerializationFunction<@Nullable U, @Nullable U> updater) {
|
||||
return Mono.usingWhen(
|
||||
this.at(null, key).single(),
|
||||
stage -> stage.updateAndGetDelta(updater, existsAlmostCertainly),
|
||||
@ -96,7 +100,7 @@ public interface DatabaseStageMap<T, U, US extends DatabaseStage<U>> extends Dat
|
||||
);
|
||||
}
|
||||
|
||||
default Mono<Delta<U>> updateValueAndGetDelta(T key, Function<@Nullable U, @Nullable U> updater) {
|
||||
default Mono<Delta<U>> updateValueAndGetDelta(T key, SerializationFunction<@Nullable U, @Nullable U> updater) {
|
||||
return updateValueAndGetDelta(key, false, updater);
|
||||
}
|
||||
|
||||
@ -221,7 +225,7 @@ public interface DatabaseStageMap<T, U, US extends DatabaseStage<U>> extends Dat
|
||||
}
|
||||
|
||||
@Override
|
||||
default Mono<Delta<Map<T, U>>> updateAndGetDelta(Function<@Nullable Map<T, U>, @Nullable Map<T, U>> updater,
|
||||
default Mono<Delta<Map<T, U>>> updateAndGetDelta(SerializationFunction<@Nullable Map<T, U>, @Nullable Map<T, U>> updater,
|
||||
boolean existsAlmostCertainly) {
|
||||
return this
|
||||
.getUpdateMode()
|
||||
@ -236,11 +240,15 @@ public interface DatabaseStageMap<T, U, US extends DatabaseStage<U>> extends Dat
|
||||
if (v.isEmpty()) {
|
||||
v = null;
|
||||
}
|
||||
var result = updater.apply(v);
|
||||
if (result != null && result.isEmpty()) {
|
||||
result = null;
|
||||
try {
|
||||
var result = updater.apply(v);
|
||||
if (result != null && result.isEmpty()) {
|
||||
result = null;
|
||||
}
|
||||
sink.next(Tuples.of(Optional.ofNullable(v), Optional.ofNullable(result)));
|
||||
} catch (SerializationException ex) {
|
||||
sink.error(ex);
|
||||
}
|
||||
sink.next(Tuples.of(Optional.ofNullable(v), Optional.ofNullable(result)));
|
||||
})
|
||||
.flatMap(result -> Mono
|
||||
.justOrEmpty(result.getT2())
|
||||
|
@ -3,6 +3,7 @@ package it.cavallium.dbengine.database.collections;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import it.cavallium.dbengine.database.LLUtils;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationException;
|
||||
import it.cavallium.dbengine.database.serialization.Serializer;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@ -23,7 +24,7 @@ class ValueWithHashSerializer<X, Y> implements Serializer<Entry<X, Y>, ByteBuf>
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Entry<X, Y> deserialize(@NotNull ByteBuf serialized) {
|
||||
public @NotNull Entry<X, Y> deserialize(@NotNull ByteBuf serialized) throws SerializationException {
|
||||
try {
|
||||
X deserializedKey = keySuffixSerializer.deserialize(serialized.retain());
|
||||
Y deserializedValue = valueSerializer.deserialize(serialized.retain());
|
||||
@ -34,7 +35,7 @@ class ValueWithHashSerializer<X, Y> implements Serializer<Entry<X, Y>, ByteBuf>
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ByteBuf serialize(@NotNull Entry<X, Y> deserialized) {
|
||||
public @NotNull ByteBuf serialize(@NotNull Entry<X, Y> deserialized) throws SerializationException {
|
||||
ByteBuf keySuffix = keySuffixSerializer.serialize(deserialized.getKey());
|
||||
try {
|
||||
ByteBuf value = valueSerializer.serialize(deserialized.getValue());
|
||||
|
@ -2,6 +2,7 @@ package it.cavallium.dbengine.database.collections;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationException;
|
||||
import it.cavallium.dbengine.database.serialization.Serializer;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArraySet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
@ -23,7 +24,7 @@ class ValuesSetSerializer<X> implements Serializer<ObjectArraySet<X>, ByteBuf> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ObjectArraySet<X> deserialize(@NotNull ByteBuf serialized) {
|
||||
public @NotNull ObjectArraySet<X> deserialize(@NotNull ByteBuf serialized) throws SerializationException {
|
||||
try {
|
||||
int entriesLength = serialized.readInt();
|
||||
ArrayList<X> deserializedElements = new ArrayList<>(entriesLength);
|
||||
@ -38,18 +39,18 @@ class ValuesSetSerializer<X> implements Serializer<ObjectArraySet<X>, ByteBuf> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ByteBuf serialize(@NotNull ObjectArraySet<X> deserialized) {
|
||||
public @NotNull ByteBuf serialize(@NotNull ObjectArraySet<X> deserialized) throws SerializationException {
|
||||
ByteBuf output = allocator.buffer();
|
||||
try {
|
||||
output.writeInt(deserialized.size());
|
||||
deserialized.forEach((entry) -> {
|
||||
for (X entry : deserialized) {
|
||||
ByteBuf serialized = entrySerializer.serialize(entry);
|
||||
try {
|
||||
output.writeBytes(serialized);
|
||||
} finally {
|
||||
serialized.release();
|
||||
}
|
||||
});
|
||||
}
|
||||
return output.retain();
|
||||
} finally {
|
||||
output.release();
|
||||
|
@ -18,6 +18,8 @@ import it.cavallium.dbengine.database.LLUtils;
|
||||
import it.cavallium.dbengine.database.RepeatedElementList;
|
||||
import it.cavallium.dbengine.database.UpdateMode;
|
||||
import it.cavallium.dbengine.database.UpdateReturnMode;
|
||||
import it.cavallium.dbengine.database.serialization.BiSerializationFunction;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationFunction;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -567,7 +569,7 @@ public class LLLocalDictionary implements LLDictionary {
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Override
|
||||
public Mono<ByteBuf> update(Mono<ByteBuf> keyMono,
|
||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||
SerializationFunction<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||
UpdateReturnMode updateReturnMode,
|
||||
boolean existsAlmostCertainly) {
|
||||
return Mono.usingWhen(keyMono,
|
||||
@ -700,7 +702,7 @@ public class LLLocalDictionary implements LLDictionary {
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Override
|
||||
public Mono<Delta<ByteBuf>> updateAndGetDelta(Mono<ByteBuf> keyMono,
|
||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||
SerializationFunction<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||
boolean existsAlmostCertainly) {
|
||||
return Mono.usingWhen(keyMono,
|
||||
key -> this.runOnDb(() -> {
|
||||
@ -1111,7 +1113,7 @@ public class LLLocalDictionary implements LLDictionary {
|
||||
|
||||
@Override
|
||||
public <X> Flux<ExtraKeyOperationResult<ByteBuf, X>> updateMulti(Flux<Tuple2<ByteBuf, X>> entries,
|
||||
BiFunction<ByteBuf, X, ByteBuf> updateFunction) {
|
||||
BiSerializationFunction<ByteBuf, X, ByteBuf> updateFunction) {
|
||||
return entries
|
||||
.buffer(Math.min(MULTI_GET_WINDOW, CAPPED_WRITE_BATCH_CAP))
|
||||
.flatMapSequential(ew -> Flux
|
||||
|
@ -11,6 +11,9 @@ import it.cavallium.dbengine.database.LLRange;
|
||||
import it.cavallium.dbengine.database.LLSnapshot;
|
||||
import it.cavallium.dbengine.database.LLUtils;
|
||||
import it.cavallium.dbengine.database.UpdateMode;
|
||||
import it.cavallium.dbengine.database.serialization.BiSerializationFunction;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationException;
|
||||
import it.cavallium.dbengine.database.serialization.SerializationFunction;
|
||||
import it.unimi.dsi.fastutil.bytes.ByteList;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
@ -165,7 +168,7 @@ public class LLMemoryDictionary implements LLDictionary {
|
||||
|
||||
@Override
|
||||
public Mono<Delta<ByteBuf>> updateAndGetDelta(Mono<ByteBuf> keyMono,
|
||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||
SerializationFunction<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||
boolean existsAlmostCertainly) {
|
||||
return Mono.usingWhen(keyMono,
|
||||
key -> Mono.fromCallable(() -> {
|
||||
@ -174,7 +177,12 @@ public class LLMemoryDictionary implements LLDictionary {
|
||||
if (old != null) {
|
||||
oldRef.set(kk(old));
|
||||
}
|
||||
var v = updater.apply(old != null ? kk(old) : null);
|
||||
ByteBuf v = null;
|
||||
try {
|
||||
v = updater.apply(old != null ? kk(old) : null);
|
||||
} catch (SerializationException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
try {
|
||||
return k(v);
|
||||
} finally {
|
||||
@ -258,7 +266,7 @@ public class LLMemoryDictionary implements LLDictionary {
|
||||
|
||||
@Override
|
||||
public <X> Flux<ExtraKeyOperationResult<ByteBuf, X>> updateMulti(Flux<Tuple2<ByteBuf, X>> entries,
|
||||
BiFunction<ByteBuf, X, ByteBuf> updateFunction) {
|
||||
BiSerializationFunction<ByteBuf, X, ByteBuf> updateFunction) {
|
||||
return Flux.error(new UnsupportedOperationException("Not implemented"));
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
package it.cavallium.dbengine.database.serialization;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface BiSerializationFunction<T1, T2, U> {
|
||||
|
||||
U apply(T1 argument1, T2 argument2) throws SerializationException;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package it.cavallium.dbengine.database.serialization;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
|
||||
public class SerializationException extends Exception {
|
||||
|
||||
public SerializationException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public SerializationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SerializationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SerializationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package it.cavallium.dbengine.database.serialization;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SerializationFunction<T, U> {
|
||||
|
||||
U apply(T argument) throws SerializationException;
|
||||
}
|
@ -9,9 +9,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface Serializer<A, B> {
|
||||
|
||||
@NotNull A deserialize(@NotNull B serialized);
|
||||
@NotNull A deserialize(@NotNull B serialized) throws SerializationException;
|
||||
|
||||
@NotNull B serialize(@NotNull A deserialized);
|
||||
@NotNull B serialize(@NotNull A deserialized) throws SerializationException;
|
||||
|
||||
Serializer<ByteBuf, ByteBuf> NOOP_SERIALIZER = new Serializer<>() {
|
||||
@Override
|
||||
|
@ -8,7 +8,6 @@ import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.PooledByteBufAllocator;
|
||||
import java.io.NotSerializableException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.apache.commons.lang3.SerializationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ -53,7 +52,7 @@ public interface SerializerFixedBinaryLength<A, B> extends Serializer<A, B> {
|
||||
static SerializerFixedBinaryLength<String, ByteBuf> utf8(ByteBufAllocator allocator, int length) {
|
||||
return new SerializerFixedBinaryLength<>() {
|
||||
@Override
|
||||
public @NotNull String deserialize(@NotNull ByteBuf serialized) {
|
||||
public @NotNull String deserialize(@NotNull ByteBuf serialized) throws SerializationException {
|
||||
try {
|
||||
if (serialized.readableBytes() != getSerializedBinaryLength()) {
|
||||
throw new SerializationException(
|
||||
@ -69,7 +68,7 @@ public interface SerializerFixedBinaryLength<A, B> extends Serializer<A, B> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ByteBuf serialize(@NotNull String deserialized) {
|
||||
public @NotNull ByteBuf serialize(@NotNull String deserialized) throws SerializationException {
|
||||
// UTF-8 uses max. 3 bytes per char, so calculate the worst case.
|
||||
ByteBuf buf = allocator.buffer(ByteBufUtil.utf8MaxBytes(deserialized));
|
||||
try {
|
||||
|
Loading…
Reference in New Issue
Block a user