no allocations on read/write block chunks
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
This commit is contained in:
parent
f49e87261a
commit
8bdebb16c2
@ -1996,6 +1996,7 @@ Performance improvements
|
|||||||
- Block chunk disk map writes files without allocating a buffer
|
- Block chunk disk map writes files without allocating a buffer
|
||||||
- Increase memory limit 6GB->8GB
|
- Increase memory limit 6GB->8GB
|
||||||
- Server block chunk disk map writes directly to output stream instead of inbetween buffer
|
- Server block chunk disk map writes directly to output stream instead of inbetween buffer
|
||||||
|
- No-allocation block chunk read/write in disk map
|
||||||
Increase human move speed
|
Increase human move speed
|
||||||
LOD components re-attach physics
|
LOD components re-attach physics
|
||||||
VectorPool->JomlPool
|
VectorPool->JomlPool
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
package electrosphere.server.physics.block.diskmap;
|
package electrosphere.server.physics.block.diskmap;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ShortBuffer;
|
import java.nio.ShortBuffer;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.ReadableByteChannel;
|
||||||
|
import java.nio.channels.WritableByteChannel;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.zip.DeflaterOutputStream;
|
import java.util.zip.DataFormatException;
|
||||||
import java.util.zip.InflaterOutputStream;
|
import java.util.zip.Deflater;
|
||||||
|
import java.util.zip.Inflater;
|
||||||
|
|
||||||
import electrosphere.client.block.BlockChunkData;
|
import electrosphere.client.block.BlockChunkData;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
@ -50,22 +53,64 @@ public class ServerBlockChunkDiskMap {
|
|||||||
*/
|
*/
|
||||||
static final int HEADER_HOMOGENOUS = 1;
|
static final int HEADER_HOMOGENOUS = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total size of the file potentially
|
||||||
|
*/
|
||||||
|
static final int FILE_MAX_SIZE = FILE_HEADER + BlockChunkData.TOTAL_DATA_WIDTH * (2 * 2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The map of world position+chunk type to the file that actually houses that information
|
* The map of world position+chunk type to the file that actually houses that information
|
||||||
*/
|
*/
|
||||||
Map<Long,String> worldPosFileMap;
|
private Map<Long,String> worldPosFileMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locks the chunk disk map for thread safety
|
* Locks the chunk disk map for thread safety
|
||||||
*/
|
*/
|
||||||
@Exclude
|
@Exclude
|
||||||
ReentrantLock lock = new ReentrantLock();
|
private ReentrantLock lock = new ReentrantLock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The buffer used for writing out files
|
||||||
|
*/
|
||||||
|
@Exclude
|
||||||
|
private ByteBuffer outputBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buffer for compression input
|
||||||
|
*/
|
||||||
|
@Exclude
|
||||||
|
private ByteBuffer compressInputBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The buffer used for reading in files
|
||||||
|
*/
|
||||||
|
@Exclude
|
||||||
|
private ByteBuffer inputBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deflater used for compressing outgoing files
|
||||||
|
*/
|
||||||
|
@Exclude
|
||||||
|
private Deflater deflater;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inflater used for decompressing incoming files
|
||||||
|
*/
|
||||||
|
@Exclude
|
||||||
|
private Inflater inflater;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
private ServerBlockChunkDiskMap(){
|
private ServerBlockChunkDiskMap(){
|
||||||
worldPosFileMap = new HashMap<Long,String>();
|
worldPosFileMap = new HashMap<Long,String>();
|
||||||
|
outputBuffer = ByteBuffer.allocate(FILE_MAX_SIZE);
|
||||||
|
compressInputBuffer = ByteBuffer.allocate(FILE_MAX_SIZE);
|
||||||
|
inputBuffer = ByteBuffer.allocate(FILE_MAX_SIZE);
|
||||||
|
deflater = new Deflater();
|
||||||
|
deflater.setInput(compressInputBuffer);
|
||||||
|
inflater = new Inflater();
|
||||||
|
inflater.setInput(compressInputBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,30 +184,42 @@ public class ServerBlockChunkDiskMap {
|
|||||||
if(this.containsBlocksAtPosition(worldX, worldY, worldZ)){
|
if(this.containsBlocksAtPosition(worldX, worldY, worldZ)){
|
||||||
//read file
|
//read file
|
||||||
String fileName = worldPosFileMap.get(getBlockChunkKey(worldX, worldY, worldZ));
|
String fileName = worldPosFileMap.get(getBlockChunkKey(worldX, worldY, worldZ));
|
||||||
byte[] rawDataCompressed = FileUtils.loadBinaryFromSavePath(Globals.serverState.currentSave.getName(), fileName);
|
|
||||||
//decompress
|
|
||||||
byte[] rawData = null;
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
||||||
InflaterOutputStream inflaterInputStream = new InflaterOutputStream(out);
|
|
||||||
try {
|
try {
|
||||||
inflaterInputStream.write(rawDataCompressed);
|
//Construct the channel
|
||||||
inflaterInputStream.flush();
|
InputStream inputStream = FileUtils.getSavePathAsInputStream(Globals.serverState.currentSave.getName(), fileName);
|
||||||
inflaterInputStream.close();
|
ReadableByteChannel channel = Channels.newChannel(inputStream);
|
||||||
rawData = out.toByteArray();
|
|
||||||
} catch (IOException e) {
|
//setup compression input buffer
|
||||||
LoggerInterface.loggerFileIO.ERROR(e);
|
compressInputBuffer.position(0);
|
||||||
}
|
compressInputBuffer.limit(FILE_MAX_SIZE);
|
||||||
//parse
|
|
||||||
if(rawData != null){
|
//Read the file into the channel
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(rawData);
|
channel.read(compressInputBuffer);
|
||||||
|
compressInputBuffer.flip();
|
||||||
|
|
||||||
|
//setup the inflater
|
||||||
|
inflater.setInput(compressInputBuffer);
|
||||||
|
|
||||||
|
//decompress
|
||||||
|
inflater.inflate(inputBuffer);
|
||||||
|
inputBuffer.flip();
|
||||||
|
|
||||||
|
//error check
|
||||||
|
if(!inflater.finished()){
|
||||||
|
throw new Error("Failed to read!");
|
||||||
|
}
|
||||||
|
|
||||||
|
//parse
|
||||||
rVal = new BlockChunkData();
|
rVal = new BlockChunkData();
|
||||||
|
|
||||||
|
|
||||||
int headerHomogenousType = buffer.getInt();
|
int headerHomogenousType = inputBuffer.getInt();
|
||||||
if(headerHomogenousType == HEADER_NON_HOMOGENOUS){
|
if(headerHomogenousType == HEADER_NON_HOMOGENOUS){
|
||||||
|
|
||||||
//read a non-homogenous chunk
|
//read a non-homogenous chunk
|
||||||
ShortBuffer shortView = buffer.asShortBuffer();
|
ShortBuffer shortView = inputBuffer.asShortBuffer();
|
||||||
short[] type = BlockChunkPool.getShort();
|
short[] type = BlockChunkPool.getShort();
|
||||||
short[] metadata = BlockChunkPool.getShort();
|
short[] metadata = BlockChunkPool.getShort();
|
||||||
short firstType = -1;
|
short firstType = -1;
|
||||||
@ -186,7 +243,7 @@ public class ServerBlockChunkDiskMap {
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
//read a homogenous chunk
|
//read a homogenous chunk
|
||||||
short homogenousValue = buffer.getShort();
|
short homogenousValue = inputBuffer.getShort();
|
||||||
rVal.setHomogenousValue(homogenousValue);
|
rVal.setHomogenousValue(homogenousValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,6 +252,32 @@ public class ServerBlockChunkDiskMap {
|
|||||||
rVal.setWorldY(worldY);
|
rVal.setWorldY(worldY);
|
||||||
rVal.setWorldZ(worldZ);
|
rVal.setWorldZ(worldZ);
|
||||||
rVal.setLod(BlockChunkData.LOD_FULL_RES);
|
rVal.setLod(BlockChunkData.LOD_FULL_RES);
|
||||||
|
|
||||||
|
|
||||||
|
//close channel
|
||||||
|
channel.close();
|
||||||
|
inputStream.close();
|
||||||
|
|
||||||
|
//reset buffers
|
||||||
|
inflater.reset();
|
||||||
|
compressInputBuffer.position(0);
|
||||||
|
compressInputBuffer.limit(FILE_MAX_SIZE);
|
||||||
|
inputBuffer.position(0);
|
||||||
|
inputBuffer.limit(FILE_MAX_SIZE);
|
||||||
|
} catch (IOException ex){
|
||||||
|
inflater.reset();
|
||||||
|
compressInputBuffer.position(0);
|
||||||
|
compressInputBuffer.limit(FILE_MAX_SIZE);
|
||||||
|
inputBuffer.position(0);
|
||||||
|
inputBuffer.limit(FILE_MAX_SIZE);
|
||||||
|
LoggerInterface.loggerFileIO.ERROR(ex);
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
inflater.reset();
|
||||||
|
compressInputBuffer.position(0);
|
||||||
|
compressInputBuffer.limit(FILE_MAX_SIZE);
|
||||||
|
inputBuffer.position(0);
|
||||||
|
inputBuffer.limit(FILE_MAX_SIZE);
|
||||||
|
LoggerInterface.loggerFileIO.ERROR(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
@ -218,39 +301,65 @@ public class ServerBlockChunkDiskMap {
|
|||||||
}
|
}
|
||||||
//compress
|
//compress
|
||||||
try {
|
try {
|
||||||
OutputStream out = FileUtils.getBinarySavePathOutputStream(Globals.serverState.currentSave.getName(), fileName);
|
|
||||||
DeflaterOutputStream deflaterOutStream = new DeflaterOutputStream(out);
|
|
||||||
DataOutputStream dataOut = new DataOutputStream(deflaterOutStream);
|
|
||||||
|
|
||||||
//generate binary for the file
|
//generate binary for the file
|
||||||
short[] type = chunkData.getType();
|
short[] type = chunkData.getType();
|
||||||
short[] metadata = chunkData.getMetadata();
|
short[] metadata = chunkData.getMetadata();
|
||||||
|
|
||||||
//push data
|
//push data
|
||||||
|
compressInputBuffer.position(0);
|
||||||
if(chunkData.getHomogenousValue() == BlockChunkData.NOT_HOMOGENOUS){
|
if(chunkData.getHomogenousValue() == BlockChunkData.NOT_HOMOGENOUS){
|
||||||
//put header
|
//put header
|
||||||
dataOut.writeInt(HEADER_NON_HOMOGENOUS);
|
compressInputBuffer.putInt(HEADER_NON_HOMOGENOUS);
|
||||||
//put data
|
//put data
|
||||||
for(int i = 0; i < BlockChunkData.TOTAL_DATA_WIDTH; i++){
|
for(int i = 0; i < BlockChunkData.TOTAL_DATA_WIDTH; i++){
|
||||||
dataOut.writeShort(type[i]);
|
compressInputBuffer.putShort(type[i]);
|
||||||
}
|
}
|
||||||
for(int i = 0; i < BlockChunkData.TOTAL_DATA_WIDTH; i++){
|
for(int i = 0; i < BlockChunkData.TOTAL_DATA_WIDTH; i++){
|
||||||
dataOut.writeShort(metadata[i]);
|
compressInputBuffer.putShort(metadata[i]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//put header
|
//put header
|
||||||
dataOut.writeInt(HEADER_HOMOGENOUS);
|
compressInputBuffer.putInt(HEADER_HOMOGENOUS);
|
||||||
//put data
|
//put data
|
||||||
dataOut.writeShort(chunkData.getHomogenousValue());
|
compressInputBuffer.putShort(chunkData.getHomogenousValue());
|
||||||
|
}
|
||||||
|
compressInputBuffer.flip();
|
||||||
|
|
||||||
|
//setup deflater
|
||||||
|
deflater.setInput(compressInputBuffer);
|
||||||
|
deflater.finish();
|
||||||
|
|
||||||
|
//construct channel
|
||||||
|
OutputStream out = FileUtils.getBinarySavePathOutputStream(Globals.serverState.currentSave.getName(), fileName);
|
||||||
|
WritableByteChannel channel = Channels.newChannel(out);
|
||||||
|
|
||||||
|
//write
|
||||||
|
while(!deflater.finished()){
|
||||||
|
deflater.deflate(outputBuffer);
|
||||||
|
outputBuffer.flip();
|
||||||
|
channel.write(outputBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
//flush and close
|
//flush and close
|
||||||
dataOut.flush();
|
channel.close();
|
||||||
dataOut.close();
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
|
||||||
|
//reset buffers
|
||||||
|
deflater.reset();
|
||||||
|
compressInputBuffer.position(0);
|
||||||
|
compressInputBuffer.limit(FILE_MAX_SIZE);
|
||||||
|
outputBuffer.position(0);
|
||||||
|
outputBuffer.limit(FILE_MAX_SIZE);
|
||||||
|
|
||||||
//save to the map of filenames
|
//save to the map of filenames
|
||||||
worldPosFileMap.put(chunkKey,fileName);
|
worldPosFileMap.put(chunkKey,fileName);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
deflater.reset();
|
||||||
|
compressInputBuffer.position(0);
|
||||||
|
compressInputBuffer.limit(FILE_MAX_SIZE);
|
||||||
|
outputBuffer.position(0);
|
||||||
|
outputBuffer.limit(FILE_MAX_SIZE);
|
||||||
LoggerInterface.loggerFileIO.ERROR(e);
|
LoggerInterface.loggerFileIO.ERROR(e);
|
||||||
}
|
}
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|||||||
@ -385,6 +385,17 @@ public class FileUtils {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a save files as an input stream
|
||||||
|
* @param saveName The save name
|
||||||
|
* @param pathName The path within the save folder
|
||||||
|
* @return The input stream
|
||||||
|
*/
|
||||||
|
public static InputStream getSavePathAsInputStream(String saveName, String pathName) throws IOException {
|
||||||
|
String sanitizedFilePath = FileUtils.sanitizeFilePath(pathName);
|
||||||
|
return Files.newInputStream(FileUtils.getSaveFile(saveName,sanitizedFilePath).toPath());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a binary file to a save folder's file
|
* Writes a binary file to a save folder's file
|
||||||
* @param saveName The name of the save
|
* @param saveName The name of the save
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user