diff --git a/src/main/java/com/volmit/iris/Iris.java b/src/main/java/com/volmit/iris/Iris.java index b1866351e..fd93d97a8 100644 --- a/src/main/java/com/volmit/iris/Iris.java +++ b/src/main/java/com/volmit/iris/Iris.java @@ -27,6 +27,7 @@ import com.volmit.iris.core.link.MultiverseCoreLink; import com.volmit.iris.core.link.MythicMobsLink; import com.volmit.iris.core.link.OraxenLink; import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.core.project.IrisProject; import com.volmit.iris.core.project.loader.IrisData; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.engine.object.biome.IrisBiome; @@ -164,7 +165,6 @@ public class Iris extends VolmitPlugin implements Listener { HandlerList.unregisterAll((Plugin) this); postShutdown.forEach(Runnable::run); services.clear(); - MultiBurst.burst.close(); super.onDisable(); } diff --git a/src/main/java/com/volmit/iris/core/command/studio/CommandIrisStudioUpdate.java b/src/main/java/com/volmit/iris/core/command/studio/CommandIrisStudioUpdate.java index dcb5d5ee1..f705d75e8 100644 --- a/src/main/java/com/volmit/iris/core/command/studio/CommandIrisStudioUpdate.java +++ b/src/main/java/com/volmit/iris/core/command/studio/CommandIrisStudioUpdate.java @@ -66,7 +66,7 @@ public class CommandIrisStudioUpdate extends MortarCommand { IrisData data = IrisData.get(Iris.service(StudioSVC.class).getWorkspaceFolder(args[0])); int t = data.getObjectLoader().getPossibleKeys().length; ChronoLatch cl = new ChronoLatch(250, false); - MultiBurst bx = MultiBurst.burst; + MultiBurst bx = new MultiBurst("Object Rewriter", Thread.MIN_PRIORITY, Runtime.getRuntime().availableProcessors()); BurstExecutor b = bx.burst(); int g = 0; for (String f : data.getObjectLoader().getPossibleKeys()) { @@ -102,6 +102,7 @@ public class CommandIrisStudioUpdate extends MortarCommand { int finalG = g; J.a(() -> { b.complete(); + bx.shutdownNow(); sender.sendMessage("Done! Rewrote " + Form.f(finalG) + " Objects!"); }); } diff --git a/src/main/java/com/volmit/iris/core/decrees/DecStudio.java b/src/main/java/com/volmit/iris/core/decrees/DecStudio.java index 00f4f1275..7a243f2aa 100644 --- a/src/main/java/com/volmit/iris/core/decrees/DecStudio.java +++ b/src/main/java/com/volmit/iris/core/decrees/DecStudio.java @@ -133,7 +133,7 @@ public class DecStudio implements DecreeExecutor { KList jobs = new KList<>(); KList files = new KList(); files(Iris.instance.getDataFolder("packs", project.getLoadKey()), files); - MultiBurst burst = MultiBurst.burst; + MultiBurst burst = new MultiBurst("Cleaner", Thread.MIN_PRIORITY, Runtime.getRuntime().availableProcessors() * 2); jobs.add(new SingleJob("Updating Workspace", () -> { if (!new IrisProject(Iris.service(StudioSVC.class).getWorkspaceFolder(project.getLoadKey())).updateWorkspace()) { @@ -237,6 +237,8 @@ public class DecStudio implements DecreeExecutor { jobs.add(q); } + jobs.add(new SingleJob("Finishing Up", burst::shutdownNow)); + new JobCollection("Cleaning", jobs).execute(sender()); } diff --git a/src/main/java/com/volmit/iris/core/gui/NoiseExplorerGUI.java b/src/main/java/com/volmit/iris/core/gui/NoiseExplorerGUI.java index 36a631e17..fa612adcb 100644 --- a/src/main/java/com/volmit/iris/core/gui/NoiseExplorerGUI.java +++ b/src/main/java/com/volmit/iris/core/gui/NoiseExplorerGUI.java @@ -59,7 +59,7 @@ public class NoiseExplorerGUI extends JPanel implements MouseWheelListener, List static double ascale = 10; CNG cng = NoiseStyle.STATIC.create(new RNG(RNG.r.nextLong())); @SuppressWarnings("CanBeFinal") - MultiBurst gx = MultiBurst.burst; + MultiBurst gx = new MultiBurst("Iris Noise Renderer", Thread.MAX_PRIORITY, Runtime.getRuntime().availableProcessors()); ReentrantLock l = new ReentrantLock(); BufferedImage img; int w = 0; @@ -299,6 +299,7 @@ public class NoiseExplorerGUI extends JPanel implements MouseWheelListener, List frame.addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(java.awt.event.WindowEvent windowEvent) { + nv.gx.shutdownLater(); Iris.instance.unregisterListener(nv); } }); diff --git a/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java b/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java index 137a57595..43e9ca166 100644 --- a/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java +++ b/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java @@ -41,7 +41,7 @@ public class AsyncPregenMethod implements PregeneratorMethod { } this.world = world; - burst = MultiBurst.burst; + burst = new MultiBurst("Iris Async Pregenerator", IrisSettings.get().getConcurrency().getPregenThreadPriority(), threads); future = new KList<>(1024); } @@ -92,6 +92,7 @@ public class AsyncPregenMethod implements PregeneratorMethod { @Override public void close() { waitForChunks(); + burst.shutdownAndAwait(); unloadAndSaveAllChunks(); } diff --git a/src/main/java/com/volmit/iris/core/service/PreservationSVC.java b/src/main/java/com/volmit/iris/core/service/PreservationSVC.java index a6ea2ac7f..49a7a8ad0 100644 --- a/src/main/java/com/volmit/iris/core/service/PreservationSVC.java +++ b/src/main/java/com/volmit/iris/core/service/PreservationSVC.java @@ -31,6 +31,7 @@ import java.util.concurrent.ExecutorService; public class PreservationSVC implements IrisService { private KList threads = new KList<>(); + private KList bursts = new KList<>(); private KList services = new KList<>(); private Looper dereferencer; @@ -41,7 +42,7 @@ public class PreservationSVC implements IrisService public void register(MultiBurst burst) { - + bursts.add(burst); } public void register(ExecutorService service) @@ -93,6 +94,20 @@ public class PreservationSVC implements IrisService } } + for(MultiBurst i : bursts) + { + try + { + i.shutdownNow(); + Iris.info("Shutdown Multiburst " + i); + } + + catch(Throwable e) + { + Iris.reportError(e); + } + } + for(ExecutorService i : services) { try diff --git a/src/main/java/com/volmit/iris/engine/framework/EngineTarget.java b/src/main/java/com/volmit/iris/engine/framework/EngineTarget.java index 7a7c18b4a..250b343cb 100644 --- a/src/main/java/com/volmit/iris/engine/framework/EngineTarget.java +++ b/src/main/java/com/volmit/iris/engine/framework/EngineTarget.java @@ -36,7 +36,9 @@ public class EngineTarget { this.world = world; this.dimension = dimension; this.data = data; - this.burster = MultiBurst.burst; + this.burster = new MultiBurst("Iris Engine " + dimension.getName(), + IrisSettings.get().getConcurrency().getEngineThreadPriority(), + IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getEngineThreadCount())); } public int getHeight() { @@ -44,6 +46,6 @@ public class EngineTarget { } public void close() { - + burster.shutdownLater(); } } diff --git a/src/main/java/com/volmit/iris/engine/platform/HeadlessGenerator.java b/src/main/java/com/volmit/iris/engine/platform/HeadlessGenerator.java index 4def637ca..f3701efb2 100644 --- a/src/main/java/com/volmit/iris/engine/platform/HeadlessGenerator.java +++ b/src/main/java/com/volmit/iris/engine/platform/HeadlessGenerator.java @@ -58,7 +58,7 @@ public class HeadlessGenerator implements PlatformChunkGenerator { public HeadlessGenerator(HeadlessWorld world) { this.world = world; - burst = MultiBurst.burst; + burst = new MultiBurst("Iris Headless Generator", 9, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount())); writer = new NBTWorld(world.getWorld().worldFolder()); engine = new IrisEngine(new EngineTarget(world.getWorld(), world.getDimension(), world.getDimension().getLoader()), isStudio()); } @@ -131,6 +131,7 @@ public class HeadlessGenerator implements PlatformChunkGenerator { } public void close() { + burst.shutdownAndAwait(); getEngine().close(); writer.close(); } diff --git a/src/main/java/com/volmit/iris/util/parallel/MultiBurst.java b/src/main/java/com/volmit/iris/util/parallel/MultiBurst.java index d625cbe59..92a07825e 100644 --- a/src/main/java/com/volmit/iris/util/parallel/MultiBurst.java +++ b/src/main/java/com/volmit/iris/util/parallel/MultiBurst.java @@ -19,9 +19,13 @@ package com.volmit.iris.util.parallel; import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.service.PreservationSVC; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.io.InstanceState; import com.volmit.iris.util.math.M; +import com.volmit.iris.util.scheduling.J; +import com.volmit.iris.util.scheduling.Looper; import java.util.List; import java.util.concurrent.*; @@ -29,39 +33,66 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Supplier; public class MultiBurst { - public static final MultiBurst burst = new MultiBurst(); + public static final MultiBurst burst = new MultiBurst("Iris", IrisSettings.get().getConcurrency().getMiscThreadPriority(), IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getMiscThreadCount())); private ExecutorService service; + private final Looper heartbeat; private final AtomicLong last; + private int tid; private final String name; + private final int tc; private final int priority; + private final int instance; - public MultiBurst() { - this("Iris", Thread.MIN_PRIORITY); + public MultiBurst(int tc) { + this("Iris", 6, tc); } - public MultiBurst(String name, int priority) { + public MultiBurst(String name, int priority, int tc) { this.name = name; this.priority = priority; + this.tc = tc; + instance = InstanceState.getInstanceId(); last = new AtomicLong(M.ms()); + heartbeat = new Looper() { + @Override + protected long loop() { + if (instance != InstanceState.getInstanceId()) { + shutdownNow(); + return -1; + } + + if (M.ms() - last.get() > TimeUnit.MINUTES.toMillis(1) && service != null) { + service.shutdown(); + service = null; + Iris.debug("Shutting down MultiBurst Pool " + getName() + " to conserve resources."); + } + + return 30000; + } + }; + heartbeat.setName(name + " Monitor"); + heartbeat.start(); Iris.service(PreservationSVC.class).register(this); } private synchronized ExecutorService getService() { last.set(M.ms()); if (service == null || service.isShutdown()) { - service = new ForkJoinPool(Runtime.getRuntime().availableProcessors(), - new ForkJoinPool.ForkJoinWorkerThreadFactory() { - int m = 0; + service = Executors.newFixedThreadPool(Math.max(tc, 1), r -> { + tid++; + Thread t = new Thread(r); + t.setName(name + " " + tid); + t.setPriority(priority); + t.setUncaughtExceptionHandler((et, e) -> + { + Iris.info("Exception encountered in " + et.getName()); + e.printStackTrace(); + }); - @Override - public ForkJoinWorkerThread newThread(ForkJoinPool pool) { - final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool); - worker.setPriority(priority); - worker.setName(name + " " + ++m); - return worker; - } - }, - (t, e) -> e.printStackTrace(), true); + return t; + }); + Iris.service(PreservationSVC.class).register(service); + Iris.debug("Started MultiBurst Pool " + name + " with " + tc + " threads at " + priority + " priority."); } return service; @@ -115,7 +146,56 @@ public class MultiBurst { return CompletableFuture.supplyAsync(o, getService()); } - public void close() { + public void shutdownNow() { + Iris.debug("Shutting down MultiBurst Pool " + heartbeat.getName() + "."); + heartbeat.interrupt(); + + if (service != null) { + service.shutdownNow().forEach(Runnable::run); + } + } + + public void shutdown() { + Iris.debug("Shutting down MultiBurst Pool " + heartbeat.getName() + "."); + heartbeat.interrupt(); + + if (service != null) { + service.shutdown(); + } + } + + public void shutdownLater() { + if (service != null) { + try + { + service.submit(() -> { + J.sleep(3000); + Iris.debug("Shutting down MultiBurst Pool " + heartbeat.getName() + "."); + + if (service != null) { + service.shutdown(); + } + }); + + heartbeat.interrupt(); + } + + catch(Throwable e) + { + Iris.debug("Shutting down MultiBurst Pool " + heartbeat.getName() + "."); + + if (service != null) { + service.shutdown(); + } + + heartbeat.interrupt(); + } + } + } + + public void shutdownAndAwait() { + Iris.debug("Shutting down MultiBurst Pool " + heartbeat.getName() + "."); + heartbeat.interrupt(); if (service != null) { service.shutdown(); try {