2021-07-10 20:52:01 +02:00
|
|
|
package it.cavallium.dbengine.database.memory;
|
|
|
|
|
2021-10-30 11:13:46 +02:00
|
|
|
import io.micrometer.core.instrument.MeterRegistry;
|
2021-09-17 16:56:28 +02:00
|
|
|
import io.net5.buffer.api.BufferAllocator;
|
2022-01-15 20:00:10 +01:00
|
|
|
import it.cavallium.dbengine.client.MemoryStats;
|
2021-07-10 20:52:01 +02:00
|
|
|
import it.cavallium.dbengine.database.LLDictionary;
|
|
|
|
import it.cavallium.dbengine.database.LLKeyValueDatabase;
|
|
|
|
import it.cavallium.dbengine.database.LLSingleton;
|
|
|
|
import it.cavallium.dbengine.database.LLSnapshot;
|
2022-01-26 14:22:54 +01:00
|
|
|
import it.cavallium.dbengine.database.LLUtils;
|
2021-07-10 20:52:01 +02:00
|
|
|
import it.cavallium.dbengine.database.UpdateMode;
|
2022-03-02 12:34:30 +01:00
|
|
|
import it.cavallium.dbengine.rpc.current.data.Column;
|
2021-07-10 20:52:01 +02:00
|
|
|
import it.unimi.dsi.fastutil.bytes.ByteList;
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import java.util.concurrent.ConcurrentSkipListMap;
|
|
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
|
import reactor.core.publisher.Mono;
|
|
|
|
|
|
|
|
public class LLMemoryKeyValueDatabase implements LLKeyValueDatabase {
|
|
|
|
|
2022-01-26 14:22:54 +01:00
|
|
|
static {
|
|
|
|
LLUtils.initHooks();
|
|
|
|
}
|
|
|
|
|
2021-08-31 09:14:46 +02:00
|
|
|
private final BufferAllocator allocator;
|
2021-10-30 11:13:46 +02:00
|
|
|
private final MeterRegistry meterRegistry;
|
2021-07-10 20:52:01 +02:00
|
|
|
private final String name;
|
|
|
|
private final AtomicLong nextSnapshotNumber = new AtomicLong(1);
|
|
|
|
|
|
|
|
private final ConcurrentHashMap<Long, ConcurrentHashMap<String, ConcurrentSkipListMap<ByteList, ByteList>>> snapshots = new ConcurrentHashMap<>();
|
|
|
|
private final ConcurrentHashMap<String, ConcurrentSkipListMap<ByteList, ByteList>> mainDb;
|
2021-07-18 19:37:24 +02:00
|
|
|
private final ConcurrentHashMap<String, LLMemoryDictionary> singletons = new ConcurrentHashMap<>();
|
2021-07-10 20:52:01 +02:00
|
|
|
|
2021-10-30 11:13:46 +02:00
|
|
|
public LLMemoryKeyValueDatabase(BufferAllocator allocator,
|
|
|
|
MeterRegistry meterRegistry,
|
|
|
|
String name,
|
|
|
|
List<Column> columns) {
|
2021-07-10 20:52:01 +02:00
|
|
|
this.allocator = allocator;
|
2021-10-30 11:13:46 +02:00
|
|
|
this.meterRegistry = meterRegistry;
|
2021-07-10 20:52:01 +02:00
|
|
|
this.name = name;
|
|
|
|
this.mainDb = new ConcurrentHashMap<>();
|
|
|
|
for (Column column : columns) {
|
|
|
|
mainDb.put(column.name(), new ConcurrentSkipListMap<>());
|
|
|
|
}
|
|
|
|
this.snapshots.put(Long.MIN_VALUE + 1L, this.mainDb);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-07-18 19:37:24 +02:00
|
|
|
public Mono<? extends LLSingleton> getSingleton(byte[] singletonListColumnName, byte[] singletonName, byte[] defaultValue) {
|
|
|
|
var columnNameString = new String(singletonListColumnName, StandardCharsets.UTF_8);
|
|
|
|
var dict = singletons.computeIfAbsent(columnNameString, _unused -> new LLMemoryDictionary(allocator,
|
|
|
|
name,
|
|
|
|
columnNameString,
|
|
|
|
UpdateMode.ALLOW,
|
|
|
|
snapshots,
|
|
|
|
mainDb
|
|
|
|
));
|
|
|
|
return Mono
|
|
|
|
.fromCallable(() -> new LLMemorySingleton(dict, singletonName)).flatMap(singleton -> singleton
|
|
|
|
.get(null)
|
|
|
|
.switchIfEmpty(singleton.set(defaultValue).then(Mono.empty()))
|
|
|
|
.thenReturn(singleton)
|
|
|
|
);
|
2021-07-10 20:52:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Mono<? extends LLDictionary> getDictionary(byte[] columnName, UpdateMode updateMode) {
|
|
|
|
var columnNameString = new String(columnName, StandardCharsets.UTF_8);
|
|
|
|
return Mono.fromCallable(() -> new LLMemoryDictionary(allocator,
|
|
|
|
name,
|
|
|
|
columnNameString,
|
|
|
|
updateMode,
|
|
|
|
snapshots,
|
|
|
|
mainDb
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Mono<Long> getProperty(String propertyName) {
|
|
|
|
return Mono.empty();
|
|
|
|
}
|
|
|
|
|
2022-01-15 20:00:10 +01:00
|
|
|
@Override
|
|
|
|
public Mono<MemoryStats> getMemoryStats() {
|
|
|
|
return Mono.just(new MemoryStats(0, 0, 0, 0, 0, 0));
|
|
|
|
}
|
|
|
|
|
2021-07-10 20:52:01 +02:00
|
|
|
@Override
|
|
|
|
public Mono<Void> verifyChecksum() {
|
|
|
|
return Mono.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-08-31 09:14:46 +02:00
|
|
|
public BufferAllocator getAllocator() {
|
2021-07-10 20:52:01 +02:00
|
|
|
return allocator;
|
|
|
|
}
|
|
|
|
|
2021-10-30 11:13:46 +02:00
|
|
|
@Override
|
|
|
|
public MeterRegistry getMeterRegistry() {
|
|
|
|
return meterRegistry;
|
|
|
|
}
|
|
|
|
|
2021-07-10 20:52:01 +02:00
|
|
|
@Override
|
|
|
|
public Mono<Void> close() {
|
|
|
|
return Mono
|
|
|
|
.fromRunnable(() -> {
|
|
|
|
snapshots.forEach((snapshot, dbs) -> dbs.forEach((columnName, db) -> {
|
|
|
|
db.clear();
|
|
|
|
}));
|
|
|
|
mainDb.forEach((columnName, db) -> {
|
|
|
|
db.clear();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String getDatabaseName() {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Mono<LLSnapshot> takeSnapshot() {
|
|
|
|
return Mono
|
|
|
|
.fromCallable(() -> {
|
|
|
|
var snapshotNumber = nextSnapshotNumber.getAndIncrement();
|
|
|
|
var snapshot = new ConcurrentHashMap<String, ConcurrentSkipListMap<ByteList, ByteList>>();
|
|
|
|
mainDb.forEach((columnName, column) -> {
|
|
|
|
var cloned = column.clone();
|
|
|
|
snapshot.put(columnName, cloned);
|
|
|
|
});
|
|
|
|
snapshots.put(snapshotNumber, snapshot);
|
|
|
|
return new LLSnapshot(snapshotNumber);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Mono<Void> releaseSnapshot(LLSnapshot snapshot) {
|
|
|
|
return Mono
|
|
|
|
.fromCallable(() -> snapshots.remove(snapshot.getSequenceNumber()))
|
|
|
|
.then();
|
|
|
|
}
|
|
|
|
}
|