Began work on configuration system for storage
This commit is contained in:
@@ -8,7 +8,7 @@ yarn_mappings=1.20.4+build.1
|
|||||||
loader_version=0.15.0
|
loader_version=0.15.0
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version = 0.0.5-alpha
|
mod_version = 0.0.6-alpha
|
||||||
maven_group = me.cortex
|
maven_group = me.cortex
|
||||||
archives_base_name = voxy
|
archives_base_name = voxy
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,16 @@ package me.cortex.voxy.client;
|
|||||||
|
|
||||||
import me.cortex.voxy.client.config.VoxyConfig;
|
import me.cortex.voxy.client.config.VoxyConfig;
|
||||||
import me.cortex.voxy.client.core.VoxelCore;
|
import me.cortex.voxy.client.core.VoxelCore;
|
||||||
import me.cortex.voxy.client.mixin.minecraft.MixinWorldRenderer;
|
|
||||||
import me.cortex.voxy.client.terrain.WorldImportCommand;
|
import me.cortex.voxy.client.terrain.WorldImportCommand;
|
||||||
import me.cortex.voxy.common.storage.CompressionStorageAdaptor;
|
import me.cortex.voxy.common.storage.config.Serialization;
|
||||||
import me.cortex.voxy.common.storage.FragmentedStorageBackendAdaptor;
|
import me.cortex.voxy.common.storage.other.CompressionStorageAdaptor;
|
||||||
import me.cortex.voxy.common.storage.StorageBackend;
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
import me.cortex.voxy.common.storage.ZSTDCompressor;
|
import me.cortex.voxy.common.storage.compressors.ZSTDCompressor;
|
||||||
|
import me.cortex.voxy.common.storage.other.FragmentedStorageBackendAdaptor;
|
||||||
import me.cortex.voxy.common.storage.rocksdb.RocksDBStorageBackend;
|
import me.cortex.voxy.common.storage.rocksdb.RocksDBStorageBackend;
|
||||||
import me.cortex.voxy.common.world.WorldEngine;
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
||||||
import net.minecraft.client.render.WorldRenderer;
|
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -20,13 +19,19 @@ import java.io.File;
|
|||||||
public class Voxy implements ClientModInitializer {
|
public class Voxy implements ClientModInitializer {
|
||||||
@Override
|
@Override
|
||||||
public void onInitializeClient() {
|
public void onInitializeClient() {
|
||||||
|
//var cfg = new CompressionStorageAdaptor.Config();
|
||||||
|
//cfg.compressor = new ZSTDCompressor.Config();
|
||||||
|
//cfg.backend = new FragmentedStorageBackendAdaptor.Config();
|
||||||
|
//((FragmentedStorageBackendAdaptor.Config)cfg.backend).backends.add(new RocksDBStorageBackend.Config());
|
||||||
|
//System.out.println(Serialization.GSON.toJson(cfg));
|
||||||
|
|
||||||
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
|
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
|
||||||
dispatcher.register(WorldImportCommand.register());
|
dispatcher.register(WorldImportCommand.register());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static VoxelCore createVoxelCore(ClientWorld world) {
|
public static VoxelCore createVoxelCore(ClientWorld world) {
|
||||||
StorageBackend storage = new RocksDBStorageBackend(new File(VoxyConfig.CONFIG.storagePath));
|
StorageBackend storage = new RocksDBStorageBackend(VoxyConfig.CONFIG.storagePath);
|
||||||
//StorageBackend storage = new FragmentedStorageBackendAdaptor(new File(VoxyConfig.CONFIG.storagePath));
|
//StorageBackend storage = new FragmentedStorageBackendAdaptor(new File(VoxyConfig.CONFIG.storagePath));
|
||||||
storage = new CompressionStorageAdaptor(new ZSTDCompressor(VoxyConfig.CONFIG.savingCompressionLevel), storage);
|
storage = new CompressionStorageAdaptor(new ZSTDCompressor(VoxyConfig.CONFIG.savingCompressionLevel), storage);
|
||||||
var engine = new WorldEngine(storage, VoxyConfig.CONFIG.ingestThreads, VoxyConfig.CONFIG.savingThreads, 5);
|
var engine = new WorldEngine(storage, VoxyConfig.CONFIG.ingestThreads, VoxyConfig.CONFIG.savingThreads, 5);
|
||||||
|
|||||||
@@ -29,14 +29,6 @@ public class VoxyConfig {
|
|||||||
public int savingCompressionLevel = 7;
|
public int savingCompressionLevel = 7;
|
||||||
public String storagePath = "voxy_db";
|
public String storagePath = "voxy_db";
|
||||||
|
|
||||||
transient StorageConfig storageConfig;
|
|
||||||
public static abstract class StorageConfig { }
|
|
||||||
public static class FragmentedStorageConfig extends StorageConfig { }
|
|
||||||
public static class LmdbStorageConfig extends StorageConfig { }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static VoxyConfig loadOrCreate() {
|
public static VoxyConfig loadOrCreate() {
|
||||||
var path = getConfigPath();
|
var path = getConfigPath();
|
||||||
|
|||||||
@@ -6,12 +6,8 @@ import me.cortex.voxy.client.core.rendering.*;
|
|||||||
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
|
import me.cortex.voxy.client.core.rendering.building.RenderGenerationService;
|
||||||
import me.cortex.voxy.client.core.rendering.post.PostProcessing;
|
import me.cortex.voxy.client.core.rendering.post.PostProcessing;
|
||||||
import me.cortex.voxy.client.core.util.DebugUtil;
|
import me.cortex.voxy.client.core.util.DebugUtil;
|
||||||
import me.cortex.voxy.common.storage.CompressionStorageAdaptor;
|
|
||||||
import me.cortex.voxy.common.storage.ZSTDCompressor;
|
|
||||||
import me.cortex.voxy.common.storage.rocksdb.RocksDBStorageBackend;
|
|
||||||
import me.cortex.voxy.common.world.WorldEngine;
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
import me.cortex.voxy.client.importers.WorldImporter;
|
import me.cortex.voxy.client.importers.WorldImporter;
|
||||||
import me.cortex.voxy.common.storage.FragmentedStorageBackendAdaptor;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.render.Camera;
|
import net.minecraft.client.render.Camera;
|
||||||
import net.minecraft.client.render.Frustum;
|
import net.minecraft.client.render.Frustum;
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package me.cortex.voxy.client.saver;
|
package me.cortex.voxy.client.saver;
|
||||||
|
|
||||||
import me.cortex.voxy.client.config.VoxyConfig;
|
import me.cortex.voxy.client.config.VoxyConfig;
|
||||||
import me.cortex.voxy.common.storage.CompressionStorageAdaptor;
|
import me.cortex.voxy.common.storage.other.CompressionStorageAdaptor;
|
||||||
import me.cortex.voxy.common.storage.FragmentedStorageBackendAdaptor;
|
import me.cortex.voxy.common.storage.other.FragmentedStorageBackendAdaptor;
|
||||||
import me.cortex.voxy.common.storage.ZSTDCompressor;
|
import me.cortex.voxy.common.storage.compressors.ZSTDCompressor;
|
||||||
import me.cortex.voxy.common.world.WorldEngine;
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -30,9 +29,6 @@ public class SaveSelectionSystem {
|
|||||||
// FragmentedStorageBackendAdaptorConfig(File)
|
// FragmentedStorageBackendAdaptorConfig(File)
|
||||||
// RocksDBStorageBackendConfig(File)
|
// RocksDBStorageBackendConfig(File)
|
||||||
// RedisStorageBackendConfig(String, int, String)
|
// RedisStorageBackendConfig(String, int, String)
|
||||||
|
return null;
|
||||||
|
|
||||||
var storage = new CompressionStorageAdaptor(new ZSTDCompressor(VoxyConfig.CONFIG.savingCompressionLevel), new FragmentedStorageBackendAdaptor(new File(VoxyConfig.CONFIG.storagePath)));
|
|
||||||
return new WorldEngine(storage, VoxyConfig.CONFIG.ingestThreads, VoxyConfig.CONFIG.savingThreads, 5);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package me.cortex.voxy.common.storage;
|
package me.cortex.voxy.common.storage.compressors;
|
||||||
|
|
||||||
|
import me.cortex.voxy.common.storage.StorageCompressor;
|
||||||
|
import me.cortex.voxy.common.storage.config.CompressorConfig;
|
||||||
|
import me.cortex.voxy.common.storage.config.ConfigBuildCtx;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@@ -34,4 +37,17 @@ public class ZSTDCompressor implements StorageCompressor {
|
|||||||
public void close() {
|
public void close() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Config extends CompressorConfig {
|
||||||
|
public int compressionLevel;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StorageCompressor build(ConfigBuildCtx ctx) {
|
||||||
|
return new ZSTDCompressor(this.compressionLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getConfigTypeName() {
|
||||||
|
return "ZSTD";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package me.cortex.voxy.common.storage.config;
|
||||||
|
|
||||||
|
import me.cortex.voxy.common.storage.StorageCompressor;
|
||||||
|
|
||||||
|
public abstract class CompressorConfig {
|
||||||
|
static {
|
||||||
|
Serialization.CONFIG_TYPES.add(CompressorConfig.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract StorageCompressor build(ConfigBuildCtx ctx);
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package me.cortex.voxy.common.storage.config;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class ConfigBuildCtx {
|
||||||
|
//List of tokens
|
||||||
|
public static final String BASE_LEVEL_PATH = "{base_level_path}";
|
||||||
|
|
||||||
|
//Pushes a path to the BuildCtx path stack so that when resolving with resolvePath it uses the entire path stack
|
||||||
|
public ConfigBuildCtx pushPath(String path) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigBuildCtx popPath() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a path with the current build context path
|
||||||
|
* @param other path to resolve against
|
||||||
|
* @return resolved path
|
||||||
|
*/
|
||||||
|
public String resolvePath(String other) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Substitutes special tokens in the string the configured values
|
||||||
|
* @param string the string to substitute
|
||||||
|
* @return substituted string
|
||||||
|
*/
|
||||||
|
public String substituteString(String string) {
|
||||||
|
//This is e.g. so you can have dbs spread across multiple disks if you want
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the path provided exists, if not, create it
|
||||||
|
* @param path the path to make
|
||||||
|
* @return the input
|
||||||
|
*/
|
||||||
|
public String ensurePathExists(String path) {
|
||||||
|
try {
|
||||||
|
Files.createDirectories(new File(path).toPath());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package me.cortex.voxy.common.storage.config;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.TypeAdapter;
|
||||||
|
import com.google.gson.TypeAdapterFactory;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
public class GsonTypeAdaptor<T> implements TypeAdapterFactory {
|
||||||
|
@Override
|
||||||
|
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package me.cortex.voxy.common.storage.config;
|
||||||
|
|
||||||
|
import com.google.gson.*;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class Serialization {
|
||||||
|
public static final Set<Class<?>> CONFIG_TYPES = new HashSet<>();
|
||||||
|
public static final Gson GSON;
|
||||||
|
|
||||||
|
private static final class GsonConfigSerialization <T> {
|
||||||
|
private final String typeField = "config_type";
|
||||||
|
private final Class<T> clz;
|
||||||
|
|
||||||
|
private final Map<String, Class<? extends T>> name2type = new HashMap<>();
|
||||||
|
private final Map<Class<? extends T>, String> type2name = new HashMap<>();
|
||||||
|
|
||||||
|
private GsonConfigSerialization(Class<T> clz) {
|
||||||
|
this.clz = clz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GsonConfigSerialization<T> register(String typeName, Class<? extends T> cls) {
|
||||||
|
if (this.name2type.put(typeName, cls) != null) {
|
||||||
|
throw new IllegalStateException("Type name already registered: " + typeName);
|
||||||
|
}
|
||||||
|
if (this.type2name.put(cls, typeName) != null) {
|
||||||
|
throw new IllegalStateException("Class already registered with type name: " + typeName + ", " + cls);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
Map<Class<?>, GsonConfigSerialization<?>> serializers = new HashMap<>();
|
||||||
|
outer:
|
||||||
|
for (var clzName : collectAllClasses("me.cortex.voxy.common.storage")) {
|
||||||
|
if (clzName.equals(Serialization.class.getName())) {
|
||||||
|
continue;//Dont want to load ourselves
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var clz = Class.forName(clzName);
|
||||||
|
var original = clz;
|
||||||
|
while ((clz = clz.getSuperclass()) != null) {
|
||||||
|
if (CONFIG_TYPES.contains(clz)) {
|
||||||
|
Method nameMethod = null;
|
||||||
|
try {
|
||||||
|
nameMethod = original.getMethod("getConfigTypeName");
|
||||||
|
nameMethod.setAccessible(true);
|
||||||
|
} catch (NoSuchMethodException e) {}
|
||||||
|
if (nameMethod == null) {
|
||||||
|
System.err.println("WARNING: Config class " + clzName + " doesnt contain a getConfigTypeName and thus wont be serializable");
|
||||||
|
continue outer;
|
||||||
|
}
|
||||||
|
String name = (String) nameMethod.invoke(null);
|
||||||
|
serializers.computeIfAbsent(clz, GsonConfigSerialization::new)
|
||||||
|
.register(name, (Class) original);
|
||||||
|
System.out.println("Registered " + original.getSimpleName() + " as " + name + " for config type " + clz.getSimpleName());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Error while setting up config serialization");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new GsonBuilder();
|
||||||
|
//for (var entry : serializers.entrySet()) {
|
||||||
|
// builder.registerTypeHierarchyAdapter(entry.getKey(), entry.getValue());
|
||||||
|
//}
|
||||||
|
|
||||||
|
GSON = builder.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<String> collectAllClasses(String pack) {
|
||||||
|
InputStream stream = Serialization.class.getClassLoader()
|
||||||
|
.getResourceAsStream(pack.replaceAll("[.]", "/"));
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
|
||||||
|
return reader.lines().flatMap(inner -> {
|
||||||
|
if (inner.endsWith(".class")) {
|
||||||
|
return Stream.of(pack + "." + inner.replace(".class", ""));
|
||||||
|
} else if (!inner.contains(".")) {
|
||||||
|
return collectAllClasses(pack + "." + inner).stream();
|
||||||
|
} else {
|
||||||
|
return Stream.of();
|
||||||
|
}
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package me.cortex.voxy.common.storage.config;
|
||||||
|
|
||||||
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
|
|
||||||
|
public abstract class StorageConfig {
|
||||||
|
static {
|
||||||
|
Serialization.CONFIG_TYPES.add(StorageConfig.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract StorageBackend build(ConfigBuildCtx ctx);
|
||||||
|
}
|
||||||
@@ -6,12 +6,13 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
|||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectCollection;
|
import it.unimi.dsi.fastutil.objects.ObjectCollection;
|
||||||
import me.cortex.voxy.common.storage.StorageBackend;
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
|
import me.cortex.voxy.common.storage.config.ConfigBuildCtx;
|
||||||
|
import me.cortex.voxy.common.storage.config.StorageConfig;
|
||||||
import net.minecraft.util.math.random.RandomSeed;
|
import net.minecraft.util.math.random.RandomSeed;
|
||||||
import org.apache.commons.lang3.stream.Streams;
|
import org.apache.commons.lang3.stream.Streams;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class MemoryStorageBackend extends StorageBackend {
|
public class MemoryStorageBackend extends StorageBackend {
|
||||||
private final Long2ObjectMap<ByteBuffer>[] maps;
|
private final Long2ObjectMap<ByteBuffer>[] maps;
|
||||||
@@ -105,4 +106,15 @@ public class MemoryStorageBackend extends StorageBackend {
|
|||||||
Streams.of(this.maps).map(Long2ObjectMap::values).flatMap(ObjectCollection::stream).forEach(MemoryUtil::memFree);
|
Streams.of(this.maps).map(Long2ObjectMap::values).flatMap(ObjectCollection::stream).forEach(MemoryUtil::memFree);
|
||||||
this.idMappings.values().forEach(MemoryUtil::memFree);
|
this.idMappings.values().forEach(MemoryUtil::memFree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Config extends StorageConfig {
|
||||||
|
@Override
|
||||||
|
public StorageBackend build(ConfigBuildCtx ctx) {
|
||||||
|
return new MemoryStorageBackend();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getConfigTypeName() {
|
||||||
|
return "Memory";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ package me.cortex.voxy.common.storage.lmdb;
|
|||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import me.cortex.voxy.common.storage.StorageBackend;
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
|
import me.cortex.voxy.common.storage.config.ConfigBuildCtx;
|
||||||
|
import me.cortex.voxy.common.storage.config.StorageConfig;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
import org.lwjgl.util.lmdb.MDBVal;
|
import org.lwjgl.util.lmdb.MDBVal;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@@ -24,10 +25,10 @@ public class LMDBStorageBackend extends StorageBackend {
|
|||||||
private final LMDBInterface dbi;
|
private final LMDBInterface dbi;
|
||||||
private final LMDBInterface.Database sectionDatabase;
|
private final LMDBInterface.Database sectionDatabase;
|
||||||
private final LMDBInterface.Database idMappingDatabase;
|
private final LMDBInterface.Database idMappingDatabase;
|
||||||
public LMDBStorageBackend(File file) {
|
public LMDBStorageBackend(String file) {
|
||||||
this.dbi = new LMDBInterface.Builder()
|
this.dbi = new LMDBInterface.Builder()
|
||||||
.setMaxDbs(2)
|
.setMaxDbs(2)
|
||||||
.open(file.getAbsolutePath(), MDB_NOSUBDIR)//MDB_NOLOCK (IF I DO THIS, must sync the db manually)// TODO: THIS
|
.open(file, MDB_NOSUBDIR)//MDB_NOLOCK (IF I DO THIS, must sync the db manually)// TODO: THIS
|
||||||
.fetch();
|
.fetch();
|
||||||
this.dbi.setMapSize(GROW_SIZE);
|
this.dbi.setMapSize(GROW_SIZE);
|
||||||
this.sectionDatabase = this.dbi.createDb("world_sections");
|
this.sectionDatabase = this.dbi.createDb("world_sections");
|
||||||
@@ -156,4 +157,17 @@ public class LMDBStorageBackend extends StorageBackend {
|
|||||||
this.idMappingDatabase.close();
|
this.idMappingDatabase.close();
|
||||||
this.dbi.close();
|
this.dbi.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Config extends StorageConfig {
|
||||||
|
public String path;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StorageBackend build(ConfigBuildCtx ctx) {
|
||||||
|
return new LMDBStorageBackend(ctx.ensurePathExists(ctx.substituteString(ctx.resolvePath(this.path))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getConfigTypeName() {
|
||||||
|
return "LMDB";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
package me.cortex.voxy.common.storage;
|
package me.cortex.voxy.common.storage.other;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import me.cortex.voxy.common.storage.StorageCompressor;
|
||||||
import me.cortex.voxy.common.storage.lmdb.LMDBStorageBackend;
|
import me.cortex.voxy.common.storage.config.CompressorConfig;
|
||||||
import net.minecraft.util.math.random.RandomSeed;
|
import me.cortex.voxy.common.storage.config.ConfigBuildCtx;
|
||||||
|
import me.cortex.voxy.common.storage.config.StorageConfig;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
//Compresses the section data
|
//Compresses the section data
|
||||||
public class CompressionStorageAdaptor extends StorageBackend {
|
public class CompressionStorageAdaptor extends StorageBackend {
|
||||||
@@ -65,4 +62,18 @@ public class CompressionStorageAdaptor extends StorageBackend {
|
|||||||
this.compressor.close();
|
this.compressor.close();
|
||||||
this.child.close();
|
this.child.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Config extends StorageConfig {
|
||||||
|
public CompressorConfig compressor;
|
||||||
|
public StorageConfig backend;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StorageBackend build(ConfigBuildCtx ctx) {
|
||||||
|
return new CompressionStorageAdaptor(this.compressor.build(ctx), this.backend.build(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getConfigTypeName() {
|
||||||
|
return "CompressionAdaptor";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,42 +1,32 @@
|
|||||||
package me.cortex.voxy.common.storage;
|
package me.cortex.voxy.common.storage.other;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import me.cortex.voxy.common.storage.lmdb.LMDBStorageBackend;
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
|
import me.cortex.voxy.common.storage.config.ConfigBuildCtx;
|
||||||
|
import me.cortex.voxy.common.storage.config.StorageConfig;
|
||||||
import net.minecraft.util.math.random.RandomSeed;
|
import net.minecraft.util.math.random.RandomSeed;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.file.Files;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
//Segments the section data into multiple dbs
|
//Segments the section data into multiple dbs
|
||||||
public class FragmentedStorageBackendAdaptor extends StorageBackend {
|
public class FragmentedStorageBackendAdaptor extends StorageBackend {
|
||||||
private final StorageBackend[] backends = new StorageBackend[32];
|
private final StorageBackend[] backends;
|
||||||
|
|
||||||
public FragmentedStorageBackendAdaptor(File directory) {
|
public FragmentedStorageBackendAdaptor(StorageBackend... backends) {
|
||||||
try {
|
this.backends = backends;
|
||||||
Files.createDirectories(directory.toPath());
|
int len = backends.length;
|
||||||
} catch (IOException e) {
|
if ((len&(len-1)) != (len-1)) {
|
||||||
throw new RuntimeException(e);
|
throw new IllegalArgumentException("Backend count not a power of 2");
|
||||||
}
|
|
||||||
for (int i = 0; i < this.backends.length; i++) {
|
|
||||||
this.backends[i] = new LMDBStorageBackend(directory.toPath().resolve("storage-db-"+i+".db").toFile());//
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//public static long getWorldSectionId(int lvl, int x, int y, int z) {
|
|
||||||
// return ((long)lvl<<60)|((long)(y&0xFF)<<52)|((long)(z&((1<<24)-1))<<28)|((long)(x&((1<<24)-1))<<4);//NOTE: 4 bits spare for whatever
|
|
||||||
// }
|
|
||||||
//private int getSegmentId(long key) {
|
|
||||||
// return (int) (((key>>4)&1)|((key>>27)&0b10)|((key>>50)&0b100));
|
|
||||||
//}
|
|
||||||
|
|
||||||
private int getSegmentId(long key) {
|
private int getSegmentId(long key) {
|
||||||
return (int) (RandomSeed.mixStafford13(RandomSeed.mixStafford13(key)^key)&0x1F);
|
return (int) (RandomSeed.mixStafford13(RandomSeed.mixStafford13(key)^key)&(this.backends.length-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: reencode the key to be shifted one less OR
|
//TODO: reencode the key to be shifted one less OR
|
||||||
@@ -140,4 +130,22 @@ public class FragmentedStorageBackendAdaptor extends StorageBackend {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Config extends StorageConfig {
|
||||||
|
public List<StorageConfig> backends = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StorageBackend build(ConfigBuildCtx ctx) {
|
||||||
|
StorageBackend[] builtBackends = new StorageBackend[this.backends.size()];
|
||||||
|
for (int i = 0; i < this.backends.size(); i++) {
|
||||||
|
//TODO: put each backend in a different folder?
|
||||||
|
builtBackends[i] = this.backends.get(i).build(ctx);
|
||||||
|
}
|
||||||
|
return new FragmentedStorageBackendAdaptor(builtBackends);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getConfigTypeName() {
|
||||||
|
return "FragmentationAdaptor";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,8 @@ package me.cortex.voxy.common.storage.redis;
|
|||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import me.cortex.voxy.common.storage.StorageBackend;
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
|
import me.cortex.voxy.common.storage.config.ConfigBuildCtx;
|
||||||
|
import me.cortex.voxy.common.storage.config.StorageConfig;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
import redis.clients.jedis.JedisPool;
|
import redis.clients.jedis.JedisPool;
|
||||||
|
|
||||||
@@ -9,17 +11,31 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class RedisStorageBackend extends StorageBackend {
|
public class RedisStorageBackend extends StorageBackend {
|
||||||
private final JedisPool pool = new JedisPool("localhost", 6379);
|
private final JedisPool pool;
|
||||||
private final byte[] WORLD = "world_sections".getBytes(StandardCharsets.UTF_8);
|
private final String user;
|
||||||
private final byte[] MAPPINGS = "id_mappings".getBytes(StandardCharsets.UTF_8);
|
private final String password;
|
||||||
|
private final byte[] WORLD;
|
||||||
|
private final byte[] MAPPINGS;
|
||||||
|
|
||||||
public RedisStorageBackend() {
|
public RedisStorageBackend(String host, int port, String prefix) {
|
||||||
|
this(host, port, prefix, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RedisStorageBackend(String host, int port, String prefix, String user, String password) {
|
||||||
|
this.pool = new JedisPool(host, port);
|
||||||
|
this.user = user;
|
||||||
|
this.password = password;
|
||||||
|
this.WORLD = (prefix+"world_sections").getBytes(StandardCharsets.UTF_8);
|
||||||
|
this.MAPPINGS = (prefix+"id_mappings").getBytes(StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer getSectionData(long key) {
|
public ByteBuffer getSectionData(long key) {
|
||||||
try (var jedis = this.pool.getResource()) {
|
try (var jedis = this.pool.getResource()) {
|
||||||
|
if (this.user != null) {
|
||||||
|
jedis.auth(this.user, this.password);
|
||||||
|
}
|
||||||
|
|
||||||
var result = jedis.hget(WORLD, longToBytes(key));
|
var result = jedis.hget(WORLD, longToBytes(key));
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -35,6 +51,10 @@ public class RedisStorageBackend extends StorageBackend {
|
|||||||
@Override
|
@Override
|
||||||
public void setSectionData(long key, ByteBuffer data) {
|
public void setSectionData(long key, ByteBuffer data) {
|
||||||
try (var jedis = this.pool.getResource()) {
|
try (var jedis = this.pool.getResource()) {
|
||||||
|
if (this.user != null) {
|
||||||
|
jedis.auth(this.user, this.password);
|
||||||
|
}
|
||||||
|
|
||||||
var buffer = new byte[data.remaining()];
|
var buffer = new byte[data.remaining()];
|
||||||
data.get(buffer);
|
data.get(buffer);
|
||||||
data.rewind();
|
data.rewind();
|
||||||
@@ -45,6 +65,10 @@ public class RedisStorageBackend extends StorageBackend {
|
|||||||
@Override
|
@Override
|
||||||
public void deleteSectionData(long key) {
|
public void deleteSectionData(long key) {
|
||||||
try (var jedis = this.pool.getResource()) {
|
try (var jedis = this.pool.getResource()) {
|
||||||
|
if (this.user != null) {
|
||||||
|
jedis.auth(this.user, this.password);
|
||||||
|
}
|
||||||
|
|
||||||
jedis.hdel(WORLD, longToBytes(key));
|
jedis.hdel(WORLD, longToBytes(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,6 +76,10 @@ public class RedisStorageBackend extends StorageBackend {
|
|||||||
@Override
|
@Override
|
||||||
public void putIdMapping(int id, ByteBuffer data) {
|
public void putIdMapping(int id, ByteBuffer data) {
|
||||||
try (var jedis = this.pool.getResource()) {
|
try (var jedis = this.pool.getResource()) {
|
||||||
|
if (this.user != null) {
|
||||||
|
jedis.auth(this.user, this.password);
|
||||||
|
}
|
||||||
|
|
||||||
var buffer = new byte[data.remaining()];
|
var buffer = new byte[data.remaining()];
|
||||||
data.get(buffer);
|
data.get(buffer);
|
||||||
data.rewind();
|
data.rewind();
|
||||||
@@ -62,6 +90,10 @@ public class RedisStorageBackend extends StorageBackend {
|
|||||||
@Override
|
@Override
|
||||||
public Int2ObjectOpenHashMap<byte[]> getIdMappingsData() {
|
public Int2ObjectOpenHashMap<byte[]> getIdMappingsData() {
|
||||||
try (var jedis = this.pool.getResource()) {
|
try (var jedis = this.pool.getResource()) {
|
||||||
|
if (this.user != null) {
|
||||||
|
jedis.auth(this.user, this.password);
|
||||||
|
}
|
||||||
|
|
||||||
var mappings = jedis.hgetAll(MAPPINGS);
|
var mappings = jedis.hgetAll(MAPPINGS);
|
||||||
var out = new Int2ObjectOpenHashMap<byte[]>();
|
var out = new Int2ObjectOpenHashMap<byte[]>();
|
||||||
if (mappings == null) {
|
if (mappings == null) {
|
||||||
@@ -108,4 +140,19 @@ public class RedisStorageBackend extends StorageBackend {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Config extends StorageConfig {
|
||||||
|
public String host;
|
||||||
|
public int port;
|
||||||
|
public String prefix;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StorageBackend build(ConfigBuildCtx ctx) {
|
||||||
|
return new RedisStorageBackend(this.host, this.port, ctx.substituteString(this.prefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getConfigTypeName() {
|
||||||
|
return "Redis";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ package me.cortex.voxy.common.storage.rocksdb;
|
|||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import me.cortex.voxy.common.storage.StorageBackend;
|
import me.cortex.voxy.common.storage.StorageBackend;
|
||||||
|
import me.cortex.voxy.common.storage.config.ConfigBuildCtx;
|
||||||
|
import me.cortex.voxy.common.storage.config.StorageConfig;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
import org.rocksdb.*;
|
import org.rocksdb.*;
|
||||||
import redis.clients.jedis.JedisPool;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -23,9 +23,9 @@ public class RocksDBStorageBackend extends StorageBackend {
|
|||||||
//NOTE: closes in order
|
//NOTE: closes in order
|
||||||
private final List<AbstractImmutableNativeReference> closeList = new ArrayList<>();
|
private final List<AbstractImmutableNativeReference> closeList = new ArrayList<>();
|
||||||
|
|
||||||
public RocksDBStorageBackend(File path) {
|
public RocksDBStorageBackend(String path) {
|
||||||
try {
|
try {
|
||||||
var lockPath = path.toPath().resolve("LOCK");
|
var lockPath = new File(path).toPath().resolve("LOCK");
|
||||||
if (Files.exists(lockPath)) {
|
if (Files.exists(lockPath)) {
|
||||||
System.err.println("WARNING, deleting rocksdb LOCK file");
|
System.err.println("WARNING, deleting rocksdb LOCK file");
|
||||||
Files.delete(lockPath);
|
Files.delete(lockPath);
|
||||||
@@ -50,7 +50,7 @@ public class RocksDBStorageBackend extends StorageBackend {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
this.db = RocksDB.open(options,
|
this.db = RocksDB.open(options,
|
||||||
path.getPath(), cfDescriptors,
|
path, cfDescriptors,
|
||||||
handles);
|
handles);
|
||||||
|
|
||||||
this.closeList.addAll(handles);
|
this.closeList.addAll(handles);
|
||||||
@@ -164,4 +164,17 @@ public class RocksDBStorageBackend extends StorageBackend {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Config extends StorageConfig {
|
||||||
|
public String path;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StorageBackend build(ConfigBuildCtx ctx) {
|
||||||
|
return new RocksDBStorageBackend(ctx.ensurePathExists(ctx.substituteString(ctx.resolvePath(this.path))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getConfigTypeName() {
|
||||||
|
return "RocksDB";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user