2021-01-31 21:23:43 +01:00
|
|
|
package it.cavallium.dbengine.database.collections;
|
|
|
|
|
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.Resource;
|
|
|
|
import io.netty.buffer.api.Send;
|
2021-08-22 18:20:05 +02:00
|
|
|
import io.netty.util.IllegalReferenceCountException;
|
2021-05-02 19:18:15 +02:00
|
|
|
import io.netty.util.ReferenceCounted;
|
2021-06-26 02:35:33 +02:00
|
|
|
import it.cavallium.dbengine.client.BadBlock;
|
2021-01-31 21:23:43 +01:00
|
|
|
import it.cavallium.dbengine.client.CompositeSnapshot;
|
|
|
|
import it.cavallium.dbengine.database.LLDictionary;
|
2021-03-14 03:13:19 +01:00
|
|
|
import it.cavallium.dbengine.database.LLDictionaryResultType;
|
2021-01-31 21:23:43 +01:00
|
|
|
import it.cavallium.dbengine.database.LLRange;
|
|
|
|
import it.cavallium.dbengine.database.LLSnapshot;
|
2021-04-30 19:15:04 +02:00
|
|
|
import it.cavallium.dbengine.database.LLUtils;
|
2021-05-02 19:18:15 +02:00
|
|
|
import it.cavallium.dbengine.database.UpdateMode;
|
2021-03-14 19:38:20 +01:00
|
|
|
import it.cavallium.dbengine.database.disk.LLLocalDictionary;
|
2021-08-22 21:23:22 +02:00
|
|
|
import it.cavallium.dbengine.database.serialization.SerializationException;
|
2021-02-02 19:40:37 +01:00
|
|
|
import it.cavallium.dbengine.database.serialization.SerializerFixedBinaryLength;
|
2021-05-02 19:18:15 +02:00
|
|
|
import java.util.Collection;
|
2021-05-03 00:29:26 +02:00
|
|
|
import java.util.List;
|
2021-01-31 21:23:43 +01:00
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Map.Entry;
|
|
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
import reactor.core.publisher.Flux;
|
|
|
|
import reactor.core.publisher.Mono;
|
2021-08-28 22:42:51 +02:00
|
|
|
import reactor.util.function.Tuples;
|
2021-05-02 19:18:15 +02:00
|
|
|
|
2021-08-22 18:20:05 +02:00
|
|
|
// todo: implement optimized methods (which?)
|
2021-01-31 21:23:43 +01:00
|
|
|
public class DatabaseMapDictionaryDeep<T, U, US extends DatabaseStage<U>> implements DatabaseStageMap<T, U, US> {
|
|
|
|
|
|
|
|
protected final LLDictionary dictionary;
|
2021-08-29 23:18:03 +02:00
|
|
|
private final BufferAllocator alloc;
|
2021-01-31 21:23:43 +01:00
|
|
|
protected final SubStageGetter<U, US> subStageGetter;
|
2021-08-29 23:18:03 +02:00
|
|
|
protected final SerializerFixedBinaryLength<T, Send<Buffer>> keySuffixSerializer;
|
|
|
|
protected final Buffer keyPrefix;
|
2021-04-30 19:15:04 +02:00
|
|
|
protected final int keyPrefixLength;
|
2021-01-31 21:23:43 +01:00
|
|
|
protected final int keySuffixLength;
|
|
|
|
protected final int keyExtLength;
|
|
|
|
protected final LLRange range;
|
2021-08-29 23:18:03 +02:00
|
|
|
protected final Mono<Send<LLRange>> rangeMono;
|
2021-05-02 19:18:15 +02:00
|
|
|
private volatile boolean released;
|
2021-01-31 21:23:43 +01:00
|
|
|
|
2021-08-29 23:18:03 +02:00
|
|
|
private static Send<Buffer> incrementPrefix(BufferAllocator alloc, Send<Buffer> originalKeySend, int prefixLength) {
|
|
|
|
try (var originalKey = originalKeySend.receive()) {
|
2021-04-30 19:15:04 +02:00
|
|
|
assert originalKey.readableBytes() >= prefixLength;
|
2021-08-31 15:50:11 +02:00
|
|
|
var originalKeyStartOffset = originalKey.readerOffset();
|
|
|
|
var originalKeyLength = originalKey.readableBytes();
|
|
|
|
try (Buffer copiedBuf = alloc.allocate(originalKey.readableBytes())) {
|
2021-04-30 19:15:04 +02:00
|
|
|
boolean overflowed = true;
|
|
|
|
final int ff = 0xFF;
|
|
|
|
int writtenBytes = 0;
|
2021-08-29 23:18:03 +02:00
|
|
|
copiedBuf.writerOffset(prefixLength);
|
2021-04-30 19:15:04 +02:00
|
|
|
for (int i = prefixLength - 1; i >= 0; i--) {
|
|
|
|
int iByte = originalKey.getUnsignedByte(i);
|
|
|
|
if (iByte != ff) {
|
2021-08-29 23:18:03 +02:00
|
|
|
copiedBuf.setUnsignedByte(i, iByte + 1);
|
2021-04-30 19:15:04 +02:00
|
|
|
writtenBytes++;
|
|
|
|
overflowed = false;
|
|
|
|
break;
|
|
|
|
} else {
|
2021-08-29 23:18:03 +02:00
|
|
|
copiedBuf.setUnsignedByte(i, 0x00);
|
2021-04-30 19:15:04 +02:00
|
|
|
writtenBytes++;
|
|
|
|
overflowed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert prefixLength - writtenBytes >= 0;
|
|
|
|
if (prefixLength - writtenBytes > 0) {
|
2021-08-29 23:18:03 +02:00
|
|
|
originalKey.copyInto(0, copiedBuf, 0, (prefixLength - writtenBytes));
|
2021-04-30 19:15:04 +02:00
|
|
|
}
|
|
|
|
|
2021-08-31 15:50:11 +02:00
|
|
|
copiedBuf.writerOffset(originalKeyLength);
|
2021-04-30 19:15:04 +02:00
|
|
|
|
2021-08-31 15:50:11 +02:00
|
|
|
if (originalKeyLength - prefixLength > 0) {
|
|
|
|
originalKey.copyInto(prefixLength, copiedBuf, prefixLength, originalKeyLength - prefixLength);
|
2021-04-30 19:15:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (overflowed) {
|
2021-08-31 15:50:11 +02:00
|
|
|
copiedBuf.ensureWritable(originalKeyLength + 1);
|
|
|
|
copiedBuf.writerOffset(originalKeyLength + 1);
|
|
|
|
for (int i = 0; i < originalKeyLength; i++) {
|
2021-08-29 23:18:03 +02:00
|
|
|
copiedBuf.setUnsignedByte(i, 0xFF);
|
2021-04-30 19:15:04 +02:00
|
|
|
}
|
2021-08-31 15:50:11 +02:00
|
|
|
copiedBuf.setUnsignedByte(originalKeyLength, (byte) 0x00);
|
2021-04-30 19:15:04 +02:00
|
|
|
}
|
2021-08-29 23:18:03 +02:00
|
|
|
return copiedBuf.send();
|
2021-03-13 19:01:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-29 23:18:03 +02:00
|
|
|
static Send<Buffer> firstRangeKey(BufferAllocator alloc,
|
|
|
|
Send<Buffer> prefixKey,
|
2021-08-22 18:20:05 +02:00
|
|
|
int prefixLength,
|
|
|
|
int suffixLength,
|
|
|
|
int extLength) {
|
2021-04-30 19:15:04 +02:00
|
|
|
return zeroFillKeySuffixAndExt(alloc, prefixKey, prefixLength, suffixLength, extLength);
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
2021-08-29 23:18:03 +02:00
|
|
|
static Send<Buffer> nextRangeKey(BufferAllocator alloc,
|
|
|
|
Send<Buffer> prefixKey,
|
2021-08-22 18:20:05 +02:00
|
|
|
int prefixLength,
|
|
|
|
int suffixLength,
|
|
|
|
int extLength) {
|
2021-08-29 23:18:03 +02:00
|
|
|
try (prefixKey) {
|
|
|
|
try (Send<Buffer> nonIncremented = zeroFillKeySuffixAndExt(alloc, prefixKey, prefixLength, suffixLength,
|
|
|
|
extLength)) {
|
|
|
|
return incrementPrefix(alloc, nonIncremented, prefixLength);
|
2021-04-30 19:15:04 +02:00
|
|
|
}
|
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
2021-08-29 23:18:03 +02:00
|
|
|
protected static Send<Buffer> zeroFillKeySuffixAndExt(BufferAllocator alloc,
|
|
|
|
Send<Buffer> prefixKeySend,
|
2021-08-22 18:20:05 +02:00
|
|
|
int prefixLength,
|
|
|
|
int suffixLength,
|
|
|
|
int extLength) {
|
2021-08-29 23:18:03 +02:00
|
|
|
try (var prefixKey = prefixKeySend.receive()) {
|
2021-04-30 19:15:04 +02:00
|
|
|
assert prefixKey.readableBytes() == prefixLength;
|
|
|
|
assert suffixLength > 0;
|
|
|
|
assert extLength >= 0;
|
2021-08-29 23:18:03 +02:00
|
|
|
try (Buffer zeroSuffixAndExt = alloc.allocate(suffixLength + extLength)) {
|
|
|
|
for (int i = 0; i < suffixLength + extLength; i++) {
|
|
|
|
zeroSuffixAndExt.writeByte((byte) 0x0);
|
|
|
|
}
|
2021-08-31 15:50:11 +02:00
|
|
|
try (Buffer result = LLUtils.compositeBuffer(alloc, prefixKey.send(), zeroSuffixAndExt.send()).receive()) {
|
|
|
|
return result.send();
|
2021-05-02 19:18:15 +02:00
|
|
|
}
|
2021-04-30 19:15:04 +02:00
|
|
|
}
|
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
2021-08-29 23:18:03 +02:00
|
|
|
static Send<Buffer> firstRangeKey(
|
|
|
|
BufferAllocator alloc,
|
|
|
|
Send<Buffer> prefixKey,
|
|
|
|
Send<Buffer> suffixKey,
|
2021-02-01 11:00:27 +01:00
|
|
|
int prefixLength,
|
|
|
|
int suffixLength,
|
|
|
|
int extLength) {
|
2021-04-30 19:15:04 +02:00
|
|
|
return zeroFillKeyExt(alloc, prefixKey, suffixKey, prefixLength, suffixLength, extLength);
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
2021-08-29 23:18:03 +02:00
|
|
|
static Send<Buffer> nextRangeKey(
|
|
|
|
BufferAllocator alloc,
|
|
|
|
Send<Buffer> prefixKey,
|
|
|
|
Send<Buffer> suffixKey,
|
2021-02-01 11:00:27 +01:00
|
|
|
int prefixLength,
|
|
|
|
int suffixLength,
|
|
|
|
int extLength) {
|
2021-08-29 23:18:03 +02:00
|
|
|
try (Send<Buffer> nonIncremented = zeroFillKeyExt(alloc,
|
|
|
|
prefixKey,
|
|
|
|
suffixKey,
|
|
|
|
prefixLength,
|
|
|
|
suffixLength,
|
|
|
|
extLength
|
|
|
|
)) {
|
|
|
|
return incrementPrefix(alloc, nonIncremented, prefixLength + suffixLength);
|
2021-04-30 19:15:04 +02:00
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
2021-08-29 23:18:03 +02:00
|
|
|
protected static Send<Buffer> zeroFillKeyExt(
|
|
|
|
BufferAllocator alloc,
|
|
|
|
Send<Buffer> prefixKeySend,
|
|
|
|
Send<Buffer> suffixKeySend,
|
2021-01-31 21:23:43 +01:00
|
|
|
int prefixLength,
|
|
|
|
int suffixLength,
|
2021-04-03 19:09:06 +02:00
|
|
|
int extLength) {
|
2021-08-29 23:18:03 +02:00
|
|
|
try (var prefixKey = prefixKeySend.receive()) {
|
|
|
|
try (var suffixKey = suffixKeySend.receive()) {
|
|
|
|
assert prefixKey.readableBytes() == prefixLength;
|
|
|
|
assert suffixKey.readableBytes() == suffixLength;
|
|
|
|
assert suffixLength > 0;
|
|
|
|
assert extLength >= 0;
|
|
|
|
|
|
|
|
try (var ext = alloc.allocate(extLength)) {
|
|
|
|
for (int i = 0; i < extLength; i++) {
|
|
|
|
ext.writeByte((byte) 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
try (Buffer result = LLUtils.compositeBuffer(alloc, prefixKey.send(), suffixKey.send(), ext.send())
|
|
|
|
.receive()) {
|
|
|
|
assert result.readableBytes() == prefixLength + suffixLength + extLength;
|
|
|
|
return result.send();
|
|
|
|
}
|
|
|
|
}
|
2021-05-02 19:18:15 +02:00
|
|
|
}
|
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Use DatabaseMapDictionaryRange.simple instead
|
|
|
|
*/
|
|
|
|
@Deprecated
|
2021-02-02 19:40:37 +01:00
|
|
|
public static <T, U> DatabaseMapDictionaryDeep<T, U, DatabaseStageEntry<U>> simple(LLDictionary dictionary,
|
2021-08-29 23:18:03 +02:00
|
|
|
SerializerFixedBinaryLength<T, Send<Buffer>> keySerializer,
|
2021-02-02 19:40:37 +01:00
|
|
|
SubStageGetterSingle<U> subStageGetter) {
|
2021-08-29 23:18:03 +02:00
|
|
|
return new DatabaseMapDictionaryDeep<>(dictionary, dictionary.getAllocator().allocate(0).send(),
|
|
|
|
keySerializer, subStageGetter, 0);
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
2021-02-02 19:40:37 +01:00
|
|
|
public static <T, U, US extends DatabaseStage<U>> DatabaseMapDictionaryDeep<T, U, US> deepTail(LLDictionary dictionary,
|
2021-08-29 23:18:03 +02:00
|
|
|
SerializerFixedBinaryLength<T, Send<Buffer>> keySerializer,
|
2021-02-02 19:40:37 +01:00
|
|
|
int keyExtLength,
|
|
|
|
SubStageGetter<U, US> subStageGetter) {
|
2021-05-03 21:41:51 +02:00
|
|
|
return new DatabaseMapDictionaryDeep<>(dictionary,
|
2021-08-29 23:18:03 +02:00
|
|
|
dictionary.getAllocator().allocate(0).send(),
|
2021-05-03 21:41:51 +02:00
|
|
|
keySerializer,
|
|
|
|
subStageGetter,
|
|
|
|
keyExtLength
|
|
|
|
);
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
2021-02-02 19:40:37 +01:00
|
|
|
public static <T, U, US extends DatabaseStage<U>> DatabaseMapDictionaryDeep<T, U, US> deepIntermediate(LLDictionary dictionary,
|
2021-08-29 23:18:03 +02:00
|
|
|
Send<Buffer> prefixKey,
|
|
|
|
SerializerFixedBinaryLength<T, Send<Buffer>> keySuffixSerializer,
|
2021-02-02 19:40:37 +01:00
|
|
|
SubStageGetter<U, US> subStageGetter,
|
2021-01-31 21:23:43 +01:00
|
|
|
int keyExtLength) {
|
2021-02-02 19:40:37 +01:00
|
|
|
return new DatabaseMapDictionaryDeep<>(dictionary, prefixKey, keySuffixSerializer, subStageGetter, keyExtLength);
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
protected DatabaseMapDictionaryDeep(LLDictionary dictionary,
|
2021-08-31 15:50:11 +02:00
|
|
|
Send<Buffer> prefixKeyToReceive,
|
2021-08-29 23:18:03 +02:00
|
|
|
SerializerFixedBinaryLength<T, Send<Buffer>> keySuffixSerializer,
|
2021-02-02 19:40:37 +01:00
|
|
|
SubStageGetter<U, US> subStageGetter,
|
2021-01-31 21:23:43 +01:00
|
|
|
int keyExtLength) {
|
2021-08-31 15:50:11 +02:00
|
|
|
try (var prefixKey = prefixKeyToReceive.receive()) {
|
|
|
|
this.dictionary = dictionary;
|
|
|
|
this.alloc = dictionary.getAllocator();
|
|
|
|
this.subStageGetter = subStageGetter;
|
|
|
|
this.keySuffixSerializer = keySuffixSerializer;
|
|
|
|
this.keyPrefix = prefixKey.copy();
|
|
|
|
assert keyPrefix.isAccessible();
|
|
|
|
this.keyPrefixLength = keyPrefix.readableBytes();
|
|
|
|
this.keySuffixLength = keySuffixSerializer.getSerializedBinaryLength();
|
|
|
|
this.keyExtLength = keyExtLength;
|
|
|
|
try (Buffer firstKey = firstRangeKey(alloc,
|
|
|
|
prefixKey.copy().send(),
|
2021-04-30 19:15:04 +02:00
|
|
|
keyPrefixLength,
|
|
|
|
keySuffixLength,
|
|
|
|
keyExtLength
|
2021-08-31 15:50:11 +02:00
|
|
|
).receive().compact()) {
|
|
|
|
try (Buffer nextRangeKey = nextRangeKey(alloc,
|
|
|
|
prefixKey.copy().send(),
|
|
|
|
keyPrefixLength,
|
|
|
|
keySuffixLength,
|
|
|
|
keyExtLength
|
|
|
|
).receive().compact()) {
|
|
|
|
assert keyPrefix.isAccessible();
|
|
|
|
assert keyPrefixLength == 0 || !LLUtils.equals(firstKey, nextRangeKey);
|
|
|
|
this.range = keyPrefixLength == 0 ? LLRange.all() : LLRange.of(firstKey.send(), nextRangeKey.send());
|
|
|
|
this.rangeMono = LLUtils.lazyRetainRange(this.range);
|
|
|
|
assert subStageKeysConsistency(keyPrefixLength + keySuffixLength + keyExtLength);
|
|
|
|
}
|
2021-04-30 19:15:04 +02:00
|
|
|
}
|
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unused")
|
|
|
|
protected boolean suffixKeyConsistency(int keySuffixLength) {
|
|
|
|
return this.keySuffixLength == keySuffixLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unused")
|
|
|
|
protected boolean extKeyConsistency(int keyExtLength) {
|
|
|
|
return this.keyExtLength == keyExtLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unused")
|
|
|
|
protected boolean suffixAndExtKeyConsistency(int keySuffixAndExtLength) {
|
|
|
|
return this.keySuffixLength + this.keyExtLength == keySuffixAndExtLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Keep only suffix and ext
|
|
|
|
*/
|
2021-08-29 23:18:03 +02:00
|
|
|
protected Send<Buffer> stripPrefix(Send<Buffer> keyToReceive) {
|
|
|
|
try (var key = keyToReceive.receive()) {
|
|
|
|
return key.copy(this.keyPrefixLength, key.readableBytes() - this.keyPrefixLength).send();
|
2021-05-02 19:18:15 +02:00
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove ext from full key
|
|
|
|
*/
|
2021-08-29 23:18:03 +02:00
|
|
|
protected Send<Buffer> removeExtFromFullKey(Send<Buffer> keyToReceive) {
|
|
|
|
try (var key = keyToReceive.receive()) {
|
|
|
|
return key.copy(key.readerOffset(), keyPrefixLength + keySuffixLength).send();
|
2021-04-30 19:15:04 +02:00
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add prefix to suffix
|
|
|
|
*/
|
2021-08-29 23:18:03 +02:00
|
|
|
protected Send<Buffer> toKeyWithoutExt(Send<Buffer> suffixKeyToReceive) {
|
|
|
|
try (var suffixKey = suffixKeyToReceive.receive()) {
|
2021-04-30 19:15:04 +02:00
|
|
|
assert suffixKey.readableBytes() == keySuffixLength;
|
2021-08-29 23:18:03 +02:00
|
|
|
try (Buffer result = LLUtils.compositeBuffer(alloc, keyPrefix.copy().send(), suffixKey.send()).receive()) {
|
2021-05-02 19:18:15 +02:00
|
|
|
assert result.readableBytes() == keyPrefixLength + keySuffixLength;
|
2021-08-29 23:18:03 +02:00
|
|
|
return result.send();
|
2021-05-02 19:18:15 +02:00
|
|
|
}
|
2021-04-30 19:15:04 +02:00
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
protected LLSnapshot resolveSnapshot(@Nullable CompositeSnapshot snapshot) {
|
|
|
|
if (snapshot == null) {
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
return snapshot.getSnapshot(dictionary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-29 23:18:03 +02:00
|
|
|
protected Send<LLRange> toExtRange(Buffer keySuffix) {
|
|
|
|
try (Buffer first = firstRangeKey(alloc,
|
|
|
|
keyPrefix.copy().send(),
|
|
|
|
keySuffix.copy().send(),
|
|
|
|
keyPrefixLength,
|
|
|
|
keySuffixLength,
|
|
|
|
keyExtLength
|
|
|
|
).receive()) {
|
|
|
|
try (Buffer end = nextRangeKey(alloc,
|
|
|
|
keyPrefix.copy().send(),
|
|
|
|
keySuffix.copy().send(),
|
2021-04-30 19:15:04 +02:00
|
|
|
keyPrefixLength,
|
|
|
|
keySuffixLength,
|
|
|
|
keyExtLength
|
2021-08-29 23:18:03 +02:00
|
|
|
).receive()) {
|
|
|
|
return LLRange.of(first.send(), end.send()).send();
|
|
|
|
}
|
2021-04-30 19:15:04 +02:00
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
2021-02-24 16:43:07 +01:00
|
|
|
@Override
|
|
|
|
public Mono<Long> leavesCount(@Nullable CompositeSnapshot snapshot, boolean fast) {
|
2021-08-22 18:20:05 +02:00
|
|
|
return dictionary.sizeRange(resolveSnapshot(snapshot), rangeMono, fast);
|
2021-02-24 16:43:07 +01:00
|
|
|
}
|
|
|
|
|
2021-03-14 03:13:19 +01:00
|
|
|
@Override
|
|
|
|
public Mono<Boolean> isEmpty(@Nullable CompositeSnapshot snapshot) {
|
2021-08-22 18:20:05 +02:00
|
|
|
return dictionary.isRangeEmpty(resolveSnapshot(snapshot), rangeMono);
|
2021-03-14 03:13:19 +01:00
|
|
|
}
|
|
|
|
|
2021-01-31 21:23:43 +01:00
|
|
|
@Override
|
|
|
|
public Mono<US> at(@Nullable CompositeSnapshot snapshot, T keySuffix) {
|
2021-08-22 19:52:19 +02:00
|
|
|
return Mono.using(
|
2021-08-29 23:18:03 +02:00
|
|
|
() -> serializeSuffix(keySuffix).receive(),
|
|
|
|
keySuffixData -> Mono.using(
|
|
|
|
() -> toKeyWithoutExt(keySuffixData.send()).receive(),
|
|
|
|
keyWithoutExt -> this.subStageGetter
|
|
|
|
.subStage(dictionary, snapshot, LLUtils.lazyRetain(keyWithoutExt)),
|
|
|
|
Resource::close
|
|
|
|
),
|
|
|
|
Resource::close
|
2021-08-27 02:49:51 +02:00
|
|
|
).transform(LLUtils::handleDiscard).doOnDiscard(DatabaseStage.class, DatabaseStage::release);
|
2021-05-02 19:18:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Mono<UpdateMode> getUpdateMode() {
|
|
|
|
return dictionary.getUpdateMode();
|
|
|
|
}
|
|
|
|
|
2021-06-26 02:35:33 +02:00
|
|
|
@Override
|
|
|
|
public Flux<BadBlock> badBlocks() {
|
2021-08-22 18:20:05 +02:00
|
|
|
return dictionary.badBlocks(rangeMono);
|
2021-06-26 02:35:33 +02:00
|
|
|
}
|
|
|
|
|
2021-08-29 23:18:03 +02:00
|
|
|
private static record GroupBuffers(Buffer groupKeyWithExt, Buffer groupKeyWithoutExt, Buffer groupSuffix) {}
|
2021-01-31 21:23:43 +01:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public Flux<Entry<T, US>> getAllStages(@Nullable CompositeSnapshot snapshot) {
|
2021-08-28 22:42:51 +02:00
|
|
|
|
2021-05-12 21:41:47 +02:00
|
|
|
return Flux
|
2021-08-28 22:42:51 +02:00
|
|
|
.defer(() -> dictionary.getRangeKeyPrefixes(resolveSnapshot(snapshot), rangeMono, keyPrefixLength + keySuffixLength))
|
2021-08-29 23:18:03 +02:00
|
|
|
.flatMapSequential(groupKeyWithoutExtSend -> Mono
|
2021-08-28 22:42:51 +02:00
|
|
|
.using(
|
|
|
|
() -> {
|
2021-08-29 23:18:03 +02:00
|
|
|
try (var groupKeyWithoutExt = groupKeyWithoutExtSend.receive()) {
|
|
|
|
try (var groupSuffix = this.stripPrefix(groupKeyWithoutExt.copy().send()).receive()) {
|
2021-08-28 22:42:51 +02:00
|
|
|
assert subStageKeysConsistency(groupKeyWithoutExt.readableBytes() + keyExtLength);
|
2021-08-29 23:18:03 +02:00
|
|
|
return Tuples.of(groupKeyWithoutExt, groupSuffix);
|
2021-07-23 22:18:08 +02:00
|
|
|
}
|
2021-05-12 21:41:47 +02:00
|
|
|
}
|
2021-08-28 22:42:51 +02:00
|
|
|
},
|
|
|
|
groupKeyWithoutExtAndGroupSuffix -> this.subStageGetter
|
|
|
|
.subStage(dictionary,
|
|
|
|
snapshot,
|
|
|
|
LLUtils.lazyRetain(groupKeyWithoutExtAndGroupSuffix.getT1())
|
2021-05-12 21:41:47 +02:00
|
|
|
)
|
2021-08-28 22:42:51 +02:00
|
|
|
.<Entry<T, US>>handle((us, sink) -> {
|
|
|
|
try {
|
2021-08-29 23:18:03 +02:00
|
|
|
sink.next(Map.entry(this.deserializeSuffix(groupKeyWithoutExtAndGroupSuffix.getT2().send()),
|
|
|
|
us));
|
2021-08-28 22:42:51 +02:00
|
|
|
} catch (SerializationException ex) {
|
|
|
|
sink.error(ex);
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
entry -> {
|
2021-08-29 23:18:03 +02:00
|
|
|
entry.getT1().close();
|
|
|
|
entry.getT2().close();
|
2021-08-28 22:42:51 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.transform(LLUtils::handleDiscard);
|
2021-02-02 15:36:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private boolean subStageKeysConsistency(int totalKeyLength) {
|
|
|
|
if (subStageGetter instanceof SubStageGetterMapDeep) {
|
|
|
|
return totalKeyLength
|
2021-04-30 19:15:04 +02:00
|
|
|
== keyPrefixLength + keySuffixLength + ((SubStageGetterMapDeep<?, ?, ?>) subStageGetter).getKeyBinaryLength();
|
2021-02-02 15:36:11 +01:00
|
|
|
} else if (subStageGetter instanceof SubStageGetterMap) {
|
|
|
|
return totalKeyLength
|
2021-04-30 19:15:04 +02:00
|
|
|
== keyPrefixLength + keySuffixLength + ((SubStageGetterMap<?, ?>) subStageGetter).getKeyBinaryLength();
|
2021-02-02 15:36:11 +01:00
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Flux<Entry<T, U>> setAllValuesAndGetPrevious(Flux<Entry<T, U>> entries) {
|
2021-05-02 19:18:15 +02:00
|
|
|
return this
|
|
|
|
.getAllValues(null)
|
|
|
|
.concatWith(this
|
|
|
|
.clear()
|
2021-08-22 18:20:05 +02:00
|
|
|
.then(this.putMulti(entries))
|
|
|
|
.then(Mono.empty())
|
2021-05-02 19:18:15 +02:00
|
|
|
);
|
2021-03-11 02:22:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Mono<Void> clear() {
|
2021-05-12 21:41:47 +02:00
|
|
|
return Mono
|
|
|
|
.defer(() -> {
|
|
|
|
if (range.isAll()) {
|
|
|
|
return dictionary.clear();
|
|
|
|
} else if (range.isSingle()) {
|
|
|
|
return dictionary
|
2021-08-29 23:18:03 +02:00
|
|
|
.remove(LLUtils.lazyRetain(range::getSingle), LLDictionaryResultType.VOID)
|
|
|
|
.doOnNext(Send::close)
|
2021-05-12 21:41:47 +02:00
|
|
|
.then();
|
|
|
|
} else {
|
2021-08-22 19:52:19 +02:00
|
|
|
return dictionary.setRange(LLUtils.lazyRetainRange(range), Flux.empty());
|
2021-05-12 21:41:47 +02:00
|
|
|
}
|
|
|
|
});
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//todo: temporary wrapper. convert the whole class to buffers
|
2021-08-29 23:18:03 +02:00
|
|
|
protected T deserializeSuffix(Send<Buffer> keySuffixToReceive) throws SerializationException {
|
|
|
|
try (var keySuffix = keySuffixToReceive.receive()) {
|
2021-05-02 19:18:15 +02:00
|
|
|
assert suffixKeyConsistency(keySuffix.readableBytes());
|
2021-08-29 23:18:03 +02:00
|
|
|
var result = keySuffixSerializer.deserialize(keySuffix.send());
|
|
|
|
assert keyPrefix.isAccessible();
|
2021-05-02 19:18:15 +02:00
|
|
|
return result;
|
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//todo: temporary wrapper. convert the whole class to buffers
|
2021-08-29 23:18:03 +02:00
|
|
|
protected Send<Buffer> serializeSuffix(T keySuffix) throws SerializationException {
|
|
|
|
try (Buffer suffixData = keySuffixSerializer.serialize(keySuffix).receive()) {
|
|
|
|
assert suffixKeyConsistency(suffixData.readableBytes());
|
|
|
|
assert keyPrefix.isAccessible();
|
|
|
|
return suffixData.send();
|
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|
2021-04-30 19:15:04 +02:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void release() {
|
2021-05-02 19:18:15 +02:00
|
|
|
if (!released) {
|
|
|
|
released = true;
|
2021-08-29 23:18:03 +02:00
|
|
|
this.range.close();
|
|
|
|
this.keyPrefix.close();
|
2021-05-02 19:18:15 +02:00
|
|
|
} else {
|
2021-08-22 18:20:05 +02:00
|
|
|
throw new IllegalReferenceCountException(0, -1);
|
2021-05-02 19:18:15 +02:00
|
|
|
}
|
2021-04-30 19:15:04 +02:00
|
|
|
}
|
2021-01-31 21:23:43 +01:00
|
|
|
}
|