Use a new approach to completely avoid memory leaks
This commit is contained in:
parent
9d326f5a8b
commit
435e7d4886
|
@ -23,17 +23,17 @@ public interface LLDictionary extends LLKeyValueDatabaseStructure {
|
||||||
|
|
||||||
ByteBufAllocator getAllocator();
|
ByteBufAllocator getAllocator();
|
||||||
|
|
||||||
Mono<ByteBuf> get(@Nullable LLSnapshot snapshot, ByteBuf key, boolean existsAlmostCertainly);
|
Mono<ByteBuf> get(@Nullable LLSnapshot snapshot, Mono<ByteBuf> key, boolean existsAlmostCertainly);
|
||||||
|
|
||||||
default Mono<ByteBuf> get(@Nullable LLSnapshot snapshot, ByteBuf key) {
|
default Mono<ByteBuf> get(@Nullable LLSnapshot snapshot, Mono<ByteBuf> key) {
|
||||||
return get(snapshot, key, false);
|
return get(snapshot, key, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mono<ByteBuf> put(ByteBuf key, ByteBuf value, LLDictionaryResultType resultType);
|
Mono<ByteBuf> put(Mono<ByteBuf> key, Mono<ByteBuf> value, LLDictionaryResultType resultType);
|
||||||
|
|
||||||
Mono<UpdateMode> getUpdateMode();
|
Mono<UpdateMode> getUpdateMode();
|
||||||
|
|
||||||
default Mono<ByteBuf> update(ByteBuf key,
|
default Mono<ByteBuf> update(Mono<ByteBuf> key,
|
||||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||||
UpdateReturnMode updateReturnMode,
|
UpdateReturnMode updateReturnMode,
|
||||||
boolean existsAlmostCertainly) {
|
boolean existsAlmostCertainly) {
|
||||||
|
@ -42,24 +42,24 @@ public interface LLDictionary extends LLKeyValueDatabaseStructure {
|
||||||
.transform(prev -> LLUtils.resolveDelta(prev, updateReturnMode));
|
.transform(prev -> LLUtils.resolveDelta(prev, updateReturnMode));
|
||||||
}
|
}
|
||||||
|
|
||||||
default Mono<ByteBuf> update(ByteBuf key,
|
default Mono<ByteBuf> update(Mono<ByteBuf> key,
|
||||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||||
UpdateReturnMode returnMode) {
|
UpdateReturnMode returnMode) {
|
||||||
return update(key, updater, returnMode, false);
|
return update(key, updater, returnMode, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mono<Delta<ByteBuf>> updateAndGetDelta(ByteBuf key,
|
Mono<Delta<ByteBuf>> updateAndGetDelta(Mono<ByteBuf> key,
|
||||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||||
boolean existsAlmostCertainly);
|
boolean existsAlmostCertainly);
|
||||||
|
|
||||||
default Mono<Delta<ByteBuf>> updateAndGetDelta(ByteBuf key,
|
default Mono<Delta<ByteBuf>> updateAndGetDelta(Mono<ByteBuf> key,
|
||||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater) {
|
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater) {
|
||||||
return updateAndGetDelta(key, updater, false);
|
return updateAndGetDelta(key, updater, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mono<Void> clear();
|
Mono<Void> clear();
|
||||||
|
|
||||||
Mono<ByteBuf> remove(ByteBuf key, LLDictionaryResultType resultType);
|
Mono<ByteBuf> remove(Mono<ByteBuf> key, LLDictionaryResultType resultType);
|
||||||
|
|
||||||
<K> Flux<Tuple3<K, ByteBuf, Optional<ByteBuf>>> getMulti(@Nullable LLSnapshot snapshot,
|
<K> Flux<Tuple3<K, ByteBuf, Optional<ByteBuf>>> getMulti(@Nullable LLSnapshot snapshot,
|
||||||
Flux<Tuple2<K, ByteBuf>> keys,
|
Flux<Tuple2<K, ByteBuf>> keys,
|
||||||
|
@ -74,34 +74,34 @@ public interface LLDictionary extends LLKeyValueDatabaseStructure {
|
||||||
<X> Flux<ExtraKeyOperationResult<ByteBuf, X>> updateMulti(Flux<Tuple2<ByteBuf, X>> entries,
|
<X> Flux<ExtraKeyOperationResult<ByteBuf, X>> updateMulti(Flux<Tuple2<ByteBuf, X>> entries,
|
||||||
BiFunction<ByteBuf, X, ByteBuf> updateFunction);
|
BiFunction<ByteBuf, X, ByteBuf> updateFunction);
|
||||||
|
|
||||||
Flux<Entry<ByteBuf, ByteBuf>> getRange(@Nullable LLSnapshot snapshot, LLRange range, boolean existsAlmostCertainly);
|
Flux<Entry<ByteBuf, ByteBuf>> getRange(@Nullable LLSnapshot snapshot, Mono<LLRange> range, boolean existsAlmostCertainly);
|
||||||
|
|
||||||
default Flux<Entry<ByteBuf, ByteBuf>> getRange(@Nullable LLSnapshot snapshot, LLRange range) {
|
default Flux<Entry<ByteBuf, ByteBuf>> getRange(@Nullable LLSnapshot snapshot, Mono<LLRange> range) {
|
||||||
return getRange(snapshot, range, false);
|
return getRange(snapshot, range, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Flux<List<Entry<ByteBuf, ByteBuf>>> getRangeGrouped(@Nullable LLSnapshot snapshot,
|
Flux<List<Entry<ByteBuf, ByteBuf>>> getRangeGrouped(@Nullable LLSnapshot snapshot,
|
||||||
LLRange range,
|
Mono<LLRange> range,
|
||||||
int prefixLength,
|
int prefixLength,
|
||||||
boolean existsAlmostCertainly);
|
boolean existsAlmostCertainly);
|
||||||
|
|
||||||
default Flux<List<Entry<ByteBuf, ByteBuf>>> getRangeGrouped(@Nullable LLSnapshot snapshot,
|
default Flux<List<Entry<ByteBuf, ByteBuf>>> getRangeGrouped(@Nullable LLSnapshot snapshot,
|
||||||
LLRange range,
|
Mono<LLRange> range,
|
||||||
int prefixLength) {
|
int prefixLength) {
|
||||||
return getRangeGrouped(snapshot, range, prefixLength, false);
|
return getRangeGrouped(snapshot, range, prefixLength, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Flux<ByteBuf> getRangeKeys(@Nullable LLSnapshot snapshot, LLRange range);
|
Flux<ByteBuf> getRangeKeys(@Nullable LLSnapshot snapshot, Mono<LLRange> range);
|
||||||
|
|
||||||
Flux<List<ByteBuf>> getRangeKeysGrouped(@Nullable LLSnapshot snapshot, LLRange range, int prefixLength);
|
Flux<List<ByteBuf>> getRangeKeysGrouped(@Nullable LLSnapshot snapshot, Mono<LLRange> range, int prefixLength);
|
||||||
|
|
||||||
Flux<ByteBuf> getRangeKeyPrefixes(@Nullable LLSnapshot snapshot, LLRange range, int prefixLength);
|
Flux<ByteBuf> getRangeKeyPrefixes(@Nullable LLSnapshot snapshot, Mono<LLRange> range, int prefixLength);
|
||||||
|
|
||||||
Flux<BadBlock> badBlocks(LLRange range);
|
Flux<BadBlock> badBlocks(Mono<LLRange> range);
|
||||||
|
|
||||||
Mono<Void> setRange(LLRange range, Flux<Entry<ByteBuf, ByteBuf>> entries);
|
Mono<Void> setRange(Mono<LLRange> range, Flux<Entry<ByteBuf, ByteBuf>> entries);
|
||||||
|
|
||||||
default Mono<Void> replaceRange(LLRange range,
|
default Mono<Void> replaceRange(Mono<LLRange> range,
|
||||||
boolean canKeysChange,
|
boolean canKeysChange,
|
||||||
Function<Entry<ByteBuf, ByteBuf>, Mono<Entry<ByteBuf, ByteBuf>>> entriesReplacer,
|
Function<Entry<ByteBuf, ByteBuf>, Mono<Entry<ByteBuf, ByteBuf>>> entriesReplacer,
|
||||||
boolean existsAlmostCertainly) {
|
boolean existsAlmostCertainly) {
|
||||||
|
@ -122,19 +122,19 @@ public interface LLDictionary extends LLKeyValueDatabaseStructure {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
default Mono<Void> replaceRange(LLRange range,
|
default Mono<Void> replaceRange(Mono<LLRange> range,
|
||||||
boolean canKeysChange,
|
boolean canKeysChange,
|
||||||
Function<Entry<ByteBuf, ByteBuf>, Mono<Entry<ByteBuf, ByteBuf>>> entriesReplacer) {
|
Function<Entry<ByteBuf, ByteBuf>, Mono<Entry<ByteBuf, ByteBuf>>> entriesReplacer) {
|
||||||
return replaceRange(range, canKeysChange, entriesReplacer, false);
|
return replaceRange(range, canKeysChange, entriesReplacer, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mono<Boolean> isRangeEmpty(@Nullable LLSnapshot snapshot, LLRange range);
|
Mono<Boolean> isRangeEmpty(@Nullable LLSnapshot snapshot, Mono<LLRange> range);
|
||||||
|
|
||||||
Mono<Long> sizeRange(@Nullable LLSnapshot snapshot, LLRange range, boolean fast);
|
Mono<Long> sizeRange(@Nullable LLSnapshot snapshot, Mono<LLRange> range, boolean fast);
|
||||||
|
|
||||||
Mono<Entry<ByteBuf, ByteBuf>> getOne(@Nullable LLSnapshot snapshot, LLRange range);
|
Mono<Entry<ByteBuf, ByteBuf>> getOne(@Nullable LLSnapshot snapshot, Mono<LLRange> range);
|
||||||
|
|
||||||
Mono<ByteBuf> getOneKey(@Nullable LLSnapshot snapshot, LLRange range);
|
Mono<ByteBuf> getOneKey(@Nullable LLSnapshot snapshot, Mono<LLRange> range);
|
||||||
|
|
||||||
Mono<Entry<ByteBuf, ByteBuf>> removeOne(LLRange range);
|
Mono<Entry<ByteBuf, ByteBuf>> removeOne(Mono<LLRange> range);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
package it.cavallium.dbengine.database.disk;
|
package it.cavallium.dbengine.database.disk;
|
||||||
|
|
||||||
|
import static io.netty.buffer.Unpooled.wrappedBuffer;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufAllocator;
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
import io.netty.util.ReferenceCounted;
|
import io.netty.util.ReferenceCounted;
|
||||||
import it.cavallium.dbengine.client.BadBlock;
|
import it.cavallium.dbengine.client.BadBlock;
|
||||||
import it.cavallium.dbengine.database.Column;
|
|
||||||
import it.cavallium.dbengine.client.DatabaseOptions;
|
import it.cavallium.dbengine.client.DatabaseOptions;
|
||||||
|
import it.cavallium.dbengine.database.Column;
|
||||||
import it.cavallium.dbengine.database.Delta;
|
import it.cavallium.dbengine.database.Delta;
|
||||||
import it.cavallium.dbengine.database.ExtraKeyOperationResult;
|
import it.cavallium.dbengine.database.ExtraKeyOperationResult;
|
||||||
import it.cavallium.dbengine.database.KeyOperationResult;
|
|
||||||
import it.cavallium.dbengine.database.LLDictionary;
|
import it.cavallium.dbengine.database.LLDictionary;
|
||||||
import it.cavallium.dbengine.database.LLDictionaryResultType;
|
import it.cavallium.dbengine.database.LLDictionaryResultType;
|
||||||
import it.cavallium.dbengine.database.LLRange;
|
import it.cavallium.dbengine.database.LLRange;
|
||||||
|
@ -17,16 +18,13 @@ import it.cavallium.dbengine.database.LLUtils;
|
||||||
import it.cavallium.dbengine.database.RepeatedElementList;
|
import it.cavallium.dbengine.database.RepeatedElementList;
|
||||||
import it.cavallium.dbengine.database.UpdateMode;
|
import it.cavallium.dbengine.database.UpdateMode;
|
||||||
import it.cavallium.dbengine.database.UpdateReturnMode;
|
import it.cavallium.dbengine.database.UpdateReturnMode;
|
||||||
import it.unimi.dsi.fastutil.booleans.BooleanArrayList;
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
@ -68,7 +66,6 @@ import reactor.core.scheduler.Scheduler;
|
||||||
import reactor.util.function.Tuple2;
|
import reactor.util.function.Tuple2;
|
||||||
import reactor.util.function.Tuple3;
|
import reactor.util.function.Tuple3;
|
||||||
import reactor.util.function.Tuples;
|
import reactor.util.function.Tuples;
|
||||||
import static io.netty.buffer.Unpooled.*;
|
|
||||||
|
|
||||||
@NotAtomic
|
@NotAtomic
|
||||||
public class LLLocalDictionary implements LLDictionary {
|
public class LLLocalDictionary implements LLDictionary {
|
||||||
|
@ -237,11 +234,14 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
return alloc;
|
return alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <T> Mono<T> runOnDb(Callable<@Nullable T> callable) {
|
||||||
|
return Mono.fromCallable(callable).subscribeOn(dbScheduler);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ByteBuf> get(@Nullable LLSnapshot snapshot, ByteBuf key, boolean existsAlmostCertainly) {
|
public Mono<ByteBuf> get(@Nullable LLSnapshot snapshot, Mono<ByteBuf> keyMono, boolean existsAlmostCertainly) {
|
||||||
try {
|
return Mono.usingWhen(keyMono,
|
||||||
return Mono
|
key -> runOnDb(() -> {
|
||||||
.fromCallable(() -> {
|
|
||||||
StampedLock lock;
|
StampedLock lock;
|
||||||
long stamp;
|
long stamp;
|
||||||
if (updateMode == UpdateMode.ALLOW) {
|
if (updateMode == UpdateMode.ALLOW) {
|
||||||
|
@ -262,14 +262,9 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
lock.unlockRead(stamp);
|
lock.unlockRead(stamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}).onErrorMap(cause -> new IOException("Failed to read " + LLUtils.toStringSafe(key), cause)),
|
||||||
.subscribeOn(dbScheduler)
|
key -> Mono.fromRunnable(key::release)
|
||||||
.onErrorMap(cause -> new IOException("Failed to read " + LLUtils.toStringSafe(key), cause))
|
);
|
||||||
.doFirst(key::retain)
|
|
||||||
.doAfterTerminate(key::release);
|
|
||||||
} finally {
|
|
||||||
key.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ByteBuf dbGet(ColumnFamilyHandle cfh,
|
private ByteBuf dbGet(ColumnFamilyHandle cfh,
|
||||||
|
@ -287,9 +282,7 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
throw new RocksDBException("Key buffer must be direct");
|
throw new RocksDBException("Key buffer must be direct");
|
||||||
}
|
}
|
||||||
ByteBuffer keyNioBuffer = LLUtils.toDirect(key);
|
ByteBuffer keyNioBuffer = LLUtils.toDirect(key);
|
||||||
if (databaseOptions.enableDbAssertionsWhenUsingAssertions()) {
|
assert !databaseOptions.enableDbAssertionsWhenUsingAssertions() || keyNioBuffer.isDirect();
|
||||||
assert keyNioBuffer.isDirect();
|
|
||||||
}
|
|
||||||
// Create a direct result buffer because RocksDB works only with direct buffers
|
// Create a direct result buffer because RocksDB works only with direct buffers
|
||||||
ByteBuf resultBuf = alloc.directBuffer(LLLocalDictionary.INITIAL_DIRECT_READ_BYTE_BUF_SIZE_BYTES);
|
ByteBuf resultBuf = alloc.directBuffer(LLLocalDictionary.INITIAL_DIRECT_READ_BYTE_BUF_SIZE_BYTES);
|
||||||
try {
|
try {
|
||||||
|
@ -388,6 +381,7 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
private void dbPut(ColumnFamilyHandle cfh, @Nullable WriteOptions writeOptions, ByteBuf key, ByteBuf value)
|
private void dbPut(ColumnFamilyHandle cfh, @Nullable WriteOptions writeOptions, ByteBuf key, ByteBuf value)
|
||||||
throws RocksDBException {
|
throws RocksDBException {
|
||||||
try {
|
try {
|
||||||
|
@ -399,15 +393,11 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
throw new RocksDBException("Value buffer must be direct");
|
throw new RocksDBException("Value buffer must be direct");
|
||||||
}
|
}
|
||||||
var keyNioBuffer = LLUtils.toDirect(key);
|
var keyNioBuffer = LLUtils.toDirect(key);
|
||||||
if (databaseOptions.enableDbAssertionsWhenUsingAssertions()) {
|
assert !databaseOptions.enableDbAssertionsWhenUsingAssertions() || keyNioBuffer.isDirect();
|
||||||
assert keyNioBuffer.isDirect();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var valueNioBuffer = LLUtils.toDirect(value);
|
var valueNioBuffer = LLUtils.toDirect(value);
|
||||||
if (databaseOptions.enableDbAssertionsWhenUsingAssertions()) {
|
assert !databaseOptions.enableDbAssertionsWhenUsingAssertions() || valueNioBuffer.isDirect();
|
||||||
assert valueNioBuffer.isDirect();
|
|
||||||
}
|
|
||||||
db.put(cfh, Objects.requireNonNullElse(writeOptions, EMPTY_WRITE_OPTIONS), keyNioBuffer, valueNioBuffer);
|
db.put(cfh, Objects.requireNonNullElse(writeOptions, EMPTY_WRITE_OPTIONS), keyNioBuffer, valueNioBuffer);
|
||||||
} else {
|
} else {
|
||||||
db.put(cfh, Objects.requireNonNullElse(writeOptions, EMPTY_WRITE_OPTIONS), LLUtils.toArray(key), LLUtils.toArray(value));
|
db.put(cfh, Objects.requireNonNullElse(writeOptions, EMPTY_WRITE_OPTIONS), LLUtils.toArray(key), LLUtils.toArray(value));
|
||||||
|
@ -419,28 +409,22 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Boolean> isRangeEmpty(@Nullable LLSnapshot snapshot, LLRange range) {
|
public Mono<Boolean> isRangeEmpty(@Nullable LLSnapshot snapshot, Mono<LLRange> rangeMono) {
|
||||||
try {
|
return Mono.usingWhen(rangeMono,
|
||||||
return Mono
|
range -> {
|
||||||
.defer(() -> {
|
|
||||||
if (range.isSingle()) {
|
if (range.isSingle()) {
|
||||||
return this.containsKey(snapshot, range.getSingle().retain());
|
return this.containsKey(snapshot, Mono.just(range.getSingle()).map(ByteBuf::retain));
|
||||||
} else {
|
} else {
|
||||||
return this.containsRange(snapshot, range.retain());
|
return this.containsRange(snapshot, Mono.just(range).map(LLRange::retain));
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(isContained -> !isContained)
|
|
||||||
.doFirst(range::retain)
|
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
range -> Mono.fromRunnable(range::release)
|
||||||
|
).map(isContained -> !isContained);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mono<Boolean> containsRange(@Nullable LLSnapshot snapshot, LLRange range) {
|
public Mono<Boolean> containsRange(@Nullable LLSnapshot snapshot, Mono<LLRange> rangeMono) {
|
||||||
try {
|
return Mono.usingWhen(rangeMono,
|
||||||
return Mono
|
range -> runOnDb(() -> {
|
||||||
.fromCallable(() -> {
|
|
||||||
try (var readOpts = new ReadOptions(resolveSnapshot(snapshot))) {
|
try (var readOpts = new ReadOptions(resolveSnapshot(snapshot))) {
|
||||||
readOpts.setVerifyChecksums(VERIFY_CHECKSUMS_WHEN_NOT_NEEDED);
|
readOpts.setVerifyChecksums(VERIFY_CHECKSUMS_WHEN_NOT_NEEDED);
|
||||||
readOpts.setFillCache(false);
|
readOpts.setFillCache(false);
|
||||||
|
@ -478,20 +462,14 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
return rocksIterator.isValid();
|
return rocksIterator.isValid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}).onErrorMap(cause -> new IOException("Failed to read range " + range.toString(), cause)),
|
||||||
.onErrorMap(cause -> new IOException("Failed to read range " + range.toString(), cause))
|
range -> Mono.fromRunnable(range::release));
|
||||||
.subscribeOn(dbScheduler)
|
|
||||||
.doFirst(range::retain)
|
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<Boolean> containsKey(@Nullable LLSnapshot snapshot, ByteBuf key) {
|
private Mono<Boolean> containsKey(@Nullable LLSnapshot snapshot, Mono<ByteBuf> keyMono) {
|
||||||
try {
|
return Mono.usingWhen(keyMono,
|
||||||
return Mono
|
key -> runOnDb(() -> {
|
||||||
.fromCallable(() -> {
|
|
||||||
StampedLock lock;
|
StampedLock lock;
|
||||||
long stamp;
|
long stamp;
|
||||||
if (updateMode == UpdateMode.ALLOW) {
|
if (updateMode == UpdateMode.ALLOW) {
|
||||||
|
@ -520,23 +498,18 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
lock.unlockRead(stamp);
|
lock.unlockRead(stamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}).onErrorMap(cause -> new IOException("Failed to read " + LLUtils.toStringSafe(key), cause)),
|
||||||
.onErrorMap(cause -> new IOException("Failed to read " + LLUtils.toStringSafe(key), cause))
|
key -> Mono.fromRunnable(key::release)
|
||||||
.subscribeOn(dbScheduler)
|
);
|
||||||
.doFirst(key::retain)
|
|
||||||
.doAfterTerminate(key::release);
|
|
||||||
} finally {
|
|
||||||
key.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ByteBuf> put(ByteBuf key, ByteBuf value, LLDictionaryResultType resultType) {
|
public Mono<ByteBuf> put(Mono<ByteBuf> keyMono, Mono<ByteBuf> valueMono, LLDictionaryResultType resultType) {
|
||||||
try {
|
return Mono.usingWhen(keyMono,
|
||||||
return Mono
|
key -> this
|
||||||
.defer(() -> getPreviousData(key.retain(), resultType))
|
.getPreviousData(Mono.just(key).map(ByteBuf::retain), resultType)
|
||||||
.concatWith(Mono
|
.concatWith(Mono.usingWhen(valueMono,
|
||||||
.<ByteBuf>fromCallable(() -> {
|
value -> this.<ByteBuf>runOnDb(() -> {
|
||||||
StampedLock lock;
|
StampedLock lock;
|
||||||
long stamp;
|
long stamp;
|
||||||
if (updateMode == UpdateMode.ALLOW) {
|
if (updateMode == UpdateMode.ALLOW) {
|
||||||
|
@ -558,23 +531,12 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
lock.unlockWrite(stamp);
|
lock.unlockWrite(stamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
.subscribeOn(dbScheduler)
|
value -> Mono.fromRunnable(value::release)
|
||||||
.onErrorMap(cause -> new IOException("Failed to write " + LLUtils.toStringSafe(key), cause))
|
).onErrorMap(cause -> new IOException("Failed to write " + LLUtils.toStringSafe(key), cause)))
|
||||||
)
|
.singleOrEmpty(),
|
||||||
.singleOrEmpty()
|
key -> Mono.fromRunnable(key::release)
|
||||||
.doFirst(() -> {
|
);
|
||||||
key.retain();
|
|
||||||
value.retain();
|
|
||||||
})
|
|
||||||
.doAfterTerminate(() -> {
|
|
||||||
key.release();
|
|
||||||
value.release();
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
key.release();
|
|
||||||
value.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -585,13 +547,12 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
// Remember to change also updateAndGetDelta() if you are modifying this function
|
// Remember to change also updateAndGetDelta() if you are modifying this function
|
||||||
@SuppressWarnings("DuplicatedCode")
|
@SuppressWarnings("DuplicatedCode")
|
||||||
@Override
|
@Override
|
||||||
public Mono<ByteBuf> update(ByteBuf key,
|
public Mono<ByteBuf> update(Mono<ByteBuf> keyMono,
|
||||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||||
UpdateReturnMode updateReturnMode,
|
UpdateReturnMode updateReturnMode,
|
||||||
boolean existsAlmostCertainly) {
|
boolean existsAlmostCertainly) {
|
||||||
try {
|
return Mono.usingWhen(keyMono,
|
||||||
return Mono
|
key -> runOnDb(() -> {
|
||||||
.fromCallable(() -> {
|
|
||||||
if (updateMode == UpdateMode.DISALLOW) {
|
if (updateMode == UpdateMode.DISALLOW) {
|
||||||
throw new UnsupportedOperationException("update() is disallowed");
|
throw new UnsupportedOperationException("update() is disallowed");
|
||||||
}
|
}
|
||||||
|
@ -704,25 +665,19 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
lock.unlock(stamp);
|
lock.unlock(stamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}).onErrorMap(cause -> new IOException("Failed to read or write " + LLUtils.toStringSafe(key), cause)),
|
||||||
.onErrorMap(cause -> new IOException("Failed to read or write " + LLUtils.toStringSafe(key), cause))
|
key -> Mono.fromRunnable(key::release)
|
||||||
.subscribeOn(dbScheduler)
|
);
|
||||||
.doFirst(key::retain)
|
|
||||||
.doAfterTerminate(key::release);
|
|
||||||
} finally {
|
|
||||||
key.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember to change also update() if you are modifying this function
|
// Remember to change also update() if you are modifying this function
|
||||||
@SuppressWarnings("DuplicatedCode")
|
@SuppressWarnings("DuplicatedCode")
|
||||||
@Override
|
@Override
|
||||||
public Mono<Delta<ByteBuf>> updateAndGetDelta(ByteBuf key,
|
public Mono<Delta<ByteBuf>> updateAndGetDelta(Mono<ByteBuf> keyMono,
|
||||||
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
Function<@Nullable ByteBuf, @Nullable ByteBuf> updater,
|
||||||
boolean existsAlmostCertainly) {
|
boolean existsAlmostCertainly) {
|
||||||
try {
|
return Mono.usingWhen(keyMono,
|
||||||
return Mono
|
key -> this.runOnDb(() -> {
|
||||||
.fromCallable(() -> {
|
|
||||||
if (updateMode == UpdateMode.DISALLOW) throw new UnsupportedOperationException("update() is disallowed");
|
if (updateMode == UpdateMode.DISALLOW) throw new UnsupportedOperationException("update() is disallowed");
|
||||||
StampedLock lock;
|
StampedLock lock;
|
||||||
long stamp;
|
long stamp;
|
||||||
|
@ -760,11 +715,10 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
ByteBuf prevDataToSendToUpdater = prevData == null ? null : prevData.retainedSlice();
|
ByteBuf prevDataToSendToUpdater = prevData == null ? null : prevData.retainedSlice();
|
||||||
try {
|
try {
|
||||||
newData = updater.apply(prevDataToSendToUpdater == null ? null : prevDataToSendToUpdater.retain());
|
newData = updater.apply(prevDataToSendToUpdater == null ? null : prevDataToSendToUpdater.retain());
|
||||||
if (databaseOptions.enableDbAssertionsWhenUsingAssertions()) {
|
assert !databaseOptions.enableDbAssertionsWhenUsingAssertions()
|
||||||
assert prevDataToSendToUpdater == null
|
|| prevDataToSendToUpdater == null
|
||||||
|| prevDataToSendToUpdater.readerIndex() == 0
|
|| prevDataToSendToUpdater.readerIndex() == 0
|
||||||
|| !prevDataToSendToUpdater.isReadable();
|
|| !prevDataToSendToUpdater.isReadable();
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
if (prevDataToSendToUpdater != null) {
|
if (prevDataToSendToUpdater != null) {
|
||||||
prevDataToSendToUpdater.release();
|
prevDataToSendToUpdater.release();
|
||||||
|
@ -827,14 +781,9 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
lock.unlock(stamp);
|
lock.unlock(stamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}).onErrorMap(cause -> new IOException("Failed to read or write " + LLUtils.toStringSafe(key), cause)),
|
||||||
.onErrorMap(cause -> new IOException("Failed to read or write " + LLUtils.toStringSafe(key), cause))
|
key -> Mono.fromRunnable(key::release)
|
||||||
.subscribeOn(dbScheduler)
|
);
|
||||||
.doFirst(key::retain)
|
|
||||||
.doAfterTerminate(key::release);
|
|
||||||
} finally {
|
|
||||||
key.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dbDelete(ColumnFamilyHandle cfh, @Nullable WriteOptions writeOptions, ByteBuf key)
|
private void dbDelete(ColumnFamilyHandle cfh, @Nullable WriteOptions writeOptions, ByteBuf key)
|
||||||
|
@ -855,12 +804,12 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ByteBuf> remove(ByteBuf key, LLDictionaryResultType resultType) {
|
public Mono<ByteBuf> remove(Mono<ByteBuf> keyMono, LLDictionaryResultType resultType) {
|
||||||
try {
|
return Mono.usingWhen(keyMono,
|
||||||
return Mono
|
key -> this
|
||||||
.defer(() -> getPreviousData(key.retain(), resultType))
|
.getPreviousData(Mono.just(key).map(ByteBuf::retain), resultType)
|
||||||
.concatWith(Mono
|
.concatWith(this
|
||||||
.fromCallable(() -> {
|
.<ByteBuf>runOnDb(() -> {
|
||||||
StampedLock lock;
|
StampedLock lock;
|
||||||
long stamp;
|
long stamp;
|
||||||
if (updateMode == UpdateMode.ALLOW) {
|
if (updateMode == UpdateMode.ALLOW) {
|
||||||
|
@ -884,29 +833,21 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.onErrorMap(cause -> new IOException("Failed to delete " + LLUtils.toStringSafe(key), cause))
|
.onErrorMap(cause -> new IOException("Failed to delete " + LLUtils.toStringSafe(key), cause))
|
||||||
.subscribeOn(dbScheduler)
|
|
||||||
.then(Mono.empty())
|
|
||||||
)
|
)
|
||||||
.singleOrEmpty()
|
.singleOrEmpty(),
|
||||||
.doFirst(key::retain)
|
key -> Mono.fromCallable(key::release));
|
||||||
.doAfterTerminate(key::release);
|
|
||||||
} finally {
|
|
||||||
key.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<ByteBuf> getPreviousData(ByteBuf key, LLDictionaryResultType resultType) {
|
private Mono<ByteBuf> getPreviousData(Mono<ByteBuf> keyMono, LLDictionaryResultType resultType) {
|
||||||
try {
|
|
||||||
return Mono
|
return Mono
|
||||||
.defer(() -> switch (resultType) {
|
.usingWhen(keyMono,
|
||||||
|
key -> switch (resultType) {
|
||||||
case PREVIOUS_VALUE_EXISTENCE -> this
|
case PREVIOUS_VALUE_EXISTENCE -> this
|
||||||
.containsKey(null, key.retain())
|
.containsKey(null, Mono.just(key).map(ByteBuf::retain))
|
||||||
.single()
|
.single()
|
||||||
.map(LLUtils::booleanToResponseByteBuffer)
|
.map(LLUtils::booleanToResponseByteBuffer)
|
||||||
.doAfterTerminate(() -> {
|
.doAfterTerminate(() -> {
|
||||||
if (databaseOptions.enableDbAssertionsWhenUsingAssertions()) {
|
assert !databaseOptions.enableDbAssertionsWhenUsingAssertions() || key.refCnt() > 0;
|
||||||
assert key.refCnt() > 0;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
case PREVIOUS_VALUE -> Mono
|
case PREVIOUS_VALUE -> Mono
|
||||||
.fromCallable(() -> {
|
.fromCallable(() -> {
|
||||||
|
@ -932,9 +873,7 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
try {
|
try {
|
||||||
return dbGet(cfh, null, key.retain(), true);
|
return dbGet(cfh, null, key.retain(), true);
|
||||||
} finally {
|
} finally {
|
||||||
if (databaseOptions.enableDbAssertionsWhenUsingAssertions()) {
|
assert !databaseOptions.enableDbAssertionsWhenUsingAssertions() || key.refCnt() > 0;
|
||||||
assert key.refCnt() > 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -949,12 +888,9 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
.onErrorMap(cause -> new IOException("Failed to read " + LLUtils.toStringSafe(key), cause))
|
.onErrorMap(cause -> new IOException("Failed to read " + LLUtils.toStringSafe(key), cause))
|
||||||
.subscribeOn(dbScheduler);
|
.subscribeOn(dbScheduler);
|
||||||
case VOID -> Mono.empty();
|
case VOID -> Mono.empty();
|
||||||
})
|
},
|
||||||
.doFirst(key::retain)
|
key -> Mono.fromRunnable(key::release)
|
||||||
.doAfterTerminate(key::release);
|
);
|
||||||
} finally {
|
|
||||||
key.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1284,61 +1220,51 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<Entry<ByteBuf, ByteBuf>> getRange(@Nullable LLSnapshot snapshot,
|
public Flux<Entry<ByteBuf, ByteBuf>> getRange(@Nullable LLSnapshot snapshot,
|
||||||
LLRange range,
|
Mono<LLRange> rangeMono,
|
||||||
boolean existsAlmostCertainly) {
|
boolean existsAlmostCertainly) {
|
||||||
try {
|
return Flux.usingWhen(rangeMono,
|
||||||
return Flux
|
range -> {
|
||||||
.defer(() -> {
|
|
||||||
if (range.isSingle()) {
|
if (range.isSingle()) {
|
||||||
return getRangeSingle(snapshot, range.getMin().retain(), existsAlmostCertainly);
|
return getRangeSingle(snapshot, Mono.just(range.getMin()).map(ByteBuf::retain), existsAlmostCertainly);
|
||||||
} else {
|
} else {
|
||||||
return getRangeMulti(snapshot, range.retain());
|
return getRangeMulti(snapshot, Mono.just(range).map(LLRange::retain));
|
||||||
}
|
|
||||||
})
|
|
||||||
.doFirst(range::retain)
|
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
range -> Mono.fromRunnable(range::release)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<List<Entry<ByteBuf, ByteBuf>>> getRangeGrouped(@Nullable LLSnapshot snapshot,
|
public Flux<List<Entry<ByteBuf, ByteBuf>>> getRangeGrouped(@Nullable LLSnapshot snapshot,
|
||||||
LLRange range,
|
Mono<LLRange> rangeMono,
|
||||||
int prefixLength, boolean existsAlmostCertainly) {
|
int prefixLength, boolean existsAlmostCertainly) {
|
||||||
try {
|
return Flux.usingWhen(rangeMono,
|
||||||
return Flux
|
range -> {
|
||||||
.defer(() -> {
|
|
||||||
if (range.isSingle()) {
|
if (range.isSingle()) {
|
||||||
return getRangeSingle(snapshot, range.getMin().retain(), existsAlmostCertainly).map(List::of);
|
var rangeSingleMono = Mono.just(range.getMin()).map(ByteBuf::retain);
|
||||||
|
return getRangeSingle(snapshot, rangeSingleMono, existsAlmostCertainly).map(List::of);
|
||||||
} else {
|
} else {
|
||||||
return getRangeMultiGrouped(snapshot, range.retain(), prefixLength);
|
return getRangeMultiGrouped(snapshot, Mono.just(range).map(LLRange::retain), prefixLength);
|
||||||
}
|
|
||||||
})
|
|
||||||
.doFirst(range::retain)
|
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
range -> Mono.fromRunnable(range::release)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Flux<Entry<ByteBuf, ByteBuf>> getRangeSingle(LLSnapshot snapshot, ByteBuf key, boolean existsAlmostCertainly) {
|
private Flux<Entry<ByteBuf, ByteBuf>> getRangeSingle(LLSnapshot snapshot,
|
||||||
try {
|
Mono<ByteBuf> keyMono,
|
||||||
return Mono
|
boolean existsAlmostCertainly) {
|
||||||
.defer(() -> this.get(snapshot, key.retain(), existsAlmostCertainly))
|
return Flux.usingWhen(keyMono,
|
||||||
.map(value -> Map.entry(key.retain(), value))
|
key -> this
|
||||||
.flux()
|
.get(snapshot, Mono.just(key).map(ByteBuf::retain), existsAlmostCertainly)
|
||||||
.doFirst(key::retain)
|
.map(value -> Map.entry(key.retain(), value)),
|
||||||
.doAfterTerminate(key::release);
|
key -> Mono.fromRunnable(key::release)
|
||||||
} finally {
|
);
|
||||||
key.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("Convert2MethodRef")
|
private Flux<Entry<ByteBuf, ByteBuf>> getRangeMulti(LLSnapshot snapshot, Mono<LLRange> rangeMono) {
|
||||||
private Flux<Entry<ByteBuf, ByteBuf>> getRangeMulti(LLSnapshot snapshot, LLRange range) {
|
return Flux.usingWhen(rangeMono,
|
||||||
try {
|
range -> Flux
|
||||||
return Flux
|
|
||||||
.using(
|
.using(
|
||||||
() -> new LLLocalEntryReactiveRocksIterator(db,
|
() -> new LLLocalEntryReactiveRocksIterator(db,
|
||||||
alloc,
|
alloc,
|
||||||
|
@ -1348,27 +1274,18 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
resolveSnapshot(snapshot),
|
resolveSnapshot(snapshot),
|
||||||
getRangeMultiDebugName
|
getRangeMultiDebugName
|
||||||
),
|
),
|
||||||
llLocalEntryReactiveRocksIterator -> llLocalEntryReactiveRocksIterator.flux(),
|
llLocalEntryReactiveRocksIterator -> llLocalEntryReactiveRocksIterator
|
||||||
|
.flux()
|
||||||
|
.subscribeOn(dbScheduler),
|
||||||
LLLocalReactiveRocksIterator::release
|
LLLocalReactiveRocksIterator::release
|
||||||
)
|
),
|
||||||
.doOnDiscard(Entry.class, entry -> {
|
range -> Mono.fromRunnable(range::release)
|
||||||
//noinspection unchecked
|
);
|
||||||
var castedEntry = (Entry<ByteBuf, ByteBuf>) entry;
|
|
||||||
castedEntry.getKey().release();
|
|
||||||
castedEntry.getValue().release();
|
|
||||||
})
|
|
||||||
.subscribeOn(dbScheduler)
|
|
||||||
.doFirst(range::retain)
|
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("Convert2MethodRef")
|
private Flux<List<Entry<ByteBuf, ByteBuf>>> getRangeMultiGrouped(LLSnapshot snapshot, Mono<LLRange> rangeMono, int prefixLength) {
|
||||||
private Flux<List<Entry<ByteBuf, ByteBuf>>> getRangeMultiGrouped(LLSnapshot snapshot, LLRange range, int prefixLength) {
|
return Flux.usingWhen(rangeMono,
|
||||||
try {
|
range -> Flux
|
||||||
return Flux
|
|
||||||
.using(
|
.using(
|
||||||
() -> new LLLocalGroupedEntryReactiveRocksIterator(db,
|
() -> new LLLocalGroupedEntryReactiveRocksIterator(db,
|
||||||
alloc,
|
alloc,
|
||||||
|
@ -1379,39 +1296,35 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
resolveSnapshot(snapshot),
|
resolveSnapshot(snapshot),
|
||||||
"getRangeMultiGrouped"
|
"getRangeMultiGrouped"
|
||||||
),
|
),
|
||||||
llLocalGroupedEntryReactiveRocksIterator -> llLocalGroupedEntryReactiveRocksIterator.flux(),
|
reactiveRocksIterator -> reactiveRocksIterator
|
||||||
|
.flux()
|
||||||
|
.subscribeOn(dbScheduler),
|
||||||
LLLocalGroupedReactiveRocksIterator::release
|
LLLocalGroupedReactiveRocksIterator::release
|
||||||
)
|
),
|
||||||
.subscribeOn(dbScheduler)
|
range -> Mono.fromRunnable(range::release)
|
||||||
.doFirst(range::retain)
|
);
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<ByteBuf> getRangeKeys(@Nullable LLSnapshot snapshot, LLRange range) {
|
public Flux<ByteBuf> getRangeKeys(@Nullable LLSnapshot snapshot, Mono<LLRange> rangeMono) {
|
||||||
try {
|
return Flux.usingWhen(rangeMono,
|
||||||
return Flux
|
range -> {
|
||||||
.defer(() -> {
|
|
||||||
if (range.isSingle()) {
|
if (range.isSingle()) {
|
||||||
return this.getRangeKeysSingle(snapshot, range.getMin().retain());
|
return this.getRangeKeysSingle(snapshot, Mono.just(range.getMin()).map(ByteBuf::retain));
|
||||||
} else {
|
} else {
|
||||||
return this.getRangeKeysMulti(snapshot, range.retain());
|
return this.getRangeKeysMulti(snapshot, Mono.just(range).map(LLRange::retain));
|
||||||
}
|
|
||||||
})
|
|
||||||
.doFirst(range::retain)
|
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
range -> Mono.fromRunnable(range::release)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<List<ByteBuf>> getRangeKeysGrouped(@Nullable LLSnapshot snapshot, LLRange range, int prefixLength) {
|
public Flux<List<ByteBuf>> getRangeKeysGrouped(@Nullable LLSnapshot snapshot,
|
||||||
try {
|
Mono<LLRange> rangeMono,
|
||||||
return Flux
|
int prefixLength) {
|
||||||
|
return Flux.usingWhen(rangeMono,
|
||||||
|
range -> Flux
|
||||||
.using(
|
.using(
|
||||||
() -> new LLLocalGroupedKeyReactiveRocksIterator(db,
|
() -> new LLLocalGroupedKeyReactiveRocksIterator(db,
|
||||||
alloc,
|
alloc,
|
||||||
|
@ -1421,21 +1334,18 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
databaseOptions.allowNettyDirect(),
|
databaseOptions.allowNettyDirect(),
|
||||||
resolveSnapshot(snapshot),
|
resolveSnapshot(snapshot),
|
||||||
"getRangeKeysGrouped"
|
"getRangeKeysGrouped"
|
||||||
),
|
), reactiveRocksIterator -> reactiveRocksIterator.flux()
|
||||||
LLLocalGroupedReactiveRocksIterator::flux,
|
.subscribeOn(dbScheduler),
|
||||||
LLLocalGroupedReactiveRocksIterator::release
|
LLLocalGroupedReactiveRocksIterator::release
|
||||||
)
|
),
|
||||||
.subscribeOn(dbScheduler)
|
range -> Mono.fromRunnable(range::release)
|
||||||
.doFirst(range::retain)
|
);
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<BadBlock> badBlocks(LLRange range) {
|
public Flux<BadBlock> badBlocks(Mono<LLRange> rangeMono) {
|
||||||
return Flux
|
return Flux.usingWhen(rangeMono,
|
||||||
|
range -> Flux
|
||||||
.<BadBlock>create(sink -> {
|
.<BadBlock>create(sink -> {
|
||||||
try (var ro = new ReadOptions(getReadOptions(null))) {
|
try (var ro = new ReadOptions(getReadOptions(null))) {
|
||||||
ro.setFillCache(false);
|
ro.setFillCache(false);
|
||||||
|
@ -1470,15 +1380,15 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
sink.error(ex);
|
sink.error(ex);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.subscribeOn(dbScheduler)
|
.subscribeOn(dbScheduler),
|
||||||
.doFirst(range::retain)
|
range -> Mono.fromRunnable(range::release)
|
||||||
.doAfterTerminate(range::release);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<ByteBuf> getRangeKeyPrefixes(@Nullable LLSnapshot snapshot, LLRange range, int prefixLength) {
|
public Flux<ByteBuf> getRangeKeyPrefixes(@Nullable LLSnapshot snapshot, Mono<LLRange> rangeMono, int prefixLength) {
|
||||||
try {
|
return Flux.usingWhen(rangeMono,
|
||||||
return Flux
|
range -> Flux
|
||||||
.using(
|
.using(
|
||||||
() -> new LLLocalKeyPrefixReactiveRocksIterator(db,
|
() -> new LLLocalKeyPrefixReactiveRocksIterator(db,
|
||||||
alloc,
|
alloc,
|
||||||
|
@ -1493,18 +1403,15 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
LLLocalKeyPrefixReactiveRocksIterator::flux,
|
LLLocalKeyPrefixReactiveRocksIterator::flux,
|
||||||
LLLocalKeyPrefixReactiveRocksIterator::release
|
LLLocalKeyPrefixReactiveRocksIterator::release
|
||||||
)
|
)
|
||||||
.subscribeOn(dbScheduler)
|
.subscribeOn(dbScheduler),
|
||||||
.doFirst(range::retain)
|
range -> Mono.fromRunnable(range::release)
|
||||||
.doAfterTerminate(range::release);
|
);
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Flux<ByteBuf> getRangeKeysSingle(LLSnapshot snapshot, ByteBuf key) {
|
private Flux<ByteBuf> getRangeKeysSingle(LLSnapshot snapshot, Mono<ByteBuf> keyMono) {
|
||||||
try {
|
return Flux.usingWhen(keyMono,
|
||||||
return Mono
|
key -> this
|
||||||
.defer(() -> this.containsKey(snapshot, key.retain()))
|
.containsKey(snapshot, Mono.just(key).map(ByteBuf::retain))
|
||||||
.flux()
|
.flux()
|
||||||
.<ByteBuf>handle((contains, sink) -> {
|
.<ByteBuf>handle((contains, sink) -> {
|
||||||
if (contains) {
|
if (contains) {
|
||||||
|
@ -1513,18 +1420,15 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
sink.complete();
|
sink.complete();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.doOnDiscard(ByteBuf.class, ReferenceCounted::release)
|
.doOnDiscard(ByteBuf.class, ReferenceCounted::release),
|
||||||
.doFirst(key::retain)
|
key -> Mono.fromRunnable(key::release)
|
||||||
.doAfterTerminate(key::release);
|
);
|
||||||
} finally {
|
|
||||||
key.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("Convert2MethodRef")
|
@SuppressWarnings("Convert2MethodRef")
|
||||||
private Flux<ByteBuf> getRangeKeysMulti(LLSnapshot snapshot, LLRange range) {
|
private Flux<ByteBuf> getRangeKeysMulti(LLSnapshot snapshot, Mono<LLRange> rangeMono) {
|
||||||
try {
|
return Flux.usingWhen(rangeMono,
|
||||||
return Flux
|
range -> Flux
|
||||||
.using(
|
.using(
|
||||||
() -> new LLLocalKeyReactiveRocksIterator(db,
|
() -> new LLLocalKeyReactiveRocksIterator(db,
|
||||||
alloc,
|
alloc,
|
||||||
|
@ -1538,17 +1442,15 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
LLLocalReactiveRocksIterator::release
|
LLLocalReactiveRocksIterator::release
|
||||||
)
|
)
|
||||||
.doOnDiscard(ByteBuf.class, ReferenceCounted::release)
|
.doOnDiscard(ByteBuf.class, ReferenceCounted::release)
|
||||||
.subscribeOn(dbScheduler)
|
.subscribeOn(dbScheduler),
|
||||||
.doFirst(range::retain)
|
range -> Mono.fromRunnable(range::release)
|
||||||
.doAfterTerminate(range::release);
|
);
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> setRange(LLRange range, Flux<Entry<ByteBuf, ByteBuf>> entries) {
|
public Mono<Void> setRange(Mono<LLRange> rangeMono, Flux<Entry<ByteBuf, ByteBuf>> entries) {
|
||||||
try {
|
return Mono.usingWhen(rangeMono,
|
||||||
|
range -> {
|
||||||
if (USE_WINDOW_IN_SET_RANGE) {
|
if (USE_WINDOW_IN_SET_RANGE) {
|
||||||
return Mono
|
return Mono
|
||||||
.<Void>fromCallable(() -> {
|
.<Void>fromCallable(() -> {
|
||||||
|
@ -1673,17 +1575,15 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.then()
|
.then()
|
||||||
.onErrorMap(cause -> new IOException("Failed to write range", cause))
|
.onErrorMap(cause -> new IOException("Failed to write range", cause));
|
||||||
.doFirst(range::retain)
|
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} else {
|
} else {
|
||||||
if (USE_WRITE_BATCHES_IN_SET_RANGE) {
|
if (USE_WRITE_BATCHES_IN_SET_RANGE) {
|
||||||
return Mono.fromCallable(() -> {
|
return Mono.fromCallable(() -> {
|
||||||
throw new UnsupportedOperationException("Can't use write batches in setRange without window. Please fix params");
|
throw new UnsupportedOperationException("Can't use write batches in setRange without window. Please fix params");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Flux
|
return this
|
||||||
.defer(() -> this.getRange(null, range.retain(), false))
|
.getRange(null, Mono.just(range).map(LLRange::retain), false)
|
||||||
.flatMap(oldValue -> Mono
|
.flatMap(oldValue -> Mono
|
||||||
.<Void>fromCallable(() -> {
|
.<Void>fromCallable(() -> {
|
||||||
try {
|
try {
|
||||||
|
@ -1697,20 +1597,29 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
.subscribeOn(dbScheduler)
|
.subscribeOn(dbScheduler)
|
||||||
)
|
)
|
||||||
.then(entries
|
.then(entries
|
||||||
.flatMap(entry -> this.put(entry.getKey(), entry.getValue(), LLDictionaryResultType.VOID))
|
.flatMap(entry -> Mono.using(
|
||||||
.doOnNext(ReferenceCounted::release)
|
() -> entry,
|
||||||
|
releasableEntry -> this
|
||||||
|
.put(Mono.just(entry.getKey()).map(ByteBuf::retain),
|
||||||
|
Mono.just(entry.getValue()).map(ByteBuf::retain),
|
||||||
|
LLDictionaryResultType.VOID
|
||||||
|
)
|
||||||
|
.doOnNext(ReferenceCounted::release),
|
||||||
|
releasableEntry -> {
|
||||||
|
releasableEntry.getKey().release();
|
||||||
|
releasableEntry.getValue().release();
|
||||||
|
})
|
||||||
|
)
|
||||||
.then(Mono.<Void>empty())
|
.then(Mono.<Void>empty())
|
||||||
)
|
)
|
||||||
.onErrorMap(cause -> new IOException("Failed to write range", cause))
|
.onErrorMap(cause -> new IOException("Failed to write range", cause));
|
||||||
.doFirst(range::retain)
|
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
range -> Mono.fromRunnable(range::release)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: this is broken, check why
|
//todo: this is broken, check why. (is this still true?)
|
||||||
private void deleteSmallRangeWriteBatch(CappedWriteBatch writeBatch, LLRange range)
|
private void deleteSmallRangeWriteBatch(CappedWriteBatch writeBatch, LLRange range)
|
||||||
throws RocksDBException {
|
throws RocksDBException {
|
||||||
try (var readOpts = new ReadOptions(getReadOptions(null))) {
|
try (var readOpts = new ReadOptions(getReadOptions(null))) {
|
||||||
|
@ -1932,18 +1841,15 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Long> sizeRange(@Nullable LLSnapshot snapshot, LLRange range, boolean fast) {
|
public Mono<Long> sizeRange(@Nullable LLSnapshot snapshot, Mono<LLRange> rangeMono, boolean fast) {
|
||||||
try {
|
return Mono.usingWhen(rangeMono,
|
||||||
return Mono
|
range -> {
|
||||||
.defer(() -> {
|
|
||||||
if (range.isAll()) {
|
if (range.isAll()) {
|
||||||
return Mono
|
return this
|
||||||
.fromCallable(() -> fast ? fastSizeAll(snapshot) : exactSizeAll(snapshot))
|
.runOnDb(() -> fast ? fastSizeAll(snapshot) : exactSizeAll(snapshot))
|
||||||
.onErrorMap(IOException::new)
|
.onErrorMap(IOException::new);
|
||||||
.subscribeOn(dbScheduler);
|
|
||||||
} else {
|
} else {
|
||||||
return Mono
|
return runOnDb(() -> {
|
||||||
.fromCallable(() -> {
|
|
||||||
try (var readOpts = new ReadOptions(resolveSnapshot(snapshot))) {
|
try (var readOpts = new ReadOptions(resolveSnapshot(snapshot))) {
|
||||||
readOpts.setFillCache(false);
|
readOpts.setFillCache(false);
|
||||||
readOpts.setVerifyChecksums(VERIFY_CHECKSUMS_WHEN_NOT_NEEDED);
|
readOpts.setVerifyChecksums(VERIFY_CHECKSUMS_WHEN_NOT_NEEDED);
|
||||||
|
@ -1998,24 +1904,17 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
minBound.release();
|
minBound.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}).onErrorMap(cause -> new IOException("Failed to get size of range " + range, cause));
|
||||||
.onErrorMap(cause -> new IOException("Failed to get size of range "
|
|
||||||
+ range, cause))
|
|
||||||
.subscribeOn(dbScheduler);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.doFirst(range::retain)
|
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
range -> Mono.fromRunnable(range::release)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Entry<ByteBuf, ByteBuf>> getOne(@Nullable LLSnapshot snapshot, LLRange range) {
|
public Mono<Entry<ByteBuf, ByteBuf>> getOne(@Nullable LLSnapshot snapshot, Mono<LLRange> rangeMono) {
|
||||||
try {
|
return Mono.usingWhen(rangeMono,
|
||||||
return Mono
|
range -> runOnDb(() -> {
|
||||||
.fromCallable(() -> {
|
|
||||||
try (var readOpts = new ReadOptions(resolveSnapshot(snapshot))) {
|
try (var readOpts = new ReadOptions(resolveSnapshot(snapshot))) {
|
||||||
ReleasableSlice minBound;
|
ReleasableSlice minBound;
|
||||||
if (range.hasMin()) {
|
if (range.hasMin()) {
|
||||||
|
@ -2067,20 +1966,15 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
minBound.release();
|
minBound.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
.subscribeOn(dbScheduler)
|
range -> Mono.fromRunnable(range::release)
|
||||||
.doFirst(range::retain)
|
);
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ByteBuf> getOneKey(@Nullable LLSnapshot snapshot, LLRange range) {
|
public Mono<ByteBuf> getOneKey(@Nullable LLSnapshot snapshot, Mono<LLRange> rangeMono) {
|
||||||
try {
|
return Mono.usingWhen(rangeMono,
|
||||||
return Mono
|
range -> runOnDb(() -> {
|
||||||
.fromCallable(() -> {
|
|
||||||
try (var readOpts = new ReadOptions(resolveSnapshot(snapshot))) {
|
try (var readOpts = new ReadOptions(resolveSnapshot(snapshot))) {
|
||||||
ReleasableSlice minBound;
|
ReleasableSlice minBound;
|
||||||
if (range.hasMin()) {
|
if (range.hasMin()) {
|
||||||
|
@ -2124,13 +2018,9 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
minBound.release();
|
minBound.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
.subscribeOn(dbScheduler)
|
range -> Mono.fromRunnable(range::release)
|
||||||
.doFirst(range::retain)
|
);
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private long fastSizeAll(@Nullable LLSnapshot snapshot) throws RocksDBException {
|
private long fastSizeAll(@Nullable LLSnapshot snapshot) throws RocksDBException {
|
||||||
|
@ -2242,10 +2132,9 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Entry<ByteBuf, ByteBuf>> removeOne(LLRange range) {
|
public Mono<Entry<ByteBuf, ByteBuf>> removeOne(Mono<LLRange> rangeMono) {
|
||||||
try {
|
return Mono.usingWhen(rangeMono,
|
||||||
return Mono
|
range -> runOnDb(() -> {
|
||||||
.fromCallable(() -> {
|
|
||||||
try (var readOpts = new ReadOptions(getReadOptions(null))) {
|
try (var readOpts = new ReadOptions(getReadOptions(null))) {
|
||||||
ReleasableSlice minBound;
|
ReleasableSlice minBound;
|
||||||
if (range.hasMin()) {
|
if (range.hasMin()) {
|
||||||
|
@ -2289,14 +2178,9 @@ public class LLLocalDictionary implements LLDictionary {
|
||||||
minBound.release();
|
minBound.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}).onErrorMap(cause -> new IOException("Failed to delete " + range.toString(), cause)),
|
||||||
.onErrorMap(cause -> new IOException("Failed to delete " + range.toString(), cause))
|
range -> Mono.fromRunnable(range::release)
|
||||||
.subscribeOn(dbScheduler)
|
);
|
||||||
.doFirst(range::retain)
|
|
||||||
.doAfterTerminate(range::release);
|
|
||||||
} finally {
|
|
||||||
range.release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|
Loading…
Reference in New Issue
Block a user