Optimizations aswell as the option to disable section verification
This commit is contained in:
@@ -20,20 +20,17 @@ public class ZSTDCompressor implements StorageCompressor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer compress(ByteBuffer saveData) {
|
public MemoryBuffer compress(MemoryBuffer saveData) {
|
||||||
ByteBuffer compressedData = MemoryUtil.memAlloc((int)ZSTD_COMPRESSBOUND(saveData.remaining()));
|
MemoryBuffer compressedData = new MemoryBuffer((int)ZSTD_COMPRESSBOUND(saveData.size));
|
||||||
long compressedSize = ZSTD_compress(compressedData, saveData, this.level);
|
long compressedSize = nZSTD_compress(compressedData.address, compressedData.size, saveData.address, saveData.size, this.level);
|
||||||
compressedData.limit((int) compressedSize);
|
return compressedData.subSize(compressedSize);
|
||||||
compressedData.rewind();
|
|
||||||
return compressedData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MemoryBuffer decompress(MemoryBuffer saveData) {
|
public MemoryBuffer decompress(MemoryBuffer saveData) {
|
||||||
var decompressed = new MemoryBuffer(SaveLoadSystem.BIGGEST_SERIALIZED_SECTION_SIZE);
|
var decompressed = new MemoryBuffer(SaveLoadSystem.BIGGEST_SERIALIZED_SECTION_SIZE);
|
||||||
//TODO: mark the size of the decompressed data to verify its length later
|
|
||||||
long size = nZSTD_decompress(decompressed.address, decompressed.size, saveData.address, saveData.size);
|
long size = nZSTD_decompress(decompressed.address, decompressed.size, saveData.address, saveData.size);
|
||||||
return decompressed;
|
return decompressed.subSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ public class MemoryBuffer extends TrackedObject {
|
|||||||
this.address = MemoryUtil.nmemAlloc(size);
|
this.address = MemoryUtil.nmemAlloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MemoryBuffer(long address, long size) {
|
||||||
|
this.size = size;
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
public void cpyTo(long dst) {
|
public void cpyTo(long dst) {
|
||||||
super.assertNotFreed();
|
super.assertNotFreed();
|
||||||
UnsafeUtil.memcpy(this.address, dst, this.size);
|
UnsafeUtil.memcpy(this.address, dst, this.size);
|
||||||
@@ -27,4 +32,15 @@ public class MemoryBuffer extends TrackedObject {
|
|||||||
this.cpyTo(copy.address);
|
this.cpyTo(copy.address);
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Creates a new MemoryBuffer, defunking this buffer and sets the size to be a subsize of the current size
|
||||||
|
public MemoryBuffer subSize(long size) {
|
||||||
|
if (size > this.size) {
|
||||||
|
throw new IllegalArgumentException("Requested size larger than current size");
|
||||||
|
}
|
||||||
|
//Free the current object, but not the memory associated with it
|
||||||
|
super.free0();
|
||||||
|
|
||||||
|
return new MemoryBuffer(this.address, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,12 @@ public abstract class TrackedObject {
|
|||||||
public static final boolean TRACK_OBJECT_ALLOCATION_STACKS = System.getProperty("voxy.trackObjectAllocationStacks", "false").equals("true");
|
public static final boolean TRACK_OBJECT_ALLOCATION_STACKS = System.getProperty("voxy.trackObjectAllocationStacks", "false").equals("true");
|
||||||
|
|
||||||
private final Ref ref;
|
private final Ref ref;
|
||||||
public TrackedObject() {
|
protected TrackedObject() {
|
||||||
this.ref = register(this);
|
this(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TrackedObject(boolean shouldTrack) {
|
||||||
|
this.ref = register(shouldTrack, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void free0() {
|
protected void free0() {
|
||||||
@@ -44,10 +48,10 @@ public abstract class TrackedObject {
|
|||||||
cleaner = null;
|
cleaner = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static Ref register(Object obj) {
|
public static Ref register(boolean track, Object obj) {
|
||||||
boolean[] freed = new boolean[1];
|
boolean[] freed = new boolean[1];
|
||||||
Cleaner.Cleanable cleanable = null;
|
Cleaner.Cleanable cleanable = null;
|
||||||
if (TRACK_OBJECT_ALLOCATIONS) {
|
if (TRACK_OBJECT_ALLOCATIONS && track) {
|
||||||
String clazz = obj.getClass().getName();
|
String clazz = obj.getClass().getName();
|
||||||
Throwable trace;
|
Throwable trace;
|
||||||
if (TRACK_OBJECT_ALLOCATION_STACKS) {
|
if (TRACK_OBJECT_ALLOCATION_STACKS) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public class UnsafeUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final long BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
|
private static final long BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
|
||||||
|
private static final long SHORT_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(short[].class);
|
||||||
|
|
||||||
public static void memcpy(long src, long dst, long length) {
|
public static void memcpy(long src, long dst, long length) {
|
||||||
UNSAFE.copyMemory(src, dst, length);
|
UNSAFE.copyMemory(src, dst, length);
|
||||||
@@ -31,6 +32,9 @@ public class UnsafeUtil {
|
|||||||
public static void memcpy(byte[] src, long dst) {
|
public static void memcpy(byte[] src, long dst) {
|
||||||
UNSAFE.copyMemory(src, BYTE_ARRAY_BASE_OFFSET, null, dst, src.length);
|
UNSAFE.copyMemory(src, BYTE_ARRAY_BASE_OFFSET, null, dst, src.length);
|
||||||
}
|
}
|
||||||
|
public static void memcpy(short[] src, long dst) {
|
||||||
|
UNSAFE.copyMemory(src, SHORT_ARRAY_BASE_OFFSET, null, dst, (long) src.length <<1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.nio.ByteBuffer;
|
|||||||
import static org.lwjgl.util.zstd.Zstd.*;
|
import static org.lwjgl.util.zstd.Zstd.*;
|
||||||
|
|
||||||
public class SaveLoadSystem {
|
public class SaveLoadSystem {
|
||||||
|
public static final boolean VERIFY_HASH_ON_LOAD = System.getProperty("voxy.verifySectionOnLoad", "true").equals("true");
|
||||||
public static final int BIGGEST_SERIALIZED_SECTION_SIZE = 32 * 32 * 32 * 8 * 2;
|
public static final int BIGGEST_SERIALIZED_SECTION_SIZE = 32 * 32 * 32 * 8 * 2;
|
||||||
|
|
||||||
public static int lin2z(int i) {
|
public static int lin2z(int i) {
|
||||||
@@ -47,46 +48,46 @@ public class SaveLoadSystem {
|
|||||||
pHash ^= block;
|
pHash ^= block;
|
||||||
}
|
}
|
||||||
long[] lut = LUTVAL.toLongArray();
|
long[] lut = LUTVAL.toLongArray();
|
||||||
ByteBuffer raw = MemoryUtil.memAlloc(compressed.length*2+lut.length*8+512);
|
MemoryBuffer raw = new MemoryBuffer(compressed.length*2L+lut.length*8L+512);
|
||||||
|
long ptr = raw.address;
|
||||||
|
|
||||||
long hash = section.key^(lut.length*1293481298141L);
|
long hash = section.key^(lut.length*1293481298141L);
|
||||||
raw.putLong(section.key);
|
MemoryUtil.memPutLong(ptr, section.key); ptr += 8;
|
||||||
raw.putInt(lut.length);
|
MemoryUtil.memPutInt(ptr, lut.length); ptr += 8;
|
||||||
for (long id : lut) {
|
for (long id : lut) {
|
||||||
raw.putLong(id);
|
MemoryUtil.memPutLong(ptr, id); ptr += 8;
|
||||||
hash *= 1230987149811L;
|
hash *= 1230987149811L;
|
||||||
hash += 12831;
|
hash += 12831;
|
||||||
hash ^= id;
|
hash ^= id;
|
||||||
}
|
}
|
||||||
hash ^= pHash;
|
hash ^= pHash;
|
||||||
|
|
||||||
for (short block : compressed) {
|
UnsafeUtil.memcpy(compressed, ptr); ptr += compressed.length*2L;
|
||||||
raw.putShort(block);
|
|
||||||
|
MemoryUtil.memPutLong(ptr, hash); ptr += 8;
|
||||||
|
|
||||||
|
return raw.subSize(ptr-raw.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
raw.putLong(hash);
|
public static boolean deserialize(WorldSection section, MemoryBuffer data) {
|
||||||
//The amount of memory copies are not ideal
|
|
||||||
var out = new MemoryBuffer(raw.position());
|
|
||||||
UnsafeUtil.memcpy(MemoryUtil.memAddress(raw), out.address, out.size);
|
|
||||||
MemoryUtil.memFree(raw);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean deserialize(WorldSection section, MemoryBuffer data, boolean ignoreMismatchPosition) {
|
|
||||||
long ptr = data.address;
|
long ptr = data.address;
|
||||||
long hash = 0;
|
long hash = 0;
|
||||||
long key = MemoryUtil.memGetLong(ptr); ptr += 8;
|
long key = MemoryUtil.memGetLong(ptr); ptr += 8;
|
||||||
int lutLen = MemoryUtil.memGetInt(ptr); ptr += 4;
|
int lutLen = MemoryUtil.memGetInt(ptr); ptr += 4;
|
||||||
long[] lut = new long[lutLen];
|
long[] lut = new long[lutLen];
|
||||||
|
if (VERIFY_HASH_ON_LOAD) {
|
||||||
hash = key ^ (lut.length * 1293481298141L);
|
hash = key ^ (lut.length * 1293481298141L);
|
||||||
|
}
|
||||||
for (int i = 0; i < lutLen; i++) {
|
for (int i = 0; i < lutLen; i++) {
|
||||||
lut[i] = MemoryUtil.memGetLong(ptr); ptr += 8;
|
lut[i] = MemoryUtil.memGetLong(ptr); ptr += 8;
|
||||||
|
if (VERIFY_HASH_ON_LOAD) {
|
||||||
hash *= 1230987149811L;
|
hash *= 1230987149811L;
|
||||||
hash += 12831;
|
hash += 12831;
|
||||||
hash ^= lut[i];
|
hash ^= lut[i];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((!ignoreMismatchPosition) && section.key != key) {
|
if (section.key != key) {
|
||||||
//throw new IllegalStateException("Decompressed section not the same as requested. got: " + key + " expected: " + section.key);
|
//throw new IllegalStateException("Decompressed section not the same as requested. got: " + key + " expected: " + section.key);
|
||||||
System.err.println("Decompressed section not the same as requested. got: " + key + " expected: " + section.key);
|
System.err.println("Decompressed section not the same as requested. got: " + key + " expected: " + section.key);
|
||||||
return false;
|
return false;
|
||||||
@@ -96,6 +97,7 @@ public class SaveLoadSystem {
|
|||||||
section.data[z2lin(i)] = lut[MemoryUtil.memGetShort(ptr)]; ptr += 2;
|
section.data[z2lin(i)] = lut[MemoryUtil.memGetShort(ptr)]; ptr += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (VERIFY_HASH_ON_LOAD) {
|
||||||
long pHash = 99;
|
long pHash = 99;
|
||||||
for (long block : section.data) {
|
for (long block : section.data) {
|
||||||
pHash *= 127817112311121L;
|
pHash *= 127817112311121L;
|
||||||
@@ -111,7 +113,7 @@ public class SaveLoadSystem {
|
|||||||
System.err.println("Hash mismatch got: " + hash + " expected: " + expectedHash + " removing region");
|
System.err.println("Hash mismatch got: " + hash + " expected: " + expectedHash + " removing region");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class WorldEngine {
|
|||||||
var data = this.storage.getSectionData(into.key);
|
var data = this.storage.getSectionData(into.key);
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
try {
|
try {
|
||||||
if (!SaveLoadSystem.deserialize(into, data, true)) {
|
if (!SaveLoadSystem.deserialize(into, data)) {
|
||||||
this.storage.deleteSectionData(into.key);
|
this.storage.deleteSectionData(into.key);
|
||||||
//TODO: regenerate the section from children
|
//TODO: regenerate the section from children
|
||||||
Arrays.fill(into.data, Mapper.AIR);
|
Arrays.fill(into.data, Mapper.AIR);
|
||||||
|
|||||||
Reference in New Issue
Block a user