Reduced coordinate routing contention

- Published router reads bypass the attachment monitor

- Detached routing retains synchronized validation

- Concurrent reads retain coordinate and lifecycle checks
This commit is contained in:
Brian Neumann-Fopiano
2026-09-06 14:21:54 -04:00
2 changed files with 122 additions and 1 deletions
@@ -992,6 +992,10 @@ public class IrisEngine implements Engine {
}
public Optional<GenerationHistoryRuntimeRouter> getGenerationHistoryRuntimeRouter() {
GenerationHistoryRuntimeRouter router = generationHistoryRuntimeRouter;
if (router != null) {
return Optional.of(router);
}
synchronized (generationHistoryRuntimeRouterLock) {
return Optional.ofNullable(generationHistoryRuntimeRouter);
}
@@ -1001,7 +1005,10 @@ public class IrisEngine implements Engine {
int blockX,
int blockZ
) throws IOException {
GenerationHistoryRuntimeRouter router;
GenerationHistoryRuntimeRouter router = generationHistoryRuntimeRouter;
if (router != null) {
return router.openCoordinateScope(blockX, blockZ);
}
synchronized (generationHistoryRuntimeRouterLock) {
router = generationHistoryRuntimeRouter;
if (router == null && generationHistoryRoutingRequired) {
@@ -45,7 +45,10 @@ import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -554,6 +557,109 @@ public class IrisEngineGenerationRuntimeScopeTest {
assertThrows(IllegalStateException.class, () -> engine.getHeight(0, 0));
}
@Test
public void publishedRouterLookupDoesNotWaitForTheAttachmentMonitor() throws Exception {
RuntimeFixture active = runtime(1, 1D, 1D, 1D);
IrisEngine engine = engine(active.runtime, mock(EngineEffects.class), mock(EngineWorldManager.class));
GenerationHistoryRuntimeRouter router = historyRouter(engine);
engine.attachGenerationHistoryRuntimeRouter(router);
FutureTask<Optional<GenerationHistoryRuntimeRouter>> read = new FutureTask<>(engine::getGenerationHistoryRuntimeRouter);
Thread reader = new Thread(read, "History router lookup");
try {
synchronized (engine.generationHistoryRuntimeRouterLock) {
reader.start();
assertSame(router, read.get(5, TimeUnit.SECONDS).orElseThrow());
}
} finally {
reader.join(5_000L);
assertTrue("Router lookup did not finish", !reader.isAlive());
}
}
@Test
public void publishedCoordinateReadDoesNotWaitForTheAttachmentMonitor() throws Exception {
RuntimeFixture active = runtime(1, 1D, 1D, 1D);
IrisEngine engine = engine(active.runtime, mock(EngineEffects.class), mock(EngineWorldManager.class));
GenerationHistoryRuntimeRouter router = historyRouter(engine);
engine.attachGenerationHistoryRuntimeRouter(router);
GenerationHistoryRuntimeRouter.CoordinateScope scope = mock(GenerationHistoryRuntimeRouter.CoordinateScope.class);
when(router.openCoordinateScope(-17, 32)).thenReturn(scope);
FutureTask<GenerationHistoryRuntimeRouter.CoordinateScope> read =
new FutureTask<>(() -> engine.openGenerationHistoryCoordinateScope(-17, 32));
Thread reader = new Thread(read, "History coordinate read");
try {
synchronized (engine.generationHistoryRuntimeRouterLock) {
reader.start();
assertSame(scope, read.get(5, TimeUnit.SECONDS));
}
} finally {
reader.join(5_000L);
assertTrue("Coordinate read did not finish", !reader.isAlive());
}
verify(router).openCoordinateScope(-17, 32);
}
@Test
public void missingRouterReadWaitsForAttachmentPublication() throws Exception {
RuntimeFixture active = runtime(1, 1D, 1D, 1D);
IrisEngine engine = engine(active.runtime, mock(EngineEffects.class), mock(EngineWorldManager.class));
GenerationHistoryRuntimeRouter router = historyRouter(engine);
GenerationHistoryRuntimeRouter.CoordinateScope scope = mock(GenerationHistoryRuntimeRouter.CoordinateScope.class);
when(router.openCoordinateScope(-17, 32)).thenReturn(scope);
CountDownLatch started = new CountDownLatch(1);
FutureTask<GenerationHistoryRuntimeRouter.CoordinateScope> read = new FutureTask<>(() -> {
started.countDown();
return engine.openGenerationHistoryCoordinateScope(-17, 32);
});
Thread reader = new Thread(read, "Pending history attachment");
try {
synchronized (engine.generationHistoryRuntimeRouterLock) {
reader.start();
assertTrue(started.await(5, TimeUnit.SECONDS));
awaitBlocked(reader);
engine.attachGenerationHistoryRuntimeRouter(router);
}
assertSame(scope, read.get(5, TimeUnit.SECONDS));
} finally {
reader.join(5_000L);
assertTrue("Pending router read did not finish", !reader.isAlive());
}
}
@Test
public void detachedRouterReadRemainsFailClosedAcrossThreads() throws Exception {
RuntimeFixture active = runtime(1, 1D, 1D, 1D);
IrisEngine engine = engine(active.runtime, mock(EngineEffects.class), mock(EngineWorldManager.class));
GenerationHistoryRuntimeRouter router = historyRouter(engine);
engine.attachGenerationHistoryRuntimeRouter(router);
CountDownLatch started = new CountDownLatch(1);
FutureTask<GenerationHistoryRuntimeRouter.CoordinateScope> read = new FutureTask<>(() -> {
started.countDown();
return engine.openGenerationHistoryCoordinateScope(-17, 32);
});
Thread reader = new Thread(read, "Detached history read");
try {
synchronized (engine.generationHistoryRuntimeRouterLock) {
engine.detachGenerationHistoryRuntimeRouter(router);
reader.start();
assertTrue(started.await(5, TimeUnit.SECONDS));
awaitBlocked(reader);
}
ExecutionException failure = assertThrows(ExecutionException.class, () -> read.get(5, TimeUnit.SECONDS));
assertTrue(failure.getCause() instanceof IllegalStateException);
assertEquals("Iris generation-history runtime router is detached.", failure.getCause().getMessage());
assertTrue(engine.getGenerationHistoryRuntimeRouter().isEmpty());
} finally {
reader.join(5_000L);
assertTrue("Detached router read did not finish", !reader.isAlive());
}
verify(router, never()).openCoordinateScope(anyInt(), anyInt());
}
@Test
public void transferredMantleIsNotClosedWithTheRetiredRuntime() throws Exception {
RuntimeFixture active = runtime(1, 1D, 1D, 1D);
@@ -717,6 +823,14 @@ public class IrisEngineGenerationRuntimeScopeTest {
return router;
}
private static void awaitBlocked(Thread thread) throws InterruptedException {
long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(5L);
while (thread.getState() != Thread.State.BLOCKED && thread.isAlive() && System.nanoTime() < deadline) {
Thread.sleep(1L);
}
assertEquals(Thread.State.BLOCKED, thread.getState());
}
private static IrisEngine engine(
GenerationRuntime generationRuntime,
EngineEffects effects,