minecraft-source/src/net/minecraft/server/level/ChunkTaskPriorityQueueSorte...

169 lines
7.8 KiB
Java

package net.minecraft.server.level;
import org.apache.logging.log4j.LogManager;
import com.google.common.annotations.VisibleForTesting;
import com.mojang.datafixers.util.Either;
import java.util.stream.Stream;
import net.minecraft.Util;
import java.util.stream.Collector;
import java.util.concurrent.CompletableFuture;
import java.util.Optional;
import java.util.function.IntConsumer;
import net.minecraft.world.level.ChunkPos;
import java.util.function.IntSupplier;
import com.google.common.collect.Sets;
import java.util.stream.Collectors;
import java.util.concurrent.Executor;
import java.util.List;
import net.minecraft.util.thread.StrictQueue;
import net.minecraft.util.thread.ProcessorMailbox;
import java.util.Set;
import net.minecraft.util.Unit;
import java.util.function.Function;
import net.minecraft.util.thread.ProcessorHandle;
import java.util.Map;
import org.apache.logging.log4j.Logger;
public class ChunkTaskPriorityQueueSorter implements AutoCloseable, ChunkHolder.LevelChangeListener {
private static final Logger LOGGER;
private final Map<ProcessorHandle<?>, ChunkTaskPriorityQueue<? extends Function<ProcessorHandle<Unit>, ?>>> queues;
private final Set<ProcessorHandle<?>> sleeping;
private final ProcessorMailbox<StrictQueue.IntRunnable> mailbox;
public ChunkTaskPriorityQueueSorter(final List<ProcessorHandle<?>> list, final Executor executor, final int integer) {
final ChunkTaskPriorityQueue chunkTaskPriorityQueue;
this.queues = list.stream().collect(Collectors.toMap(Function.identity(), air -> {
new ChunkTaskPriorityQueue(air.name() + "_queue", integer);
return chunkTaskPriorityQueue;
}));
this.sleeping = Sets.newHashSet(list);
this.mailbox = new ProcessorMailbox<StrictQueue.IntRunnable>(new StrictQueue.FixedPriorityQueue(4), executor, "sorter");
}
public static Message<Runnable> message(final Runnable runnable, final long long2, final IntSupplier intSupplier) {
return new Message<Runnable>(air -> () -> {
runnable.run();
air.tell(Unit.INSTANCE);
}, long2, intSupplier);
}
public static Message<Runnable> message(final ChunkHolder wo, final Runnable runnable) {
return message(runnable, wo.getPos().toLong(), wo::getQueueLevel);
}
public static Release release(final Runnable runnable, final long long2, final boolean boolean3) {
return new Release(runnable, long2, boolean3);
}
public <T> ProcessorHandle<Message<T>> getProcessor(final ProcessorHandle<T> air, final boolean boolean2) {
return this.mailbox.<ProcessorHandle<Message<T>>>ask(air3 -> new StrictQueue.IntRunnable(0, () -> {
this.<T>getQueue(air);
air3.tell(ProcessorHandle.of("chunk priority sorter around " + air.name(), a -> this.<T>submit(air, a.task, a.pos, a.level, boolean2)));
})).join();
}
public ProcessorHandle<Release> getReleaseProcessor(final ProcessorHandle<Runnable> air) {
return this.mailbox.<ProcessorHandle<Release>>ask(air2 -> new StrictQueue.IntRunnable(0, () -> air2.tell(ProcessorHandle.of("chunk priority sorter around " + air.name(), b -> this.<Runnable>release(air, b.pos, b.task, b.clearQueue))))).join();
}
@Override
public void onLevelChange(final ChunkPos bje, final IntSupplier intSupplier, final int integer, final IntConsumer intConsumer) {
final int integer2;
this.mailbox.tell(new StrictQueue.IntRunnable(0, () -> {
integer2 = intSupplier.getAsInt();
this.queues.values().forEach(wq -> wq.resortChunkTasks(integer2, bje, integer));
intConsumer.accept(integer);
}));
}
private <T> void release(final ProcessorHandle<T> air, final long long2, final Runnable runnable, final boolean boolean4) {
final ChunkTaskPriorityQueue<Function<ProcessorHandle<Unit>, Object>> wq7;
this.mailbox.tell(new StrictQueue.IntRunnable(1, () -> {
wq7 = this.getQueue(air);
wq7.release(long2, boolean4);
if (this.sleeping.remove(air)) {
this.pollTask(wq7, (ProcessorHandle<Object>)air);
}
runnable.run();
}));
}
private <T> void submit(final ProcessorHandle<T> air, final Function<ProcessorHandle<Unit>, T> function, final long long3, final IntSupplier intSupplier, final boolean boolean5) {
final ChunkTaskPriorityQueue<Function<ProcessorHandle<Unit>, Object>> wq8;
final int integer9;
this.mailbox.tell(new StrictQueue.IntRunnable(2, () -> {
wq8 = this.getQueue(air);
integer9 = intSupplier.getAsInt();
wq8.submit(Optional.<Function<ProcessorHandle<Unit>, Object>>of((Function<ProcessorHandle<Unit>, Object>)function), long3, integer9);
if (boolean5) {
wq8.submit(Optional.<Function<ProcessorHandle<Unit>, Object>>empty(), long3, integer9);
}
if (this.sleeping.remove(air)) {
this.pollTask(wq8, (ProcessorHandle<Object>)air);
}
}));
}
private <T> void pollTask(final ChunkTaskPriorityQueue<Function<ProcessorHandle<Unit>, T>> wq, final ProcessorHandle<T> air) {
final Stream<Either<Function<ProcessorHandle<Unit>, Object>, Runnable>> stream4;
this.mailbox.tell(new StrictQueue.IntRunnable(3, () -> {
stream4 = (Stream<Either<Function<ProcessorHandle<Unit>, Object>, Runnable>>)wq.pop();
if (stream4 == null) {
this.sleeping.add(air);
}
else {
Util.sequence(stream4.map(either -> (CompletableFuture)either.map((Function)air::ask, runnable -> {
runnable.run();
return CompletableFuture.<Unit>completedFuture(Unit.INSTANCE);
})).collect(Collectors.toList())).thenAccept(list -> this.pollTask((ChunkTaskPriorityQueue<Function<ProcessorHandle<Unit>, Object>>)wq, (ProcessorHandle<Object>)air));
}
}));
}
private <T> ChunkTaskPriorityQueue<Function<ProcessorHandle<Unit>, T>> getQueue(final ProcessorHandle<T> air) {
final ChunkTaskPriorityQueue<? extends Function<ProcessorHandle<Unit>, ?>> wq3 = this.queues.get(air);
if (wq3 == null) {
throw Util.<IllegalArgumentException>pauseInIde(new IllegalArgumentException("No queue for: " + air));
}
return (ChunkTaskPriorityQueue<Function<ProcessorHandle<Unit>, T>>)wq3;
}
@VisibleForTesting
public String getDebugStatus() {
return this.queues.entrySet().stream().map(entry -> entry.getKey().name() + "=[" + ((ChunkTaskPriorityQueue)entry.getValue()).getAcquired().stream().map(long1 -> long1 + ":" + new ChunkPos(long1)).collect(Collectors.joining(",")) + "]").collect(Collectors.joining(",")) + ", s=" + this.sleeping.size();
}
@Override
public void close() {
this.queues.keySet().forEach(ProcessorHandle::close);
}
static {
LOGGER = LogManager.getLogger();
}
public static final class Message<T> {
private final Function<ProcessorHandle<Unit>, T> task;
private final long pos;
private final IntSupplier level;
private Message(final Function<ProcessorHandle<Unit>, T> function, final long long2, final IntSupplier intSupplier) {
this.task = function;
this.pos = long2;
this.level = intSupplier;
}
}
public static final class Release {
private final Runnable task;
private final long pos;
private final boolean clearQueue;
private Release(final Runnable runnable, final long long2, final boolean boolean3) {
this.task = runnable;
this.pos = long2;
this.clearQueue = boolean3;
}
}
}