strangedb/src/main/java/org/warp/jcwdb/JCWDatabase.java

164 lines
4.2 KiB
Java
Raw Normal View History

2018-11-19 15:16:12 +01:00
package org.warp.jcwdb;
2018-12-15 01:01:23 +01:00
import it.unimi.dsi.fastutil.longs.LongArrayList;
2018-11-19 15:16:12 +01:00
import java.io.IOException;
import java.nio.file.Path;
2018-11-27 17:47:19 +01:00
public class JCWDatabase implements AutoCloseable, Cleanable {
2018-12-06 12:30:04 +01:00
public final static long MAX_LOADED_INDICES = 10000;
2018-12-15 01:01:23 +01:00
2018-11-27 17:47:19 +01:00
private final TypesManager typesManager;
private final MixedIndexDatabase indices;
private final Cleaner databaseCleaner;
2018-12-05 02:39:41 +01:00
private final EntryReferenceTools entryReferenceTools = new EntryReferenceTools();
2018-11-22 23:31:41 +01:00
private volatile boolean closed;
private final Object closeLock = new Object();
private final Object indicesAccessLock = new Object();
2018-11-19 15:16:12 +01:00
public JCWDatabase(Path dataFile, Path metadataFile) throws IOException {
2018-11-21 01:02:25 +01:00
this.typesManager = new TypesManager(this);
2018-12-19 12:19:03 +01:00
this.indices = new MixedIndexDatabase(dataFile, metadataFile);
2018-11-22 23:31:41 +01:00
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
JCWDatabase.this.close();
} catch (Exception e) {
e.printStackTrace();
}
}));
2018-11-27 17:47:19 +01:00
this.databaseCleaner = new Cleaner(this);
2018-12-15 01:01:23 +01:00
2018-12-19 12:19:03 +01:00
this.databaseCleaner.start();
2018-11-20 18:39:48 +01:00
}
2018-11-21 01:02:25 +01:00
2018-11-22 23:31:41 +01:00
public <T> EntryReference<LightList<T>> getRoot() throws IOException {
checkClosed();
if (exists(0)) {
2018-11-21 01:02:25 +01:00
return get(0);
2018-11-22 23:31:41 +01:00
} else {
2018-12-20 01:12:46 +01:00
LightList<T> newRoot = new LightArrayList<>(this);
2018-11-22 23:31:41 +01:00
return set(0, newRoot);
2018-11-21 01:02:25 +01:00
}
}
2018-12-20 00:16:16 +01:00
public <T> EntryReference<LightList<T>> getRoot(Class<T> clazz) throws IOException {
return getRoot().cast();
}
2018-11-21 01:02:25 +01:00
public <T> EntryReference<T> get(long index) throws IOException {
2018-11-22 23:31:41 +01:00
checkClosed();
2018-12-15 01:01:23 +01:00
int type;
long hash;
synchronized (indicesAccessLock) {
type = this.indices.getType(index);
hash = this.indices.getHash(index);
2018-11-21 01:02:25 +01:00
}
2018-12-15 01:01:23 +01:00
DBTypeParser<T> typeParser = this.typesManager.get(type);
return new EntryReference<>(entryReferenceTools, index, hash, typeParser);
2018-11-21 01:02:25 +01:00
}
2018-11-22 23:31:41 +01:00
protected <T> EntryReference<T> add(T value) throws IOException {
checkClosed();
2018-12-15 01:01:23 +01:00
DBTypeParser<T> typeParser = this.typesManager.get((Class<T>) value.getClass());
long index;
long hash;
synchronized (indicesAccessLock) {
index = indices.add(typeParser.getWriter(value));
hash = indices.getHash(index);
2018-11-20 18:39:48 +01:00
}
2018-12-15 01:01:23 +01:00
return new EntryReference<>(entryReferenceTools, index, hash, typeParser, value);
2018-11-22 23:31:41 +01:00
}
protected boolean exists(long index) {
checkClosed();
2018-12-15 01:01:23 +01:00
synchronized (indicesAccessLock) {
return this.indices.has(index);
2018-11-22 23:31:41 +01:00
}
}
protected <T> EntryReference<T> set(long index, T value) throws IOException {
checkClosed();
2018-12-15 01:01:23 +01:00
EntryReference<T> ref;
if (exists(index)) {
ref = get(index);
ref.setValue(value);
return ref;
} else {
@SuppressWarnings("unchecked")
DBTypeParser<T> typeParser = this.typesManager.get((Class<T>) value.getClass());
long hash;
synchronized (indicesAccessLock) {
IndexDetails returnedDetails = indices.set(index, typeParser.getWriter(value));
hash = returnedDetails.getHash();
2018-11-22 23:31:41 +01:00
}
2018-12-15 01:01:23 +01:00
return new EntryReference<>(entryReferenceTools, index, hash, typeParser);
2018-11-22 23:31:41 +01:00
}
2018-11-20 18:39:48 +01:00
}
2018-12-15 01:01:23 +01:00
public <U> void registerType(Class<U> clazz, short type, DBTypeParser<U> parser) {
final int addition = 0xEFFF8000;
int extendedType = addition | (type & 0x7FFF);
typesManager.registerType(clazz, extendedType, parser);
}
public <U> void registerClass(Class<U> clazz, int type) {
typesManager.registerGenericClass(clazz, type);
}
2018-12-06 12:30:04 +01:00
public boolean isOpen() {
return !closed;
}
2018-11-21 01:02:25 +01:00
@Override
public void close() throws IOException {
2018-11-22 23:31:41 +01:00
if (closed) {
return;
}
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
2018-12-05 02:39:41 +01:00
this.databaseCleaner.stop();
2018-11-22 23:31:41 +01:00
synchronized (indicesAccessLock) {
this.indices.close();
}
System.out.println("Database closed.");
}
private void checkClosed() {
if (closed) {
throw new RuntimeException("Index Manager is closed.");
2018-11-21 01:02:25 +01:00
}
2018-11-19 15:16:12 +01:00
}
2018-11-27 17:47:19 +01:00
@Override
public long clean() {
2018-12-15 01:01:23 +01:00
long removedItems = indices.clean();
2018-12-05 02:39:41 +01:00
return removedItems;
2018-11-27 17:47:19 +01:00
}
2018-12-05 02:39:41 +01:00
public class EntryReferenceTools {
private EntryReferenceTools() {
}
public <T> T read(long index, DBReader<T> reader) throws IOException {
return indices.get(index, reader);
}
2018-12-11 23:00:51 +01:00
public <T> IndexDetails write(long index, DBDataOutput<T> writer) throws IOException {
return indices.set(index, writer);
2018-12-05 02:39:41 +01:00
}
}
2018-12-04 23:57:49 +01:00
@SuppressWarnings("unchecked")
protected <T> long calculateHash(T o) {
return ((DBTypeParser<T>) typesManager.get(o.getClass())).calculateHash(o);
}
2018-11-19 15:16:12 +01:00
}