2022-04-30 01:49:44 +02:00
|
|
|
package it.cavallium.dbengine.database.disk;
|
|
|
|
|
|
|
|
import static com.google.common.collect.Lists.partition;
|
|
|
|
|
2022-07-02 11:44:13 +02:00
|
|
|
import it.cavallium.dbengine.database.LLUtils;
|
2023-05-22 19:12:05 +02:00
|
|
|
import it.cavallium.dbengine.utils.SimpleResource;
|
2022-04-30 01:49:44 +02:00
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
|
|
|
import org.apache.logging.log4j.Logger;
|
2022-04-30 14:21:20 +02:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
2022-05-20 10:20:00 +02:00
|
|
|
import org.rocksdb.AbstractImmutableNativeReference;
|
2022-04-30 01:49:44 +02:00
|
|
|
import org.rocksdb.ColumnFamilyHandle;
|
|
|
|
import org.rocksdb.CompactionJobInfo;
|
|
|
|
import org.rocksdb.CompactionOptions;
|
|
|
|
import org.rocksdb.CompressionType;
|
|
|
|
import org.rocksdb.LevelMetaData;
|
|
|
|
import org.rocksdb.RocksDB;
|
|
|
|
import org.rocksdb.RocksDBException;
|
|
|
|
import org.rocksdb.SstFileMetaData;
|
|
|
|
import org.rocksdb.util.SizeUnit;
|
|
|
|
|
|
|
|
public class RocksDBUtils {
|
|
|
|
|
2022-04-30 02:14:44 +02:00
|
|
|
public static int getLevels(RocksDB db, ColumnFamilyHandle cfh) {
|
|
|
|
return db.numberLevels(cfh);
|
2022-04-30 01:49:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static List<String> getColumnFiles(RocksDB db, ColumnFamilyHandle cfh, boolean excludeLastLevel) {
|
|
|
|
List<String> files = new ArrayList<>();
|
|
|
|
var meta = db.getColumnFamilyMetaData(cfh);
|
2022-04-30 02:14:44 +02:00
|
|
|
var lastLevelId = excludeLastLevel ? (getLevels(db, cfh) - 1) : -1;
|
2022-04-30 01:49:44 +02:00
|
|
|
for (LevelMetaData level : meta.levels()) {
|
2022-04-30 02:14:44 +02:00
|
|
|
if (!excludeLastLevel || level.level() < lastLevelId) {
|
2022-04-30 01:49:44 +02:00
|
|
|
for (SstFileMetaData file : level.files()) {
|
|
|
|
if (file.fileName().endsWith(".sst")) {
|
|
|
|
files.add(file.fileName());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return files;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void forceCompaction(RocksDB db,
|
|
|
|
String logDbName,
|
|
|
|
ColumnFamilyHandle cfh,
|
|
|
|
int volumeId,
|
2023-02-09 23:34:25 +01:00
|
|
|
Logger logger) throws RocksDBException {
|
2022-04-30 01:49:44 +02:00
|
|
|
try (var co = new CompactionOptions()
|
|
|
|
.setCompression(CompressionType.LZ4_COMPRESSION)
|
|
|
|
.setMaxSubcompactions(0)
|
|
|
|
.setOutputFileSizeLimit(2 * SizeUnit.GB)) {
|
|
|
|
List<String> filesToCompact = getColumnFiles(db, cfh, true);
|
|
|
|
|
|
|
|
if (!filesToCompact.isEmpty()) {
|
|
|
|
var partitionSize = filesToCompact.size() / Runtime.getRuntime().availableProcessors();
|
|
|
|
List<List<String>> partitions;
|
|
|
|
if (partitionSize > 0) {
|
|
|
|
partitions = partition(filesToCompact, partitionSize);
|
|
|
|
} else {
|
|
|
|
partitions = List.of(filesToCompact);
|
|
|
|
}
|
2022-04-30 02:14:44 +02:00
|
|
|
int finalBottommostLevelId = getLevels(db, cfh) - 1;
|
2023-02-09 23:34:25 +01:00
|
|
|
for (List<String> partition : partitions) {
|
2022-04-30 01:49:44 +02:00
|
|
|
logger.info("Compacting {} files in database {} in column family {} to level {}",
|
|
|
|
partition.size(),
|
|
|
|
logDbName,
|
|
|
|
new String(cfh.getName(), StandardCharsets.UTF_8),
|
2022-04-30 02:14:44 +02:00
|
|
|
finalBottommostLevelId
|
2022-04-30 01:49:44 +02:00
|
|
|
);
|
|
|
|
if (!partition.isEmpty()) {
|
|
|
|
var coi = new CompactionJobInfo();
|
|
|
|
try {
|
2022-04-30 02:14:44 +02:00
|
|
|
db.compactFiles(co, cfh, partition, finalBottommostLevelId, volumeId, coi);
|
2022-04-30 01:49:44 +02:00
|
|
|
logger.info("Compacted {} files in database {} in column family {} to level {}: {}",
|
|
|
|
partition.size(),
|
|
|
|
logDbName,
|
|
|
|
new String(cfh.getName(), StandardCharsets.UTF_8),
|
2022-04-30 02:14:44 +02:00
|
|
|
finalBottommostLevelId,
|
2022-04-30 01:49:44 +02:00
|
|
|
coi.status().getCodeString()
|
|
|
|
);
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
logger.error("Failed to compact {} files in database {} in column family {} to level {}",
|
|
|
|
partition.size(),
|
|
|
|
logDbName,
|
|
|
|
new String(cfh.getName(), StandardCharsets.UTF_8),
|
2022-04-30 02:14:44 +02:00
|
|
|
finalBottommostLevelId,
|
2022-04-30 01:49:44 +02:00
|
|
|
ex
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2023-02-09 23:34:25 +01:00
|
|
|
};
|
2022-04-30 01:49:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-04-30 14:21:20 +02:00
|
|
|
|
2022-05-20 10:20:00 +02:00
|
|
|
public static void ensureOpen(RocksDB db, @Nullable ColumnFamilyHandle cfh) {
|
2023-02-09 23:34:25 +01:00
|
|
|
if (LLUtils.isInNonBlockingThread()) {
|
2022-04-30 14:21:20 +02:00
|
|
|
throw new UnsupportedOperationException("Called in a nonblocking thread");
|
|
|
|
}
|
|
|
|
ensureOwned(db);
|
|
|
|
ensureOwned(cfh);
|
|
|
|
}
|
|
|
|
|
2022-05-20 10:20:00 +02:00
|
|
|
public static void ensureOwned(@Nullable AbstractImmutableNativeReference rocksObject) {
|
2022-04-30 14:21:20 +02:00
|
|
|
if (rocksObject != null && !rocksObject.isOwningHandle()) {
|
|
|
|
throw new IllegalStateException("Not owning handle");
|
|
|
|
}
|
|
|
|
}
|
2023-05-22 19:12:05 +02:00
|
|
|
|
|
|
|
public static void ensureOwned(@Nullable SimpleResource simpleResource) {
|
|
|
|
if (simpleResource != null && simpleResource.isClosed()) {
|
|
|
|
throw new IllegalStateException("Resource is closed");
|
|
|
|
}
|
|
|
|
}
|
2022-04-30 01:49:44 +02:00
|
|
|
}
|