mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-08-16 08:15:50 +00:00
fix more unsafe mantle chunk accesses
This commit is contained in:
parent
16a4d20c90
commit
556bef6e43
@ -47,7 +47,6 @@ import org.bukkit.Chunk;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@ -58,16 +57,18 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
*/
|
||||
|
||||
public class Mantle {
|
||||
private static final int LOCK_SIZE = Short.MAX_VALUE;
|
||||
|
||||
private final File dataFolder;
|
||||
@Getter
|
||||
private final int worldHeight;
|
||||
private final Map<Long, Long> lastUse;
|
||||
private final Map<Long, TectonicPlate> loadedRegions;
|
||||
private final KMap<Long, Long> lastUse;
|
||||
private final KMap<Long, TectonicPlate> loadedRegions;
|
||||
private final HyperLock hyperLock;
|
||||
private final AtomicBoolean closed;
|
||||
private final MultiBurst ioBurst;
|
||||
private final AtomicBoolean ioTrim;
|
||||
private final AtomicBoolean ioTectonicUnload;
|
||||
private final Semaphore ioTrim;
|
||||
private final Semaphore ioTectonicUnload;
|
||||
private final AtomicDouble adjustedIdleDuration;
|
||||
private final KSet<Long> toUnload;
|
||||
|
||||
@ -83,8 +84,8 @@ public class Mantle {
|
||||
this.closed = new AtomicBoolean(false);
|
||||
this.dataFolder = dataFolder;
|
||||
this.worldHeight = worldHeight;
|
||||
this.ioTrim = new AtomicBoolean(false);
|
||||
this.ioTectonicUnload = new AtomicBoolean(false);
|
||||
this.ioTrim = new Semaphore(LOCK_SIZE, true);
|
||||
this.ioTectonicUnload = new Semaphore(LOCK_SIZE, true);
|
||||
loadedRegions = new KMap<>();
|
||||
lastUse = new KMap<>();
|
||||
ioBurst = MultiBurst.burst;
|
||||
@ -428,7 +429,7 @@ public class Mantle {
|
||||
}
|
||||
adjustedIdleDuration.set(idleDuration);
|
||||
|
||||
ioTrim.set(true);
|
||||
ioTrim.acquireUninterruptibly(LOCK_SIZE);
|
||||
try {
|
||||
Iris.debug("Trimming Tectonic Plates older than " + Form.duration(idleDuration, 0));
|
||||
|
||||
@ -446,7 +447,7 @@ public class Mantle {
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
} finally {
|
||||
ioTrim.set(false);
|
||||
ioTrim.release(LOCK_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -459,7 +460,7 @@ public class Mantle {
|
||||
BurstExecutor burst = ioBurst.burst(toUnload.size());
|
||||
burst.setMulticore(toUnload.size() > tectonicLimit);
|
||||
|
||||
ioTectonicUnload.set(true);
|
||||
ioTectonicUnload.acquireUninterruptibly(LOCK_SIZE);
|
||||
try {
|
||||
for (long id : toUnload) {
|
||||
double unloadTime = M.ms() - adjustedIdleDuration.get();
|
||||
@ -478,15 +479,14 @@ public class Mantle {
|
||||
|
||||
if (m.inUse()) {
|
||||
Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ());
|
||||
lastUse.put(id, M.ms());
|
||||
toUnload.remove(id);
|
||||
use(id);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
m.write(fileForRegion(dataFolder, id, false));
|
||||
oldFileForRegion(dataFolder, id).delete();
|
||||
loadedRegions.remove(id);
|
||||
loadedRegions.remove(id, m);
|
||||
lastUse.remove(id);
|
||||
toUnload.remove(id);
|
||||
i.incrementAndGet();
|
||||
@ -502,7 +502,7 @@ public class Mantle {
|
||||
e.printStackTrace();
|
||||
burst.complete();
|
||||
} finally {
|
||||
ioTectonicUnload.set(false);
|
||||
ioTectonicUnload.release(LOCK_SIZE);
|
||||
}
|
||||
return i.get();
|
||||
}
|
||||
@ -518,32 +518,39 @@ public class Mantle {
|
||||
*/
|
||||
@RegionCoordinates
|
||||
private TectonicPlate get(int x, int z) {
|
||||
if (ioTrim.get() || ioTectonicUnload.get()) {
|
||||
boolean trim = ioTrim.tryAcquire();
|
||||
boolean unload = ioTectonicUnload.tryAcquire();
|
||||
try {
|
||||
if (!trim || !unload) {
|
||||
try {
|
||||
return getSafe(x, z).get();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Long key = key(x, z);
|
||||
TectonicPlate p = loadedRegions.get(key);
|
||||
|
||||
if (p != null && !p.isClosed()) {
|
||||
use(key);
|
||||
return p;
|
||||
}
|
||||
|
||||
try {
|
||||
return getSafe(x, z).get();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread intterruption (hotload?)");
|
||||
Iris.reportError(e);
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)");
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}
|
||||
|
||||
Long key = key(x, z);
|
||||
TectonicPlate p = loadedRegions.get(key);
|
||||
|
||||
if (p != null) {
|
||||
use(key);
|
||||
return p;
|
||||
}
|
||||
|
||||
try {
|
||||
return getSafe(x, z).get();
|
||||
} catch (InterruptedException e) {
|
||||
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread intterruption (hotload?)");
|
||||
Iris.reportError(e);
|
||||
} catch (ExecutionException e) {
|
||||
Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a thread execution exception (engine close?)");
|
||||
Iris.reportError(e);
|
||||
} finally {
|
||||
if (trim) ioTrim.release();
|
||||
if (unload) ioTectonicUnload.release();
|
||||
}
|
||||
|
||||
Iris.warn("Retrying to get " + x + " " + z + " Mantle Region");
|
||||
@ -560,19 +567,12 @@ public class Mantle {
|
||||
*/
|
||||
@RegionCoordinates
|
||||
private Future<TectonicPlate> getSafe(int x, int z) {
|
||||
Long k = key(x, z);
|
||||
TectonicPlate p = loadedRegions.get(k);
|
||||
|
||||
if (p != null) {
|
||||
use(k);
|
||||
return CompletableFuture.completedFuture(p);
|
||||
}
|
||||
|
||||
return ioBurst.completeValue(() -> hyperLock.withResult(x, z, () -> {
|
||||
Long k = key(x, z);
|
||||
use(k);
|
||||
TectonicPlate region = loadedRegions.get(k);
|
||||
|
||||
if (region != null) {
|
||||
if (region != null && !region.isClosed()) {
|
||||
return region;
|
||||
}
|
||||
|
||||
@ -600,12 +600,14 @@ public class Mantle {
|
||||
Iris.debug("Created new Tectonic Plate (Due to Load Failure) " + C.DARK_GREEN + x + " " + z);
|
||||
}
|
||||
|
||||
use(k);
|
||||
return region;
|
||||
}
|
||||
|
||||
region = new TectonicPlate(worldHeight, x, z);
|
||||
loadedRegions.put(k, region);
|
||||
Iris.debug("Created new Tectonic Plate " + C.DARK_GREEN + x + " " + z);
|
||||
use(k);
|
||||
return region;
|
||||
}));
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
/**
|
||||
@ -52,6 +53,7 @@ public class TectonicPlate {
|
||||
|
||||
private final int sectionHeight;
|
||||
private final AtomicReferenceArray<MantleChunk> chunks;
|
||||
private final AtomicBoolean closed;
|
||||
|
||||
@Getter
|
||||
private final int x;
|
||||
@ -67,6 +69,7 @@ public class TectonicPlate {
|
||||
public TectonicPlate(int worldHeight, int x, int z) {
|
||||
this.sectionHeight = worldHeight >> 4;
|
||||
this.chunks = new AtomicReferenceArray<>(1024);
|
||||
this.closed = new AtomicBoolean(false);
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
@ -143,6 +146,7 @@ public class TectonicPlate {
|
||||
}
|
||||
|
||||
public void close() throws InterruptedException {
|
||||
closed.set(true);
|
||||
for (int i = 0; i < chunks.length(); i++) {
|
||||
MantleChunk chunk = chunks.get(i);
|
||||
if (chunk != null) {
|
||||
@ -151,6 +155,10 @@ public class TectonicPlate {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return closed.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a chunk exists in this plate or not (same as get(x, z) != null)
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user