mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-25 21:40:05 +00:00
One thread frame per engine
- runtime assembly, biome environment and runtime scope share one ThreadLocal frame - engine getters do a single ThreadLocal lookup
This commit is contained in:
1 parent
badca54e5d
commit
d0008086ac
11 files changed
+296
-151
No files matched your search
@@ -81,7 +81,7 @@ final class EngineHotloader {
|
|||||||
previousGeneration.transitionPlan());
|
previousGeneration.transitionPlan());
|
||||||
PreparedHydrologyCacheIdentity cacheIdentity = PreparedHydrologyCacheIdentity.capture(
|
PreparedHydrologyCacheIdentity cacheIdentity = PreparedHydrologyCacheIdentity.capture(
|
||||||
assembly.target, assembly.runtimeKernel, assembly.transitionPlan, engine.isStudio());
|
assembly.target, assembly.runtimeKernel, assembly.transitionPlan, engine.isStudio());
|
||||||
engine.runtimeAssembly.set(assembly);
|
engine.threadState.setAssembly(assembly);
|
||||||
EngineRuntime next;
|
EngineRuntime next;
|
||||||
try (IrisContext.Scope ignored = IrisContext.open(engine, engine.getGenerationSessions().currentSessionId(), null)) {
|
try (IrisContext.Scope ignored = IrisContext.open(engine, engine.getGenerationSessions().currentSessionId(), null)) {
|
||||||
assembly.complex = assembly.runtimeKernel.createComplex(engine, assembly.transitionPlan, false);
|
assembly.complex = assembly.runtimeKernel.createComplex(engine, assembly.transitionPlan, false);
|
||||||
@@ -97,7 +97,7 @@ final class EngineHotloader {
|
|||||||
biomeMaxes);
|
biomeMaxes);
|
||||||
next = previous.withGeneration(nextGeneration);
|
next = previous.withGeneration(nextGeneration);
|
||||||
} finally {
|
} finally {
|
||||||
engine.runtimeAssembly.remove();
|
engine.threadState.setAssembly(null);
|
||||||
}
|
}
|
||||||
Throwable retirementFailure = runCleanup(null, previousGeneration.complex()::close);
|
Throwable retirementFailure = runCleanup(null, previousGeneration.complex()::close);
|
||||||
if (retirementFailure != null) {
|
if (retirementFailure != null) {
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ final class EngineRuntimeBuilder {
|
|||||||
mantleStorageDirectory,
|
mantleStorageDirectory,
|
||||||
selectRuntimeKernel(kernelVersion),
|
selectRuntimeKernel(kernelVersion),
|
||||||
transitionPlan);
|
transitionPlan);
|
||||||
engine.runtimeAssembly.set(assembly);
|
engine.threadState.setAssembly(assembly);
|
||||||
try (IrisContext.Scope ignored = IrisContext.open(engine, engine.getGenerationSessions().currentSessionId(), null)) {
|
try (IrisContext.Scope ignored = IrisContext.open(engine, engine.getGenerationSessions().currentSessionId(), null)) {
|
||||||
IrisLogging.debug("Setup Engine " + assembly.cacheId);
|
IrisLogging.debug("Setup Engine " + assembly.cacheId);
|
||||||
long started = M.ms();
|
long started = M.ms();
|
||||||
@@ -148,7 +148,7 @@ final class EngineRuntimeBuilder {
|
|||||||
}
|
}
|
||||||
throw new IllegalStateException("Failed to build a complete Iris engine runtime.", e);
|
throw new IllegalStateException("Failed to build a complete Iris engine runtime.", e);
|
||||||
} finally {
|
} finally {
|
||||||
engine.runtimeAssembly.remove();
|
engine.threadState.setAssembly(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ final class EngineRuntimeBuilder {
|
|||||||
transitionPlan);
|
transitionPlan);
|
||||||
PreparedHydrologyCacheIdentity cacheIdentity = PreparedHydrologyCacheIdentity.capture(
|
PreparedHydrologyCacheIdentity cacheIdentity = PreparedHydrologyCacheIdentity.capture(
|
||||||
runtimeTarget, assembly.runtimeKernel, transitionPlan, engine.isStudio());
|
runtimeTarget, assembly.runtimeKernel, transitionPlan, engine.isStudio());
|
||||||
engine.runtimeAssembly.set(assembly);
|
engine.threadState.setAssembly(assembly);
|
||||||
try (IrisContext.Scope ignored = IrisContext.open(engine, engine.getGenerationSessions().currentSessionId(), null)) {
|
try (IrisContext.Scope ignored = IrisContext.open(engine, engine.getGenerationSessions().currentSessionId(), null)) {
|
||||||
IrisLogging.debug("Setup Detached Generation Runtime " + assembly.cacheId);
|
IrisLogging.debug("Setup Detached Generation Runtime " + assembly.cacheId);
|
||||||
assembly.mantle = assembly.runtimeKernel.createMantle(engine, assembly.mantleStorageDirectory);
|
assembly.mantle = assembly.runtimeKernel.createMantle(engine, assembly.mantleStorageDirectory);
|
||||||
@@ -201,7 +201,7 @@ final class EngineRuntimeBuilder {
|
|||||||
}
|
}
|
||||||
throw new IllegalStateException("Failed to build a detached Iris generation runtime.", e);
|
throw new IllegalStateException("Failed to build a detached Iris generation runtime.", e);
|
||||||
} finally {
|
} finally {
|
||||||
engine.runtimeAssembly.remove();
|
engine.threadState.setAssembly(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -264,20 +264,16 @@ final class EngineShutdownSequence {
|
|||||||
return failure;
|
return failure;
|
||||||
}
|
}
|
||||||
incompleteAssemblies.add(assembly);
|
incompleteAssemblies.add(assembly);
|
||||||
RuntimeAssembly previous = engine == null ? null : engine.runtimeAssembly.get();
|
RuntimeAssembly previous = engine == null ? null : engine.threadState.assembly();
|
||||||
if (engine != null) {
|
if (engine != null) {
|
||||||
engine.runtimeAssembly.set(assembly);
|
engine.threadState.setAssembly(assembly);
|
||||||
}
|
}
|
||||||
Throwable assemblyFailure;
|
Throwable assemblyFailure;
|
||||||
try {
|
try {
|
||||||
assemblyFailure = closeAssemblyResources(assembly);
|
assemblyFailure = closeAssemblyResources(assembly);
|
||||||
} finally {
|
} finally {
|
||||||
if (engine != null) {
|
if (engine != null) {
|
||||||
if (previous == null) {
|
engine.threadState.setAssembly(previous);
|
||||||
engine.runtimeAssembly.remove();
|
|
||||||
} else {
|
|
||||||
engine.runtimeAssembly.set(previous);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (assemblyFailure == null) {
|
if (assemblyFailure == null) {
|
||||||
@@ -401,7 +397,7 @@ final class EngineShutdownSequence {
|
|||||||
engine,
|
engine,
|
||||||
generationRuntime);
|
generationRuntime);
|
||||||
Throwable runtimeFailure;
|
Throwable runtimeFailure;
|
||||||
try (IrisEngine.GenerationRuntimeScope ignored = engine.generationRuntimeScopes.open(binding)) {
|
try (IrisEngine.GenerationRuntimeScope ignored = engine.threadState.open(binding)) {
|
||||||
runtimeFailure = closeGenerationRuntime(generationRuntime, null);
|
runtimeFailure = closeGenerationRuntime(generationRuntime, null);
|
||||||
} catch (Throwable scopeFailure) {
|
} catch (Throwable scopeFailure) {
|
||||||
runtimeFailure = scopeFailure;
|
runtimeFailure = scopeFailure;
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package art.arcane.iris.generation.runtime;
|
||||||
|
|
||||||
|
import art.arcane.iris.generation.runtime.EngineRuntimeBuilder.RuntimeAssembly;
|
||||||
|
import art.arcane.iris.generation.runtime.IrisEngine.BiomeEnvironmentBinding;
|
||||||
|
import art.arcane.iris.generation.runtime.IrisEngine.GenerationRuntimeBinding;
|
||||||
|
import art.arcane.iris.generation.runtime.IrisEngine.GenerationRuntimeScope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every per-thread engine binding (runtime assembly, biome environment, generation runtime scope) in one frame,
|
||||||
|
* so the engine getters on generation hot paths pay a single ThreadLocal lookup.
|
||||||
|
*/
|
||||||
|
final class EngineThreadState {
|
||||||
|
private final ThreadLocal<Frame> frames = new ThreadLocal<>();
|
||||||
|
|
||||||
|
Frame current() {
|
||||||
|
return frames.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerationRuntimeBinding binding() {
|
||||||
|
Frame frame = frames.get();
|
||||||
|
return frame == null ? null : frame.binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeAssembly assembly() {
|
||||||
|
Frame frame = frames.get();
|
||||||
|
return frame == null ? null : frame.assembly;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAssembly(RuntimeAssembly assembly) {
|
||||||
|
if (assembly != null) {
|
||||||
|
frame().assembly = assembly;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Frame frame = frames.get();
|
||||||
|
if (frame != null) {
|
||||||
|
frame.assembly = null;
|
||||||
|
releaseIfEmpty(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BiomeEnvironmentBinding environment() {
|
||||||
|
Frame frame = frames.get();
|
||||||
|
return frame == null ? null : frame.environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEnvironment(BiomeEnvironmentBinding environment) {
|
||||||
|
if (environment != null) {
|
||||||
|
frame().environment = environment;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Frame frame = frames.get();
|
||||||
|
if (frame != null) {
|
||||||
|
frame.environment = null;
|
||||||
|
releaseIfEmpty(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerationRuntimeScope open(GenerationRuntimeBinding binding) {
|
||||||
|
Thread owner = Thread.currentThread();
|
||||||
|
Frame frame = frame();
|
||||||
|
GenerationRuntimeBinding previous = frame.binding;
|
||||||
|
frame.binding = binding;
|
||||||
|
return new GenerationRuntimeScope(this, owner, previous, binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
void close(
|
||||||
|
Thread owner,
|
||||||
|
GenerationRuntimeBinding previous,
|
||||||
|
GenerationRuntimeBinding installed
|
||||||
|
) {
|
||||||
|
if (Thread.currentThread() != owner) {
|
||||||
|
throw new IllegalStateException("Iris generation runtime scope closed from a different thread.");
|
||||||
|
}
|
||||||
|
Frame frame = frames.get();
|
||||||
|
if ((frame == null ? null : frame.binding) != installed) {
|
||||||
|
throw new IllegalStateException("Iris generation runtime scopes must close in LIFO order.");
|
||||||
|
}
|
||||||
|
if (previous != null) {
|
||||||
|
frame().binding = previous;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (frame != null) {
|
||||||
|
frame.binding = null;
|
||||||
|
releaseIfEmpty(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Frame frame() {
|
||||||
|
Frame frame = frames.get();
|
||||||
|
if (frame == null) {
|
||||||
|
frame = new Frame();
|
||||||
|
frames.set(frame);
|
||||||
|
}
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void releaseIfEmpty(Frame frame) {
|
||||||
|
if (frame.assembly == null && frame.environment == null && frame.binding == null) {
|
||||||
|
frames.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class Frame {
|
||||||
|
RuntimeAssembly assembly;
|
||||||
|
BiomeEnvironmentBinding environment;
|
||||||
|
GenerationRuntimeBinding binding;
|
||||||
|
}
|
||||||
|
}
|
||||||
-55
@@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
|
||||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package art.arcane.iris.generation.runtime;
|
|
||||||
|
|
||||||
import art.arcane.iris.generation.runtime.IrisEngine.GenerationRuntimeBinding;
|
|
||||||
import art.arcane.iris.generation.runtime.IrisEngine.GenerationRuntimeScope;
|
|
||||||
|
|
||||||
final class GenerationRuntimeScopeState {
|
|
||||||
private final ThreadLocal<GenerationRuntimeBinding> current = new ThreadLocal<>();
|
|
||||||
|
|
||||||
GenerationRuntimeBinding current() {
|
|
||||||
return current.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
GenerationRuntimeScope open(GenerationRuntimeBinding binding) {
|
|
||||||
Thread owner = Thread.currentThread();
|
|
||||||
GenerationRuntimeBinding previous = current.get();
|
|
||||||
current.set(binding);
|
|
||||||
return new GenerationRuntimeScope(this, owner, previous, binding);
|
|
||||||
}
|
|
||||||
|
|
||||||
void close(
|
|
||||||
Thread owner,
|
|
||||||
GenerationRuntimeBinding previous,
|
|
||||||
GenerationRuntimeBinding installed
|
|
||||||
) {
|
|
||||||
if (Thread.currentThread() != owner) {
|
|
||||||
throw new IllegalStateException("Iris generation runtime scope closed from a different thread.");
|
|
||||||
}
|
|
||||||
if (current.get() != installed) {
|
|
||||||
throw new IllegalStateException("Iris generation runtime scopes must close in LIFO order.");
|
|
||||||
}
|
|
||||||
if (previous == null) {
|
|
||||||
current.remove();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
current.set(previous);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -117,13 +117,7 @@ public class IrisEngine implements Engine {
|
|||||||
final Object generationHistoryRuntimeRouterLock = new Object();
|
final Object generationHistoryRuntimeRouterLock = new Object();
|
||||||
@Getter(AccessLevel.NONE)
|
@Getter(AccessLevel.NONE)
|
||||||
@Setter(AccessLevel.NONE)
|
@Setter(AccessLevel.NONE)
|
||||||
final ThreadLocal<RuntimeAssembly> runtimeAssembly = new ThreadLocal<>();
|
final EngineThreadState threadState = new EngineThreadState();
|
||||||
@Getter(AccessLevel.NONE)
|
|
||||||
@Setter(AccessLevel.NONE)
|
|
||||||
final ThreadLocal<BiomeEnvironmentBinding> biomeEnvironmentScopes = new ThreadLocal<>();
|
|
||||||
@Getter(AccessLevel.NONE)
|
|
||||||
@Setter(AccessLevel.NONE)
|
|
||||||
final GenerationRuntimeScopeState generationRuntimeScopes = new GenerationRuntimeScopeState();
|
|
||||||
@Getter(AccessLevel.NONE)
|
@Getter(AccessLevel.NONE)
|
||||||
@Setter(AccessLevel.NONE)
|
@Setter(AccessLevel.NONE)
|
||||||
final Set<GenerationRuntime> detachedGenerationRuntimes = Collections.synchronizedSet(
|
final Set<GenerationRuntime> detachedGenerationRuntimes = Collections.synchronizedSet(
|
||||||
@@ -383,7 +377,7 @@ public class IrisEngine implements Engine {
|
|||||||
throw new IllegalStateException("World entry hydrology preparation could not acquire its generation session.", failure);
|
throw new IllegalStateException("World entry hydrology preparation could not acquire its generation session.", failure);
|
||||||
}
|
}
|
||||||
try (lease;
|
try (lease;
|
||||||
GenerationRuntimeScope runtimeScope = generationRuntimeScopes.open(binding);
|
GenerationRuntimeScope runtimeScope = threadState.open(binding);
|
||||||
IrisContext.Scope context = IrisContext.open(this, lease.sessionId(), null)) {
|
IrisContext.Scope context = IrisContext.open(this, lease.sessionId(), null)) {
|
||||||
getComplex().getHydrologyRuntime().prepareChunkColumns(blockX, blockZ);
|
getComplex().getHydrologyRuntime().prepareChunkColumns(blockX, blockZ);
|
||||||
} catch (Exception failure) {
|
} catch (Exception failure) {
|
||||||
@@ -573,8 +567,8 @@ public class IrisEngine implements Engine {
|
|||||||
@Override
|
@Override
|
||||||
public BiomeEnvironment.Scope openBiomeEnvironmentScope(BiomeEnvironment environment) {
|
public BiomeEnvironment.Scope openBiomeEnvironmentScope(BiomeEnvironment environment) {
|
||||||
BiomeEnvironmentBinding binding = new BiomeEnvironmentBinding(
|
BiomeEnvironmentBinding binding = new BiomeEnvironmentBinding(
|
||||||
Objects.requireNonNull(environment, "environment"), biomeEnvironmentScopes.get());
|
Objects.requireNonNull(environment, "environment"), threadState.environment());
|
||||||
biomeEnvironmentScopes.set(binding);
|
threadState.setEnvironment(binding);
|
||||||
return binding;
|
return binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -980,7 +974,7 @@ public class IrisEngine implements Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasGenerationRuntimeScope() {
|
public boolean hasGenerationRuntimeScope() {
|
||||||
return generationRuntimeScopes.current() != null;
|
return threadState.binding() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean usesScopedNaturalTerrain() {
|
private boolean usesScopedNaturalTerrain() {
|
||||||
@@ -1059,7 +1053,7 @@ public class IrisEngine implements Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public GenerationRuntimeBinding captureGenerationRuntimeBinding() {
|
public GenerationRuntimeBinding captureGenerationRuntimeBinding() {
|
||||||
GenerationRuntimeBinding scoped = generationRuntimeScopes.current();
|
GenerationRuntimeBinding scoped = threadState.binding();
|
||||||
return scoped == null ? getActiveGenerationRuntimeBinding() : scoped;
|
return scoped == null ? getActiveGenerationRuntimeBinding() : scoped;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1075,7 +1069,7 @@ public class IrisEngine implements Engine {
|
|||||||
if (!isGenerationRuntimeBindingLive(required)) {
|
if (!isGenerationRuntimeBindingLive(required)) {
|
||||||
throw new IllegalStateException("Iris generation runtime binding is closed or no longer owned.");
|
throw new IllegalStateException("Iris generation runtime binding is closed or no longer owned.");
|
||||||
}
|
}
|
||||||
return generationRuntimeScopes.open(required);
|
return threadState.open(required);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1266,75 +1260,85 @@ public class IrisEngine implements Engine {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SeedManager getSeedManager() {
|
public SeedManager getSeedManager() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
EngineThreadState.Frame frame = threadState.current();
|
||||||
|
RuntimeAssembly assembly = frame == null ? null : frame.assembly;
|
||||||
if (assembly != null) {
|
if (assembly != null) {
|
||||||
return assembly.seedManager;
|
return assembly.seedManager;
|
||||||
}
|
}
|
||||||
GenerationRuntime current = selectedGenerationRuntime();
|
GenerationRuntime current = selectedGenerationRuntime(frame);
|
||||||
return current == null ? seedManager : current.seedManager();
|
return current == null ? seedManager : current.seedManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IrisComplex getComplex() {
|
public IrisComplex getComplex() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
EngineThreadState.Frame frame = threadState.current();
|
||||||
|
RuntimeAssembly assembly = frame == null ? null : frame.assembly;
|
||||||
if (assembly != null && assembly.complex != null) {
|
if (assembly != null && assembly.complex != null) {
|
||||||
return assembly.complex;
|
return assembly.complex;
|
||||||
}
|
}
|
||||||
GenerationRuntime current = selectedGenerationRuntime();
|
GenerationRuntime current = selectedGenerationRuntime(frame);
|
||||||
return current == null ? null : current.complex();
|
return current == null ? null : current.complex();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EngineTarget getTarget() {
|
public EngineTarget getTarget() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
EngineThreadState.Frame frame = threadState.current();
|
||||||
|
RuntimeAssembly assembly = frame == null ? null : frame.assembly;
|
||||||
if (assembly != null) {
|
if (assembly != null) {
|
||||||
return assembly.target;
|
return assembly.target;
|
||||||
}
|
}
|
||||||
GenerationRuntime current = selectedGenerationRuntime();
|
GenerationRuntime current = selectedGenerationRuntime(frame);
|
||||||
return current == null ? publishedTarget : current.target();
|
return current == null ? publishedTarget : current.target();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IrisData getData() {
|
public IrisData getData() {
|
||||||
BiomeEnvironmentBinding environment = biomeEnvironmentScopes.get();
|
EngineThreadState.Frame frame = threadState.current();
|
||||||
if (environment != null && !hasGenerationRuntimeScope()) {
|
if (frame != null) {
|
||||||
return environment.environment.data();
|
BiomeEnvironmentBinding environment = frame.environment;
|
||||||
|
if (environment != null && frame.binding == null) {
|
||||||
|
return environment.environment.data();
|
||||||
|
}
|
||||||
|
RuntimeAssembly assembly = frame.assembly;
|
||||||
|
if (assembly != null) {
|
||||||
|
return assembly.target.getData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
GenerationRuntime current = selectedGenerationRuntime(frame);
|
||||||
if (assembly != null) {
|
|
||||||
return assembly.target.getData();
|
|
||||||
}
|
|
||||||
GenerationRuntime current = selectedGenerationRuntime();
|
|
||||||
return current == null ? publishedTarget.getData() : current.data();
|
return current == null ? publishedTarget.getData() : current.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IrisDimension getDimension() {
|
public IrisDimension getDimension() {
|
||||||
BiomeEnvironmentBinding environment = biomeEnvironmentScopes.get();
|
EngineThreadState.Frame frame = threadState.current();
|
||||||
if (environment != null && !hasGenerationRuntimeScope()) {
|
if (frame != null) {
|
||||||
return environment.environment.dimension();
|
BiomeEnvironmentBinding environment = frame.environment;
|
||||||
|
if (environment != null && frame.binding == null) {
|
||||||
|
return environment.environment.dimension();
|
||||||
|
}
|
||||||
|
RuntimeAssembly assembly = frame.assembly;
|
||||||
|
if (assembly != null) {
|
||||||
|
return assembly.target.getDimension();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
GenerationRuntime current = selectedGenerationRuntime(frame);
|
||||||
if (assembly != null) {
|
|
||||||
return assembly.target.getDimension();
|
|
||||||
}
|
|
||||||
GenerationRuntime current = selectedGenerationRuntime();
|
|
||||||
return current == null ? publishedTarget.getDimension() : current.dimension();
|
return current == null ? publishedTarget.getDimension() : current.dimension();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EngineMantle getMantle() {
|
public EngineMantle getMantle() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
EngineThreadState.Frame frame = threadState.current();
|
||||||
|
RuntimeAssembly assembly = frame == null ? null : frame.assembly;
|
||||||
if (assembly != null && assembly.mantle != null) {
|
if (assembly != null && assembly.mantle != null) {
|
||||||
return assembly.mantle;
|
return assembly.mantle;
|
||||||
}
|
}
|
||||||
GenerationRuntime current = selectedGenerationRuntime();
|
GenerationRuntime current = selectedGenerationRuntime(frame);
|
||||||
return current == null ? null : current.mantle();
|
return current == null ? null : current.mantle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EngineMode getMode() {
|
public EngineMode getMode() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
RuntimeAssembly assembly = threadState.assembly();
|
||||||
if (assembly != null && assembly.mode != null) {
|
if (assembly != null && assembly.mode != null) {
|
||||||
return assembly.mode;
|
return assembly.mode;
|
||||||
}
|
}
|
||||||
@@ -1344,7 +1348,7 @@ public class IrisEngine implements Engine {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EngineEffects getEffects() {
|
public EngineEffects getEffects() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
RuntimeAssembly assembly = threadState.assembly();
|
||||||
if (assembly != null && assembly.effects != null) {
|
if (assembly != null && assembly.effects != null) {
|
||||||
return assembly.effects;
|
return assembly.effects;
|
||||||
}
|
}
|
||||||
@@ -1354,7 +1358,7 @@ public class IrisEngine implements Engine {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EngineWorldManager getWorldManager() {
|
public EngineWorldManager getWorldManager() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
RuntimeAssembly assembly = threadState.assembly();
|
||||||
if (assembly != null && assembly.worldManager != null) {
|
if (assembly != null && assembly.worldManager != null) {
|
||||||
return assembly.worldManager;
|
return assembly.worldManager;
|
||||||
}
|
}
|
||||||
@@ -1364,27 +1368,29 @@ public class IrisEngine implements Engine {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UpperDimensionContext getUpperContext() {
|
public UpperDimensionContext getUpperContext() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
EngineThreadState.Frame frame = threadState.current();
|
||||||
|
RuntimeAssembly assembly = frame == null ? null : frame.assembly;
|
||||||
if (assembly != null) {
|
if (assembly != null) {
|
||||||
return assembly.upperContext;
|
return assembly.upperContext;
|
||||||
}
|
}
|
||||||
GenerationRuntime current = selectedGenerationRuntime();
|
GenerationRuntime current = selectedGenerationRuntime(frame);
|
||||||
return current == null ? null : current.upperContext();
|
return current == null ? null : current.upperContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DimensionStackContext getDimensionStackContext() {
|
public DimensionStackContext getDimensionStackContext() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
EngineThreadState.Frame frame = threadState.current();
|
||||||
|
RuntimeAssembly assembly = frame == null ? null : frame.assembly;
|
||||||
if (assembly != null) {
|
if (assembly != null) {
|
||||||
return assembly.dimensionStackContext;
|
return assembly.dimensionStackContext;
|
||||||
}
|
}
|
||||||
GenerationRuntime current = selectedGenerationRuntime();
|
GenerationRuntime current = selectedGenerationRuntime(frame);
|
||||||
return current == null ? null : current.dimensionStackContext();
|
return current == null ? null : current.dimensionStackContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Long> getHash32() {
|
public CompletableFuture<Long> getHash32() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
RuntimeAssembly assembly = threadState.assembly();
|
||||||
if (assembly != null && assembly.hash32 != null) {
|
if (assembly != null && assembly.hash32 != null) {
|
||||||
return assembly.hash32;
|
return assembly.hash32;
|
||||||
}
|
}
|
||||||
@@ -1579,16 +1585,21 @@ public class IrisEngine implements Engine {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCacheID() {
|
public int getCacheID() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
EngineThreadState.Frame frame = threadState.current();
|
||||||
|
RuntimeAssembly assembly = frame == null ? null : frame.assembly;
|
||||||
if (assembly != null) {
|
if (assembly != null) {
|
||||||
return assembly.cacheId;
|
return assembly.cacheId;
|
||||||
}
|
}
|
||||||
GenerationRuntime current = selectedGenerationRuntime();
|
GenerationRuntime current = selectedGenerationRuntime(frame);
|
||||||
return current == null ? -1 : current.cacheId();
|
return current == null ? -1 : current.cacheId();
|
||||||
}
|
}
|
||||||
|
|
||||||
private GenerationRuntime selectedGenerationRuntime() {
|
private GenerationRuntime selectedGenerationRuntime() {
|
||||||
GenerationRuntimeBinding scoped = generationRuntimeScopes.current();
|
return selectedGenerationRuntime(threadState.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
private GenerationRuntime selectedGenerationRuntime(EngineThreadState.Frame frame) {
|
||||||
|
GenerationRuntimeBinding scoped = frame == null ? null : frame.binding;
|
||||||
if (scoped != null && isGenerationRuntimeBindingLive(scoped)) {
|
if (scoped != null && isGenerationRuntimeBindingLive(scoped)) {
|
||||||
return scoped.runtime;
|
return scoped.runtime;
|
||||||
}
|
}
|
||||||
@@ -1597,7 +1608,7 @@ public class IrisEngine implements Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public GenerationKernelRegistry.Version getGenerationKernelVersion() {
|
public GenerationKernelRegistry.Version getGenerationKernelVersion() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
RuntimeAssembly assembly = threadState.assembly();
|
||||||
if (assembly != null) {
|
if (assembly != null) {
|
||||||
return assembly.kernelVersion;
|
return assembly.kernelVersion;
|
||||||
}
|
}
|
||||||
@@ -1605,7 +1616,7 @@ public class IrisEngine implements Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public GenerationKernelRegistry.RuntimeKernel getGenerationRuntimeKernel() {
|
public GenerationKernelRegistry.RuntimeKernel getGenerationRuntimeKernel() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
RuntimeAssembly assembly = threadState.assembly();
|
||||||
if (assembly != null) {
|
if (assembly != null) {
|
||||||
return assembly.runtimeKernel;
|
return assembly.runtimeKernel;
|
||||||
}
|
}
|
||||||
@@ -1613,7 +1624,7 @@ public class IrisEngine implements Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TransitionGenerationPlan getTransitionGenerationPlan() {
|
public TransitionGenerationPlan getTransitionGenerationPlan() {
|
||||||
RuntimeAssembly assembly = runtimeAssembly.get();
|
RuntimeAssembly assembly = threadState.assembly();
|
||||||
if (assembly != null) {
|
if (assembly != null) {
|
||||||
return assembly.transitionPlan;
|
return assembly.transitionPlan;
|
||||||
}
|
}
|
||||||
@@ -1737,14 +1748,14 @@ public class IrisEngine implements Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static final class GenerationRuntimeScope implements AutoCloseable {
|
public static final class GenerationRuntimeScope implements AutoCloseable {
|
||||||
private final GenerationRuntimeScopeState state;
|
private final EngineThreadState state;
|
||||||
private final Thread owner;
|
private final Thread owner;
|
||||||
private final GenerationRuntimeBinding previous;
|
private final GenerationRuntimeBinding previous;
|
||||||
private final GenerationRuntimeBinding installed;
|
private final GenerationRuntimeBinding installed;
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
|
|
||||||
GenerationRuntimeScope(
|
GenerationRuntimeScope(
|
||||||
GenerationRuntimeScopeState state,
|
EngineThreadState state,
|
||||||
Thread owner,
|
Thread owner,
|
||||||
GenerationRuntimeBinding previous,
|
GenerationRuntimeBinding previous,
|
||||||
GenerationRuntimeBinding installed
|
GenerationRuntimeBinding installed
|
||||||
@@ -1766,7 +1777,7 @@ public class IrisEngine implements Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private final class BiomeEnvironmentBinding implements BiomeEnvironment.Scope {
|
final class BiomeEnvironmentBinding implements BiomeEnvironment.Scope {
|
||||||
private final BiomeEnvironment environment;
|
private final BiomeEnvironment environment;
|
||||||
private final BiomeEnvironmentBinding previous;
|
private final BiomeEnvironmentBinding previous;
|
||||||
private final Thread owner = Thread.currentThread();
|
private final Thread owner = Thread.currentThread();
|
||||||
@@ -1785,14 +1796,10 @@ public class IrisEngine implements Engine {
|
|||||||
if (closed) {
|
if (closed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (biomeEnvironmentScopes.get() != this) {
|
if (threadState.environment() != this) {
|
||||||
throw new IllegalStateException("Biome environment scopes must close in reverse order.");
|
throw new IllegalStateException("Biome environment scopes must close in reverse order.");
|
||||||
}
|
}
|
||||||
if (previous == null) {
|
threadState.setEnvironment(previous);
|
||||||
biomeEnvironmentScopes.remove();
|
|
||||||
} else {
|
|
||||||
biomeEnvironmentScopes.set(previous);
|
|
||||||
}
|
|
||||||
closed = true;
|
closed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ public class EngineShutdownDrainTest {
|
|||||||
doAnswer(invocation -> {
|
doAnswer(invocation -> {
|
||||||
Future<?> continuation = worker.submit(() -> {
|
Future<?> continuation = worker.submit(() -> {
|
||||||
try (IrisEngine.GenerationRuntimeScope ignored = fixture.engine.openGenerationRuntimeScope(binding)) {
|
try (IrisEngine.GenerationRuntimeScope ignored = fixture.engine.openGenerationRuntimeScope(binding)) {
|
||||||
assertSame(binding, fixture.engine.generationRuntimeScopes.current());
|
assertSame(binding, fixture.engine.threadState.binding());
|
||||||
assertSame(fixture.runtime, fixture.engine.runtime);
|
assertSame(fixture.runtime, fixture.engine.runtime);
|
||||||
assertTrue(fixture.engine.getClosing().get());
|
assertTrue(fixture.engine.getClosing().get());
|
||||||
assertThrows(IllegalStateException.class, () -> fixture.engine.requireRunning("start generation"));
|
assertThrows(IllegalStateException.class, () -> fixture.engine.requireRunning("start generation"));
|
||||||
@@ -513,16 +513,16 @@ public class EngineShutdownDrainTest {
|
|||||||
assembly.mantle = mock(EngineMantle.class);
|
assembly.mantle = mock(EngineMantle.class);
|
||||||
assembly.ownsMantle = true;
|
assembly.ownsMantle = true;
|
||||||
RuntimeAssembly previous = mock(RuntimeAssembly.class);
|
RuntimeAssembly previous = mock(RuntimeAssembly.class);
|
||||||
fixture.engine.runtimeAssembly.set(previous);
|
fixture.engine.threadState.setAssembly(previous);
|
||||||
IllegalStateException failure = new IllegalStateException("Planner still active");
|
IllegalStateException failure = new IllegalStateException("Planner still active");
|
||||||
doAnswer(invocation -> {
|
doAnswer(invocation -> {
|
||||||
assertSame(assembly, fixture.engine.runtimeAssembly.get());
|
assertSame(assembly, fixture.engine.threadState.assembly());
|
||||||
throw failure;
|
throw failure;
|
||||||
}).when(assembly.complex).close();
|
}).when(assembly.complex).close();
|
||||||
|
|
||||||
assertSame(failure, fixture.shutdown.closeAssembly(assembly, null));
|
assertSame(failure, fixture.shutdown.closeAssembly(assembly, null));
|
||||||
assertSame(previous, fixture.engine.runtimeAssembly.get());
|
assertSame(previous, fixture.engine.threadState.assembly());
|
||||||
fixture.engine.runtimeAssembly.remove();
|
fixture.engine.threadState.setAssembly(null);
|
||||||
assertTrue(fixture.shutdown.retainsData(detachedTarget.getData()));
|
assertTrue(fixture.shutdown.retainsData(detachedTarget.getData()));
|
||||||
assertTrue(fixture.shutdown.closeDetachedTarget(detachedTarget, null) instanceof IllegalStateException);
|
assertTrue(fixture.shutdown.closeDetachedTarget(detachedTarget, null) instanceof IllegalStateException);
|
||||||
verify(detachedTarget, never()).close();
|
verify(detachedTarget, never()).close();
|
||||||
@@ -531,13 +531,13 @@ public class EngineShutdownDrainTest {
|
|||||||
verify(fixture.target, never()).close();
|
verify(fixture.target, never()).close();
|
||||||
verifyNoInteractions(assembly.mantle);
|
verifyNoInteractions(assembly.mantle);
|
||||||
doAnswer(invocation -> {
|
doAnswer(invocation -> {
|
||||||
assertSame(assembly, fixture.engine.runtimeAssembly.get());
|
assertSame(assembly, fixture.engine.threadState.assembly());
|
||||||
return null;
|
return null;
|
||||||
}).when(assembly.complex).close();
|
}).when(assembly.complex).close();
|
||||||
fixture.shutdown.close();
|
fixture.shutdown.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
assertNull(fixture.engine.runtimeAssembly.get());
|
assertNull(fixture.engine.threadState.assembly());
|
||||||
assertFalse(assembly.ownsMantle);
|
assertFalse(assembly.ownsMantle);
|
||||||
assertFalse(fixture.shutdown.retainsData(detachedTarget.getData()));
|
assertFalse(fixture.shutdown.retainsData(detachedTarget.getData()));
|
||||||
verify(assembly.mantle).close();
|
verify(assembly.mantle).close();
|
||||||
@@ -851,10 +851,9 @@ public class EngineShutdownDrainTest {
|
|||||||
setField(engine, "shutdownSequence", shutdown);
|
setField(engine, "shutdownSequence", shutdown);
|
||||||
setField(engine, "engineDataStore", mock(EngineDataStore.class));
|
setField(engine, "engineDataStore", mock(EngineDataStore.class));
|
||||||
setField(engine, "lifecycleLock", new Object());
|
setField(engine, "lifecycleLock", new Object());
|
||||||
setField(engine, "runtimeAssembly", new ThreadLocal<RuntimeAssembly>());
|
setField(engine, "threadState", new EngineThreadState());
|
||||||
setField(engine, "detachedGenerationRuntimes", ConcurrentHashMap.newKeySet());
|
setField(engine, "detachedGenerationRuntimes", ConcurrentHashMap.newKeySet());
|
||||||
setField(engine, "retiringGenerationRuntimes", ConcurrentHashMap.newKeySet());
|
setField(engine, "retiringGenerationRuntimes", ConcurrentHashMap.newKeySet());
|
||||||
setField(engine, "generationRuntimeScopes", new GenerationRuntimeScopeState());
|
|
||||||
AtomicBoolean closing = new AtomicBoolean();
|
AtomicBoolean closing = new AtomicBoolean();
|
||||||
setField(engine, "closing", closing);
|
setField(engine, "closing", closing);
|
||||||
when(engine.getClosing()).thenReturn(closing);
|
when(engine.getClosing()).thenReturn(closing);
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package art.arcane.iris.generation.runtime;
|
||||||
|
|
||||||
|
import art.arcane.iris.generation.runtime.EngineRuntimeBuilder.RuntimeAssembly;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
import static org.junit.Assert.assertThrows;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
public class EngineThreadStateTest {
|
||||||
|
@Test
|
||||||
|
public void bindingsShareOneFrameAndReleaseItWhenAllAreCleared() {
|
||||||
|
EngineThreadState state = new EngineThreadState();
|
||||||
|
RuntimeAssembly assembly = mock(RuntimeAssembly.class);
|
||||||
|
IrisEngine.GenerationRuntimeBinding binding = new IrisEngine.GenerationRuntimeBinding(
|
||||||
|
mock(IrisEngine.class), mock(GenerationRuntime.class));
|
||||||
|
|
||||||
|
assertNull(state.current());
|
||||||
|
state.setAssembly(assembly);
|
||||||
|
IrisEngine.GenerationRuntimeScope scope = state.open(binding);
|
||||||
|
EngineThreadState.Frame frame = state.current();
|
||||||
|
assertSame(assembly, frame.assembly);
|
||||||
|
assertSame(binding, frame.binding);
|
||||||
|
|
||||||
|
state.setAssembly(null);
|
||||||
|
assertSame(frame, state.current());
|
||||||
|
assertSame(binding, state.binding());
|
||||||
|
scope.close();
|
||||||
|
assertNull(state.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nestedScopesRestoreThePreviousBindingInOrder() {
|
||||||
|
EngineThreadState state = new EngineThreadState();
|
||||||
|
IrisEngine.GenerationRuntimeBinding outer = new IrisEngine.GenerationRuntimeBinding(
|
||||||
|
mock(IrisEngine.class), mock(GenerationRuntime.class));
|
||||||
|
IrisEngine.GenerationRuntimeBinding inner = new IrisEngine.GenerationRuntimeBinding(
|
||||||
|
mock(IrisEngine.class), mock(GenerationRuntime.class));
|
||||||
|
|
||||||
|
IrisEngine.GenerationRuntimeScope outerScope = state.open(outer);
|
||||||
|
IrisEngine.GenerationRuntimeScope innerScope = state.open(inner);
|
||||||
|
assertThrows(IllegalStateException.class, outerScope::close);
|
||||||
|
innerScope.close();
|
||||||
|
assertSame(outer, state.binding());
|
||||||
|
outerScope.close();
|
||||||
|
assertNull(state.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void framesAreThreadConfinedAndScopesRejectForeignClose() throws InterruptedException {
|
||||||
|
EngineThreadState state = new EngineThreadState();
|
||||||
|
IrisEngine.GenerationRuntimeBinding binding = new IrisEngine.GenerationRuntimeBinding(
|
||||||
|
mock(IrisEngine.class), mock(GenerationRuntime.class));
|
||||||
|
IrisEngine.GenerationRuntimeScope scope = state.open(binding);
|
||||||
|
AtomicReference<Object> seen = new AtomicReference<>(binding);
|
||||||
|
AtomicReference<Throwable> foreignClose = new AtomicReference<>();
|
||||||
|
Thread other = new Thread(() -> {
|
||||||
|
seen.set(state.current());
|
||||||
|
try {
|
||||||
|
scope.close();
|
||||||
|
} catch (Throwable failure) {
|
||||||
|
foreignClose.set(failure);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
other.start();
|
||||||
|
other.join();
|
||||||
|
|
||||||
|
assertNull(seen.get());
|
||||||
|
assertSame(IllegalStateException.class, foreignClose.get().getClass());
|
||||||
|
scope.close();
|
||||||
|
assertNull(state.current());
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-6
@@ -103,7 +103,7 @@ public class IrisCarveWallPaletteScopeTest {
|
|||||||
IrisContext.Scope context = IrisContext.open(fixture.engine, 71L, fixture.context);
|
IrisContext.Scope context = IrisContext.open(fixture.engine, 71L, fixture.context);
|
||||||
MockedStatic<TerrainMatterView> terrain = mockStatic(TerrainMatterView.class)) {
|
MockedStatic<TerrainMatterView> terrain = mockStatic(TerrainMatterView.class)) {
|
||||||
if (mode == Mode.ASSEMBLY) {
|
if (mode == Mode.ASSEMBLY) {
|
||||||
fixture.engine.runtimeAssembly.set(fixture.assembly);
|
fixture.engine.threadState.setAssembly(fixture.assembly);
|
||||||
}
|
}
|
||||||
terrain.when(() -> TerrainMatterView.iterate(eq(fixture.chunk), eq(MatterCavern.class), any()))
|
terrain.when(() -> TerrainMatterView.iterate(eq(fixture.chunk), eq(MatterCavern.class), any()))
|
||||||
.thenAnswer(call -> {
|
.thenAnswer(call -> {
|
||||||
@@ -137,7 +137,7 @@ public class IrisCarveWallPaletteScopeTest {
|
|||||||
verify(fixture.chunk).release();
|
verify(fixture.chunk).release();
|
||||||
assertEquals(1, fixture.dataLookups.get());
|
assertEquals(1, fixture.dataLookups.get());
|
||||||
} finally {
|
} finally {
|
||||||
fixture.engine.runtimeAssembly.remove();
|
fixture.engine.threadState.setAssembly(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertSame(fixture.active.data(), fixture.engine.getData());
|
assertSame(fixture.active.data(), fixture.engine.getData());
|
||||||
@@ -199,9 +199,7 @@ public class IrisCarveWallPaletteScopeTest {
|
|||||||
active = runtime(mock(IrisData.class), mock(IrisComplex.class), engineMantle);
|
active = runtime(mock(IrisData.class), mock(IrisComplex.class), engineMantle);
|
||||||
detached = runtime(mock(IrisData.class), mock(IrisComplex.class), engineMantle);
|
detached = runtime(mock(IrisData.class), mock(IrisComplex.class), engineMantle);
|
||||||
field(engine, IrisEngine.class, "lifecycleLock", new Object());
|
field(engine, IrisEngine.class, "lifecycleLock", new Object());
|
||||||
field(engine, IrisEngine.class, "runtimeAssembly", new ThreadLocal<EngineRuntimeBuilder.RuntimeAssembly>());
|
field(engine, IrisEngine.class, "threadState", new EngineThreadState());
|
||||||
field(engine, IrisEngine.class, "biomeEnvironmentScopes", new ThreadLocal<>());
|
|
||||||
field(engine, IrisEngine.class, "generationRuntimeScopes", new GenerationRuntimeScopeState());
|
|
||||||
field(engine, IrisEngine.class, "detachedGenerationRuntimes", Collections.newSetFromMap(new IdentityHashMap<>()));
|
field(engine, IrisEngine.class, "detachedGenerationRuntimes", Collections.newSetFromMap(new IdentityHashMap<>()));
|
||||||
field(engine, IrisEngine.class, "retiringGenerationRuntimes", Collections.newSetFromMap(new IdentityHashMap<>()));
|
field(engine, IrisEngine.class, "retiringGenerationRuntimes", Collections.newSetFromMap(new IdentityHashMap<>()));
|
||||||
engine.detachedGenerationRuntimes.add(detached);
|
engine.detachedGenerationRuntimes.add(detached);
|
||||||
@@ -255,7 +253,7 @@ public class IrisCarveWallPaletteScopeTest {
|
|||||||
private IrisBiome scopedBiome(IrisBiome biome) {
|
private IrisBiome scopedBiome(IrisBiome biome) {
|
||||||
try (IrisEngine.GenerationRuntimeScope ignored = engine.openGenerationRuntimeScope(
|
try (IrisEngine.GenerationRuntimeScope ignored = engine.openGenerationRuntimeScope(
|
||||||
new IrisEngine.GenerationRuntimeBinding(engine, active))) {
|
new IrisEngine.GenerationRuntimeBinding(engine, active))) {
|
||||||
assertSame(engine.runtimeAssembly.get() == null ? active.data() : assemblyData, engine.getData());
|
assertSame(engine.threadState.assembly() == null ? active.data() : assemblyData, engine.getData());
|
||||||
}
|
}
|
||||||
return biome;
|
return biome;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -62,7 +62,7 @@ public class IrisEngineEntryHydrologyTest {
|
|||||||
doAnswer(invocation -> {
|
doAnswer(invocation -> {
|
||||||
assertSame(engine, IrisContext.require().getEngine());
|
assertSame(engine, IrisContext.require().getEngine());
|
||||||
assertEquals(93L, IrisContext.require().getGenerationSessionId());
|
assertEquals(93L, IrisContext.require().getGenerationSessionId());
|
||||||
assertSame(binding, engine.generationRuntimeScopes.current());
|
assertSame(binding, engine.threadState.binding());
|
||||||
return null;
|
return null;
|
||||||
}).when(hydrology).prepareChunkColumns(0, 0);
|
}).when(hydrology).prepareChunkColumns(0, 0);
|
||||||
AtomicReference<Callable<Void>> queued = new AtomicReference<>();
|
AtomicReference<Callable<Void>> queued = new AtomicReference<>();
|
||||||
@@ -75,7 +75,7 @@ public class IrisEngineEntryHydrologyTest {
|
|||||||
verify(hydrology).prepareChunkColumns(0, 0);
|
verify(hydrology).prepareChunkColumns(0, 0);
|
||||||
verify(lease).close();
|
verify(lease).close();
|
||||||
assertNull(IrisContext.get());
|
assertNull(IrisContext.get());
|
||||||
assertNull(engine.generationRuntimeScopes.current());
|
assertNull(engine.threadState.binding());
|
||||||
tasks.drainBackgroundTasks("test").requireComplete("test");
|
tasks.drainBackgroundTasks("test").requireComplete("test");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,9 +325,9 @@ public class IrisEngineEntryHydrologyTest {
|
|||||||
Field closing = IrisEngine.class.getDeclaredField("closing");
|
Field closing = IrisEngine.class.getDeclaredField("closing");
|
||||||
closing.setAccessible(true);
|
closing.setAccessible(true);
|
||||||
closing.set(engine, new AtomicBoolean());
|
closing.set(engine, new AtomicBoolean());
|
||||||
Field scopes = IrisEngine.class.getDeclaredField("generationRuntimeScopes");
|
Field scopes = IrisEngine.class.getDeclaredField("threadState");
|
||||||
scopes.setAccessible(true);
|
scopes.setAccessible(true);
|
||||||
scopes.set(engine, new GenerationRuntimeScopeState());
|
scopes.set(engine, new EngineThreadState());
|
||||||
Field lifecycle = IrisEngine.class.getDeclaredField("lifecycleLock");
|
Field lifecycle = IrisEngine.class.getDeclaredField("lifecycleLock");
|
||||||
lifecycle.setAccessible(true);
|
lifecycle.setAccessible(true);
|
||||||
lifecycle.set(engine, new Object());
|
lifecycle.set(engine, new Object());
|
||||||
|
|||||||
+1
-3
@@ -923,9 +923,7 @@ public class IrisEngineGenerationRuntimeScopeTest {
|
|||||||
IrisEngine engine = mock(IrisEngine.class, CALLS_REAL_METHODS);
|
IrisEngine engine = mock(IrisEngine.class, CALLS_REAL_METHODS);
|
||||||
setField(engine, "lifecycleLock", new Object());
|
setField(engine, "lifecycleLock", new Object());
|
||||||
setField(engine, "generationHistoryRuntimeRouterLock", new Object());
|
setField(engine, "generationHistoryRuntimeRouterLock", new Object());
|
||||||
setField(engine, "runtimeAssembly", new ThreadLocal<EngineRuntimeBuilder.RuntimeAssembly>());
|
setField(engine, "threadState", new EngineThreadState());
|
||||||
setField(engine, "biomeEnvironmentScopes", new ThreadLocal<Object>());
|
|
||||||
setField(engine, "generationRuntimeScopes", new GenerationRuntimeScopeState());
|
|
||||||
Set<GenerationRuntime> detached = Collections.synchronizedSet(
|
Set<GenerationRuntime> detached = Collections.synchronizedSet(
|
||||||
Collections.newSetFromMap(new IdentityHashMap<GenerationRuntime, Boolean>()));
|
Collections.newSetFromMap(new IdentityHashMap<GenerationRuntime, Boolean>()));
|
||||||
setField(engine, "detachedGenerationRuntimes", detached);
|
setField(engine, "detachedGenerationRuntimes", detached);
|
||||||
|
|||||||
Reference in new issue
Block a user