fix engines not closing on server stop

This commit is contained in:
Julian Krings 2025-05-21 13:09:08 +02:00 committed by Julian Krings
parent 97ddfd309b
commit e42317139d
7 changed files with 111 additions and 82 deletions

View File

@ -572,12 +572,17 @@ public class Iris extends VolmitPlugin implements Listener {
} }
public void onDisable() { public void onDisable() {
Bukkit.getWorlds()
.parallelStream()
.map(IrisToolbelt::access)
.filter(Objects::nonNull)
.forEach(PlatformChunkGenerator::close);
services.values().forEach(IrisService::onDisable); services.values().forEach(IrisService::onDisable);
Bukkit.getScheduler().cancelTasks(this); Bukkit.getScheduler().cancelTasks(this);
HandlerList.unregisterAll((Plugin) this); HandlerList.unregisterAll((Plugin) this);
postShutdown.forEach(Runnable::run); postShutdown.forEach(Runnable::run);
services.clear();
MultiBurst.burst.close(); MultiBurst.burst.close();
services.clear();
super.onDisable(); super.onDisable();
} }

View File

@ -288,11 +288,10 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
return; return;
} }
var chunk = mantle.getChunk(c); var chunk = mantle.getChunk(c).use();
if (chunk.isFlagged(MantleFlag.ETCHED)) return; try {
chunk.flag(MantleFlag.ETCHED, true);
Semaphore semaphore = new Semaphore(3); Semaphore semaphore = new Semaphore(3);
chunk.raiseFlag(MantleFlag.ETCHED, () -> {
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> J.s(() -> { chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> J.s(() -> {
mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> { mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> {
int betterY = y + getWorld().minHeight(); int betterY = y + getWorld().minHeight();
@ -354,10 +353,14 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class); mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class);
getMetrics().getUpdates().put(p.getMilliseconds()); getMetrics().getUpdates().put(p.getMilliseconds());
}, RNG.r.i(0, 20)))); }, RNG.r.i(0, 20))));
});
try { try {
semaphore.acquire(3); semaphore.acquire(3);
} catch (InterruptedException ignored) {} } catch (InterruptedException ignored) {}
} finally {
chunk.release();
}
} }
private static Runnable run(Semaphore semaphore, Runnable runnable) { private static Runnable run(Semaphore semaphore, Runnable runnable) {

View File

@ -359,16 +359,18 @@ public class Mantle {
} }
closed.set(true); closed.set(true);
BurstExecutor b = ioBurst.burst(loadedRegions.size()); hyperLock.disable();
for (Long i : loadedRegions.keySet()) { BurstExecutor b = ioBurst.burst(toUnload.size());
b.queue(() -> { loadedRegions.forEach((i, plate) -> b.queue(() -> {
try { try {
loadedRegions.get(i).write(fileForRegion(dataFolder, i)); plate.close();
} catch (IOException e) { plate.write(fileForRegion(dataFolder, i));
} catch (Throwable e) {
Iris.error("Failed to write Tectonic Plate " + C.DARK_GREEN + Cache.keyX(i) + " " + Cache.keyZ(i));
e.printStackTrace(); e.printStackTrace();
} }
}); }));
} loadedRegions.clear();
try { try {
b.complete(); b.complete();
@ -376,7 +378,6 @@ public class Mantle {
Iris.reportError(e); Iris.reportError(e);
} }
loadedRegions.clear();
Iris.debug("The Mantle has Closed " + C.DARK_AQUA + dataFolder.getAbsolutePath()); Iris.debug("The Mantle has Closed " + C.DARK_AQUA + dataFolder.getAbsolutePath());
} }

View File

@ -30,7 +30,8 @@ import lombok.Getter;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicIntegerArray; import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicReferenceArray; import java.util.concurrent.atomic.AtomicReferenceArray;
@ -45,7 +46,8 @@ public class MantleChunk {
private final int z; private final int z;
private final AtomicIntegerArray flags; private final AtomicIntegerArray flags;
private final AtomicReferenceArray<Matter> sections; private final AtomicReferenceArray<Matter> sections;
private final AtomicInteger ref = new AtomicInteger(); private final Semaphore ref = new Semaphore(Integer.MAX_VALUE, true);
private final AtomicBoolean closed = new AtomicBoolean(false);
/** /**
* Create a mantle chunk * Create a mantle chunk
@ -103,20 +105,27 @@ public class MantleChunk {
} }
} }
public void close() throws InterruptedException {
closed.set(true);
ref.acquire(Integer.MAX_VALUE);
}
public boolean inUse() { public boolean inUse() {
return ref.get() > 0; return ref.availablePermits() < Integer.MAX_VALUE;
} }
public MantleChunk use() { public MantleChunk use() {
ref.incrementAndGet(); if (closed.get()) throw new IllegalStateException("Chunk is closed!");
ref.acquireUninterruptibly();
return this; return this;
} }
public void release() { public void release() {
ref.decrementAndGet(); ref.release();
} }
public void flag(MantleFlag flag, boolean f) { public void flag(MantleFlag flag, boolean f) {
if (closed.get()) throw new IllegalStateException("Chunk is closed!");
flags.set(flag.ordinal(), f ? 1 : 0); flags.set(flag.ordinal(), f ? 1 : 0);
} }

View File

@ -136,6 +136,15 @@ public class TectonicPlate {
return false; return false;
} }
public void close() throws InterruptedException {
for (int i = 0; i < chunks.length(); i++) {
MantleChunk chunk = chunks.get(i);
if (chunk != null) {
chunk.close();
}
}
}
/** /**
* Check if a chunk exists in this plate or not (same as get(x, z) != null) * Check if a chunk exists in this plate or not (same as get(x, z) != null)
* *

View File

@ -143,5 +143,6 @@ public class HyperLock {
public void disable() { public void disable() {
enabled = false; enabled = false;
locks.values().forEach(ReentrantLock::lock);
} }
} }

View File

@ -32,6 +32,7 @@ import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
public class MultiBurst implements ExecutorService { public class MultiBurst implements ExecutorService {
private static final long TIMEOUT = Long.getLong("iris.burst.timeout", 15000);
public static final MultiBurst burst = new MultiBurst(); public static final MultiBurst burst = new MultiBurst();
private final AtomicLong last; private final AtomicLong last;
private final String name; private final String name;
@ -231,7 +232,7 @@ public class MultiBurst implements ExecutorService {
try { try {
while (!service.awaitTermination(1, TimeUnit.SECONDS)) { while (!service.awaitTermination(1, TimeUnit.SECONDS)) {
Iris.info("Still waiting to shutdown burster..."); Iris.info("Still waiting to shutdown burster...");
if (p.getMilliseconds() > 7000) { if (p.getMilliseconds() > TIMEOUT) {
Iris.warn("Forcing Shutdown..."); Iris.warn("Forcing Shutdown...");
try { try {