mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-03 00:17:15 +00:00
add pregen method that doesn't use waiting threads
This commit is contained in:
parent
49ce84a9e9
commit
976648340e
@ -145,7 +145,10 @@ public class IrisSettings {
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class IrisSettingsPregen {
|
public static class IrisSettingsPregen {
|
||||||
|
public boolean useCacheByDefault = true;
|
||||||
|
public boolean useHighPriority = false;
|
||||||
public boolean useVirtualThreads = false;
|
public boolean useVirtualThreads = false;
|
||||||
|
public boolean useTicketQueue = false;
|
||||||
public int maxConcurrency = 256;
|
public int maxConcurrency = 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@ import org.bukkit.Chunk;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@ -43,22 +42,22 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
public class AsyncPregenMethod implements PregeneratorMethod {
|
public class AsyncPregenMethod implements PregeneratorMethod {
|
||||||
private static final AtomicInteger THREAD_COUNT = new AtomicInteger();
|
private static final AtomicInteger THREAD_COUNT = new AtomicInteger();
|
||||||
private final World world;
|
private final World world;
|
||||||
private final ExecutorService service;
|
private final Executor executor;
|
||||||
private final Semaphore semaphore;
|
private final Semaphore semaphore;
|
||||||
private final int threads;
|
private final int threads;
|
||||||
|
private final boolean urgent;
|
||||||
private final Map<Chunk, Long> lastUse;
|
private final Map<Chunk, Long> lastUse;
|
||||||
|
|
||||||
public AsyncPregenMethod(World world, int threads) {
|
public AsyncPregenMethod(World world, int unusedThreads) {
|
||||||
if (!PaperLib.isPaper()) {
|
if (!PaperLib.isPaper()) {
|
||||||
throw new UnsupportedOperationException("Cannot use PaperAsync on non paper!");
|
throw new UnsupportedOperationException("Cannot use PaperAsync on non paper!");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.world = world;
|
this.world = world;
|
||||||
service = IrisSettings.get().getPregen().isUseVirtualThreads() ?
|
this.executor = IrisSettings.get().getPregen().isUseTicketQueue() ? new TicketExecutor() : new ServiceExecutor();
|
||||||
Executors.newVirtualThreadPerTaskExecutor() :
|
|
||||||
new MultiBurst("Iris Async Pregen", Thread.MIN_PRIORITY);
|
|
||||||
this.threads = IrisSettings.get().getPregen().getMaxConcurrency();
|
this.threads = IrisSettings.get().getPregen().getMaxConcurrency();
|
||||||
semaphore = new Semaphore(threads);
|
this.semaphore = new Semaphore(this.threads, true);
|
||||||
|
this.urgent = IrisSettings.get().getPregen().useHighPriority;
|
||||||
this.lastUse = new KMap<>();
|
this.lastUse = new KMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,13 +69,18 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Chunk i : new ArrayList<>(lastUse.keySet())) {
|
long minTime = M.ms() - 10_000;
|
||||||
Long lastUseTime = lastUse.get(i);
|
lastUse.entrySet().removeIf(i -> {
|
||||||
if (!i.isLoaded() || (lastUseTime != null && M.ms() - lastUseTime >= 10000)) {
|
final Chunk chunk = i.getKey();
|
||||||
i.unload();
|
final Long lastUseTime = i.getValue();
|
||||||
lastUse.remove(i);
|
if (!chunk.isLoaded() || lastUseTime == null)
|
||||||
}
|
return true;
|
||||||
|
if (lastUseTime < minTime) {
|
||||||
|
chunk.unload();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
world.save();
|
world.save();
|
||||||
}).get();
|
}).get();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@ -84,21 +88,6 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void completeChunk(int x, int z, PregenListener listener) {
|
|
||||||
try {
|
|
||||||
PaperLib.getChunkAtAsync(world, x, z, true).thenAccept((i) -> {
|
|
||||||
lastUse.put(i, M.ms());
|
|
||||||
listener.onChunkGenerated(x, z);
|
|
||||||
listener.onChunkCleaned(x, z);
|
|
||||||
}).get();
|
|
||||||
} catch (InterruptedException ignored) {
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
semaphore.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
unloadAndSaveAllChunks();
|
unloadAndSaveAllChunks();
|
||||||
@ -114,7 +103,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
public void close() {
|
public void close() {
|
||||||
semaphore.acquireUninterruptibly(threads);
|
semaphore.acquireUninterruptibly(threads);
|
||||||
unloadAndSaveAllChunks();
|
unloadAndSaveAllChunks();
|
||||||
service.shutdown();
|
executor.shutdown();
|
||||||
resetWorkerThreads();
|
resetWorkerThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +130,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
service.submit(() -> completeChunk(x, z, listener));
|
executor.generate(x, z, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -153,7 +142,6 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void increaseWorkerThreads() {
|
public static void increaseWorkerThreads() {
|
||||||
THREAD_COUNT.updateAndGet(i -> {
|
THREAD_COUNT.updateAndGet(i -> {
|
||||||
if (i > 0) return 1;
|
if (i > 0) return 1;
|
||||||
@ -167,7 +155,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
pool.getClass().getDeclaredMethod("adjustThreadCount", int.class).invoke(pool, adjusted);
|
pool.getClass().getDeclaredMethod("adjustThreadCount", int.class).invoke(pool, adjusted);
|
||||||
return threads;
|
return threads;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Iris.warn("Failed to increase worker threads, please increase it manually to " + adjusted);
|
Iris.warn("Failed to increase worker threads, if you are on paper or a fork of it please increase it manually to " + adjusted);
|
||||||
Iris.warn("For more information see https://docs.papermc.io/paper/reference/global-configuration#chunk_system_worker_threads");
|
Iris.warn("For more information see https://docs.papermc.io/paper/reference/global-configuration#chunk_system_worker_threads");
|
||||||
if (e instanceof InvocationTargetException) e.printStackTrace();
|
if (e instanceof InvocationTargetException) e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -191,4 +179,56 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
return i;
|
return i;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private interface Executor {
|
||||||
|
void generate(int x, int z, PregenListener listener);
|
||||||
|
default void shutdown() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ServiceExecutor implements Executor {
|
||||||
|
private final ExecutorService service = IrisSettings.get().getPregen().isUseVirtualThreads() ?
|
||||||
|
Executors.newVirtualThreadPerTaskExecutor() :
|
||||||
|
new MultiBurst("Iris Async Pregen", Thread.MIN_PRIORITY);
|
||||||
|
|
||||||
|
public void generate(int x, int z, PregenListener listener) {
|
||||||
|
service.submit(() -> {
|
||||||
|
try {
|
||||||
|
PaperLib.getChunkAtAsync(world, x, z, true, urgent).thenAccept((i) -> {
|
||||||
|
listener.onChunkGenerated(x, z);
|
||||||
|
listener.onChunkCleaned(x, z);
|
||||||
|
if (i == null) return;
|
||||||
|
lastUse.put(i, M.ms());
|
||||||
|
}).get();
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
semaphore.release();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdown() {
|
||||||
|
service.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TicketExecutor implements Executor {
|
||||||
|
@Override
|
||||||
|
public void generate(int x, int z, PregenListener listener) {
|
||||||
|
PaperLib.getChunkAtAsync(world, x, z, true, urgent)
|
||||||
|
.exceptionally(e -> {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.thenAccept(i -> {
|
||||||
|
semaphore.release();
|
||||||
|
listener.onChunkGenerated(x, z);
|
||||||
|
listener.onChunkCleaned(x, z);
|
||||||
|
if (i == null) return;
|
||||||
|
lastUse.put(i, M.ms());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ public class IrisToolbelt {
|
|||||||
* @return the pregenerator job (already started)
|
* @return the pregenerator job (already started)
|
||||||
*/
|
*/
|
||||||
public static PregeneratorJob pregenerate(PregenTask task, PregeneratorMethod method, Engine engine) {
|
public static PregeneratorJob pregenerate(PregenTask task, PregeneratorMethod method, Engine engine) {
|
||||||
return pregenerate(task, method, engine, true);
|
return pregenerate(task, method, engine, IrisSettings.get().getPregen().useCacheByDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user