Skip to content

Commit

Permalink
Merge branch 'ver/1.19.4' into feature/fast-chunk-serializer
Browse files Browse the repository at this point in the history
  • Loading branch information
ishland committed Apr 15, 2023
2 parents 7e19bfa + d80c1af commit b0ab4cb
Show file tree
Hide file tree
Showing 28 changed files with 330 additions and 117 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ configure (allprojects - project(":tests")) {
implementation "com.electronwill.night-config:toml:${night_config_version}"
implementation "org.threadly:threadly:${threadly_version}"
implementation "net.objecthunter:exp4j:${exp4j_version}"
implementation "com.github.LlamaLad7:MixinExtras:${mixinextras_version}"

annotationProcessor "com.github.LlamaLad7:MixinExtras:${mixinextras_version}"
}
}

Expand Down Expand Up @@ -149,6 +152,7 @@ dependencies {
include implementation("com.electronwill.night-config:core:${night_config_version}")
include implementation("org.threadly:threadly:${threadly_version}")
include implementation("net.objecthunter:exp4j:${exp4j_version}")
include implementation("com.github.LlamaLad7:MixinExtras:${mixinextras_version}")

// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
// You may need to force-disable transitiveness on them.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.ishland.c2me.base.ModuleEntryPoint;
import com.ishland.c2me.base.common.util.C2MENormalWorkerThreadFactory;
import net.minecraft.util.thread.TaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
Expand Down Expand Up @@ -34,6 +35,8 @@ public class GlobalExecutors {
public static final ExecutorService asyncScheduler = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(),
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ksched").build());
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("c2me-sched").build());

public static final TaskExecutor<Runnable> asyncSchedulerTaskExecutor = TaskExecutor.create(asyncScheduler, "c2me-sched");

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ishland.c2me.base.common;

import com.llamalad7.mixinextras.MixinExtrasBootstrap;
import org.objectweb.asm.tree.ClassNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -19,6 +20,7 @@ public class ModuleMixinPlugin implements IMixinConfigPlugin {

@Override
public void onLoad(String mixinPackage) {
MixinExtrasBootstrap.init();
LOGGER.info("Initializing {}", mixinPackage);
final String[] split = mixinPackage.split("\\.");
final String targetClass = String.join(".", Arrays.copyOf(split, split.length - 1)) + ".ModuleEntryPoint";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.ishland.c2me.base.common.scheduler;

import com.ishland.c2me.base.common.structs.SimpleObjectPool;
import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
import it.unimi.dsi.fastutil.objects.ReferenceArraySet;
import net.minecraft.util.math.ChunkPos;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* Not thread safe.
*/
public class NeighborLockingManager {

private static final Logger LOGGER = LoggerFactory.getLogger("NeighborLockingManager");

private final SimpleObjectPool<ReferenceArraySet<Runnable>> pool = new SimpleObjectPool<>(
pool -> new ReferenceArraySet<>(16),
ReferenceArraySet::clear,
1024
);
private final Long2ReferenceOpenHashMap<ReferenceArraySet<Runnable>> activeLocks = new Long2ReferenceOpenHashMap<>();

public boolean isLocked(long pos) {
return activeLocks.containsKey(pos);
}

public void acquireLock(long pos) {
if (isLocked(pos)) throw new IllegalStateException("Already locked");
activeLocks.put(pos, pool.alloc());
}

public void releaseLock(long pos) {
if (!isLocked(pos)) throw new IllegalStateException("Not locked");
final ReferenceArraySet<Runnable> runnables = activeLocks.remove(pos);
for (Runnable runnable : runnables) {
try {
runnable.run();
} catch (Throwable t) {
LOGGER.error("Failed to notify lock release at chunk %s".formatted(new ChunkPos(pos)), t);
}
}
runnables.clear();
pool.release(runnables);
}

public void addReleaseListener(long pos, Runnable runnable) {
if (!isLocked(pos)) throw new IllegalStateException("Not locked");
activeLocks.get(pos).add(runnable);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.ishland.c2me.base.common.scheduler;

import com.google.common.base.Preconditions;
import com.ishland.c2me.base.common.GlobalExecutors;

import java.util.concurrent.CompletableFuture;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;

public class NeighborLockingTask<T> implements ScheduledTask {

private final SchedulingManager schedulingManager;
private final long center;
private final long[] names;
private final BooleanSupplier isCancelled;
private final Supplier<CompletableFuture<T>> action;
private final String desc;
private final boolean async;
private final CompletableFuture<T> future = new CompletableFuture<>();
private boolean acquired = false;

public NeighborLockingTask(SchedulingManager schedulingManager, long center, long[] names, BooleanSupplier isCancelled, Supplier<CompletableFuture<T>> action, String desc, boolean async) {
this.schedulingManager = schedulingManager;
this.center = center;
this.names = names;
this.isCancelled = isCancelled;
this.action = action;
this.desc = desc;
this.async = async;

this.schedulingManager.enqueue(this);
}


@Override
public boolean tryPrepare() {
final NeighborLockingManager lockingManager = this.schedulingManager.getNeighborLockingManager();
for (long l : names) {
if (lockingManager.isLocked(l)) {
lockingManager.addReleaseListener(l, () -> this.schedulingManager.enqueue(this));
return false;
}
}
for (long l : names) {
lockingManager.acquireLock(l);
}
acquired = true;
return true;
}

@Override
public void runTask(Runnable postAction) {
Preconditions.checkNotNull(postAction);
if (!acquired) throw new IllegalStateException();
final CompletableFuture<T> future = this.action.get();
Preconditions.checkNotNull(future, "future");
future.handleAsync((result, throwable) -> {
this.schedulingManager.getExecutor().execute(() -> {
final NeighborLockingManager lockingManager = this.schedulingManager.getNeighborLockingManager();
for (long l : names) {
lockingManager.releaseLock(l);
}
});
try {
postAction.run();
} catch (Throwable t) {
t.printStackTrace();
}
if (throwable != null) this.future.completeExceptionally(throwable);
else this.future.complete(result);
return null;
}, GlobalExecutors.invokingExecutor);
}

@Override
public long centerPos() {
return center;
}

@Override
public boolean isAsync() {
return async;
}

public CompletableFuture<T> getFuture() {
return future;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

public interface ScheduledTask {

public boolean trySchedule();
public boolean tryPrepare();

public void addPostAction(Runnable postAction);
public void runTask(Runnable postAction);

public long centerPos();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public SchedulingAsyncCombinedLock(AsyncNamedLock<ChunkPos> lock, long center, S
}

@Override
public boolean trySchedule() {
public boolean tryPrepare() {
return tryAcquire();
}

Expand Down Expand Up @@ -94,7 +94,7 @@ synchronized boolean tryAcquire() {
}

@Override
public void addPostAction(Runnable postAction) {
public void runTask(Runnable postAction) {
Preconditions.checkNotNull(postAction);
AsyncLock.LockToken token = this.acquiredToken;
if (token == null) throw new IllegalStateException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class SchedulingManager {
private final DynamicPriorityQueue<ScheduledTask> queue = new DynamicPriorityQueue<>(MAX_LEVEL + 1);
private final Long2ReferenceOpenHashMap<ObjectArraySet<ScheduledTask>> pos2Tasks = new Long2ReferenceOpenHashMap<>();
private final Long2IntOpenHashMap prioritiesFromLevel = new Long2IntOpenHashMap();
private final NeighborLockingManager neighborLockingManager = new NeighborLockingManager();
private final AtomicInteger scheduledCount = new AtomicInteger(0);
private final AtomicBoolean scheduled = new AtomicBoolean(false);
private ChunkPos currentSyncLoad = null;
Expand Down Expand Up @@ -94,6 +95,14 @@ public void setCurrentSyncLoad(ChunkPos pos) {
});
}

public NeighborLockingManager getNeighborLockingManager() {
return this.neighborLockingManager;
}

public Executor getExecutor() {
return executor;
}

private void updateSyncLoadInternal(ChunkPos pos) {
long startTime = System.nanoTime();
for (int xOff = -8; xOff <= 8; xOff++) {
Expand Down Expand Up @@ -128,8 +137,8 @@ private ScheduleStatus scheduleExecutionInternal() {
}

private boolean schedule0(ScheduledTask task) {
if (task.trySchedule()) {
task.addPostAction(() -> {
if (task.tryPrepare()) {
task.runTask(() -> {
scheduledCount.decrementAndGet();
scheduleExecution();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.ishland.c2me.opts.allocs.common;
package com.ishland.c2me.base.common.structs;

import com.google.common.base.Preconditions;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
@Mixin(ThreadedAnvilChunkStorage.class)
public class MixinThreadedAnvilChunkStorage implements IVanillaChunkManager {

private final SchedulingManager c2me$schedulingManager = new SchedulingManager(GlobalExecutors.asyncScheduler, GlobalExecutors.GLOBAL_EXECUTOR_PARALLELISM + 1);
private final SchedulingManager c2me$schedulingManager = new SchedulingManager(GlobalExecutors.asyncSchedulerTaskExecutor::send, GlobalExecutors.GLOBAL_EXECUTOR_PARALLELISM * 2);

@Override
public SchedulingManager c2me$getSchedulingManager() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public CompletableFuture<Either<Chunk, ChunkHolder.Unloaded>> getChunkAt(ChunkSt
@Redirect(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ChunkHolder;combineSavingFuture(Ljava/util/concurrent/CompletableFuture;Ljava/lang/String;)V"))
private void synchronizeCombineSavingFuture(ChunkHolder holder, CompletableFuture<? extends Either<? extends Chunk, ChunkHolder.Unloaded>> then, String thenDesc) {
synchronized (this) {
this.combineSavingFuture(then, thenDesc);
this.combineSavingFuture(then.exceptionally(unused -> null), thenDesc);
}
}

Expand All @@ -118,7 +118,7 @@ private void synchronizeCombineSavingFuture(ChunkHolder holder, CompletableFutur
@Overwrite
public void combineSavingFuture(String string, CompletableFuture<?> completableFuture) {
synchronized (this) {
this.savingFuture = this.savingFuture.thenCombine(completableFuture, (chunk, object) -> chunk);
this.savingFuture = this.savingFuture.thenCombine(completableFuture.exceptionally(unused -> null), (chunk, object) -> chunk);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import org.threadly.concurrent.NoThreadScheduler;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;

public class NoTickSystem {
Expand All @@ -26,7 +26,7 @@ public class NoTickSystem {
final NoThreadScheduler noThreadScheduler = new NoThreadScheduler();

private final AtomicBoolean isTicking = new AtomicBoolean();
final ExecutorService executor = GlobalExecutors.asyncScheduler;
final Executor executor = GlobalExecutors.asyncSchedulerTaskExecutor::send;
private volatile LongSet noTickOnlyChunksSnapshot = LongSets.EMPTY_SET;
private volatile boolean pendingPurge = false;
private volatile long age = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public NormalTicketDistanceMap(ChunkTicketManager chunkTicketManager) {

@Override
protected int getInitialLevel(long id) {
SortedArraySet<ChunkTicket<?>> sortedArraySet = ((com.ishland.c2me.base.mixin.access.IChunkTicketManager) chunkTicketManager).getTicketsByPosition().get(id);
SortedArraySet<ChunkTicket<?>> sortedArraySet = ticketsByPosition.get(id);
if (sortedArraySet != null) {
if (sortedArraySet.isEmpty()) return Integer.MAX_VALUE;
for (ChunkTicket<?> next : sortedArraySet) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ishland.c2me.opts.allocs.common;

import com.ishland.c2me.base.common.structs.SimpleObjectPool;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.StructureWorldAccess;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.ishland.c2me.opts.allocs.mixin.object_pooling_caching;

import com.ishland.c2me.opts.allocs.common.PooledFeatureContext;
import com.ishland.c2me.opts.allocs.common.SimpleObjectPool;
import com.ishland.c2me.base.common.structs.SimpleObjectPool;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.StructureWorldAccess;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"shutdown.MixinServerEntityManager",
"shutdown.MixinServerWorld",
"task_scheduling.MixinEntityChunkDataAccess",
"task_scheduling.MixinThreadedAnvilChunkStorage",
"task_scheduling.MixinThreadExecutor"
"task_scheduling.MixinThreadedAnvilChunkStorage"
]
}
Loading

0 comments on commit b0ab4cb

Please sign in to comment.