Take chunk uses through pins

- Every getChunk(..).use() site calls Mantle.useChunk, which cannot fail because a save closed the chunk in between
- Covered-chunk cleanup, custom block and static object layers take their chunk through useChunk
- Discovered flag writes go through Mantle.flag instead of an unpinned chunk
- Test mantles stub useChunk the way the real one behaves
This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-28 15:46:54 -04:00
1 parent 8899c9e3f9
commit 59165df427
42 files changed
+94 -86

No files matched your search

@@ -212,7 +212,7 @@ public interface EngineMantle extends MatterGenerator {
boolean protectUpper = upperCtx != null;
DimensionStackContext stackContext = getEngine().getDimensionStackContext();
MantleChunk<Matter> chunk = getMantle().getChunk(x, z).use();
MantleChunk<Matter> chunk = getMantle().useChunk(x, z);
try {
if (stackContext != null) {
DimensionStackLayout[] layouts = new DimensionStackLayout[256];
@@ -317,24 +317,33 @@ public interface EngineMantle extends MatterGenerator {
}
default boolean cleanupCoveredChunk(int x, int z, boolean force) {
return cleanupCoveredChunk(getMantle().getChunk(x, z), force);
MantleChunk<Matter> chunk = getMantle().useChunk(x, z);
try {
return cleanupUsedChunk(chunk, force);
} finally {
chunk.release();
}
}
default boolean cleanupCoveredChunk(MantleChunk<Matter> chunk, boolean force) {
chunk.use();
try {
synchronized (chunk) {
if (chunk.isFlagged(MantleFlag.CLEANED)) {
return false;
}
chunk.raiseFlagUnchecked(MantleFlag.CLEANED, () -> cleanupSlices(chunk, force));
return true;
}
return cleanupUsedChunk(chunk, force);
} finally {
chunk.release();
}
}
private boolean cleanupUsedChunk(MantleChunk<Matter> chunk, boolean force) {
synchronized (chunk) {
if (chunk.isFlagged(MantleFlag.CLEANED)) {
return false;
}
chunk.raiseFlagUnchecked(MantleFlag.CLEANED, () -> cleanupSlices(chunk, force));
return true;
}
}
private void cleanupSlices(MantleChunk<Matter> chunk, boolean force) {
MantleSliceRetention.deleteUnlessRetained(chunk, NativeBlockState.class);
if (force) {
@@ -880,7 +880,7 @@ public class MantleWriter implements ObjectPassPlacer, AutoCloseable {
while (chunk == null) {
// Losing this race must release our own use, never the winner's: the winner is already
// writing through the chunk it published.
MantleChunk<Matter> acquired = mantle.getChunk(cx, cz).use();
MantleChunk<Matter> acquired = mantle.useChunk(cx, cz);
if (window.compareAndSet(index, null, acquired)) {
chunk = acquired;
} else {
@@ -26,7 +26,7 @@ public final class ObjectContinuationPersistence {
List<ObjectContinuationBundle.ChunkPosition> touched = List.copyOf(destinations.keySet());
for (Map.Entry<ObjectContinuationBundle.ChunkPosition, Supplier<Matter>> entry : destinations.entrySet()) {
ObjectContinuationBundle.ChunkPosition destination = entry.getKey();
MantleChunk<Matter> chunk = mantle.getChunk(destination.x(), destination.z()).use();
MantleChunk<Matter> chunk = mantle.useChunk(destination.x(), destination.z());
try {
synchronized (chunk) {
if (chunk.isFlagged(MantleFlag.REAL)) {
@@ -371,7 +371,7 @@ public interface Engine extends DataProvider, Fallible, BlockUpdater, Renderer,
Mantle<Matter> mantle = getMantle().getMantle();
int chunkX = x >> 4;
int chunkZ = z >> 4;
return mantle.hasTectonicPlate(chunkX >> 5, chunkZ >> 5) ? mantle.getChunk(chunkX, chunkZ).use() : null;
return mantle.hasTectonicPlate(chunkX >> 5, chunkZ >> 5) ? mantle.useChunk(chunkX, chunkZ) : null;
}
/**
@@ -763,7 +763,7 @@ public interface Engine extends DataProvider, Fallible, BlockUpdater, Renderer,
return o.getObject().getLoadKey() + "@" + o.getId();
}
MantleChunk<Matter> chunk = getMantle().getMantle().getChunk(x >> 4, z >> 4).use();
MantleChunk<Matter> chunk = getMantle().getMantle().useChunk(x >> 4, z >> 4);
try {
String raw = chunk.get(x & 15, y, z & 15, String.class);
return (raw == null || raw.isEmpty()) ? null : raw;
@@ -773,7 +773,7 @@ public interface Engine extends DataProvider, Fallible, BlockUpdater, Renderer,
}
default PlacedObject getObjectPlacement(int x, int y, int z) {
MantleChunk<Matter> chunk = getMantle().getMantle().getChunk(x >> 4, z >> 4).use();
MantleChunk<Matter> chunk = getMantle().getMantle().useChunk(x >> 4, z >> 4);
try {
return getObjectPlacement(x, y, z, chunk);
} finally {
@@ -262,7 +262,7 @@ public interface EngineMode extends Staged {
}
private void restoreObjectMetadata(int x, int z, Matter continuation) {
MantleChunk<Matter> chunk = getMantle().getMantle().getChunk(x >> 4, z >> 4).use();
MantleChunk<Matter> chunk = getMantle().getMantle().useChunk(x >> 4, z >> 4);
try {
synchronized (chunk) {
MatterSlice<NativeBlockState> states = continuation.getSlice(NativeBlockState.class);
@@ -1507,7 +1507,7 @@ public class IrisEngine implements Engine {
boolean skipRealFlag = platformHooks.shouldBypassMantleStages(this);
if (!skipRealFlag) {
MantleChunk<Matter> chunk = getMantle().getMantle().getChunk(x >> 4, z >> 4).use();
MantleChunk<Matter> chunk = getMantle().getMantle().useChunk(x >> 4, z >> 4);
try {
synchronized (chunk) {
Matter section = chunk.get(0);
@@ -157,7 +157,7 @@ final class WorldChunkMaintenance {
}
if (!J.isFolia()) {
manager.getMantle().getChunk(chunkX, chunkZ).flag(MantleFlag.DISCOVERED, true);
manager.getMantle().flag(chunkX, chunkZ, MantleFlag.DISCOVERED, true);
return;
}
@@ -473,7 +473,7 @@ final class WorldChunkMaintenance {
preparing = true;
}
opened = router.openSavedChunkMantle(target.x(), target.z());
loaded = opened.mantle().getChunk(target.x(), target.z()).use();
loaded = opened.mantle().useChunk(target.x(), target.z());
opened.detachThread();
synchronized (this) {
if (cancelled) {
@@ -124,7 +124,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
}
}
MantleChunk<Matter> mantleChunk = mantle.getChunk(x, z).use();
MantleChunk<Matter> mantleChunk = mantle.useChunk(x, z);
try {
PrecisionStopwatch resolveStopwatch = PrecisionStopwatch.start();
CaveTerrainSnapshot terrain = CaveTerrainSnapshot.capture(mantleChunk, x, z);
@@ -873,7 +873,7 @@ public class IrisCarveModifier extends EngineAssignedModifier<NativeBlockState>
context.setCaveTerrain(null);
}
if (terrain == null || !terrain.covers(blockX >> 4, blockZ >> 4)) {
MantleChunk<Matter> chunk = mantle.getChunk(blockX >> 4, blockZ >> 4).use();
MantleChunk<Matter> chunk = mantle.useChunk(blockX >> 4, blockZ >> 4);
try {
terrain = CaveTerrainSnapshot.capture(chunk, blockX >> 4, blockZ >> 4);
} finally {
@@ -19,11 +19,11 @@ public class IrisCustomModifier extends EngineAssignedModifier<NativeBlockState>
@Override
public void onModify(int x, int z, Hunk<NativeBlockState> output, boolean multicore, ChunkContext context) {
MantleChunk<Matter> mc = getEngine().getMantle().getMantle().getChunk(x >> 4, z >> 4);
MantleChunk<Matter> mc = getEngine().getMantle().getMantle().useChunk(x >> 4, z >> 4);
if (!mc.isFlagged(MantleFlag.CUSTOM_ACTIVE)) {
mc.release();
return;
}
mc.use();
BurstExecutor burst = MultiBurst.burst.burst(output.getHeight());
burst.setMulticore(multicore);
@@ -93,7 +93,7 @@ public class IrisDepositModifier extends EngineAssignedModifier<NativeBlockState
&& irisEngine.hasGenerationRuntimeScope() ? irisEngine : null;
PreparationContext preparation = new PreparationContext(context, generationEngine,
generationEngine == null ? null : generationEngine.captureGenerationRuntimeBinding(), new Throwable[PREPARATION_BATCH_COUNT]);
MantleChunk chunk = getEngine().getMantle().getMantle().getChunk(x, z).use();
MantleChunk chunk = getEngine().getMantle().getMantle().useChunk(x, z);
Throwable callerFailure = null;
try {
for (int i = 0; i < generators.size(); i++) {
@@ -82,7 +82,7 @@ public final class IrisDimensionStackActuator extends EngineAssignedActuator<Nat
if (getEngine().getDimensionStackContext() == null) {
return;
}
MantleChunk<Matter> mantleChunk = getEngine().getMantle().getMantle().getChunk(x >> 4, z >> 4).use();
MantleChunk<Matter> mantleChunk = getEngine().getMantle().getMantle().useChunk(x >> 4, z >> 4);
try {
MetadataCleaner metadata = new MetadataCleaner(mantleChunk, blocks.getHeight());
for (int localX = 0; localX < blocks.getWidth(); localX++) {
@@ -111,7 +111,7 @@ public final class IrisDimensionStackActuator extends EngineAssignedActuator<Nat
return;
}
context.setCaveTerrain(null);
MantleChunk<Matter> chunk = engine.getMantle().getMantle().getChunk(x >> 4, z >> 4).use();
MantleChunk<Matter> chunk = engine.getMantle().getMantle().useChunk(x >> 4, z >> 4);
try {
synchronized (chunk) {
clearNaturalMetadata(chunk, context, height);
@@ -132,7 +132,7 @@ public final class EngineBukkitOps {
return;
}
MantleChunk<Matter> chunk = mantle.getChunk(c).use();
MantleChunk<Matter> chunk = mantle.useChunk(c);
try {
Runnable tileTask = () -> materializeTiles(engine, c, chunk);
Runnable customTask = () -> materializeCustomBlocks(engine, c, chunk);
@@ -461,7 +461,7 @@ public final class EngineBukkitOps {
}
public static KList<IrisLootTable> getLootTables(Engine engine, RNG rng, Block b) {
MantleChunk<Matter> mc = engine.getMantle().getMantle().getChunk(b.getChunk()).use();
MantleChunk<Matter> mc = engine.getMantle().getMantle().useChunk(b.getChunk());
try {
return getLootTables(engine, rng, b, mc, hasNativeLootTable(b));
} finally {
@@ -264,7 +264,7 @@ public final class NativeStructureOwnershipStore {
@Override
public NativeStructureOwnershipBundle read(int chunkX, int chunkZ) {
RuntimeMantleOwner owner = owner();
MantleChunk<Matter> chunk = owner.mantle().getMantle().getChunk(chunkX, chunkZ).use();
MantleChunk<Matter> chunk = owner.mantle().getMantle().useChunk(chunkX, chunkZ);
try {
synchronized (chunk) {
return chunk.get(0, 0, 0, NativeStructureOwnershipBundle.class);
@@ -279,7 +279,7 @@ public final class NativeStructureOwnershipStore {
RuntimeMantleOwner owner = owner();
int targetChunkX = unpackX(target);
int targetChunkZ = unpackZ(target);
MantleChunk<Matter> chunk = owner.mantle().getMantle().getChunk(targetChunkX, targetChunkZ).use();
MantleChunk<Matter> chunk = owner.mantle().getMantle().useChunk(targetChunkX, targetChunkZ);
try {
synchronized (chunk) {
Matter section = chunk.getOrCreate(0);
@@ -302,7 +302,7 @@ public final class NativeStructureOwnershipStore {
RuntimeMantleOwner owner = owner();
int targetChunkX = unpackX(target);
int targetChunkZ = unpackZ(target);
MantleChunk<Matter> chunk = owner.mantle().getMantle().getChunk(targetChunkX, targetChunkZ).use();
MantleChunk<Matter> chunk = owner.mantle().getMantle().useChunk(targetChunkX, targetChunkZ);
try {
synchronized (chunk) {
Matter section = chunk.getOrCreate(0);
@@ -396,7 +396,7 @@ public final class NativeStructureOwnershipStore {
private void restorePendingBundle(Mantle<Matter> mantle, long target,
NativeStructureOwnershipBundle bundle) {
MantleChunk<Matter> chunk = mantle.getChunk(unpackX(target), unpackZ(target)).use();
MantleChunk<Matter> chunk = mantle.useChunk(unpackX(target), unpackZ(target));
try {
synchronized (chunk) {
Matter section = chunk.getOrCreate(0);
@@ -154,8 +154,7 @@ public final class IrisStaticObjectLayer {
return;
}
persistContinuations(engine, x >> 4, z >> 4, output.getHeight());
MantleChunk<Matter> chunk = engine.getMantle().getMantle().getChunk(x >> 4, z >> 4);
chunk.use();
MantleChunk<Matter> chunk = engine.getMantle().getMantle().useChunk(x >> 4, z >> 4);
try {
for (Block block : blocks) {
Matter section = chunk.getOrCreate(block.y() >> 4);
@@ -574,7 +574,7 @@ public final class GenerationHistoryRuntimeRouter implements AutoCloseable {
SavedMantleAccess access = acquireSavedMantle(activation, requireEpoch(activation));
try {
Mantle<Matter> mantle = access.mantle();
MantleChunk<Matter> anchor = mantle.getChunk(regionX << 5, regionZ << 5).use();
MantleChunk<Matter> anchor = mantle.useChunk(regionX << 5, regionZ << 5);
try {
TectonicPlate<Matter> plate = mantle.getLoadedRegion(regionX, regionZ);
HashMap<Long, ObjectContinuationBundle> bundles = new HashMap<>();