2021-10-13 00:23:56 +02:00
|
|
|
package it.cavallium.dbengine.database.disk;
|
|
|
|
|
2022-03-16 13:47:56 +01:00
|
|
|
import io.netty5.buffer.ByteBuf;
|
2021-10-13 00:23:56 +02:00
|
|
|
import java.io.Closeable;
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.nio.file.Files;
|
|
|
|
import java.nio.file.Path;
|
|
|
|
import java.util.Comparator;
|
2021-12-17 23:12:35 +01:00
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
import org.apache.lucene.search.DocIdSetIterator;
|
|
|
|
import org.apache.lucene.util.BitSet;
|
2021-10-13 00:23:56 +02:00
|
|
|
import org.lmdbjava.Net5ByteBufProxy;
|
|
|
|
import org.lmdbjava.Env;
|
|
|
|
import static org.lmdbjava.EnvFlags.*;
|
|
|
|
|
|
|
|
public class LLTempLMDBEnv implements Closeable {
|
|
|
|
|
2021-10-16 14:35:04 +02:00
|
|
|
private static final long TWENTY_GIBIBYTES = 20L * 1024L * 1024L * 1024L;
|
2021-12-17 23:12:35 +01:00
|
|
|
public static final int MAX_DATABASES = 1024;
|
|
|
|
private static final AtomicInteger NEXT_LMDB_ENV_ID = new AtomicInteger(0);
|
2022-02-25 15:46:32 +01:00
|
|
|
private BitSet freeIds;
|
2021-10-13 00:23:56 +02:00
|
|
|
|
2022-02-25 15:46:32 +01:00
|
|
|
private int envId;
|
|
|
|
private Path tempDirectory;
|
|
|
|
private Env<ByteBuf> env;
|
|
|
|
private volatile boolean initialized;
|
2021-10-16 14:35:04 +02:00
|
|
|
private volatile boolean closed;
|
2021-10-13 00:23:56 +02:00
|
|
|
|
2022-02-25 15:46:32 +01:00
|
|
|
public LLTempLMDBEnv() {
|
2021-12-17 23:12:35 +01:00
|
|
|
this.envId = NEXT_LMDB_ENV_ID.getAndIncrement();
|
2021-10-13 00:23:56 +02:00
|
|
|
}
|
|
|
|
|
2021-10-16 14:59:38 +02:00
|
|
|
public Env<ByteBuf> getEnv() {
|
2021-10-16 14:35:04 +02:00
|
|
|
if (closed) {
|
|
|
|
throw new IllegalStateException("Environment closed");
|
|
|
|
}
|
2022-02-25 15:46:32 +01:00
|
|
|
initializeIfPossible();
|
2021-10-13 00:23:56 +02:00
|
|
|
return env;
|
|
|
|
}
|
|
|
|
|
2022-02-25 15:46:32 +01:00
|
|
|
private void initializeIfPossible() {
|
|
|
|
if (!initialized) {
|
|
|
|
synchronized(this) {
|
|
|
|
if (!initialized) {
|
|
|
|
try {
|
|
|
|
tempDirectory = Files.createTempDirectory("lmdb");
|
|
|
|
var envBuilder = Env.create(Net5ByteBufProxy.PROXY_NETTY)
|
|
|
|
.setMapSize(TWENTY_GIBIBYTES)
|
|
|
|
.setMaxDbs(MAX_DATABASES);
|
|
|
|
//env = envBuilder.open(tempDirectory.toFile(), MDB_NOLOCK, MDB_NOSYNC, MDB_NOTLS, MDB_NORDAHEAD, MDB_WRITEMAP);
|
|
|
|
env = envBuilder.open(tempDirectory.toFile(), MDB_NOTLS, MDB_NOSYNC, MDB_NORDAHEAD, MDB_NOMETASYNC);
|
|
|
|
freeIds = BitSet.of(DocIdSetIterator.range(0, MAX_DATABASES), MAX_DATABASES);
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-17 23:12:35 +01:00
|
|
|
public int allocateDb() {
|
2022-02-25 15:46:32 +01:00
|
|
|
initializeIfPossible();
|
|
|
|
//noinspection SynchronizeOnNonFinalField
|
2021-12-17 23:12:35 +01:00
|
|
|
synchronized (freeIds) {
|
|
|
|
var freeBit = freeIds.nextSetBit(0);
|
|
|
|
if (freeBit == DocIdSetIterator.NO_MORE_DOCS) {
|
|
|
|
throw new IllegalStateException("LMDB databases limit has been reached in environment "
|
|
|
|
+ envId + ": " + MAX_DATABASES);
|
|
|
|
}
|
|
|
|
freeIds.clear(freeBit);
|
|
|
|
return freeBit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String stringifyDbId(int bit) {
|
|
|
|
return "$db_" + bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void freeDb(int db) {
|
2022-02-25 15:46:32 +01:00
|
|
|
initializeIfPossible();
|
|
|
|
//noinspection SynchronizeOnNonFinalField
|
2021-12-17 23:12:35 +01:00
|
|
|
synchronized (freeIds) {
|
|
|
|
freeIds.set(db);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-13 00:23:56 +02:00
|
|
|
@Override
|
|
|
|
public void close() throws IOException {
|
2022-02-25 15:46:32 +01:00
|
|
|
if (this.closed) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!this.initialized) {
|
|
|
|
synchronized (this) {
|
|
|
|
closed = true;
|
|
|
|
initialized = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-10-16 14:35:04 +02:00
|
|
|
this.closed = true;
|
2021-10-13 00:23:56 +02:00
|
|
|
env.close();
|
|
|
|
//noinspection ResultOfMethodCallIgnored
|
|
|
|
Files.walk(tempDirectory)
|
|
|
|
.sorted(Comparator.reverseOrder())
|
|
|
|
.map(Path::toFile)
|
|
|
|
.forEach(File::delete);
|
|
|
|
}
|
2021-12-18 21:01:14 +01:00
|
|
|
|
|
|
|
public int countUsedDbs() {
|
2022-03-10 01:43:37 +01:00
|
|
|
int freeIds;
|
|
|
|
if (this.freeIds == null) {
|
|
|
|
freeIds = MAX_DATABASES;
|
|
|
|
} else {
|
|
|
|
freeIds = this.freeIds.cardinality();
|
|
|
|
}
|
2021-12-18 21:01:14 +01:00
|
|
|
return MAX_DATABASES - freeIds;
|
|
|
|
}
|
2021-10-13 00:23:56 +02:00
|
|
|
}
|