Merged mantle infrastructure

- Sliding mantle submissions and deferred in-flight neighbour waits
This commit is contained in:
Brian Neumann-Fopiano committed 2026-10-21 23:14:43 -04:00
commit 3f07db2b9e
2 files changed
+214 -28

No files matched your search

@@ -23,13 +23,14 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public interface MatterGenerator {
MultiBurst DISPATCHER = MultiBurst.burst;
ConcurrentHashMap<MatterTaskKey, MatterComponentTask> IN_FLIGHT_COMPONENTS = new ConcurrentHashMap<>();
int COMPONENT_SUBMISSION_BATCH_SIZE = Math.max(1, Math.min(8, Runtime.getRuntime().availableProcessors()));
int COMPONENT_SUBMISSION_LIMIT = Math.max(1, Math.min(8, Runtime.getRuntime().availableProcessors()));
long COMPONENT_TASK_POLL_MS = 1000L;
long COMPONENT_TASK_TIMEOUT_MS = Long.getLong("iris.mantle.componentTimeout", 120000L);
@@ -87,7 +88,7 @@ public interface MatterGenerator {
if (passPlans.length == 0) {
return;
}
int prefetchRadius = passPlans[0].passChunkRadius();
int prefetchRadius = phasePrefetchRadius(passPlans, phase);
LongOpenHashSet partialChunks = new LongOpenHashSet();
List<MantleComponent> requiredComponents = enabledComponents();
boolean terrainOnAccess = false;
@@ -104,8 +105,9 @@ public interface MatterGenerator {
// close() releases the cached chunks, even when a pass throws, or detached pool threads
// write into released chunks.
List<MatterComponentTask> outstandingTasks = null;
List<MatterComponentTask> submittedTasks = multicore && !DISPATCHER.ownsCurrentThread()
? new ArrayList<>(COMPONENT_SUBMISSION_BATCH_SIZE)
List<DeferredComponent> deferredComponents = null;
SubmissionWindow submissions = multicore && !DISPATCHER.ownsCurrentThread()
? new SubmissionWindow()
: null;
try {
@@ -229,15 +231,17 @@ public interface MatterGenerator {
for (int componentIndex = 0; componentIndex < eligibleComponentCount; componentIndex++) {
MantleComponent component = eligibleComponents[componentIndex];
outstandingTasks.add(runComponentAsync(
chunk, component, writer, finalPassX, finalPassZ, context, submittedTasks));
if (submittedTasks != null && submittedTasks.size() >= COMPONENT_SUBMISSION_BATCH_SIZE) {
awaitComponentTasks(submittedTasks);
}
chunk, component, writer, finalPassX, finalPassZ, context, submissions));
}
} else {
for (int componentIndex = 0; componentIndex < eligibleComponentCount; componentIndex++) {
MantleComponent component = eligibleComponents[componentIndex];
runComponentInline(chunk, component, writer, finalPassX, finalPassZ, context);
if (!tryRunComponentInline(chunk, component, writer, finalPassX, finalPassZ, context)) {
if (deferredComponents == null) {
deferredComponents = new ArrayList<>();
}
deferredComponents.add(new DeferredComponent(chunk, component, finalPassX, finalPassZ));
}
}
}
}
@@ -245,9 +249,8 @@ public interface MatterGenerator {
if (asyncComponents) {
awaitComponentTasks(outstandingTasks);
if (submittedTasks != null) {
submittedTasks.clear();
}
} else if (deferredComponents != null) {
runDeferredComponents(deferredComponents, writer, context);
}
}
@@ -320,6 +323,25 @@ public interface MatterGenerator {
return new MatterGenerationPlan(plans, writerChunkRadius * 2, phase);
}
private int phasePrefetchRadius(MatterPassPlan[] passPlans, MatterGenerationPhase phase) {
int radius = 0;
for (MatterPassPlan passPlan : passPlans) {
if (passPlan.passChunkRadius() > radius && generatesInPhase(passPlan.pass(), phase)) {
radius = passPlan.passChunkRadius();
}
}
return radius;
}
private boolean generatesInPhase(MantlePass pass, MatterGenerationPhase phase) {
for (MantleComponent component : pass.components()) {
if (phase.includes(component) && shouldGenerateComponent(component)) {
return true;
}
}
return false;
}
private List<MantleComponent> enabledComponents() {
List<MantleComponent> components = new ArrayList<>();
for (MantlePass pass : getComponents()) {
@@ -376,7 +398,7 @@ public interface MatterGenerator {
int chunkX,
int chunkZ,
ChunkContext context,
List<MatterComponentTask> submittedTasks
SubmissionWindow submissions
) {
MantleFlag flag = component.getFlag();
MatterTaskKey key = new MatterTaskKey(getMantle(), chunkX, chunkZ, flag);
@@ -386,19 +408,35 @@ public interface MatterGenerator {
return task;
}
MatterComponentTask existing = IN_FLIGHT_COMPONENTS.putIfAbsent(key, task);
if (existing != null) {
return existing;
}
try {
if (DISPATCHER.ownsCurrentThread()) {
if (submissions == null) {
MatterComponentTask existing = IN_FLIGHT_COMPONENTS.putIfAbsent(key, task);
if (existing != null) {
return existing;
}
try {
// A pool thread runs its claim inline: a task queued behind pool threads that block
// on unmanaged waits (structure builds, cache locks) could starve the whole pool.
completeComponentTask(task, chunk, component, writer, chunkX, chunkZ, context, IrisContext.get());
return task;
} catch (Throwable throwable) {
task.cancel(throwable);
throw throwable;
}
}
MatterComponentTask running = IN_FLIGHT_COMPONENTS.get(key);
if (running != null) {
return running;
}
submissions.acquire();
MatterComponentTask existing = IN_FLIGHT_COMPONENTS.putIfAbsent(key, task);
if (existing != null) {
submissions.release();
return existing;
}
try {
IrisContext callerContext = IrisContext.get();
submissions.track(task);
task.setSubmission(DISPATCHER.submit(() -> completeComponentTask(
task,
chunk,
@@ -408,7 +446,6 @@ public interface MatterGenerator {
chunkZ,
context,
callerContext)));
submittedTasks.add(task);
return task;
} catch (Throwable throwable) {
task.cancel(throwable);
@@ -416,6 +453,42 @@ public interface MatterGenerator {
}
}
private boolean tryRunComponentInline(
MantleChunk<Matter> chunk,
MantleComponent component,
MantleWriter writer,
int chunkX,
int chunkZ,
ChunkContext context
) {
MantleFlag flag = component.getFlag();
if (!chunk.tryClaim(flag)) {
return chunk.isFlagged(flag);
}
boolean generated = false;
try {
writer.withComponentPriority(component.getPriority(),
() -> component.generateLayer(writer, chunkX, chunkZ, context));
generated = true;
} finally {
if (generated) {
chunk.completeClaim(flag);
} else {
chunk.abandonClaim(flag);
}
}
return true;
}
private void runDeferredComponents(List<DeferredComponent> deferredComponents, MantleWriter writer,
ChunkContext context) {
for (DeferredComponent deferred : deferredComponents) {
runComponentInline(deferred.chunk(), deferred.component(), writer, deferred.chunkX(), deferred.chunkZ(),
context);
}
deferredComponents.clear();
}
/**
* Pass barrier. Waits for every launched task, even if one of them failed, so that no task is
* still writing through the writer once this returns. The first failure is rethrown.
@@ -698,6 +771,36 @@ public interface MatterGenerator {
}
}
final class SubmissionWindow {
private final Semaphore slots = new Semaphore(COMPONENT_SUBMISSION_LIMIT);
private volatile Throwable failure;
void acquire() {
slots.acquireUninterruptibly();
Throwable observed = failure;
if (observed != null) {
slots.release();
throw new CompletionException(observed);
}
}
void release() {
slots.release();
}
void track(MatterComponentTask task) {
task.future.whenComplete((ignored, throwable) -> {
if (throwable != null && failure == null) {
failure = throwable;
}
slots.release();
});
}
}
record DeferredComponent(MantleChunk<Matter> chunk, MantleComponent component, int chunkX, int chunkZ) {
}
record MatterPassPlan(MantlePass pass, int passChunkRadius, int downstreamBlockRadius) {
}