Fix more possible leaks

This commit is contained in:
Andrea Cavalli 2022-05-21 01:06:55 +02:00
parent 18d5ddf6e1
commit 5c4519552d
14 changed files with 184 additions and 202 deletions

View File

@ -50,12 +50,12 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
private final Serializer<U> valueSerializer;
protected DatabaseMapDictionary(LLDictionary dictionary,
@Nullable Buffer prefixKey,
@Nullable BufSupplier prefixKeySupplier,
SerializerFixedBinaryLength<T> keySuffixSerializer,
Serializer<U> valueSerializer,
Runnable onClose) {
// Do not retain or release or use the prefixKey here
super(dictionary, prefixKey, keySuffixSerializer, new SubStageGetterSingle<>(valueSerializer), 0, onClose);
super(dictionary, prefixKeySupplier, keySuffixSerializer, new SubStageGetterSingle<>(valueSerializer), 0, onClose);
this.valueSerializer = valueSerializer;
}
@ -67,11 +67,11 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
}
public static <T, U> DatabaseMapDictionary<T, U> tail(LLDictionary dictionary,
@Nullable Buffer prefixKey,
@Nullable BufSupplier prefixKeySupplier,
SerializerFixedBinaryLength<T> keySuffixSerializer,
Serializer<U> valueSerializer,
Runnable onClose) {
return new DatabaseMapDictionary<>(dictionary, prefixKey, keySuffixSerializer, valueSerializer, onClose);
return new DatabaseMapDictionary<>(dictionary, prefixKeySupplier, keySuffixSerializer, valueSerializer, onClose);
}
public static <K, V> Flux<Entry<K, V>> getLeavesFrom(DatabaseMapDictionary<K, V> databaseMapDictionary,
@ -134,17 +134,19 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
if (exMessage != null && exMessage.contains("read 0 to 0, write 0 to ")) {
var totalZeroBytesErrors = this.totalZeroBytesErrors.incrementAndGet();
if (totalZeroBytesErrors < 512 || totalZeroBytesErrors % 10000 == 0) {
try (var keySuffixBytes = serializeKeySuffixToKey(keySuffix)) {
LOG.error(
"Unexpected zero-bytes value at "
+ dictionary.getDatabaseName() + ":" + dictionary.getColumnName()
+ ":" + LLUtils.toStringSafe(this.keyPrefix) + ":" + keySuffix
+ "(" + LLUtils.toStringSafe(keySuffixBytes) + ") total=" + totalZeroBytesErrors);
} catch (SerializationException e) {
LOG.error(
"Unexpected zero-bytes value at " + dictionary.getDatabaseName() + ":" + dictionary.getColumnName()
+ ":" + LLUtils.toStringSafe(this.keyPrefix) + ":" + keySuffix + "(?) total="
+ totalZeroBytesErrors);
try (var keyPrefix = keyPrefixSupplier.get()) {
try (var keySuffixBytes = serializeKeySuffixToKey(keySuffix)) {
LOG.error(
"Unexpected zero-bytes value at "
+ dictionary.getDatabaseName() + ":" + dictionary.getColumnName()
+ ":" + LLUtils.toStringSafe(keyPrefix) + ":" + keySuffix
+ "(" + LLUtils.toStringSafe(keySuffixBytes) + ") total=" + totalZeroBytesErrors);
} catch (SerializationException e) {
LOG.error(
"Unexpected zero-bytes value at " + dictionary.getDatabaseName() + ":" + dictionary.getColumnName()
+ ":" + LLUtils.toStringSafe(keyPrefix) + ":" + keySuffix + "(?) total="
+ totalZeroBytesErrors);
}
}
}
return null;
@ -169,8 +171,8 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
private Buffer serializeKeySuffixToKey(T keySuffix) throws SerializationException {
Buffer keyBuf;
if (keyPrefix != null) {
keyBuf = keyPrefix.copy();
if (keyPrefixSupplier != null) {
keyBuf = keyPrefixSupplier.get();
} else {
keyBuf = this.dictionary.getAllocator().allocate(keyPrefixLength + keySuffixLength + keyExtLength);
}
@ -188,11 +190,8 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
private Buffer toKey(Buffer suffixKey) {
assert suffixKeyLengthConsistency(suffixKey.readableBytes());
if (keyPrefix != null && keyPrefix.readableBytes() > 0) {
var result = LLUtils.compositeBuffer(dictionary.getAllocator(),
LLUtils.copy(dictionary.getAllocator(), keyPrefix),
suffixKey.send()
);
if (keyPrefixSupplier != null) {
var result = LLUtils.compositeBuffer(dictionary.getAllocator(), keyPrefixSupplier.get().send(), suffixKey.send());
try {
assert result.readableBytes() == keyPrefixLength + keySuffixLength + keyExtLength;
return result;
@ -489,9 +488,8 @@ public class DatabaseMapDictionary<T, U> extends DatabaseMapDictionaryDeep<T, U,
if (key == null) {
return null;
}
var keyWithoutExtBuf = keyPrefix == null ? alloc.allocate(keySuffixLength + keyExtLength)
// todo: use a read-only copy
: keyPrefix.copy();
var keyWithoutExtBuf =
keyPrefixSupplier == null ? alloc.allocate(keySuffixLength + keyExtLength) : keyPrefixSupplier.get();
try {
keyWithoutExtBuf.ensureWritable(keySuffixLength + keyExtLength);
serializeSuffix(key, keyWithoutExtBuf);

View File

@ -6,10 +6,10 @@ import io.netty5.buffer.api.DefaultBufferAllocators;
import io.netty5.buffer.api.Drop;
import io.netty5.buffer.api.Owned;
import io.netty5.buffer.api.Resource;
import io.netty5.buffer.api.Send;
import io.netty5.buffer.api.internal.ResourceSupport;
import it.cavallium.dbengine.client.BadBlock;
import it.cavallium.dbengine.client.CompositeSnapshot;
import it.cavallium.dbengine.database.BufSupplier;
import it.cavallium.dbengine.database.LLDictionary;
import it.cavallium.dbengine.database.LLDictionaryResultType;
import it.cavallium.dbengine.database.LLRange;
@ -24,7 +24,6 @@ import it.cavallium.dbengine.database.serialization.Serializer;
import it.cavallium.dbengine.database.serialization.SerializerFixedBinaryLength;
import it.unimi.dsi.fastutil.objects.Object2ObjectSortedMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
@ -56,19 +55,12 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> extend
LOG.error("Failed to close range", ex);
}
try {
if (obj.keyPrefix != null) {
obj.keyPrefix.close();
if (obj.keyPrefixSupplier != null) {
obj.keyPrefixSupplier.close();
}
} catch (Throwable ex) {
LOG.error("Failed to close keyPrefix", ex);
}
try {
if (obj.keySuffixAndExtZeroBuffer != null) {
obj.keySuffixAndExtZeroBuffer.close();
}
} catch (Throwable ex) {
LOG.error("Failed to close keySuffixAndExtZeroBuffer", ex);
}
try {
if (obj.onClose != null) {
obj.onClose.run();
@ -100,8 +92,7 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> extend
protected final Mono<LLRange> rangeMono;
protected RangeSupplier rangeSupplier;
protected Buffer keyPrefix;
protected Buffer keySuffixAndExtZeroBuffer;
protected BufSupplier keyPrefixSupplier;
protected Runnable onClose;
private static void incrementPrefix(Buffer prefix, int prefixLength) {
@ -199,73 +190,70 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> extend
}
public static <T, U, US extends DatabaseStage<U>> DatabaseMapDictionaryDeep<T, U, US> deepIntermediate(
LLDictionary dictionary, Buffer prefixKey, SerializerFixedBinaryLength<T> keySuffixSerializer,
LLDictionary dictionary, BufSupplier prefixKey, SerializerFixedBinaryLength<T> keySuffixSerializer,
SubStageGetter<U, US> subStageGetter, int keyExtLength, Runnable onClose) {
return new DatabaseMapDictionaryDeep<>(dictionary, prefixKey, keySuffixSerializer, subStageGetter,
keyExtLength, onClose);
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected DatabaseMapDictionaryDeep(LLDictionary dictionary, @Nullable Buffer prefixKey,
protected DatabaseMapDictionaryDeep(LLDictionary dictionary, @Nullable BufSupplier prefixKeySupplier,
SerializerFixedBinaryLength<T> keySuffixSerializer, SubStageGetter<U, US> subStageGetter, int keyExtLength,
Runnable onClose) {
super((Drop<DatabaseMapDictionaryDeep<T, U, US>>) (Drop) DROP);
try {
try (var prefixKey = prefixKeySupplier != null ? prefixKeySupplier.get() : null) {
this.dictionary = dictionary;
this.alloc = dictionary.getAllocator();
this.subStageGetter = subStageGetter;
this.keySuffixSerializer = keySuffixSerializer;
assert prefixKey == null || prefixKey.isAccessible();
this.keyPrefixLength = prefixKey == null ? 0 : prefixKey.readableBytes();
this.keyPrefixLength = prefixKey != null ? prefixKey.readableBytes() : 0;
this.keySuffixLength = keySuffixSerializer.getSerializedBinaryLength();
this.keyExtLength = keyExtLength;
this.keySuffixAndExtZeroBuffer = alloc
try (var keySuffixAndExtZeroBuffer = alloc
.allocate(keySuffixLength + keyExtLength)
.fill((byte) 0)
.writerOffset(keySuffixLength + keyExtLength)
.makeReadOnly();
assert keySuffixAndExtZeroBuffer.readableBytes() == keySuffixLength + keyExtLength :
"Key suffix and ext zero buffer readable length is not equal"
+ " to the key suffix length + key ext length. keySuffixAndExtZeroBuffer="
+ keySuffixAndExtZeroBuffer.readableBytes() + " keySuffixLength=" + keySuffixLength + " keyExtLength="
+ keyExtLength;
assert keySuffixAndExtZeroBuffer.readableBytes() > 0;
var firstKey = prefixKey == null ? alloc.allocate(keyPrefixLength + keySuffixLength + keyExtLength)
: prefixKey.copy();
try {
firstRangeKey(firstKey, keyPrefixLength, keySuffixAndExtZeroBuffer);
var nextRangeKey = prefixKey == null ? alloc.allocate(keyPrefixLength + keySuffixLength + keyExtLength)
: prefixKey.copy();
.makeReadOnly()) {
assert keySuffixAndExtZeroBuffer.readableBytes() == keySuffixLength + keyExtLength :
"Key suffix and ext zero buffer readable length is not equal"
+ " to the key suffix length + key ext length. keySuffixAndExtZeroBuffer="
+ keySuffixAndExtZeroBuffer.readableBytes() + " keySuffixLength=" + keySuffixLength + " keyExtLength="
+ keyExtLength;
assert keySuffixAndExtZeroBuffer.readableBytes() > 0;
var firstKey = prefixKey != null ? prefixKeySupplier.get()
: alloc.allocate(keyPrefixLength + keySuffixLength + keyExtLength);
try {
nextRangeKey(nextRangeKey, keyPrefixLength, keySuffixAndExtZeroBuffer);
assert prefixKey == null || prefixKey.isAccessible();
assert keyPrefixLength == 0 || !LLUtils.equals(firstKey, nextRangeKey);
if (keyPrefixLength == 0) {
this.rangeSupplier = RangeSupplier.ofOwned(LLRange.all());
firstKey.close();
firstRangeKey(firstKey, keyPrefixLength, keySuffixAndExtZeroBuffer);
var nextRangeKey = prefixKey != null ? prefixKeySupplier.get()
: alloc.allocate(keyPrefixLength + keySuffixLength + keyExtLength);
try {
nextRangeKey(nextRangeKey, keyPrefixLength, keySuffixAndExtZeroBuffer);
assert prefixKey == null || prefixKey.isAccessible();
assert keyPrefixLength == 0 || !LLUtils.equals(firstKey, nextRangeKey);
if (keyPrefixLength == 0) {
this.rangeSupplier = RangeSupplier.ofOwned(LLRange.all());
firstKey.close();
nextRangeKey.close();
} else {
this.rangeSupplier = RangeSupplier.ofOwned(LLRange.ofUnsafe(firstKey, nextRangeKey));
}
this.rangeMono = Mono.fromSupplier(rangeSupplier);
assert subStageKeysConsistency(keyPrefixLength + keySuffixLength + keyExtLength);
} catch (Throwable t) {
nextRangeKey.close();
} else {
this.rangeSupplier = RangeSupplier.ofOwned(LLRange.ofUnsafe(firstKey, nextRangeKey));
throw t;
}
this.rangeMono = Mono.fromSupplier(rangeSupplier);
assert subStageKeysConsistency(keyPrefixLength + keySuffixLength + keyExtLength);
} catch (Throwable t) {
nextRangeKey.close();
firstKey.close();
throw t;
}
} catch (Throwable t) {
firstKey.close();
throw t;
}
this.keyPrefix = prefixKey;
this.onClose = onClose;
} catch (Throwable t) {
if (this.keySuffixAndExtZeroBuffer != null && keySuffixAndExtZeroBuffer.isAccessible()) {
keySuffixAndExtZeroBuffer.close();
this.keyPrefixSupplier = prefixKeySupplier;
this.onClose = onClose;
}
if (prefixKey != null && prefixKey.isAccessible()) {
prefixKey.close();
} catch (Throwable t) {
if (prefixKeySupplier != null) {
prefixKeySupplier.close();
}
throw t;
}
@ -281,8 +269,7 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> extend
int keyExtLength,
Mono<LLRange> rangeMono,
RangeSupplier rangeSupplier,
Buffer keyPrefix,
Buffer keySuffixAndExtZeroBuffer,
BufSupplier keyPrefixSupplier,
Runnable onClose) {
super((Drop<DatabaseMapDictionaryDeep<T,U,US>>) (Drop) DROP);
this.dictionary = dictionary;
@ -295,8 +282,7 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> extend
this.rangeMono = rangeMono;
this.rangeSupplier = rangeSupplier;
this.keyPrefix = keyPrefix;
this.keySuffixAndExtZeroBuffer = keySuffixAndExtZeroBuffer;
this.keyPrefixSupplier = keyPrefixSupplier;
this.onClose = onClose;
}
@ -349,15 +335,18 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> extend
@Override
public Mono<US> at(@Nullable CompositeSnapshot snapshot, T keySuffix) {
var suffixKeyWithoutExt = Mono.fromCallable(() -> {
try (var keyWithoutExtBuf = keyPrefix == null
? alloc.allocate(keySuffixLength + keyExtLength) : keyPrefix.copy()) {
var keyWithoutExtBuf = keyPrefixSupplier == null
? alloc.allocate(keySuffixLength + keyExtLength) : keyPrefixSupplier.get();
try {
keyWithoutExtBuf.ensureWritable(keySuffixLength + keyExtLength);
serializeSuffix(keySuffix, keyWithoutExtBuf);
return keyWithoutExtBuf.send();
} catch (Throwable ex) {
keyWithoutExtBuf.close();
throw ex;
}
return keyWithoutExtBuf;
});
return this.subStageGetter
.subStage(dictionary, snapshot, suffixKeyWithoutExt);
return this.subStageGetter.subStage(dictionary, snapshot, suffixKeyWithoutExt);
}
@Override
@ -374,21 +363,17 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> extend
public Flux<SubStageEntry<T, US>> getAllStages(@Nullable CompositeSnapshot snapshot, boolean smallRange) {
return dictionary
.getRangeKeyPrefixes(resolveSnapshot(snapshot), rangeMono, keyPrefixLength + keySuffixLength, smallRange)
.flatMapSequential(groupKeyWithoutExtSend_ -> Mono.using(
() -> groupKeyWithoutExtSend_,
groupKeyWithoutExtSend -> this.subStageGetter
.subStage(dictionary, snapshot, Mono.fromCallable(() -> groupKeyWithoutExtSend.copy().send()))
.handle((us, sink) -> {
T deserializedSuffix;
try (var splittedGroupSuffix = splitGroupSuffix(groupKeyWithoutExtSend)) {
deserializedSuffix = this.deserializeSuffix(splittedGroupSuffix);
sink.next(new SubStageEntry<>(deserializedSuffix, us));
} catch (SerializationException ex) {
sink.error(ex);
}
}),
Resource::close
));
.flatMapSequential(groupKeyWithoutExt -> this.subStageGetter
.subStage(dictionary, snapshot, Mono.fromCallable(groupKeyWithoutExt::copy))
.map(us -> {
T deserializedSuffix;
try (var splittedGroupSuffix = splitGroupSuffix(groupKeyWithoutExt)) {
deserializedSuffix = this.deserializeSuffix(splittedGroupSuffix);
return new SubStageEntry<>(deserializedSuffix, us);
}
})
.doFinally(s -> groupKeyWithoutExt.close())
);
}
/**
@ -447,7 +432,6 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> extend
protected T deserializeSuffix(@NotNull Buffer keySuffix) throws SerializationException {
assert suffixKeyLengthConsistency(keySuffix.readableBytes());
var result = keySuffixSerializer.deserialize(keySuffix);
assert keyPrefix == null || keyPrefix.isAccessible();
return result;
}
@ -457,7 +441,6 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> extend
keySuffixSerializer.serialize(keySuffix, output);
var afterWriterOffset = output.writerOffset();
assert suffixKeyLengthConsistency(afterWriterOffset - beforeWriterOffset);
assert keyPrefix == null || keyPrefix.isAccessible();
}
@Override
@ -467,8 +450,7 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> extend
@Override
protected Owned<DatabaseMapDictionaryDeep<T, U, US>> prepareSend() {
var keyPrefix = this.keyPrefix.send();
var keySuffixAndExtZeroBuffer = this.keySuffixAndExtZeroBuffer.send();
var keyPrefixSupplier = this.keyPrefixSupplier;
var rangeSupplier = this.rangeSupplier;
var onClose = this.onClose;
return drop -> {
@ -481,8 +463,7 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> extend
keyExtLength,
rangeMono,
rangeSupplier,
keyPrefix.receive(),
keySuffixAndExtZeroBuffer.receive(),
keyPrefixSupplier,
onClose
);
drop.attach(instance);
@ -492,8 +473,7 @@ public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> extend
@Override
protected void makeInaccessible() {
this.keyPrefix = null;
this.keySuffixAndExtZeroBuffer = null;
this.keyPrefixSupplier = null;
this.rangeSupplier = null;
this.onClose = null;
}

View File

@ -7,6 +7,7 @@ import io.netty5.buffer.api.Owned;
import io.netty5.buffer.api.Send;
import it.cavallium.dbengine.client.BadBlock;
import it.cavallium.dbengine.client.CompositeSnapshot;
import it.cavallium.dbengine.database.BufSupplier;
import it.cavallium.dbengine.database.LLDictionary;
import it.cavallium.dbengine.database.LLUtils;
import io.netty5.buffer.api.internal.ResourceSupport;
@ -67,7 +68,7 @@ public class DatabaseMapDictionaryHashed<T, U, TH> extends
@SuppressWarnings({"unchecked", "rawtypes"})
protected DatabaseMapDictionaryHashed(LLDictionary dictionary,
@Nullable Buffer prefixKey,
@Nullable BufSupplier prefixKeySupplier,
Serializer<T> keySuffixSerializer,
Serializer<U> valueSerializer,
Function<T, TH> keySuffixHashFunction,
@ -82,7 +83,7 @@ public class DatabaseMapDictionaryHashed<T, U, TH> extends
= new ValueWithHashSerializer<>(keySuffixSerializer, valueSerializer);
ValuesSetSerializer<Entry<T, U>> valuesSetSerializer
= new ValuesSetSerializer<>(valueWithHashSerializer);
this.subDictionary = DatabaseMapDictionary.tail(dictionary, prefixKey, keySuffixHashSerializer,
this.subDictionary = DatabaseMapDictionary.tail(dictionary, prefixKeySupplier, keySuffixHashSerializer,
valuesSetSerializer, onClose);
this.keySuffixHashFunction = keySuffixHashFunction;
}
@ -117,14 +118,14 @@ public class DatabaseMapDictionaryHashed<T, U, TH> extends
}
public static <T, U, UH> DatabaseMapDictionaryHashed<T, U, UH> tail(LLDictionary dictionary,
@Nullable Buffer prefixKey,
@Nullable BufSupplier prefixKeySupplier,
Serializer<T> keySuffixSerializer,
Serializer<U> valueSerializer,
Function<T, UH> keySuffixHashFunction,
SerializerFixedBinaryLength<UH> keySuffixHashSerializer,
Runnable onClose) {
return new DatabaseMapDictionaryHashed<>(dictionary,
prefixKey,
prefixKeySupplier,
keySuffixSerializer,
valueSerializer,
keySuffixHashFunction,

View File

@ -80,13 +80,9 @@ public class DatabaseMapSingle<U> extends ResourceSupport<DatabaseStage<U>, Data
}
}
private void deserializeValue(Buffer value, SynchronousSink<U> sink) {
private U deserializeValue(Buffer value) {
try {
U deserializedValue;
try (value) {
deserializedValue = serializer.deserialize(value);
}
sink.next(deserializedValue);
return serializer.deserialize(value);
} catch (IndexOutOfBoundsException ex) {
var exMessage = ex.getMessage();
if (exMessage != null && exMessage.contains("read 0 to 0, write 0 to ")) {
@ -94,12 +90,12 @@ public class DatabaseMapSingle<U> extends ResourceSupport<DatabaseStage<U>, Data
LOG.error("Unexpected zero-bytes value at "
+ dictionary.getDatabaseName() + ":" + dictionary.getColumnName() + ":" + LLUtils.toStringSafe(key));
}
sink.complete();
return null;
} else {
sink.error(ex);
throw ex;
}
} catch (SerializationException ex) {
sink.error(ex);
throw ex;
}
}
@ -118,22 +114,24 @@ public class DatabaseMapSingle<U> extends ResourceSupport<DatabaseStage<U>, Data
@Override
public Mono<U> get(@Nullable CompositeSnapshot snapshot, boolean existsAlmostCertainly) {
return dictionary
.get(resolveSnapshot(snapshot), keyMono)
.handle(this::deserializeValue);
return Mono.usingWhen(dictionary.get(resolveSnapshot(snapshot), keyMono),
buf -> Mono.fromSupplier(() -> deserializeValue(buf)),
buf -> Mono.fromRunnable(buf::close)
);
}
@Override
public Mono<U> setAndGetPrevious(U value) {
return dictionary
.put(keyMono, Mono.fromCallable(() -> serializeValue(value)), LLDictionaryResultType.PREVIOUS_VALUE)
.handle(this::deserializeValue);
return Mono.usingWhen(dictionary
.put(keyMono, Mono.fromCallable(() -> serializeValue(value)), LLDictionaryResultType.PREVIOUS_VALUE),
buf -> Mono.fromSupplier(() -> deserializeValue(buf)),
buf -> Mono.fromRunnable(buf::close));
}
@Override
public Mono<U> update(SerializationFunction<@Nullable U, @Nullable U> updater,
UpdateReturnMode updateReturnMode) {
return dictionary
var resultMono = dictionary
.update(keyMono, (oldValueSer) -> {
U result;
if (oldValueSer == null) {
@ -147,8 +145,11 @@ public class DatabaseMapSingle<U> extends ResourceSupport<DatabaseStage<U>, Data
} else {
return serializeValue(result);
}
}, updateReturnMode)
.handle(this::deserializeValue);
}, updateReturnMode);
return Mono.usingWhen(resultMono,
result -> Mono.fromSupplier(() -> deserializeValue(result)),
result -> Mono.fromRunnable(result::close)
);
}
@Override
@ -172,9 +173,10 @@ public class DatabaseMapSingle<U> extends ResourceSupport<DatabaseStage<U>, Data
@Override
public Mono<U> clearAndGetPrevious() {
return dictionary
.remove(keyMono, LLDictionaryResultType.PREVIOUS_VALUE)
.handle(this::deserializeValue);
return Mono.usingWhen(dictionary.remove(keyMono, LLDictionaryResultType.PREVIOUS_VALUE),
result -> Mono.fromSupplier(() -> deserializeValue(result)),
result -> Mono.fromRunnable(result::close)
);
}
@Override

View File

@ -4,6 +4,7 @@ import io.netty5.buffer.api.Buffer;
import io.netty5.buffer.api.Drop;
import io.netty5.buffer.api.Send;
import it.cavallium.dbengine.client.CompositeSnapshot;
import it.cavallium.dbengine.database.BufSupplier;
import it.cavallium.dbengine.database.LLDictionary;
import it.cavallium.dbengine.database.LLUtils;
import it.cavallium.dbengine.database.collections.DatabaseEmpty.Nothing;
@ -19,10 +20,15 @@ import reactor.core.publisher.Mono;
public class DatabaseSetDictionary<T> extends DatabaseMapDictionary<T, Nothing> {
protected DatabaseSetDictionary(LLDictionary dictionary,
Buffer prefixKey,
BufSupplier prefixKeySupplier,
SerializerFixedBinaryLength<T> keySuffixSerializer,
Runnable onClose) {
super(dictionary, prefixKey, keySuffixSerializer, DatabaseEmpty.nothingSerializer(dictionary.getAllocator()), onClose);
super(dictionary,
prefixKeySupplier,
keySuffixSerializer,
DatabaseEmpty.nothingSerializer(dictionary.getAllocator()),
onClose
);
}
public static <T> DatabaseSetDictionary<T> simple(LLDictionary dictionary,
@ -32,10 +38,10 @@ public class DatabaseSetDictionary<T> extends DatabaseMapDictionary<T, Nothing>
}
public static <T> DatabaseSetDictionary<T> tail(LLDictionary dictionary,
Buffer prefixKey,
BufSupplier prefixKeySupplier,
SerializerFixedBinaryLength<T> keySuffixSerializer,
Runnable onClose) {
return new DatabaseSetDictionary<>(dictionary, prefixKey, keySuffixSerializer, onClose);
return new DatabaseSetDictionary<>(dictionary, prefixKeySupplier, keySuffixSerializer, onClose);
}
public Mono<Set<T>> getKeySet(@Nullable CompositeSnapshot snapshot) {

View File

@ -4,6 +4,7 @@ import io.netty5.buffer.api.Buffer;
import io.netty5.buffer.api.Drop;
import io.netty5.buffer.api.Send;
import it.cavallium.dbengine.client.CompositeSnapshot;
import it.cavallium.dbengine.database.BufSupplier;
import it.cavallium.dbengine.database.LLDictionary;
import it.cavallium.dbengine.database.LLUtils;
import it.cavallium.dbengine.database.collections.DatabaseEmpty.Nothing;
@ -22,13 +23,13 @@ import reactor.core.publisher.Mono;
public class DatabaseSetDictionaryHashed<T, TH> extends DatabaseMapDictionaryHashed<T, Nothing, TH> {
protected DatabaseSetDictionaryHashed(LLDictionary dictionary,
@Nullable Buffer prefixKey,
@Nullable BufSupplier prefixKeySupplier,
Serializer<T> keySuffixSerializer,
Function<T, TH> keySuffixHashFunction,
SerializerFixedBinaryLength<TH> keySuffixHashSerializer,
Runnable onClose) {
super(dictionary,
prefixKey,
prefixKeySupplier,
keySuffixSerializer,
DatabaseEmpty.nothingSerializer(dictionary.getAllocator()),
keySuffixHashFunction,
@ -52,13 +53,13 @@ public class DatabaseSetDictionaryHashed<T, TH> extends DatabaseMapDictionaryHas
}
public static <T, TH> DatabaseSetDictionaryHashed<T, TH> tail(LLDictionary dictionary,
@Nullable Buffer prefixKey,
@Nullable BufSupplier prefixKeySupplier,
Serializer<T> keySuffixSerializer,
Function<T, TH> keyHashFunction,
SerializerFixedBinaryLength<TH> keyHashSerializer,
Runnable onClose) {
return new DatabaseSetDictionaryHashed<>(dictionary,
prefixKey,
prefixKeySupplier,
keySuffixSerializer,
keyHashFunction,
keyHashSerializer,

View File

@ -11,6 +11,6 @@ public interface SubStageGetter<U, US extends DatabaseStage<U>> {
Mono<US> subStage(LLDictionary dictionary,
@Nullable CompositeSnapshot snapshot,
Mono<Send<Buffer>> prefixKey);
Mono<Buffer> prefixKey);
}

View File

@ -4,6 +4,7 @@ import io.netty5.buffer.api.Buffer;
import io.netty5.buffer.api.Resource;
import io.netty5.buffer.api.Send;
import it.cavallium.dbengine.client.CompositeSnapshot;
import it.cavallium.dbengine.database.BufSupplier;
import it.cavallium.dbengine.database.LLDictionary;
import it.cavallium.dbengine.database.LLUtils;
import it.cavallium.dbengine.database.serialization.Serializer;
@ -36,18 +37,15 @@ public class SubStageGetterHashMap<T, U, TH> implements
@Override
public Mono<DatabaseMapDictionaryHashed<T, U, TH>> subStage(LLDictionary dictionary,
@Nullable CompositeSnapshot snapshot,
Mono<Send<Buffer>> prefixKeyMono) {
return prefixKeyMono.map(prefixKeyToReceive -> {
var prefixKey = prefixKeyToReceive.receive();
return DatabaseMapDictionaryHashed.tail(dictionary,
prefixKey,
keySerializer,
valueSerializer,
keyHashFunction,
keyHashSerializer,
null
);
});
Mono<Buffer> prefixKeyMono) {
return prefixKeyMono.map(prefixKey -> DatabaseMapDictionaryHashed.tail(dictionary,
BufSupplier.ofOwned(prefixKey),
keySerializer,
valueSerializer,
keyHashFunction,
keyHashSerializer,
null
));
}
public int getKeyHashBinaryLength() {

View File

@ -4,6 +4,7 @@ import io.netty5.buffer.api.Buffer;
import io.netty5.buffer.api.Resource;
import io.netty5.buffer.api.Send;
import it.cavallium.dbengine.client.CompositeSnapshot;
import it.cavallium.dbengine.database.BufSupplier;
import it.cavallium.dbengine.database.LLDictionary;
import it.cavallium.dbengine.database.LLUtils;
import it.cavallium.dbengine.database.collections.DatabaseEmpty.Nothing;
@ -34,17 +35,14 @@ public class SubStageGetterHashSet<T, TH> implements
@Override
public Mono<DatabaseSetDictionaryHashed<T, TH>> subStage(LLDictionary dictionary,
@Nullable CompositeSnapshot snapshot,
Mono<Send<Buffer>> prefixKeyMono) {
return prefixKeyMono.map(prefixKeyToReceive -> {
var prefixKey = prefixKeyToReceive.receive();
return DatabaseSetDictionaryHashed.tail(dictionary,
prefixKey,
keySerializer,
keyHashFunction,
keyHashSerializer,
null
);
});
Mono<Buffer> prefixKeyMono) {
return prefixKeyMono.map(prefixKey -> DatabaseSetDictionaryHashed.tail(dictionary,
BufSupplier.ofOwned(prefixKey),
keySerializer,
keyHashFunction,
keyHashSerializer,
null
));
}
public int getKeyHashBinaryLength() {

View File

@ -1,15 +1,12 @@
package it.cavallium.dbengine.database.collections;
import io.netty5.buffer.api.Buffer;
import io.netty5.buffer.api.Resource;
import io.netty5.buffer.api.Send;
import it.cavallium.dbengine.client.CompositeSnapshot;
import it.cavallium.dbengine.database.BufSupplier;
import it.cavallium.dbengine.database.LLDictionary;
import it.cavallium.dbengine.database.LLUtils;
import it.cavallium.dbengine.database.serialization.Serializer;
import it.cavallium.dbengine.database.serialization.SerializerFixedBinaryLength;
import it.unimi.dsi.fastutil.objects.Object2ObjectSortedMap;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
import reactor.core.publisher.Mono;
@ -28,11 +25,13 @@ public class SubStageGetterMap<T, U> implements
@Override
public Mono<DatabaseMapDictionary<T, U>> subStage(LLDictionary dictionary,
@Nullable CompositeSnapshot snapshot,
Mono<Send<Buffer>> prefixKeyMono) {
return prefixKeyMono.map(prefixKeyToReceive -> {
var prefixKey = prefixKeyToReceive.receive();
return DatabaseMapDictionary.tail(dictionary, prefixKey, keySerializer, valueSerializer, null);
});
Mono<Buffer> prefixKeyMono) {
return prefixKeyMono.map(prefixKey -> DatabaseMapDictionary.tail(dictionary,
BufSupplier.ofOwned(prefixKey),
keySerializer,
valueSerializer,
null
));
}
public int getKeyBinaryLength() {

View File

@ -4,6 +4,7 @@ import io.netty5.buffer.api.Buffer;
import io.netty5.buffer.api.Resource;
import io.netty5.buffer.api.Send;
import it.cavallium.dbengine.client.CompositeSnapshot;
import it.cavallium.dbengine.database.BufSupplier;
import it.cavallium.dbengine.database.LLDictionary;
import it.cavallium.dbengine.database.LLUtils;
import it.cavallium.dbengine.database.serialization.SerializerFixedBinaryLength;
@ -42,17 +43,14 @@ public class SubStageGetterMapDeep<T, U, US extends DatabaseStage<U>> implements
@Override
public Mono<DatabaseMapDictionaryDeep<T, U, US>> subStage(LLDictionary dictionary,
@Nullable CompositeSnapshot snapshot,
Mono<Send<Buffer>> prefixKeyMono) {
return prefixKeyMono.map(prefixKeyToReceive -> {
var prefixKey = prefixKeyToReceive.receive();
return DatabaseMapDictionaryDeep.deepIntermediate(dictionary,
prefixKey,
keySerializer,
subStageGetter,
keyExtLength,
null
);
});
Mono<Buffer> prefixKeyMono) {
return prefixKeyMono.map(prefixKey -> DatabaseMapDictionaryDeep.deepIntermediate(dictionary,
BufSupplier.ofOwned(prefixKey),
keySerializer,
subStageGetter,
keyExtLength,
null
));
}
public int getKeyBinaryLength() {

View File

@ -4,6 +4,7 @@ import io.netty5.buffer.api.Buffer;
import io.netty5.buffer.api.Resource;
import io.netty5.buffer.api.Send;
import it.cavallium.dbengine.client.CompositeSnapshot;
import it.cavallium.dbengine.database.BufSupplier;
import it.cavallium.dbengine.database.LLDictionary;
import it.cavallium.dbengine.database.collections.DatabaseEmpty.Nothing;
import it.cavallium.dbengine.database.serialization.SerializerFixedBinaryLength;
@ -24,11 +25,12 @@ public class SubStageGetterSet<T> implements
@Override
public Mono<DatabaseSetDictionary<T>> subStage(LLDictionary dictionary,
@Nullable CompositeSnapshot snapshot,
Mono<Send<Buffer>> prefixKeyMono) {
return prefixKeyMono.map(prefixKeyToReceive -> {
var prefixKey = prefixKeyToReceive.receive();
return DatabaseSetDictionary.tail(dictionary, prefixKey, keySerializer, null);
});
Mono<Buffer> prefixKeyMono) {
return prefixKeyMono.map(prefixKey -> DatabaseSetDictionary.tail(dictionary,
BufSupplier.ofOwned(prefixKey),
keySerializer,
null
));
}
public int getKeyBinaryLength() {

View File

@ -20,8 +20,12 @@ public class SubStageGetterSingle<T> implements SubStageGetter<T, DatabaseStageE
@Override
public Mono<DatabaseStageEntry<T>> subStage(LLDictionary dictionary,
@Nullable CompositeSnapshot snapshot,
Mono<Send<Buffer>> keyPrefixMono) {
return keyPrefixMono.map(keyPrefix -> new DatabaseMapSingle<>(dictionary, BufSupplier.of(keyPrefix), serializer, null));
Mono<Buffer> keyPrefixMono) {
return keyPrefixMono.map(keyPrefix -> new DatabaseMapSingle<>(dictionary,
BufSupplier.ofOwned(keyPrefix),
serializer,
null
));
}
}

View File

@ -60,6 +60,7 @@ import org.rocksdb.Slice;
import org.rocksdb.Snapshot;
import org.rocksdb.WriteBatch;
import org.rocksdb.WriteOptions;
import reactor.core.Exceptions;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
@ -772,13 +773,7 @@ public class LLLocalDictionary implements LLDictionary {
}
private Flux<LLEntry> getRangeSingle(LLSnapshot snapshot, Mono<Buffer> keyMono) {
return Mono
.zip(keyMono, this.get(snapshot, keyMono))
.map(result -> LLEntry.of(
result.getT1().touch("get-range-single key"),
result.getT2().touch("get-range-single value")
))
.flux();
return Mono.zip(keyMono, this.get(snapshot, keyMono), LLEntry::of).flux();
}
private Flux<LLEntry> getRangeMulti(LLSnapshot snapshot,