3
0
Mirror von https://github.com/IntellectualSites/FastAsyncWorldEdit.git synchronisiert 2024-11-07 20:10:06 +01:00

Update MCAFile.java

Dieser Commit ist enthalten in:
Jesse Boyd 2019-11-02 08:40:11 +01:00
Ursprung ed7df341b4
Commit 0b2bd862a0
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 59F1DE6293AF6E1F

Datei anzeigen

@ -3,7 +3,6 @@ package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.beta.Trimable; import com.boydti.fawe.beta.Trimable;
import com.boydti.fawe.jnbt.streamer.StreamDelegate; import com.boydti.fawe.jnbt.streamer.StreamDelegate;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.RunnableVal4; import com.boydti.fawe.object.RunnableVal4;
import com.boydti.fawe.object.collection.CleanableThreadLocal; import com.boydti.fawe.object.collection.CleanableThreadLocal;
import com.boydti.fawe.object.io.BufferedRandomAccessFile; import com.boydti.fawe.object.io.BufferedRandomAccessFile;
@ -14,6 +13,7 @@ import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -23,7 +23,6 @@ import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -33,6 +32,7 @@ import java.util.zip.InflaterInputStream;
/** /**
* Chunk format: http://minecraft.gamepedia.com/Chunk_format#Entity_format * Chunk format: http://minecraft.gamepedia.com/Chunk_format#Entity_format
* e.g.: `.Level.Entities.#` (Starts with a . as the root tag is unnamed) * e.g.: `.Level.Entities.#` (Starts with a . as the root tag is unnamed)
* Note: This class isn't thread safe. You can use it in an async thread, but not multiple at the same time
*/ */
public class MCAFile implements Trimable { public class MCAFile implements Trimable {
@ -61,6 +61,7 @@ public class MCAFile implements Trimable {
private int X, Z; private int X, Z;
private MCAChunk[] chunks; private MCAChunk[] chunks;
private boolean[] chunkInitialized; private boolean[] chunkInitialized;
private Object[] locks;
final ThreadLocal<byte[]> byteStore1 = new ThreadLocal<byte[]>() { final ThreadLocal<byte[]> byteStore1 = new ThreadLocal<byte[]>() {
@Override @Override
@ -86,6 +87,10 @@ public class MCAFile implements Trimable {
this.locations = new byte[4096]; this.locations = new byte[4096];
this.chunks = new MCAChunk[32 * 32]; this.chunks = new MCAChunk[32 * 32];
this.chunkInitialized = new boolean[this.chunks.length]; this.chunkInitialized = new boolean[this.chunks.length];
this.locks = new Object[this.chunks.length];
for (int i = 0; i < locks.length; i++) {
locks[i] = new Object();
}
} }
@Override @Override
@ -106,14 +111,12 @@ public class MCAFile implements Trimable {
public MCAFile init(File file) throws FileNotFoundException { public MCAFile init(File file) throws FileNotFoundException {
String[] split = file.getName().split("\\."); String[] split = file.getName().split("\\.");
X = Integer.parseInt(split[1]); int X = Integer.parseInt(split[1]);
Z = Integer.parseInt(split[2]); int Z = Integer.parseInt(split[2]);
return init(file, X, Z); return init(file, X, Z);
} }
public MCAFile init(File file, int mcrX, int mcrZ) throws FileNotFoundException { public MCAFile init(File file, int mcrX, int mcrZ) throws FileNotFoundException {
if (raf != null) {
synchronized (raf) {
if (raf != null) { if (raf != null) {
flush(pool); flush(pool);
for (int i = 0; i < 4096; i++) { for (int i = 0; i < 4096; i++) {
@ -125,15 +128,12 @@ public class MCAFile implements Trimable {
e.printStackTrace(); e.printStackTrace();
} }
raf = null; raf = null;
}
deleted = false; deleted = false;
Arrays.fill(chunkInitialized, false); Arrays.fill(chunkInitialized, false);
readLocations = false; readLocations = false;
}
}
this.X = mcrX; this.X = mcrX;
this.Z = mcrZ; this.Z = mcrZ;
}
this.file = file; this.file = file;
if (!file.exists()) { if (!file.exists()) {
throw new FileNotFoundException(file.getName()); throw new FileNotFoundException(file.getName());
@ -178,10 +178,10 @@ public class MCAFile implements Trimable {
e.printStackTrace(); e.printStackTrace();
} }
} }
synchronized (chunks) { deleted = false;
readLocations = false;
Arrays.fill(chunkInitialized, false); Arrays.fill(chunkInitialized, false);
} }
}
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
@ -234,15 +234,25 @@ public class MCAFile implements Trimable {
public MCAChunk getChunk(int cx, int cz) throws IOException { public MCAChunk getChunk(int cx, int cz) throws IOException {
int pair = getIndex(cx, cz); int pair = getIndex(cx, cz);
MCAChunk chunk = chunks[pair]; MCAChunk chunk = chunks[pair];
if (chunk == null) {
Object lock = locks[pair];
synchronized (lock) {
chunk = chunks[pair];
if (chunk == null) { if (chunk == null) {
chunk = new MCAChunk(); chunk = new MCAChunk();
chunk.setPosition(cx, cz); chunk.setPosition(cx, cz);
chunks[pair] = chunk; chunks[pair] = chunk;
}
}
} else if (chunkInitialized[pair]) { } else if (chunkInitialized[pair]) {
return chunk; return chunk;
} }
synchronized (chunk) {
if (!chunkInitialized[pair]) {
readChunk(chunk, pair); readChunk(chunk, pair);
chunkInitialized[pair] = true; chunkInitialized[pair] = true;
}
}
return chunk; return chunk;
} }
@ -493,7 +503,6 @@ public class MCAFile implements Trimable {
if (isDeleted()) { if (isDeleted()) {
return true; return true;
} }
synchronized (chunks) {
for (int i = 0; i < chunks.length; i++) { for (int i = 0; i < chunks.length; i++) {
MCAChunk chunk = chunks[i]; MCAChunk chunk = chunks[i];
if (chunk != null && this.chunkInitialized[i]) { if (chunk != null && this.chunkInitialized[i]) {
@ -502,15 +511,14 @@ public class MCAFile implements Trimable {
} }
} }
} }
}
return false; return false;
} }
/** /**
* Write the chunk to the file * Write the chunk to the file
* @param pool * @param wait - If the flush method needs to wait for the pool
*/ */
public void flush(ForkJoinPool pool) { public void flush(boolean wait) {
synchronized (raf) { synchronized (raf) {
// If the file is marked as deleted, nothing is written // If the file is marked as deleted, nothing is written
if (isDeleted()) { if (isDeleted()) {
@ -519,12 +527,6 @@ public class MCAFile implements Trimable {
return; return;
} }
boolean wait; // If the flush method needs to wait for the pool
if (pool == null) {
wait = true;
pool = new ForkJoinPool();
} else wait = false;
// Chunks that need to be relocated // Chunks that need to be relocated
Int2ObjectOpenHashMap<byte[]> relocate = new Int2ObjectOpenHashMap<>(); Int2ObjectOpenHashMap<byte[]> relocate = new Int2ObjectOpenHashMap<>();
// The position of each chunk // The position of each chunk
@ -533,19 +535,18 @@ public class MCAFile implements Trimable {
final Int2ObjectOpenHashMap<byte[]> compressedMap = new Int2ObjectOpenHashMap<>(); final Int2ObjectOpenHashMap<byte[]> compressedMap = new Int2ObjectOpenHashMap<>();
// The data of each chunk that needs to be moved // The data of each chunk that needs to be moved
final Int2ObjectOpenHashMap<byte[]> append = new Int2ObjectOpenHashMap<>(); final Int2ObjectOpenHashMap<byte[]> append = new Int2ObjectOpenHashMap<>();
boolean modified = false; boolean[] modified = new boolean[1];
// Get the current time for the chunk timestamp // Get the current time for the chunk timestamp
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
// Load the chunks into the append or compressed map // Load the chunks into the append or compressed map
for (MCAChunk chunk : getCachedChunks()) { final ForkJoinPool finalPool = this.pool;
forEachCachedChunk(chunk -> {
if (chunk.isModified() || chunk.isDeleted()) { if (chunk.isModified() || chunk.isDeleted()) {
modified = true; modified[0] = true;
chunk.setLastUpdate(now); chunk.setLastUpdate(now);
if (!chunk.isDeleted()) { if (!chunk.isDeleted()) {
pool.submit(new Runnable() { MCAFile.this.pool.submit(() -> {
@Override
public void run() {
try { try {
byte[] compressed = toBytes(chunk); byte[] compressed = toBytes(chunk);
int pair = MathMan.pair((short) (chunk.getX() & 31), (short) (chunk.getZ() & 31)); int pair = MathMan.pair((short) (chunk.getX() & 31), (short) (chunk.getZ() & 31));
@ -561,14 +562,13 @@ public class MCAFile implements Trimable {
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
} }
}
}); });
} }
} }
} });
// If any changes were detected // If any changes were detected
if (modified) { if (modified[0]) {
file.setLastModified(now); file.setLastModified(now);
// Load the offset data into the offset map // Load the offset data into the offset map
@ -700,13 +700,9 @@ public class MCAFile implements Trimable {
e.printStackTrace(); e.printStackTrace();
} }
if (wait) { if (wait) {
pool.shutdown();
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS); pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} }
} }
} }
CleanableThreadLocal.clean(byteStore1);
CleanableThreadLocal.clean(byteStore2);
CleanableThreadLocal.clean(byteStore3);
} }
} }