CavalliumDBEngine/src/main/java/it/cavallium/dbengine/database/LLUtils.java

760 lines
22 KiB
Java
Raw Normal View History

2020-12-07 22:15:18 +01:00
package it.cavallium.dbengine.database;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
2021-08-31 09:14:46 +02:00
import io.netty.buffer.ByteBuf;
2021-08-29 23:18:03 +02:00
import io.netty.buffer.api.Buffer;
import io.netty.buffer.api.BufferAllocator;
import io.netty.buffer.api.CompositeBuffer;
import io.netty.buffer.api.Send;
import io.netty.util.IllegalReferenceCountException;
2021-08-22 21:23:22 +02:00
import it.cavallium.dbengine.database.serialization.SerializationException;
import it.cavallium.dbengine.database.serialization.SerializationFunction;
2021-01-30 22:14:48 +01:00
import it.cavallium.dbengine.lucene.RandomSortField;
2020-12-07 22:15:18 +01:00
import java.nio.ByteBuffer;
2021-08-29 23:18:03 +02:00
import java.nio.charset.Charset;
import java.util.ArrayList;
2021-05-28 16:04:59 +02:00
import java.util.Collection;
2020-12-07 22:15:18 +01:00
import java.util.List;
2021-08-22 21:23:22 +02:00
import java.util.Map;
2021-05-28 16:04:59 +02:00
import java.util.Map.Entry;
2021-05-08 03:09:00 +02:00
import java.util.Objects;
2021-08-28 22:42:51 +02:00
import java.util.Optional;
2021-08-22 19:52:19 +02:00
import java.util.concurrent.Callable;
2021-08-29 23:18:03 +02:00
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.ToIntFunction;
2020-12-07 22:15:18 +01:00
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FloatPoint;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.SortedNumericDocValuesField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.ScoreMode;
2020-12-07 22:15:18 +01:00
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.SortedNumericSortField;
import org.jetbrains.annotations.NotNull;
2020-12-07 22:15:18 +01:00
import org.jetbrains.annotations.Nullable;
import org.rocksdb.RocksDB;
2021-08-28 22:42:51 +02:00
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
2021-08-22 21:23:22 +02:00
import reactor.core.publisher.Flux;
2021-05-08 03:09:00 +02:00
import reactor.core.publisher.Mono;
2021-08-28 22:42:51 +02:00
import reactor.util.function.Tuple2;
import reactor.util.function.Tuple3;
@SuppressWarnings("unused")
2020-12-07 22:15:18 +01:00
public class LLUtils {
2021-08-28 22:42:51 +02:00
private static final Logger logger = LoggerFactory.getLogger(LLUtils.class);
2021-08-29 23:18:03 +02:00
private static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocateDirect(0);
2020-12-07 22:15:18 +01:00
private static final byte[] RESPONSE_TRUE = new byte[]{1};
private static final byte[] RESPONSE_FALSE = new byte[]{0};
private static final byte[] RESPONSE_TRUE_BUF = new byte[]{1};
private static final byte[] RESPONSE_FALSE_BUF = new byte[]{0};
2021-03-18 19:53:32 +01:00
public static final byte[][] LEXICONOGRAPHIC_ITERATION_SEEKS = new byte[256][1];
static {
for (int i1 = 0; i1 < 256; i1++) {
var b = LEXICONOGRAPHIC_ITERATION_SEEKS[i1];
b[0] = (byte) i1;
}
}
2020-12-07 22:15:18 +01:00
public static boolean responseToBoolean(byte[] response) {
return response[0] == 1;
}
2021-08-31 09:14:46 +02:00
public static boolean responseToBoolean(Send<Buffer> responseToReceive) {
try (var response = responseToReceive.receive()) {
assert response.readableBytes() == 1;
2021-08-29 23:18:03 +02:00
return response.getByte(response.readerOffset()) == 1;
}
}
2020-12-07 22:15:18 +01:00
public static byte[] booleanToResponse(boolean bool) {
return bool ? RESPONSE_TRUE : RESPONSE_FALSE;
}
2021-08-29 23:18:03 +02:00
public static Buffer booleanToResponseByteBuffer(BufferAllocator alloc, boolean bool) {
return alloc.allocate(1).writeByte(bool ? (byte) 1 : 0);
}
2020-12-07 22:15:18 +01:00
@Nullable
public static Sort toSort(@Nullable LLSort sort) {
if (sort == null) {
return null;
}
if (sort.getType() == LLSortType.LONG) {
return new Sort(new SortedNumericSortField(sort.getFieldName(), SortField.Type.LONG, sort.isReverse()));
} else if (sort.getType() == LLSortType.RANDOM) {
return new Sort(new RandomSortField());
} else if (sort.getType() == LLSortType.SCORE) {
return new Sort(SortField.FIELD_SCORE);
} else if (sort.getType() == LLSortType.DOC) {
return new Sort(SortField.FIELD_DOC);
2020-12-07 22:15:18 +01:00
}
return null;
}
public static ScoreMode toScoreMode(LLScoreMode scoreMode) {
2021-08-22 21:23:22 +02:00
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);
};
}
2020-12-07 22:15:18 +01:00
public static Term toTerm(LLTerm term) {
return new Term(term.getKey(), term.getValue());
}
public static Document toDocument(LLDocument document) {
Document d = new Document();
for (LLItem item : document.getItems()) {
d.add(LLUtils.toField(item));
}
return d;
}
2021-05-28 16:04:59 +02:00
public static Collection<Document> toDocuments(Collection<LLDocument> document) {
List<Document> d = new ArrayList<>(document.size());
2020-12-07 22:15:18 +01:00
for (LLDocument doc : document) {
d.add(LLUtils.toDocument(doc));
}
return d;
}
2021-05-28 16:04:59 +02:00
public static Collection<Document> toDocumentsFromEntries(Collection<Entry<LLTerm, LLDocument>> documentsList) {
ArrayList<Document> results = new ArrayList<>(documentsList.size());
for (Entry<LLTerm, LLDocument> entry : documentsList) {
results.add(LLUtils.toDocument(entry.getValue()));
}
return results;
}
2020-12-07 22:15:18 +01:00
public static Iterable<Term> toTerms(Iterable<LLTerm> terms) {
2021-05-28 16:04:59 +02:00
List<Term> d = new ArrayList<>();
2020-12-07 22:15:18 +01:00
for (LLTerm term : terms) {
d.add(LLUtils.toTerm(term));
}
return d;
}
private static IndexableField toField(LLItem item) {
2021-08-22 21:23:22 +02:00
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);
};
2020-12-07 22:15:18 +01:00
}
public static it.cavallium.dbengine.database.LLKeyScore toKeyScore(LLKeyScore hit) {
return new it.cavallium.dbengine.database.LLKeyScore(hit.docId(), hit.score(), hit.key());
2020-12-07 22:15:18 +01:00
}
2021-08-29 23:18:03 +02:00
public static String toStringSafe(Buffer key) {
try {
2021-08-29 23:18:03 +02:00
if (key.isAccessible()) {
return toString(key);
} else {
return "(released)";
}
} catch (IllegalReferenceCountException ex) {
return "(released)";
}
}
2021-08-29 23:18:03 +02:00
public static String toString(Buffer key) {
if (key == null) {
return "null";
} else {
2021-08-29 23:18:03 +02:00
int startIndex = key.readerOffset();
int iMax = key.readableBytes() - 1;
int iLimit = 128;
if (iMax <= -1) {
return "[]";
} else {
StringBuilder b = new StringBuilder();
b.append('[');
int i = 0;
while(true) {
b.append(key.getByte(startIndex + i));
if (i == iLimit) {
b.append("…");
}
if (i == iMax || i == iLimit) {
return b.append(']').toString();
}
b.append(", ");
++i;
}
}
}
}
2021-08-29 23:18:03 +02:00
public static boolean equals(Buffer a, Buffer b) {
if (a == null && b == null) {
return true;
} else if (a != null && b != null) {
2021-08-29 23:18:03 +02:00
var aCur = a.openCursor();
var bCur = b.openCursor();
if (aCur.bytesLeft() != bCur.bytesLeft()) {
return false;
}
while (aCur.readByte() && bCur.readByte()) {
if (aCur.getByte() != bCur.getByte()) {
return false;
}
}
return true;
} else {
return false;
}
}
2021-08-31 09:14:46 +02:00
/**
* Returns {@code true} if and only if the two specified buffers are
* identical to each other for {@code length} bytes starting at {@code aStartIndex}
* index for the {@code a} buffer and {@code bStartIndex} index for the {@code b} buffer.
* A more compact way to express this is:
* <p>
* {@code a[aStartIndex : aStartIndex + length] == b[bStartIndex : bStartIndex + length]}
*/
public static boolean equals(Buffer a, int aStartIndex, Buffer b, int bStartIndex, int length) {
var aCur = a.openCursor(aStartIndex, length);
var bCur = b.openCursor(bStartIndex, length);
if (aCur.bytesLeft() != bCur.bytesLeft()) {
return false;
}
while (aCur.readByte() && bCur.readByte()) {
if (aCur.getByte() != bCur.getByte()) {
return false;
}
}
return true;
}
2021-08-29 23:18:03 +02:00
public static byte[] toArray(Buffer key) {
byte[] array = new byte[key.readableBytes()];
key.copyInto(key.readerOffset(), array, 0, key.readableBytes());
return array;
}
2021-08-29 23:18:03 +02:00
public static List<byte[]> toArray(List<Buffer> input) {
List<byte[]> result = new ArrayList<>(input.size());
2021-08-29 23:18:03 +02:00
for (Buffer byteBuf : input) {
result.add(toArray(byteBuf));
}
return result;
}
2021-08-29 23:18:03 +02:00
public static int hashCode(Buffer buf) {
if (buf == null)
return 0;
int result = 1;
var cur = buf.openCursor();
while (cur.readByte()) {
var element = cur.getByte();
result = 31 * result + element;
}
return result;
}
2021-08-29 23:18:03 +02:00
/**
*
* @return null if size is equal to RocksDB.NOT_FOUND
*/
@Nullable
2021-08-29 23:18:03 +02:00
public static Buffer readNullableDirectNioBuffer(BufferAllocator alloc, ToIntFunction<ByteBuffer> reader) {
Buffer buffer = alloc.allocate(4096);
2021-05-02 19:18:15 +02:00
ByteBuffer nioBuffer;
int size;
do {
2021-08-29 23:18:03 +02:00
nioBuffer = LLUtils.toDirect(buffer);
nioBuffer.limit(nioBuffer.capacity());
assert nioBuffer.isDirect();
size = reader.applyAsInt(nioBuffer);
if (size != RocksDB.NOT_FOUND) {
if (size == nioBuffer.limit()) {
buffer.readerOffset(0).writerOffset(size);
return buffer;
} else {
assert size > nioBuffer.limit();
assert nioBuffer.limit() > 0;
buffer.ensureWritable(size);
2021-05-02 19:18:15 +02:00
}
}
} while (size != RocksDB.NOT_FOUND);
2021-08-29 23:18:03 +02:00
// Return null if size is equal to RocksDB.NOT_FOUND
return null;
}
@Nullable
2021-08-29 23:18:03 +02:00
public static ByteBuffer toDirectFast(Buffer buffer) {
int readableComponents = buffer.countReadableComponents();
if (readableComponents > 0) {
AtomicReference<ByteBuffer> byteBufferReference = new AtomicReference<>(null);
buffer.forEachReadable(0, (index, component) -> {
byteBufferReference.setPlain(component.readableBuffer());
return false;
});
ByteBuffer byteBuffer = byteBufferReference.getPlain();
if (byteBuffer != null && byteBuffer.isDirect()) {
byteBuffer.limit(buffer.writerOffset());
assert byteBuffer.isDirect();
assert byteBuffer.capacity() == buffer.capacity();
assert buffer.readerOffset() == byteBuffer.position();
assert byteBuffer.limit() - byteBuffer.position() == buffer.readableBytes();
return byteBuffer;
} else {
return null;
}
} else if (readableComponents == 0) {
return EMPTY_BYTE_BUFFER;
2021-05-02 19:18:15 +02:00
} else {
return null;
}
}
2021-08-29 23:18:03 +02:00
public static ByteBuffer toDirect(Buffer buffer) {
2021-05-02 19:18:15 +02:00
ByteBuffer result = toDirectFast(buffer);
if (result == null) {
2021-08-29 23:18:03 +02:00
throw new IllegalArgumentException("The supplied Buffer is not direct "
2021-05-02 19:18:15 +02:00
+ "(if it's a CompositeByteBuf it must be consolidated before)");
}
2021-05-02 19:18:15 +02:00
assert result.isDirect();
return result;
}
2021-05-03 21:41:51 +02:00
/*
2021-08-29 23:18:03 +02:00
public static Buffer toDirectCopy(Buffer buffer) {
try {
2021-08-29 23:18:03 +02:00
Buffer directCopyBuf = buffer.alloc().buffer(buffer.capacity(), buffer.maxCapacity());
directCopyBuf.writeBytes(buffer, 0, buffer.writerIndex());
return directCopyBuf;
} finally {
buffer.release();
}
}
2021-05-03 21:41:51 +02:00
*/
2021-08-29 23:18:03 +02:00
public static Buffer fromByteArray(BufferAllocator alloc, byte[] array) {
Buffer result = alloc.allocate(array.length);
2021-05-05 17:31:21 +02:00
result.writeBytes(array);
return result;
}
@NotNull
2021-08-29 23:18:03 +02:00
public static Buffer readDirectNioBuffer(BufferAllocator alloc, ToIntFunction<ByteBuffer> reader) {
var buffer = readNullableDirectNioBuffer(alloc, reader);
if (buffer == null) {
throw new IllegalStateException("A non-nullable buffer read operation tried to return a \"not found\" element");
}
return buffer;
}
2021-08-29 23:18:03 +02:00
public static Send<Buffer> compositeBuffer(BufferAllocator alloc, Send<Buffer> buffer) {
try (var composite = buffer.receive().compact()) {
assert composite.countReadableComponents() == 1 || composite.countReadableComponents() == 0;
return composite.send();
}
}
2021-08-29 23:18:03 +02:00
public static Send<Buffer> compositeBuffer(BufferAllocator alloc, Send<Buffer> buffer1, Send<Buffer> buffer2) {
try (buffer1) {
try (buffer2) {
try (var composite = CompositeBuffer.compose(alloc, buffer1, buffer2).compact()) {
assert composite.countReadableComponents() == 1 || composite.countReadableComponents() == 0;
return composite.send();
}
2021-05-02 19:18:15 +02:00
}
}
}
2021-08-29 23:18:03 +02:00
public static Send<Buffer> compositeBuffer(BufferAllocator alloc, Send<Buffer> buffer1, Send<Buffer> buffer2, Send<Buffer> buffer3) {
try (buffer1) {
try (buffer2) {
try (buffer3) {
try (var composite = CompositeBuffer.compose(alloc, buffer1, buffer2, buffer3).compact()) {
assert composite.countReadableComponents() == 1 || composite.countReadableComponents() == 0;
return composite.send();
}
}
2021-05-02 19:18:15 +02:00
}
}
}
2021-08-29 23:18:03 +02:00
public static Send<Buffer> compositeBuffer(BufferAllocator alloc, Send<Buffer>... buffers) {
2021-05-02 19:18:15 +02:00
try {
2021-08-29 23:18:03 +02:00
return switch (buffers.length) {
case 0 -> alloc.allocate(0).send();
case 1 -> compositeBuffer(alloc, buffers[0]);
case 2 -> compositeBuffer(alloc, buffers[0], buffers[1]);
case 3 -> compositeBuffer(alloc, buffers[0], buffers[1], buffers[2]);
default -> {
try (var composite = CompositeBuffer.compose(alloc, buffers).compact()) {
assert composite.countReadableComponents() == 1 || composite.countReadableComponents() == 0;
yield composite.send();
2021-05-02 19:18:15 +02:00
}
2021-08-29 23:18:03 +02:00
}
};
2021-05-02 19:18:15 +02:00
} finally {
2021-08-29 23:18:03 +02:00
for (Send<Buffer> buffer : buffers) {
buffer.close();
2021-05-02 19:18:15 +02:00
}
}
}
2021-05-08 03:09:00 +02:00
public static <T> Mono<T> resolveDelta(Mono<Delta<T>> prev, UpdateReturnMode updateReturnMode) {
return prev.handle((delta, sink) -> {
switch (updateReturnMode) {
2021-08-22 21:23:22 +02:00
case GET_NEW_VALUE -> {
2021-05-21 00:19:40 +02:00
var current = delta.current();
2021-05-08 03:09:00 +02:00
if (current != null) {
sink.next(current);
} else {
sink.complete();
}
2021-08-22 21:23:22 +02:00
}
case GET_OLD_VALUE -> {
2021-05-21 00:19:40 +02:00
var previous = delta.previous();
2021-05-08 03:09:00 +02:00
if (previous != null) {
sink.next(previous);
} else {
sink.complete();
}
2021-08-22 21:23:22 +02:00
}
case NOTHING -> sink.complete();
default -> sink.error(new IllegalStateException());
2021-05-08 03:09:00 +02:00
}
});
}
2021-08-29 23:18:03 +02:00
public static Mono<Send<Buffer>> resolveLLDelta(Mono<LLDelta> prev, UpdateReturnMode updateReturnMode) {
return prev.handle((delta, sink) -> {
try (delta) {
switch (updateReturnMode) {
case GET_NEW_VALUE -> {
var current = delta.current();
if (current != null) {
sink.next(current);
} else {
sink.complete();
}
}
case GET_OLD_VALUE -> {
var previous = delta.previous();
if (previous != null) {
sink.next(previous);
} else {
sink.complete();
}
}
case NOTHING -> sink.complete();
default -> sink.error(new IllegalStateException());
}
}
});
}
2021-08-22 21:23:22 +02:00
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);
2021-05-08 03:09:00 +02:00
}
});
}
2021-08-29 23:18:03 +02:00
public static <U> Mono<Delta<U>> mapLLDelta(Mono<LLDelta> mono,
SerializationFunction<@NotNull Send<Buffer>, @Nullable U> mapper) {
return mono.handle((delta, sink) -> {
try {
try (Send<Buffer> prev = delta.previous()) {
try (Send<Buffer> 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);
}
});
}
2021-05-08 03:09:00 +02:00
public static <R, V> boolean isDeltaChanged(Delta<V> delta) {
2021-05-21 00:19:40 +02:00
return !Objects.equals(delta.previous(), delta.current());
2021-05-08 03:09:00 +02:00
}
2021-08-29 23:18:03 +02:00
public static Mono<Send<Buffer>> lazyRetain(Buffer buf) {
return Mono.just(buf).map(b -> b.copy().send());
}
2021-08-29 23:18:03 +02:00
public static Mono<Send<LLRange>> lazyRetainRange(LLRange range) {
return Mono.just(range).map(r -> r.copy().send());
}
2021-08-22 19:52:19 +02:00
2021-08-29 23:18:03 +02:00
public static Mono<Send<Buffer>> lazyRetain(Callable<Send<Buffer>> bufCallable) {
return Mono.fromCallable(bufCallable);
2021-08-22 19:52:19 +02:00
}
2021-08-29 23:18:03 +02:00
public static Mono<Send<LLRange>> lazyRetainRange(Callable<Send<LLRange>> rangeCallable) {
return Mono.fromCallable(rangeCallable);
2021-08-22 19:52:19 +02:00
}
2021-08-22 21:23:22 +02:00
public static <T> Mono<T> handleDiscard(Mono<T> mono) {
2021-08-28 22:42:51 +02:00
return mono
.doOnDiscard(Object.class, obj -> {
2021-08-29 23:18:03 +02:00
if (obj instanceof SafeCloseable o) {
2021-08-28 22:42:51 +02:00
discardRefCounted(o);
} else if (obj instanceof Entry o) {
discardEntry(o);
} else if (obj instanceof Collection o) {
discardCollection(o);
} else if (obj instanceof Tuple3 o) {
discardTuple3(o);
} else if (obj instanceof Tuple2 o) {
discardTuple2(o);
} else if (obj instanceof LLEntry o) {
discardLLEntry(o);
} else if (obj instanceof LLRange o) {
discardLLRange(o);
} else if (obj instanceof Delta o) {
discardDelta(o);
2021-08-29 23:18:03 +02:00
} else if (obj instanceof Send o) {
discardSend(o);
2021-08-28 22:42:51 +02:00
} else if (obj instanceof Map o) {
discardMap(o);
}
});
// todo: check if the single object discard hook is more performant
/*
2021-08-29 23:18:03 +02:00
.doOnDiscard(SafeCloseable.class, LLUtils::discardRefCounted)
2021-08-28 22:42:51 +02:00
.doOnDiscard(Map.Entry.class, LLUtils::discardEntry)
.doOnDiscard(Collection.class, LLUtils::discardCollection)
.doOnDiscard(Tuple2.class, LLUtils::discardTuple2)
.doOnDiscard(Tuple3.class, LLUtils::discardTuple3)
.doOnDiscard(LLEntry.class, LLUtils::discardLLEntry)
.doOnDiscard(LLRange.class, LLUtils::discardLLRange)
.doOnDiscard(Delta.class, LLUtils::discardDelta)
2021-08-29 23:18:03 +02:00
.doOnDiscard(Send.class, LLUtils::discardSend)
2021-08-28 22:42:51 +02:00
.doOnDiscard(Map.class, LLUtils::discardMap);
*/
2021-08-22 21:23:22 +02:00
}
public static <T> Flux<T> handleDiscard(Flux<T> mono) {
return mono
2021-08-28 22:42:51 +02:00
.doOnDiscard(Object.class, obj -> {
2021-08-29 23:18:03 +02:00
if (obj instanceof SafeCloseable o) {
2021-08-28 22:42:51 +02:00
discardRefCounted(o);
} else if (obj instanceof Entry o) {
discardEntry(o);
} else if (obj instanceof Collection o) {
discardCollection(o);
} else if (obj instanceof Tuple3 o) {
discardTuple3(o);
} else if (obj instanceof Tuple2 o) {
discardTuple2(o);
} else if (obj instanceof LLEntry o) {
discardLLEntry(o);
} else if (obj instanceof LLRange o) {
discardLLRange(o);
} else if (obj instanceof Delta o) {
discardDelta(o);
2021-08-29 23:18:03 +02:00
} else if (obj instanceof Send o) {
discardSend(o);
2021-08-28 22:42:51 +02:00
} else if (obj instanceof Map o) {
discardMap(o);
}
});
// todo: check if the single object discard hook is more performant
/*
2021-08-29 23:18:03 +02:00
.doOnDiscard(SafeCloseable.class, LLUtils::discardRefCounted)
2021-08-22 23:50:50 +02:00
.doOnDiscard(Map.Entry.class, LLUtils::discardEntry)
2021-08-28 22:42:51 +02:00
.doOnDiscard(Collection.class, LLUtils::discardCollection)
.doOnDiscard(Tuple2.class, LLUtils::discardTuple2)
.doOnDiscard(Tuple3.class, LLUtils::discardTuple3)
.doOnDiscard(LLEntry.class, LLUtils::discardLLEntry)
.doOnDiscard(LLRange.class, LLUtils::discardLLRange)
.doOnDiscard(Delta.class, LLUtils::discardDelta)
2021-08-29 23:18:03 +02:00
.doOnDiscard(Send.class, LLUtils::discardSend)
2021-08-28 22:42:51 +02:00
.doOnDiscard(Map.class, LLUtils::discardMap);
*/
}
private static void discardLLEntry(LLEntry entry) {
2021-08-29 23:18:03 +02:00
logger.trace("Releasing discarded Buffer");
entry.close();
2021-08-28 22:42:51 +02:00
}
private static void discardLLRange(LLRange range) {
2021-08-29 23:18:03 +02:00
logger.trace("Releasing discarded Buffer");
range.close();
2021-08-22 21:23:22 +02:00
}
private static void discardEntry(Map.Entry<?, ?> e) {
2021-08-29 23:18:03 +02:00
if (e.getKey() instanceof Buffer bb) {
bb.close();
2021-08-22 21:23:22 +02:00
}
2021-08-29 23:18:03 +02:00
if (e.getValue() instanceof Buffer bb) {
bb.close();
2021-08-28 22:42:51 +02:00
}
}
private static void discardTuple2(Tuple2<?, ?> e) {
2021-08-29 23:18:03 +02:00
if (e.getT1() instanceof Buffer bb) {
bb.close();
2021-08-28 22:42:51 +02:00
}
2021-08-29 23:18:03 +02:00
if (e.getT2() instanceof Buffer bb) {
bb.close();
2021-08-28 22:42:51 +02:00
}
}
private static void discardTuple3(Tuple3<?, ?, ?> e) {
2021-08-29 23:18:03 +02:00
if (e.getT1() instanceof Buffer bb) {
bb.close();
2021-08-28 22:42:51 +02:00
} else if (e.getT1() instanceof Optional opt) {
2021-08-29 23:18:03 +02:00
if (opt.isPresent() && opt.get() instanceof Buffer bb) {
bb.close();
2021-08-28 22:42:51 +02:00
}
}
2021-08-29 23:18:03 +02:00
if (e.getT2() instanceof Buffer bb) {
bb.close();
2021-08-28 22:42:51 +02:00
} else if (e.getT1() instanceof Optional opt) {
2021-08-29 23:18:03 +02:00
if (opt.isPresent() && opt.get() instanceof Buffer bb) {
bb.close();
2021-08-28 22:42:51 +02:00
}
}
2021-08-29 23:18:03 +02:00
if (e.getT3() instanceof Buffer bb) {
bb.close();
2021-08-28 22:42:51 +02:00
} else if (e.getT1() instanceof Optional opt) {
2021-08-29 23:18:03 +02:00
if (opt.isPresent() && opt.get() instanceof Buffer bb) {
bb.close();
2021-08-22 21:23:22 +02:00
}
}
}
2021-08-29 23:18:03 +02:00
private static void discardRefCounted(SafeCloseable safeCloseable) {
safeCloseable.close();
2021-08-22 21:23:22 +02:00
}
2021-08-22 23:50:50 +02:00
private static void discardCollection(Collection<?> collection) {
for (Object o : collection) {
2021-08-29 23:18:03 +02:00
if (o instanceof SafeCloseable safeCloseable) {
safeCloseable.close();
2021-08-22 23:50:50 +02:00
} else if (o instanceof Map.Entry entry) {
2021-08-29 23:18:03 +02:00
if (entry.getKey() instanceof SafeCloseable bb) {
bb.close();
2021-08-22 23:50:50 +02:00
}
2021-08-29 23:18:03 +02:00
if (entry.getValue() instanceof SafeCloseable bb) {
bb.close();
2021-08-22 23:50:50 +02:00
}
} else {
break;
}
}
}
2021-08-28 22:42:51 +02:00
private static void discardDelta(Delta<?> delta) {
2021-08-29 23:18:03 +02:00
if (delta.previous() instanceof Buffer bb) {
bb.close();
2021-08-28 22:42:51 +02:00
}
2021-08-29 23:18:03 +02:00
if (delta.current() instanceof Buffer bb) {
bb.close();
2021-08-28 22:42:51 +02:00
}
}
2021-08-29 23:18:03 +02:00
private static void discardSend(Send<?> send) {
send.close();
}
2021-08-28 22:42:51 +02:00
private static void discardMap(Map<?, ?> map) {
for (Entry<?, ?> entry : map.entrySet()) {
boolean hasByteBuf = false;
2021-08-29 23:18:03 +02:00
if (entry.getKey() instanceof Buffer bb) {
bb.close();
2021-08-28 22:42:51 +02:00
hasByteBuf = true;
}
2021-08-29 23:18:03 +02:00
if (entry.getValue() instanceof Buffer bb) {
bb.close();
2021-08-28 22:42:51 +02:00
hasByteBuf = true;
}
if (!hasByteBuf) {
break;
}
}
}
2021-08-29 23:18:03 +02:00
public static boolean isDirect(Buffer key) {
if (key.countReadableComponents() == 1) {
return key.forEachReadable(0, (index, component) -> component.readableBuffer().isDirect()) >= 0;
} else {
return false;
}
}
public static String deserializeString(Send<Buffer> bufferSend, int readerOffset, int length, Charset charset) {
try (var buffer = bufferSend.receive()) {
byte[] bytes = new byte[Math.min(length, buffer.readableBytes())];
buffer.copyInto(readerOffset, bytes, 0, length);
return new String(bytes, charset);
}
}
public static int utf8MaxBytes(String deserialized) {
return deserialized.length() * 3;
}
2020-12-07 22:15:18 +01:00
}