mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-06-11 20:13:55 +00:00
Various minor
thread local cleans on close remove unnecessary loop on set remove unnecessary get on set clean CFI cache on generate
This commit is contained in:
@ -12,6 +12,7 @@ import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
public abstract class MCAWriter implements Extent {
|
||||
@ -74,6 +75,15 @@ public abstract class MCAWriter implements Extent {
|
||||
|
||||
public abstract MCAChunk write(MCAChunk input, int startX, int endX, int startZ, int endZ);
|
||||
|
||||
private static CleanableThreadLocal<MCAChunk> createCache() {
|
||||
return new CleanableThreadLocal<>(() -> {
|
||||
MCAChunk chunk = new MCAChunk();
|
||||
Arrays.fill(chunk.blocks, (char) BlockID.AIR);
|
||||
// Arrays.fill(chunk.skyLight, (byte) 255);
|
||||
return chunk;
|
||||
});
|
||||
}
|
||||
|
||||
public void generate() throws IOException {
|
||||
if (!folder.exists()) {
|
||||
folder.mkdirs();
|
||||
@ -81,122 +91,116 @@ public abstract class MCAWriter implements Extent {
|
||||
final ForkJoinPool pool = new ForkJoinPool();
|
||||
int tcx = (width - 1) >> 4;
|
||||
int tcz = (length - 1) >> 4;
|
||||
final ThreadLocal<MCAChunk> chunkStore = new ThreadLocal<MCAChunk>() {
|
||||
@Override
|
||||
protected MCAChunk initialValue() {
|
||||
MCAChunk chunk = new MCAChunk();
|
||||
Arrays.fill(chunk.blocks, (char) BlockID.AIR);
|
||||
// Arrays.fill(chunk.skyLight, (byte) 255);
|
||||
return chunk;
|
||||
});
|
||||
final ThreadLocal<byte[]> byteStore1 = ThreadLocal.withInitial(() -> new byte[500000]);
|
||||
final ThreadLocal<byte[]> byteStore2 = ThreadLocal.withInitial(() -> new byte[500000]);
|
||||
final ThreadLocal<Deflater> deflateStore = ThreadLocal
|
||||
.withInitial(() -> new Deflater(Deflater.BEST_SPEED, false));
|
||||
byte[] fileBuf = new byte[1 << 16];
|
||||
int mcaXMin = 0;
|
||||
int mcaZMin = 0;
|
||||
int mcaXMax = mcaXMin + ((width - 1) >> 9);
|
||||
int mcaZMax = mcaZMin + ((length - 1) >> 9);
|
||||
try (CleanableThreadLocal<MCAChunk> chunkStore = createCache()){
|
||||
final ThreadLocal<byte[]> byteStore1 = ThreadLocal.withInitial(() -> new byte[500000]);
|
||||
final ThreadLocal<byte[]> byteStore2 = ThreadLocal.withInitial(() -> new byte[500000]);
|
||||
final ThreadLocal<Deflater> deflateStore = ThreadLocal
|
||||
.withInitial(() -> new Deflater(Deflater.BEST_SPEED, false));
|
||||
byte[] fileBuf = new byte[1 << 16];
|
||||
int mcaXMin = 0;
|
||||
int mcaZMin = 0;
|
||||
int mcaXMax = mcaXMin + ((width - 1) >> 9);
|
||||
int mcaZMax = mcaZMin + ((length - 1) >> 9);
|
||||
|
||||
final byte[] header = new byte[4096];
|
||||
final byte[] header = new byte[4096];
|
||||
|
||||
for (int mcaZ = mcaXMin; mcaZ <= mcaZMax; mcaZ++) {
|
||||
for (int mcaX = mcaXMin; mcaX <= mcaXMax; mcaX++) {
|
||||
File file = new File(folder, "r." + (mcaX + (getOffsetX() >> 9)) + "." + (mcaZ + (getOffsetZ() >> 9)) + ".mca");
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
final BufferedRandomAccessFile raf = new BufferedRandomAccessFile(file, "rw", fileBuf);
|
||||
final byte[][] compressed = new byte[1024][];
|
||||
int bx = mcaX << 9;
|
||||
int bz = mcaZ << 9;
|
||||
int scx = bx >> 4;
|
||||
int ecx = Math.min(scx + 31, tcx);
|
||||
int scz = bz >> 4;
|
||||
int ecz = Math.min(scz + 31, tcz);
|
||||
for (int cz = scz; cz <= ecz; cz++) {
|
||||
final int csz = cz << 4;
|
||||
final int cez = Math.min(csz + 15, length - 1);
|
||||
for (int cx = scx; cx <= ecx; cx++) {
|
||||
final int csx = cx << 4;
|
||||
final int cex = Math.min(csx + 15, width - 1);
|
||||
final int fcx = cx;
|
||||
final int fcz = cz;
|
||||
if (shouldWrite(cx, cz)) {
|
||||
pool.submit(() -> {
|
||||
try {
|
||||
MCAChunk chunk = chunkStore.get();
|
||||
chunk.reset();
|
||||
chunk.setPosition(fcx, fcz);
|
||||
chunk = write(chunk, csx, cex, csz, cez);
|
||||
if (chunk != null) {
|
||||
// Generation offset
|
||||
chunk.setPosition( fcx + (getOffsetX() >> 4), fcz + (getOffsetZ() >> 4));
|
||||
for (int mcaZ = mcaXMin; mcaZ <= mcaZMax; mcaZ++) {
|
||||
for (int mcaX = mcaXMin; mcaX <= mcaXMax; mcaX++) {
|
||||
File file = new File(folder, "r." + (mcaX + (getOffsetX() >> 9)) + "." + (mcaZ + (getOffsetZ() >> 9)) + ".mca");
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
final BufferedRandomAccessFile raf = new BufferedRandomAccessFile(file, "rw", fileBuf);
|
||||
final byte[][] compressed = new byte[1024][];
|
||||
int bx = mcaX << 9;
|
||||
int bz = mcaZ << 9;
|
||||
int scx = bx >> 4;
|
||||
int ecx = Math.min(scx + 31, tcx);
|
||||
int scz = bz >> 4;
|
||||
int ecz = Math.min(scz + 31, tcz);
|
||||
for (int cz = scz; cz <= ecz; cz++) {
|
||||
final int csz = cz << 4;
|
||||
final int cez = Math.min(csz + 15, length - 1);
|
||||
for (int cx = scx; cx <= ecx; cx++) {
|
||||
final int csx = cx << 4;
|
||||
final int cex = Math.min(csx + 15, width - 1);
|
||||
final int fcx = cx;
|
||||
final int fcz = cz;
|
||||
if (shouldWrite(cx, cz)) {
|
||||
pool.submit(() -> {
|
||||
try {
|
||||
MCAChunk chunk = chunkStore.get();
|
||||
chunk.reset();
|
||||
chunk.setPosition(fcx, fcz);
|
||||
chunk = write(chunk, csx, cex, csz, cez);
|
||||
if (chunk != null) {
|
||||
// Generation offset
|
||||
chunk.setPosition(fcx + (getOffsetX() >> 4), fcz + (getOffsetZ() >> 4));
|
||||
|
||||
// Compress
|
||||
byte[] bytes = chunk.toBytes(byteStore1.get());
|
||||
byte[] compressedBytes = MainUtil.compress(bytes, byteStore2.get(), deflateStore.get());
|
||||
// Compress
|
||||
byte[] bytes = chunk.toBytes(byteStore1.get());
|
||||
byte[] compressedBytes = MainUtil.compress(bytes, byteStore2.get(), deflateStore.get());
|
||||
|
||||
// TODO optimize (avoid cloning) by add a synchronized block and write to the RAF here instead of below
|
||||
compressed[((fcx & 31)) + ((fcz & 31) << 5)] = compressedBytes.clone();
|
||||
// TODO optimize (avoid cloning) by add a synchronized block and write to the RAF here instead of below
|
||||
compressed[((fcx & 31)) + ((fcz & 31) << 5)] = compressedBytes.clone();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
pool.submit(() -> {
|
||||
try {
|
||||
int totalLength = 8192;
|
||||
for (byte[] compressedBytes : compressed) {
|
||||
if (compressedBytes != null) {
|
||||
int blocks = ((4095 + compressedBytes.length + 5) / 4096) * 4096;
|
||||
totalLength += blocks;
|
||||
}
|
||||
}
|
||||
raf.setLength(totalLength);
|
||||
int offset = 8192;
|
||||
for (int i = 0; i < compressed.length; i++) {
|
||||
byte[] compressedBytes = compressed[i];
|
||||
if (compressedBytes != null) {
|
||||
// Set header
|
||||
int index = i << 2;
|
||||
int offsetMedium = offset >> 12;
|
||||
int blocks = ((4095 + compressedBytes.length + 5) / 4096);
|
||||
header[index] = (byte) (offsetMedium >> 16);
|
||||
header[index + 1] = (byte) ((offsetMedium >> 8));
|
||||
header[index + 2] = (byte) ((offsetMedium >> 0));
|
||||
header[index + 3] = (byte) (blocks);
|
||||
// Write bytes
|
||||
raf.seek(offset);
|
||||
raf.writeInt(compressedBytes.length + 1);
|
||||
raf.write(2);
|
||||
raf.write(compressedBytes);
|
||||
offset += blocks * 4096;
|
||||
}
|
||||
}
|
||||
raf.seek(0);
|
||||
raf.write(header);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
pool.submit(() -> {
|
||||
try {
|
||||
raf.close();
|
||||
int totalLength = 8192;
|
||||
for (byte[] compressedBytes : compressed) {
|
||||
if (compressedBytes != null) {
|
||||
int blocks = ((4095 + compressedBytes.length + 5) / 4096) * 4096;
|
||||
totalLength += blocks;
|
||||
}
|
||||
}
|
||||
raf.setLength(totalLength);
|
||||
int offset = 8192;
|
||||
for (int i = 0; i < compressed.length; i++) {
|
||||
byte[] compressedBytes = compressed[i];
|
||||
if (compressedBytes != null) {
|
||||
// Set header
|
||||
int index = i << 2;
|
||||
int offsetMedium = offset >> 12;
|
||||
int blocks = ((4095 + compressedBytes.length + 5) / 4096);
|
||||
header[index] = (byte) (offsetMedium >> 16);
|
||||
header[index + 1] = (byte) ((offsetMedium >> 8));
|
||||
header[index + 2] = (byte) ((offsetMedium >> 0));
|
||||
header[index + 3] = (byte) (blocks);
|
||||
// Write bytes
|
||||
raf.seek(offset);
|
||||
raf.writeInt(compressedBytes.length + 1);
|
||||
raf.write(2);
|
||||
raf.write(compressedBytes);
|
||||
offset += blocks * 4096;
|
||||
}
|
||||
}
|
||||
raf.seek(0);
|
||||
raf.write(header);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
pool.shutdown();
|
||||
CleanableThreadLocal.clean(byteStore1);
|
||||
CleanableThreadLocal.clean(byteStore2);
|
||||
CleanableThreadLocal.clean(deflateStore);
|
||||
}
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
pool.shutdown();
|
||||
CleanableThreadLocal.clean(byteStore1);
|
||||
CleanableThreadLocal.clean(byteStore2);
|
||||
CleanableThreadLocal.clean(deflateStore);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package com.boydti.fawe.object.collection;
|
||||
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
@ -14,7 +16,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class CleanableThreadLocal<T> extends ThreadLocal<T> {
|
||||
public class CleanableThreadLocal<T> extends ThreadLocal<T> implements Closeable {
|
||||
private final Supplier<T> supplier;
|
||||
private final Function<T, T> modifier;
|
||||
private LongAdder count = new LongAdder();
|
||||
@ -167,4 +169,9 @@ public class CleanableThreadLocal<T> extends ThreadLocal<T> {
|
||||
clean(this);
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
clean();
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ public class BlockType implements FawePattern, Keyed {
|
||||
*
|
||||
* @return The default state
|
||||
*/
|
||||
public BlockState getDefaultState() {
|
||||
public final BlockState getDefaultState() {
|
||||
return this.settings.defaultState;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user