2021-10-20 01:51:34 +02:00
|
|
|
package it.cavallium.dbengine.database.disk;
|
|
|
|
|
|
|
|
import static java.util.Objects.requireNonNull;
|
|
|
|
|
2022-03-30 15:15:53 +02:00
|
|
|
import io.micrometer.core.instrument.Counter;
|
|
|
|
import io.micrometer.core.instrument.DistributionSummary;
|
2021-10-30 11:13:46 +02:00
|
|
|
import io.micrometer.core.instrument.MeterRegistry;
|
2022-03-30 15:15:53 +02:00
|
|
|
import io.micrometer.core.instrument.Timer;
|
2023-03-06 12:19:08 +01:00
|
|
|
import it.cavallium.buffer.Buf;
|
2022-03-30 15:15:53 +02:00
|
|
|
import it.cavallium.dbengine.database.LLRange;
|
2021-10-20 01:51:34 +02:00
|
|
|
import it.cavallium.dbengine.database.LLUtils;
|
|
|
|
import it.cavallium.dbengine.database.RepeatedElementList;
|
2023-05-22 19:12:05 +02:00
|
|
|
import it.cavallium.dbengine.database.disk.rocksdb.LLReadOptions;
|
|
|
|
import it.cavallium.dbengine.database.disk.rocksdb.LLSlice;
|
|
|
|
import it.cavallium.dbengine.database.disk.rocksdb.LLWriteOptions;
|
2022-05-12 19:14:27 +02:00
|
|
|
import it.cavallium.dbengine.database.disk.rocksdb.RocksIteratorObj;
|
2023-03-27 22:00:32 +02:00
|
|
|
import it.cavallium.dbengine.database.serialization.SerializationFunction;
|
2023-05-22 19:12:05 +02:00
|
|
|
import it.cavallium.dbengine.utils.SimpleResource;
|
2021-10-20 01:51:34 +02:00
|
|
|
import java.nio.ByteBuffer;
|
2022-03-30 15:15:53 +02:00
|
|
|
import java.nio.charset.StandardCharsets;
|
2021-10-20 01:51:34 +02:00
|
|
|
import java.util.List;
|
2023-01-05 02:21:09 +01:00
|
|
|
import java.util.Map;
|
2022-04-01 01:30:56 +02:00
|
|
|
import java.util.concurrent.TimeUnit;
|
2022-04-30 01:49:44 +02:00
|
|
|
import java.util.concurrent.locks.StampedLock;
|
2021-12-17 01:48:49 +01:00
|
|
|
import org.apache.logging.log4j.LogManager;
|
|
|
|
import org.apache.logging.log4j.Logger;
|
2021-10-20 01:51:34 +02:00
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
import org.jetbrains.annotations.Nullable;
|
2022-05-20 10:20:00 +02:00
|
|
|
import org.rocksdb.AbstractImmutableNativeReference;
|
2021-10-20 01:51:34 +02:00
|
|
|
import org.rocksdb.ColumnFamilyHandle;
|
|
|
|
import org.rocksdb.CompactRangeOptions;
|
|
|
|
import org.rocksdb.FlushOptions;
|
|
|
|
import org.rocksdb.Holder;
|
2022-06-09 19:45:03 +02:00
|
|
|
import org.rocksdb.KeyMayExist;
|
2021-10-20 01:51:34 +02:00
|
|
|
import org.rocksdb.RocksDB;
|
|
|
|
import org.rocksdb.RocksDBException;
|
2022-05-12 19:14:27 +02:00
|
|
|
import org.rocksdb.RocksObject;
|
2023-01-05 02:21:09 +01:00
|
|
|
import org.rocksdb.TableProperties;
|
2021-10-20 01:51:34 +02:00
|
|
|
import org.rocksdb.Transaction;
|
2022-05-12 19:14:27 +02:00
|
|
|
import org.rocksdb.TransactionOptions;
|
2021-10-20 01:51:34 +02:00
|
|
|
import org.rocksdb.WriteBatch;
|
|
|
|
|
|
|
|
public sealed abstract class AbstractRocksDBColumn<T extends RocksDB> implements RocksDBColumn
|
|
|
|
permits StandardRocksDBColumn, OptimisticRocksDBColumn, PessimisticRocksDBColumn {
|
|
|
|
private static final byte[] NO_DATA = new byte[0];
|
|
|
|
protected static final UpdateAtomicResult RESULT_NOTHING = new UpdateAtomicResultNothing();
|
|
|
|
|
2021-12-17 01:48:49 +01:00
|
|
|
protected final Logger logger = LogManager.getLogger(this.getClass());
|
2021-10-20 01:51:34 +02:00
|
|
|
|
|
|
|
private final T db;
|
2022-05-20 10:20:00 +02:00
|
|
|
private final ColumnFamilyHandle cfh;
|
2021-10-20 01:51:34 +02:00
|
|
|
|
2022-03-30 18:36:07 +02:00
|
|
|
protected final MeterRegistry meterRegistry;
|
2022-04-30 01:49:44 +02:00
|
|
|
protected final StampedLock closeLock;
|
2022-03-30 18:36:07 +02:00
|
|
|
protected final String columnName;
|
2022-03-30 15:15:53 +02:00
|
|
|
|
|
|
|
protected final DistributionSummary keyBufferSize;
|
|
|
|
protected final DistributionSummary readValueNotFoundWithoutBloomBufferSize;
|
|
|
|
protected final DistributionSummary readValueNotFoundWithBloomBufferSize;
|
2022-04-01 01:30:56 +02:00
|
|
|
protected final DistributionSummary readValueNotFoundWithMayExistBloomBufferSize;
|
2022-03-30 15:15:53 +02:00
|
|
|
protected final DistributionSummary readValueFoundWithBloomUncachedBufferSize;
|
|
|
|
protected final DistributionSummary readValueFoundWithBloomCacheBufferSize;
|
|
|
|
protected final DistributionSummary readValueFoundWithBloomSimpleBufferSize;
|
2022-04-01 01:30:56 +02:00
|
|
|
protected final DistributionSummary readValueFoundWithoutBloomBufferSize;
|
2022-03-30 15:15:53 +02:00
|
|
|
protected final DistributionSummary writeValueBufferSize;
|
|
|
|
protected final DistributionSummary readAttempts;
|
|
|
|
|
|
|
|
private final Counter startedIterSeek;
|
|
|
|
private final Counter endedIterSeek;
|
|
|
|
private final Timer iterSeekTime;
|
|
|
|
private final Counter startedIterNext;
|
|
|
|
private final Counter endedIterNext;
|
|
|
|
private final Timer iterNextTime;
|
2021-10-30 11:13:46 +02:00
|
|
|
|
2022-04-01 01:30:56 +02:00
|
|
|
private final Counter startedUpdate;
|
|
|
|
private final Counter endedUpdate;
|
|
|
|
private final Timer updateAddedTime;
|
|
|
|
private final Timer updateReplacedTime;
|
|
|
|
private final Timer updateRemovedTime;
|
|
|
|
private final Timer updateUnchangedTime;
|
2022-06-09 19:45:03 +02:00
|
|
|
private final DBColumnKeyMayExistGetter keyMayExistGetter;
|
2023-05-22 19:12:05 +02:00
|
|
|
private final IteratorMetrics iteratorMetrics;
|
2022-04-01 01:30:56 +02:00
|
|
|
|
2021-10-30 11:13:46 +02:00
|
|
|
public AbstractRocksDBColumn(T db,
|
2022-03-30 15:15:53 +02:00
|
|
|
String databaseName,
|
2022-05-20 10:20:00 +02:00
|
|
|
ColumnFamilyHandle cfh,
|
2022-04-28 23:23:26 +02:00
|
|
|
MeterRegistry meterRegistry,
|
2022-04-30 01:49:44 +02:00
|
|
|
StampedLock closeLock) {
|
2021-10-20 01:51:34 +02:00
|
|
|
this.db = db;
|
|
|
|
this.cfh = cfh;
|
2022-03-30 15:15:53 +02:00
|
|
|
String columnName;
|
|
|
|
try {
|
2022-05-20 10:20:00 +02:00
|
|
|
columnName = new String(cfh.getName(), StandardCharsets.UTF_8);
|
2022-03-30 15:15:53 +02:00
|
|
|
} catch (RocksDBException e) {
|
|
|
|
throw new IllegalStateException(e);
|
|
|
|
}
|
2022-03-30 18:36:07 +02:00
|
|
|
this.columnName = columnName;
|
2021-10-30 11:13:46 +02:00
|
|
|
this.meterRegistry = meterRegistry;
|
2022-04-30 01:49:44 +02:00
|
|
|
this.closeLock = closeLock;
|
2022-03-30 15:15:53 +02:00
|
|
|
|
|
|
|
this.keyBufferSize = DistributionSummary
|
|
|
|
.builder("buffer.size.distribution")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.baseUnit("bytes")
|
|
|
|
.scale(1)
|
|
|
|
.publishPercentileHistogram()
|
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "buffer.type", "key")
|
|
|
|
.register(meterRegistry);
|
|
|
|
this.readValueNotFoundWithoutBloomBufferSize = DistributionSummary
|
|
|
|
.builder("buffer.size.distribution")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.baseUnit("bytes")
|
|
|
|
.scale(1)
|
|
|
|
.publishPercentileHistogram()
|
2022-04-07 22:19:11 +02:00
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "buffer.type", "val.read", "found", "false", "bloom", "disabled")
|
2022-03-30 15:15:53 +02:00
|
|
|
.register(meterRegistry);
|
|
|
|
this.readValueNotFoundWithBloomBufferSize = DistributionSummary
|
|
|
|
.builder("buffer.size.distribution")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.baseUnit("bytes")
|
|
|
|
.scale(1)
|
|
|
|
.publishPercentileHistogram()
|
2022-04-07 22:19:11 +02:00
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "buffer.type", "val.read", "found", "false", "bloom", "enabled", "bloom.mayexist", "false")
|
2022-03-30 15:15:53 +02:00
|
|
|
.register(meterRegistry);
|
2022-04-01 01:30:56 +02:00
|
|
|
this.readValueNotFoundWithMayExistBloomBufferSize = DistributionSummary
|
|
|
|
.builder("buffer.size.distribution")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.baseUnit("bytes")
|
|
|
|
.scale(1)
|
|
|
|
.publishPercentileHistogram()
|
2022-04-07 22:19:11 +02:00
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "buffer.type", "val.read", "found", "false", "bloom", "enabled", "bloom.mayexist", "true", "bloom.mayexist.result", "notexists", "bloom.mayexist.cached", "false")
|
2022-04-01 01:30:56 +02:00
|
|
|
.register(meterRegistry);
|
2022-03-30 15:15:53 +02:00
|
|
|
this.readValueFoundWithBloomUncachedBufferSize = DistributionSummary
|
|
|
|
.builder("buffer.size.distribution")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.baseUnit("bytes")
|
|
|
|
.scale(1)
|
|
|
|
.publishPercentileHistogram()
|
2022-04-07 22:19:11 +02:00
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "buffer.type", "val.read", "found", "true", "bloom", "enabled", "bloom.mayexist", "true", "bloom.mayexist.result", "exists", "bloom.mayexist.cached", "false")
|
2022-03-30 15:15:53 +02:00
|
|
|
.register(meterRegistry);
|
|
|
|
this.readValueFoundWithBloomCacheBufferSize = DistributionSummary
|
|
|
|
.builder("buffer.size.distribution")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.baseUnit("bytes")
|
|
|
|
.scale(1)
|
|
|
|
.publishPercentileHistogram()
|
2022-04-07 22:19:11 +02:00
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "buffer.type", "val.read", "found", "true", "bloom", "enabled", "bloom.mayexist", "true", "bloom.mayexist.result", "exists", "bloom.mayexist.cached", "true")
|
2022-03-30 15:15:53 +02:00
|
|
|
.register(meterRegistry);
|
|
|
|
this.readValueFoundWithBloomSimpleBufferSize = DistributionSummary
|
|
|
|
.builder("buffer.size.distribution")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.baseUnit("bytes")
|
|
|
|
.scale(1)
|
|
|
|
.publishPercentileHistogram()
|
2022-04-07 22:19:11 +02:00
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "buffer.type", "val.read", "found", "true", "bloom", "enabled", "bloom.mayexist", "true", "bloom.mayexist.result", "exists", "bloom.mayexist.cached", "false")
|
2022-03-30 15:15:53 +02:00
|
|
|
.register(meterRegistry);
|
2022-04-01 01:30:56 +02:00
|
|
|
this.readValueFoundWithoutBloomBufferSize = DistributionSummary
|
2022-03-30 15:15:53 +02:00
|
|
|
.builder("buffer.size.distribution")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.baseUnit("bytes")
|
|
|
|
.scale(1)
|
|
|
|
.publishPercentileHistogram()
|
2022-04-07 22:19:11 +02:00
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "buffer.type", "val.read", "found", "true", "bloom", "disabled")
|
2022-03-30 15:15:53 +02:00
|
|
|
.register(meterRegistry);
|
|
|
|
this.writeValueBufferSize = DistributionSummary
|
|
|
|
.builder("buffer.size.distribution")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.baseUnit("bytes")
|
|
|
|
.scale(1)
|
|
|
|
.publishPercentileHistogram()
|
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "buffer.type", "val.write")
|
|
|
|
.register(meterRegistry);
|
|
|
|
this.readAttempts = DistributionSummary
|
|
|
|
.builder("db.read.attempts.distribution")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.baseUnit("times")
|
|
|
|
.scale(1)
|
|
|
|
.publishPercentileHistogram()
|
|
|
|
.tags("db.name", databaseName, "db.column", columnName)
|
|
|
|
.register(meterRegistry);
|
|
|
|
|
|
|
|
this.startedIterSeek = meterRegistry.counter("db.read.iter.seek.started.counter", "db.name", databaseName, "db.column", columnName);
|
|
|
|
this.endedIterSeek = meterRegistry.counter("db.read.iter.seek.ended.counter", "db.name", databaseName, "db.column", columnName);
|
|
|
|
this.iterSeekTime = Timer
|
|
|
|
.builder("db.read.iter.seek.timer")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.publishPercentileHistogram()
|
|
|
|
.tags("db.name", databaseName, "db.column", columnName)
|
|
|
|
.register(meterRegistry);
|
|
|
|
this.startedIterNext = meterRegistry.counter("db.read.iter.next.started.counter", "db.name", databaseName, "db.column", columnName);
|
|
|
|
this.endedIterNext = meterRegistry.counter("db.read.iter.next.ended.counter", "db.name", databaseName, "db.column", columnName);
|
|
|
|
this.iterNextTime = Timer
|
|
|
|
.builder("db.read.iter.next.timer")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.publishPercentileHistogram()
|
|
|
|
.tags("db.name", databaseName, "db.column", columnName)
|
2021-10-30 11:13:46 +02:00
|
|
|
.register(meterRegistry);
|
2022-04-01 01:30:56 +02:00
|
|
|
|
|
|
|
this.startedUpdate = meterRegistry.counter("db.write.update.started.counter", "db.name", databaseName, "db.column", columnName);
|
|
|
|
this.endedUpdate = meterRegistry.counter("db.write.update.ended.counter", "db.name", databaseName, "db.column", columnName);
|
|
|
|
this.updateAddedTime = Timer
|
|
|
|
.builder("db.write.update.timer")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.publishPercentileHistogram()
|
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "update.type", "added")
|
|
|
|
.register(meterRegistry);
|
|
|
|
this.updateReplacedTime = Timer
|
|
|
|
.builder("db.write.update.timer")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.publishPercentileHistogram()
|
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "update.type", "replaced")
|
|
|
|
.register(meterRegistry);
|
|
|
|
this.updateRemovedTime = Timer
|
|
|
|
.builder("db.write.update.timer")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.publishPercentileHistogram()
|
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "update.type", "removed")
|
|
|
|
.register(meterRegistry);
|
|
|
|
this.updateUnchangedTime = Timer
|
|
|
|
.builder("db.write.update.timer")
|
|
|
|
.publishPercentiles(0.2, 0.5, 0.95)
|
|
|
|
.publishPercentileHistogram()
|
|
|
|
.tags("db.name", databaseName, "db.column", columnName, "update.type", "unchanged")
|
|
|
|
.register(meterRegistry);
|
2023-05-22 19:12:05 +02:00
|
|
|
this.iteratorMetrics = new IteratorMetrics(this.startedIterSeek,
|
|
|
|
this.endedIterSeek,
|
|
|
|
this.iterSeekTime,
|
|
|
|
this.startedIterNext,
|
|
|
|
this.endedIterNext,
|
|
|
|
this.iterNextTime);
|
2022-06-09 19:45:03 +02:00
|
|
|
this.keyMayExistGetter = new DBColumnKeyMayExistGetter();
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
|
2022-03-30 15:15:53 +02:00
|
|
|
/**
|
|
|
|
* This method should not modify or move the writerIndex/readerIndex of the key
|
|
|
|
*/
|
2023-05-22 19:12:05 +02:00
|
|
|
static void setIterateBound(LLReadOptions readOpts, IterateBound boundType, Buf key) {
|
2023-05-22 23:08:37 +02:00
|
|
|
byte[] slice = key != null ? requireNonNull(LLUtils.asArray(key)) : null;
|
2022-03-30 15:15:53 +02:00
|
|
|
if (boundType == IterateBound.LOWER) {
|
2022-05-20 10:20:00 +02:00
|
|
|
readOpts.setIterateLowerBound(slice);
|
2022-03-30 15:15:53 +02:00
|
|
|
} else {
|
2022-05-20 10:20:00 +02:00
|
|
|
readOpts.setIterateUpperBound(slice);
|
2022-03-30 15:15:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method should not modify or move the writerIndex/readerIndex of the buffers inside the range
|
|
|
|
*/
|
2023-02-09 23:34:25 +01:00
|
|
|
@Override
|
2022-03-30 15:15:53 +02:00
|
|
|
@NotNull
|
2023-05-22 19:12:05 +02:00
|
|
|
public RocksIteratorObj newRocksIterator(LLReadOptions readOptions, LLRange range, boolean reverse)
|
2023-02-09 23:34:25 +01:00
|
|
|
throws RocksDBException {
|
|
|
|
assert !LLUtils.isInNonBlockingThread() : "Called getRocksIterator in a nonblocking thread";
|
|
|
|
var rocksIterator = this.newIterator(readOptions, range.getMin(), range.getMax());
|
2022-05-04 12:36:32 +02:00
|
|
|
try {
|
|
|
|
if (reverse) {
|
|
|
|
if (!LLLocalDictionary.PREFER_AUTO_SEEK_BOUND && range.hasMax()) {
|
2023-02-09 23:34:25 +01:00
|
|
|
rocksIterator.seekFrom(range.getMax());
|
2022-05-04 12:36:32 +02:00
|
|
|
} else {
|
|
|
|
rocksIterator.seekToLast();
|
|
|
|
}
|
2022-03-30 15:15:53 +02:00
|
|
|
} else {
|
2022-05-04 12:36:32 +02:00
|
|
|
if (!LLLocalDictionary.PREFER_AUTO_SEEK_BOUND && range.hasMin()) {
|
2023-02-09 23:34:25 +01:00
|
|
|
rocksIterator.seekTo(range.getMin());
|
2022-05-04 12:36:32 +02:00
|
|
|
} else {
|
|
|
|
rocksIterator.seekToFirst();
|
|
|
|
}
|
2022-03-30 15:15:53 +02:00
|
|
|
}
|
2022-05-12 19:14:27 +02:00
|
|
|
return rocksIterator;
|
2022-05-04 12:36:32 +02:00
|
|
|
} catch (Throwable ex) {
|
|
|
|
rocksIterator.close();
|
|
|
|
throw ex;
|
2022-03-30 15:15:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-20 01:51:34 +02:00
|
|
|
protected T getDb() {
|
|
|
|
return db;
|
|
|
|
}
|
|
|
|
|
2022-05-20 10:20:00 +02:00
|
|
|
protected ColumnFamilyHandle getCfh() {
|
2021-10-20 01:51:34 +02:00
|
|
|
return cfh;
|
|
|
|
}
|
|
|
|
|
2022-04-30 01:49:44 +02:00
|
|
|
protected void ensureOpen() {
|
2022-04-30 14:21:20 +02:00
|
|
|
RocksDBUtils.ensureOpen(db, cfh);
|
2022-04-30 01:49:44 +02:00
|
|
|
}
|
|
|
|
|
2022-05-20 10:20:00 +02:00
|
|
|
protected void ensureOwned(AbstractImmutableNativeReference rocksObject) {
|
2022-04-30 14:21:20 +02:00
|
|
|
RocksDBUtils.ensureOwned(rocksObject);
|
2022-04-30 01:49:44 +02:00
|
|
|
}
|
|
|
|
|
2022-05-12 19:14:27 +02:00
|
|
|
|
|
|
|
protected void ensureOwned(RocksObject rocksObject) {
|
|
|
|
RocksDBUtils.ensureOwned(rocksObject);
|
|
|
|
}
|
|
|
|
|
2023-05-22 19:12:05 +02:00
|
|
|
|
|
|
|
protected void ensureOwned(SimpleResource simpleResource) {
|
|
|
|
RocksDBUtils.ensureOwned(simpleResource);
|
|
|
|
}
|
|
|
|
|
2022-04-30 01:49:44 +02:00
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
public @Nullable Buf get(@NotNull LLReadOptions readOptions, Buf key) throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
|
|
|
ensureOwned(readOptions);
|
2022-06-09 19:45:03 +02:00
|
|
|
return keyMayExistGetter.get(readOptions, key);
|
2022-04-30 01:49:44 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-12-12 02:17:36 +01:00
|
|
|
}
|
2022-04-30 01:49:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
public void put(@NotNull LLWriteOptions writeOptions, Buf key, Buf value) throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
2022-05-10 16:57:41 +02:00
|
|
|
ensureOpen();
|
|
|
|
ensureOwned(writeOptions);
|
2023-02-09 23:34:25 +01:00
|
|
|
this.keyBufferSize.record(key.size());
|
|
|
|
this.writeValueBufferSize.record(value.size());
|
2023-05-22 19:12:05 +02:00
|
|
|
db.put(cfh, writeOptions.getUnsafe(), LLUtils.asArray(key), LLUtils.asArray(value));
|
2022-04-30 01:49:44 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-12-12 02:17:36 +01:00
|
|
|
}
|
2022-04-30 01:49:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
public boolean exists(@NotNull LLReadOptions readOptions, Buf key) throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
2022-03-30 15:15:53 +02:00
|
|
|
try {
|
2022-04-30 01:49:44 +02:00
|
|
|
ensureOpen();
|
|
|
|
ensureOwned(readOptions);
|
2023-02-09 23:34:25 +01:00
|
|
|
int size = RocksDB.NOT_FOUND;
|
|
|
|
byte[] keyBytes = LLUtils.asArray(key);
|
|
|
|
Holder<byte[]> data = new Holder<>();
|
|
|
|
boolean mayExistHit = false;
|
2023-05-22 19:12:05 +02:00
|
|
|
if (db.keyMayExist(cfh, readOptions.getUnsafe(), keyBytes, data)) {
|
2023-02-09 23:34:25 +01:00
|
|
|
mayExistHit = true;
|
|
|
|
if (data.getValue() != null) {
|
|
|
|
size = data.getValue().length;
|
|
|
|
} else {
|
2023-05-22 19:12:05 +02:00
|
|
|
size = db.get(cfh, readOptions.getUnsafe(), keyBytes, NO_DATA);
|
2021-12-12 02:17:36 +01:00
|
|
|
}
|
2023-02-09 23:34:25 +01:00
|
|
|
}
|
|
|
|
boolean found = size != RocksDB.NOT_FOUND;
|
|
|
|
if (found) {
|
|
|
|
readValueFoundWithBloomSimpleBufferSize.record(size);
|
2022-03-30 15:15:53 +02:00
|
|
|
} else {
|
2023-02-09 23:34:25 +01:00
|
|
|
if (mayExistHit) {
|
|
|
|
readValueNotFoundWithMayExistBloomBufferSize.record(0);
|
2022-04-30 01:49:44 +02:00
|
|
|
} else {
|
2023-02-09 23:34:25 +01:00
|
|
|
readValueNotFoundWithBloomBufferSize.record(0);
|
2022-04-30 01:49:44 +02:00
|
|
|
}
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
2023-02-09 23:34:25 +01:00
|
|
|
return found;
|
2022-03-30 15:15:53 +02:00
|
|
|
} finally {
|
2022-04-30 01:49:44 +02:00
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
public boolean mayExists(@NotNull LLReadOptions readOptions, Buf key) {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
2021-10-20 01:51:34 +02:00
|
|
|
try {
|
2022-04-30 01:49:44 +02:00
|
|
|
ensureOpen();
|
|
|
|
ensureOwned(readOptions);
|
2023-02-09 23:34:25 +01:00
|
|
|
byte[] keyBytes = LLUtils.asArray(key);
|
2023-05-22 19:12:05 +02:00
|
|
|
return db.keyMayExist(cfh, readOptions.getUnsafe(), keyBytes, null);
|
2021-10-20 01:51:34 +02:00
|
|
|
} finally {
|
2022-04-30 01:49:44 +02:00
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
public void delete(LLWriteOptions writeOptions, Buf key) throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
|
|
|
ensureOwned(writeOptions);
|
2023-02-09 23:34:25 +01:00
|
|
|
keyBufferSize.record(key.size());
|
2023-05-22 19:12:05 +02:00
|
|
|
db.delete(cfh, writeOptions.getUnsafe(), LLUtils.asArray(key));
|
2022-04-30 01:49:44 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
public void delete(LLWriteOptions writeOptions, byte[] key) throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
|
|
|
ensureOwned(writeOptions);
|
|
|
|
keyBufferSize.record(key.length);
|
2023-05-22 19:12:05 +02:00
|
|
|
db.delete(cfh, writeOptions.getUnsafe(), key);
|
2022-04-30 01:49:44 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-10-30 11:13:46 +02:00
|
|
|
}
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
public List<byte[]> multiGetAsList(LLReadOptions readOptions, List<byte[]> keys) throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
|
|
|
ensureOwned(readOptions);
|
|
|
|
for (byte[] key : keys) {
|
|
|
|
keyBufferSize.record(key.length);
|
|
|
|
}
|
2022-05-20 10:20:00 +02:00
|
|
|
var columnFamilyHandles = new RepeatedElementList<>(cfh, keys.size());
|
2023-05-22 19:12:05 +02:00
|
|
|
return db.multiGetAsList(readOptions.getUnsafe(), columnFamilyHandles, keys);
|
2022-04-30 01:49:44 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2022-03-30 15:15:53 +02:00
|
|
|
}
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void suggestCompactRange() throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
2022-05-20 10:20:00 +02:00
|
|
|
db.suggestCompactRange(cfh);
|
2022-04-30 01:49:44 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-10-30 11:13:46 +02:00
|
|
|
}
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-05-20 10:20:00 +02:00
|
|
|
public void compactRange(byte[] begin, byte[] end, CompactRangeOptions options) throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
|
|
|
ensureOwned(options);
|
2022-05-20 10:20:00 +02:00
|
|
|
db.compactRange(cfh, begin, end, options);
|
2022-04-30 01:49:44 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-10-30 11:13:46 +02:00
|
|
|
}
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-05-20 10:20:00 +02:00
|
|
|
public void flush(FlushOptions options) throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
|
|
|
ensureOwned(options);
|
2022-05-20 10:20:00 +02:00
|
|
|
db.flush(options, cfh);
|
2022-04-30 01:49:44 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-10-30 11:13:46 +02:00
|
|
|
}
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void flushWal(boolean sync) throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
|
|
|
db.flushWal(sync);
|
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-10-30 11:13:46 +02:00
|
|
|
}
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long getLongProperty(String property) throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
2022-05-20 10:20:00 +02:00
|
|
|
return db.getLongProperty(cfh, property);
|
2022-04-30 01:49:44 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-10-30 11:13:46 +02:00
|
|
|
}
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
|
2023-01-05 02:21:09 +01:00
|
|
|
@Override
|
|
|
|
public long getNumEntries() throws RocksDBException {
|
|
|
|
Map<String, TableProperties> props = db.getPropertiesOfAllTables(cfh);
|
|
|
|
long entries = 0;
|
|
|
|
for (TableProperties tableProperties : props.values()) {
|
|
|
|
entries += tableProperties.getNumEntries();
|
|
|
|
}
|
|
|
|
return entries;
|
|
|
|
}
|
|
|
|
|
2021-10-20 01:51:34 +02:00
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
public void write(LLWriteOptions writeOptions, WriteBatch writeBatch) throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
|
|
|
ensureOwned(writeOptions);
|
|
|
|
ensureOwned(writeBatch);
|
2023-05-22 19:12:05 +02:00
|
|
|
db.write(writeOptions.getUnsafe(), writeBatch);
|
2022-04-30 01:49:44 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-10-30 11:13:46 +02:00
|
|
|
}
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return true if committed successfully
|
|
|
|
*/
|
2022-05-20 10:20:00 +02:00
|
|
|
protected abstract boolean commitOptimistically(Transaction tx) throws RocksDBException;
|
2021-10-20 01:51:34 +02:00
|
|
|
|
2023-05-22 19:12:05 +02:00
|
|
|
protected abstract Transaction beginTransaction(@NotNull LLWriteOptions writeOptions,
|
2022-05-20 10:20:00 +02:00
|
|
|
TransactionOptions txOpts);
|
2021-10-20 01:51:34 +02:00
|
|
|
|
2022-03-30 15:15:53 +02:00
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
public final @NotNull UpdateAtomicResult updateAtomic(@NotNull LLReadOptions readOptions,
|
|
|
|
@NotNull LLWriteOptions writeOptions,
|
2023-02-09 23:34:25 +01:00
|
|
|
Buf key,
|
2023-03-27 22:00:32 +02:00
|
|
|
SerializationFunction<@Nullable Buf, @Nullable Buf> updater,
|
2023-03-20 00:36:27 +01:00
|
|
|
UpdateAtomicResultMode returnMode) {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
2022-04-01 01:30:56 +02:00
|
|
|
try {
|
2022-04-30 01:49:44 +02:00
|
|
|
ensureOpen();
|
|
|
|
ensureOwned(readOptions);
|
|
|
|
try {
|
2023-02-09 23:34:25 +01:00
|
|
|
keyBufferSize.record(key.size());
|
2022-04-30 01:49:44 +02:00
|
|
|
startedUpdate.increment();
|
|
|
|
return updateAtomicImpl(readOptions, writeOptions, key, updater, returnMode);
|
|
|
|
} finally {
|
|
|
|
endedUpdate.increment();
|
|
|
|
}
|
2022-04-01 01:30:56 +02:00
|
|
|
} finally {
|
2022-04-30 01:49:44 +02:00
|
|
|
closeLock.unlockRead(closeReadLock);
|
2022-04-01 01:30:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected final void recordAtomicUpdateTime(boolean changed, boolean prevSet, boolean newSet, long initTime) {
|
|
|
|
long duration = System.nanoTime() - initTime;
|
|
|
|
Timer timer;
|
|
|
|
if (changed) {
|
|
|
|
if (prevSet && newSet) {
|
|
|
|
timer = updateReplacedTime;
|
|
|
|
} else if (newSet) {
|
|
|
|
timer = updateAddedTime;
|
|
|
|
} else {
|
|
|
|
timer = updateRemovedTime;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
timer = updateUnchangedTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
timer.record(duration, TimeUnit.NANOSECONDS);
|
2022-03-30 15:15:53 +02:00
|
|
|
}
|
|
|
|
|
2023-05-22 19:12:05 +02:00
|
|
|
protected abstract @NotNull UpdateAtomicResult updateAtomicImpl(@NotNull LLReadOptions readOptions,
|
|
|
|
@NotNull LLWriteOptions writeOptions,
|
2023-02-09 23:34:25 +01:00
|
|
|
Buf key,
|
2023-03-27 22:00:32 +02:00
|
|
|
SerializationFunction<@Nullable Buf, @Nullable Buf> updater,
|
2023-03-20 00:36:27 +01:00
|
|
|
UpdateAtomicResultMode returnMode);
|
2022-03-30 15:15:53 +02:00
|
|
|
|
2021-10-20 01:51:34 +02:00
|
|
|
@Override
|
|
|
|
@NotNull
|
2023-05-22 19:12:05 +02:00
|
|
|
public RocksIteratorObj newIterator(@NotNull LLReadOptions readOptions,
|
2023-02-09 23:34:25 +01:00
|
|
|
@Nullable Buf min,
|
|
|
|
@Nullable Buf max) {
|
2022-04-30 01:49:44 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
|
|
|
ensureOwned(readOptions);
|
2023-05-22 19:12:05 +02:00
|
|
|
setIterateBound(readOptions, IterateBound.LOWER, min);
|
|
|
|
setIterateBound(readOptions, IterateBound.UPPER, max);
|
|
|
|
return readOptions.newIterator(db, cfh, iteratorMetrics);
|
2022-04-30 01:49:44 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2021-10-30 11:13:46 +02:00
|
|
|
}
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|
|
|
|
|
2022-04-30 02:14:44 +02:00
|
|
|
protected int getLevels() {
|
2022-04-30 14:21:20 +02:00
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
2022-05-20 10:20:00 +02:00
|
|
|
return RocksDBUtils.getLevels(db, cfh);
|
2022-04-30 14:21:20 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
|
|
|
}
|
2022-04-30 01:49:44 +02:00
|
|
|
}
|
|
|
|
|
2022-04-26 17:12:22 +02:00
|
|
|
@Override
|
2022-04-30 01:49:44 +02:00
|
|
|
public final void forceCompaction(int volumeId) {
|
|
|
|
var closeReadLock = closeLock.readLock();
|
|
|
|
try {
|
|
|
|
ensureOpen();
|
2022-05-20 10:20:00 +02:00
|
|
|
RocksDBUtils.forceCompaction(db, db.getName(), cfh, volumeId, logger);
|
2023-02-09 23:34:25 +01:00
|
|
|
} catch (RocksDBException e) {
|
|
|
|
throw new RuntimeException(e);
|
2022-04-30 01:49:44 +02:00
|
|
|
} finally {
|
|
|
|
closeLock.unlockRead(closeReadLock);
|
2022-04-26 17:12:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-20 01:51:34 +02:00
|
|
|
@Override
|
2022-05-20 10:20:00 +02:00
|
|
|
public ColumnFamilyHandle getColumnFamilyHandle() {
|
2021-10-20 01:51:34 +02:00
|
|
|
return cfh;
|
|
|
|
}
|
|
|
|
|
2021-10-30 11:13:46 +02:00
|
|
|
public MeterRegistry getMeterRegistry() {
|
|
|
|
return meterRegistry;
|
|
|
|
}
|
2022-04-26 17:12:22 +02:00
|
|
|
|
|
|
|
public Timer getIterNextTime() {
|
|
|
|
return iterNextTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Counter getStartedIterNext() {
|
|
|
|
return startedIterNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Counter getEndedIterNext() {
|
|
|
|
return endedIterNext;
|
|
|
|
}
|
2022-06-09 19:45:03 +02:00
|
|
|
|
|
|
|
private class DBColumnKeyMayExistGetter extends KeyMayExistGetter {
|
|
|
|
|
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
protected KeyMayExist keyMayExist(LLReadOptions readOptions, ByteBuffer key, ByteBuffer value) {
|
|
|
|
return db.keyMayExist(cfh, readOptions.getUnsafe(), key, value);
|
2022-06-09 19:45:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
protected boolean keyMayExist(LLReadOptions readOptions, byte[] key, @Nullable Holder<byte[]> valueHolder) {
|
|
|
|
return db.keyMayExist(cfh, readOptions.getUnsafe(), key, valueHolder);
|
2022-06-09 19:45:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
protected int get(LLReadOptions readOptions, ByteBuffer key, ByteBuffer value) throws RocksDBException {
|
|
|
|
return db.get(cfh, readOptions.getUnsafe(), key, value);
|
2022-06-09 19:45:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2023-05-22 19:12:05 +02:00
|
|
|
protected byte[] get(LLReadOptions readOptions, byte[] key) throws RocksDBException, IllegalArgumentException {
|
|
|
|
return db.get(cfh, readOptions.getUnsafe(), key);
|
2022-06-09 19:45:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void recordReadValueNotFoundWithMayExistBloomBufferSize(int value) {
|
|
|
|
readValueNotFoundWithMayExistBloomBufferSize.record(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void recordReadValueFoundWithBloomUncachedBufferSize(int value) {
|
|
|
|
readValueFoundWithBloomUncachedBufferSize.record(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void recordReadValueFoundWithBloomCacheBufferSize(int value) {
|
|
|
|
readValueFoundWithBloomCacheBufferSize.record(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void recordReadAttempts(int value) {
|
|
|
|
readAttempts.record(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void recordReadValueNotFoundWithBloomBufferSize(int value) {
|
|
|
|
readValueNotFoundWithBloomBufferSize.record(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void recordKeyBufferSize(int value) {
|
|
|
|
keyBufferSize.record(value);
|
|
|
|
}
|
|
|
|
}
|
2021-10-20 01:51:34 +02:00
|
|
|
}
|