diff --git a/core/src/main/java/com/volmit/iris/core/IrisSettings.java b/core/src/main/java/com/volmit/iris/core/IrisSettings.java index 2046d68d6..0748926a2 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/core/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -242,6 +242,7 @@ public class IrisSettings { public String defaultWorldType = "overworld"; public int maxBiomeChildDepth = 4; public boolean preventLeafDecay = true; + public boolean useMulticore = false; } @Data @@ -255,6 +256,7 @@ public class IrisSettings { @Data public static class IrisSettingsEngineSVC { public boolean useVirtualThreads = true; + public boolean forceMulticoreWrite = false; public int priority = Thread.NORM_PRIORITY; public int getPriority() { diff --git a/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java b/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java index 6ae9e8dbd..a9b31244d 100644 --- a/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java @@ -205,7 +205,7 @@ public class IrisEngineSVC implements IrisService { try { long unloadStart = System.currentTimeMillis(); - int count = engine.getMantle().unloadTectonicPlate(tectonicLimit()); + int count = engine.getMantle().unloadTectonicPlate(IrisSettings.get().getPerformance().getEngineSVC().forceMulticoreWrite ? 0 : tectonicLimit()); if (count > 0) { Iris.debug(C.GOLD + "Unloaded " + C.YELLOW + count + " TectonicPlates in " + C.RED + Form.duration(System.currentTimeMillis() - unloadStart, 2)); } diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java index d37814e0c..29e06e767 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java @@ -213,12 +213,16 @@ public interface EngineMantle extends IObjectPlacer { for (int j = -radius; j <= radius; j++) { int xx = x + i; int zz = z + j; - MantleChunk mc = getMantle().getChunk(xx, zz); + MantleChunk mc = getMantle().getChunk(xx, zz).use(); burst.queue(() -> { - IrisContext.touch(getEngine().getContext()); - pair.getA().forEach(k -> generateMantleComponent(writer, xx, zz, k, mc, context)); - if (last) mc.flag(MantleFlag.PLANNED, true); + try { + IrisContext.touch(getEngine().getContext()); + pair.getA().forEach(k -> generateMantleComponent(writer, xx, zz, k, mc, context)); + if (last) mc.flag(MantleFlag.PLANNED, true); + } finally { + mc.release(); + } }); } } diff --git a/core/src/main/java/com/volmit/iris/engine/modifier/IrisCarveModifier.java b/core/src/main/java/com/volmit/iris/engine/modifier/IrisCarveModifier.java index a7bb391be..36bca62e5 100644 --- a/core/src/main/java/com/volmit/iris/engine/modifier/IrisCarveModifier.java +++ b/core/src/main/java/com/volmit/iris/engine/modifier/IrisCarveModifier.java @@ -27,6 +27,7 @@ import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.data.B; +import com.volmit.iris.util.documentation.ChunkCoordinates; import com.volmit.iris.util.function.Consumer4; import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.mantle.Mantle; @@ -53,10 +54,11 @@ public class IrisCarveModifier extends EngineAssignedModifier { } @Override + @ChunkCoordinates public void onModify(int x, int z, Hunk output, boolean multicore, ChunkContext context) { PrecisionStopwatch p = PrecisionStopwatch.start(); Mantle mantle = getEngine().getMantle().getMantle(); - MantleChunk mc = getEngine().getMantle().getMantle().getChunk(x, z).use(); + MantleChunk mc = mantle.getChunk(x, z).use(); KMap> positions = new KMap<>(); KMap walls = new KMap<>(); Consumer4 iterator = (xx, yy, zz, c) -> { @@ -81,19 +83,19 @@ public class IrisCarveModifier extends EngineAssignedModifier { //todo: Fix chunk decoration not working on chunk's border - if (rz < 15 && mantle.get(xx, yy, zz + 1, MatterCavern.class) == null) { + if (rz < 15 && mc.get(xx, yy, zz + 1, MatterCavern.class) == null) { walls.put(new IrisPosition(rx, yy, rz + 1), c); } - if (rx < 15 && mantle.get(xx + 1, yy, zz, MatterCavern.class) == null) { + if (rx < 15 && mc.get(xx + 1, yy, zz, MatterCavern.class) == null) { walls.put(new IrisPosition(rx + 1, yy, rz), c); } - if (rz > 0 && mantle.get(xx, yy, zz - 1, MatterCavern.class) == null) { + if (rz > 0 && mc.get(xx, yy, zz - 1, MatterCavern.class) == null) { walls.put(new IrisPosition(rx, yy, rz - 1), c); } - if (rx > 0 && mantle.get(xx - 1, yy, zz, MatterCavern.class) == null) { + if (rx > 0 && mc.get(xx - 1, yy, zz, MatterCavern.class) == null) { walls.put(new IrisPosition(rx - 1, yy, rz), c); } diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index 1f7fbd9a6..f212f087d 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -19,6 +19,7 @@ package com.volmit.iris.engine.platform; import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisWorlds; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; @@ -34,7 +35,6 @@ import com.volmit.iris.engine.object.StudioMode; import com.volmit.iris.engine.platform.studio.StudioGenerator; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.data.IrisBiomeStorage; -import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder; import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder; import com.volmit.iris.util.io.ReactiveFolder; @@ -46,8 +46,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Setter; import org.bukkit.*; -import org.bukkit.block.Biome; -import org.bukkit.block.data.BlockData; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -367,7 +365,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun } else { ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc); BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight()); - getEngine().generate(x << 4, z << 4, blocks, biomes, false); + getEngine().generate(x << 4, z << 4, blocks, biomes, IrisSettings.get().getGenerator().useMulticore); blocks.apply(); biomes.apply(); } diff --git a/core/src/main/java/com/volmit/iris/util/context/IrisContext.java b/core/src/main/java/com/volmit/iris/util/context/IrisContext.java index 73bae0e5e..a6b72cf9f 100644 --- a/core/src/main/java/com/volmit/iris/util/context/IrisContext.java +++ b/core/src/main/java/com/volmit/iris/util/context/IrisContext.java @@ -29,7 +29,7 @@ import lombok.Data; @Data public class IrisContext { private static final KMap context = new KMap<>(); - private static ChronoLatch cl = new ChronoLatch(60000); + private static final ChronoLatch cl = new ChronoLatch(60000); private final Engine engine; private ChunkContext chunkContext; @@ -53,9 +53,10 @@ public class IrisContext { } public static void touch(IrisContext c) { - synchronized (context) { - context.put(Thread.currentThread(), c); + context.put(Thread.currentThread(), c); + if (!cl.couldFlip()) return; + synchronized (cl) { if (cl.flip()) { dereference(); } @@ -63,15 +64,13 @@ public class IrisContext { } public static void dereference() { - synchronized (context) { - for (Thread i : context.k()) { - if (!i.isAlive() || context.get(i).engine.isClosed()) { - if (context.get(i).engine.isClosed()) { - Iris.debug("Dereferenced Context " + i.getName() + " " + i.getId()); - } - - context.remove(i); + for (Thread i : context.k()) { + if (!i.isAlive() || context.get(i).engine.isClosed()) { + if (context.get(i).engine.isClosed()) { + Iris.debug("Dereferenced Context " + i.getName() + " " + i.threadId()); } + + context.remove(i); } } } diff --git a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java index bcb211937..82f3cbe08 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -529,30 +529,31 @@ public class Mantle { try { if (!trim || !unload) { try { - return getSafe(x, z).get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { + return getSafe(x, z); + } catch (Throwable e) { e.printStackTrace(); } + } else { + Long key = key(x, z); + TectonicPlate p = loadedRegions.get(key); + + if (p != null && !p.isClosed()) { + use(key); + return p; + } } - 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(); + return getSafe(x, z); } 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); + } catch (Throwable e) { + Iris.warn("Failed to get Tectonic Plate " + x + " " + z + " Due to a unknown exception"); + Iris.reportError(e); } } finally { if (trim) ioTrim.release(); @@ -572,50 +573,52 @@ public class Mantle { * @return the future of a tectonic plate. */ @RegionCoordinates - private Future getSafe(int x, int z) { - return ioBurst.completeValue(() -> hyperLock.withResult(x, z, () -> { + private TectonicPlate getSafe(int x, int z) throws Throwable { + return hyperLock.withNastyResult(x, z, () -> { Long k = key(x, z); use(k); - TectonicPlate region = loadedRegions.get(k); - - if (region != null && !region.isClosed()) { - return region; + TectonicPlate r = loadedRegions.get(k); + if (r != null && !r.isClosed()) { + return r; } - File file = fileForRegion(dataFolder, x, z); - if (file.exists()) { - try { - Iris.addPanic("reading.tectonic-plate", file.getAbsolutePath()); - region = worker.read(file.getName()); + return ioBurst.completeValue(() -> { + TectonicPlate region; + File file = fileForRegion(dataFolder, x, z); + if (file.exists()) { + try { + Iris.addPanic("reading.tectonic-plate", file.getAbsolutePath()); + region = worker.read(file.getName()); - if (region.getX() != x || region.getZ() != z) { - Iris.warn("Loaded Tectonic Plate " + x + "," + z + " but read it as " + region.getX() + "," + region.getZ() + "... Assuming " + x + "," + z); + if (region.getX() != x || region.getZ() != z) { + Iris.warn("Loaded Tectonic Plate " + x + "," + z + " but read it as " + region.getX() + "," + region.getZ() + "... Assuming " + x + "," + z); + } + + loadedRegions.put(k, region); + Iris.debug("Loaded Tectonic Plate " + C.DARK_GREEN + x + " " + z + C.DARK_AQUA + " " + file.getName()); + } catch (Throwable e) { + Iris.error("Failed to read Tectonic Plate " + file.getAbsolutePath() + " creating a new chunk instead."); + Iris.reportError(e); + if (!(e instanceof EOFException)) { + e.printStackTrace(); + } + Iris.panic(); + region = new TectonicPlate(worldHeight, x, z); + loadedRegions.put(k, region); + Iris.debug("Created new Tectonic Plate (Due to Load Failure) " + C.DARK_GREEN + x + " " + z); } - loadedRegions.put(k, region); - Iris.debug("Loaded Tectonic Plate " + C.DARK_GREEN + x + " " + z + C.DARK_AQUA + " " + file.getName()); - } catch (Throwable e) { - Iris.error("Failed to read Tectonic Plate " + file.getAbsolutePath() + " creating a new chunk instead."); - Iris.reportError(e); - if (!(e instanceof EOFException)) { - e.printStackTrace(); - } - Iris.panic(); - region = new TectonicPlate(worldHeight, x, z); - loadedRegions.put(k, region); - 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; - } - - 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; - })); + }).get(); + }); } private void use(Long key) { diff --git a/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java b/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java index 8ebda5ebb..fe5f0cec7 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/MantleChunk.java @@ -21,6 +21,7 @@ package com.volmit.iris.util.mantle; import com.volmit.iris.Iris; import com.volmit.iris.util.data.Varint; import com.volmit.iris.util.documentation.ChunkCoordinates; +import com.volmit.iris.util.documentation.ChunkRelativeBlockCoordinates; import com.volmit.iris.util.function.Consumer4; import com.volmit.iris.util.io.CountingDataInputStream; import com.volmit.iris.util.matter.IrisMatter; @@ -28,6 +29,7 @@ import com.volmit.iris.util.matter.Matter; import com.volmit.iris.util.matter.MatterSlice; import lombok.Getter; import lombok.SneakyThrows; +import org.jetbrains.annotations.Nullable; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; @@ -146,11 +148,10 @@ public class MantleChunk { } public void raiseFlag(MantleFlag flag, Runnable r) { - synchronized (this) { - if (!isFlagged(flag)) flag(flag, true); - else return; + if (closed.get()) throw new IllegalStateException("Chunk is closed!"); + if (flags.getAndSet(flag.ordinal(), 1) == 0) { + r.run(); } - r.run(); } public boolean isFlagged(MantleFlag flag) { @@ -179,6 +180,15 @@ public class MantleChunk { return sections.get(section); } + @Nullable + @ChunkRelativeBlockCoordinates + @SuppressWarnings("unchecked") + public T get(int x, int y, int z, Class type) { + return (T) getOrCreate(y >> 4) + .slice(type) + .get(x & 15, y & 15, z & 15); + } + /** * Clear all matter from this chunk */ diff --git a/core/src/main/java/com/volmit/iris/util/parallel/HyperLock.java b/core/src/main/java/com/volmit/iris/util/parallel/HyperLock.java index 6d0eaaee0..56596eddf 100644 --- a/core/src/main/java/com/volmit/iris/util/parallel/HyperLock.java +++ b/core/src/main/java/com/volmit/iris/util/parallel/HyperLock.java @@ -22,6 +22,7 @@ import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap; import com.volmit.iris.Iris; import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.util.function.NastyRunnable; +import com.volmit.iris.util.function.NastySupplier; import com.volmit.iris.util.io.IORunnable; import java.io.IOException; @@ -107,6 +108,15 @@ public class HyperLock { return t; } + public T withNastyResult(int x, int z, NastySupplier r) throws Throwable { + lock(x, z); + try { + return r.get(); + } finally { + unlock(x, z); + } + } + public boolean tryLock(int x, int z) { return getLock(x, z).tryLock(); }