Ars Nouveau

Ars Nouveau

49M Downloads

Mana Condenser may freeze server

Jackiecrazy opened this issue ยท 6 comments

commented

It appears that line 65 in ManaCondenserTile may be called while the world is loading. The chunk will get notified but cannot be queried while it is loading, and the chunk cannot load until it finishes the event handling, leading to a deadlock. I am not sure how prevalent this issue is, as it seems rare, but I dealt with these before and a simple test for whether the chunk is loaded should suffice.

commented

Why would a crop growth event occur before the chunk is loaded?

commented

I agree with Bailey as this seems incredibly unlikely. The BlockEvent.CropGrowEvent.Post only fires in randomTick methods which only happens after a chunk is created and is now ticking. There should be no case where the event fires during worldgen as it does not make sense for it to fire then at all.

jackiecrazy, do you have evidence that it is indeed that line deadlocking the world? Have you or the players ran VisualVM and do a thread dump when the world was deadlocked? The thread dump will find for sure, exactly what line deadlocked the world.

commented

I have, and I assumed it was ars nouveau, since it's what the server was locked on:

threaddump-1623584119952.txt Line 430

commented

thread dump mapped a bit.

"Server thread" #173 prio=5 os_prio=0 cpu=122804.39ms elapsed=205.01s tid=0x00007fdf92748800 nid=0x167c68 waiting on condition  [0x00007fdfc5ffd000]
   java.lang.Thread.State: WAITING (parking)
	at jdk.internal.misc.Unsafe.park([email protected]/Native Method)
	- parking to wait for  <0x00000006aa1b0ae0> (a java.util.concurrent.CompletableFuture$Signaller)
	at java.util.concurrent.locks.LockSupport.park([email protected]/LockSupport.java:194)
	at java.util.concurrent.CompletableFuture$Signaller.block([email protected]/CompletableFuture.java:1796)
	at java.util.concurrent.ForkJoinPool.managedBlock([email protected]/ForkJoinPool.java:3128)
	at java.util.concurrent.CompletableFuture.waitingGet([email protected]/CompletableFuture.java:1823)
	at java.util.concurrent.CompletableFuture.join([email protected]/CompletableFuture.java:2043)
	at net.minecraft.world.server.ServerChunkProvider.func_212849_a_(ServerChunkProvider.java:113)
	at net.minecraft.world.World.func_217353_a(World.java:167)
	at net.minecraft.world.IWorldReader.func_217348_a(IWorldReader.java:112)
	at net.minecraft.world.World.func_212866_a_(World.java:163)
	at net.minecraft.world.World.func_180495_p(World.java:379)
	at com.hollingsworth.arsnouveau.common.block.tile.ManaCondenserTile.cropGrow(ManaCondenserTile.java:65)
	at net.minecraftforge.eventbus.ASMEventHandler_2146_ManaCondenserTile_cropGrow_Post.invoke(.dynamic)
	at net.minecraftforge.eventbus.ASMEventHandler.invoke(ASMEventHandler.java:85)
	at net.minecraftforge.eventbus.EventBus$$Lambda$2768/0x0000000800c3f040.invoke(Unknown Source)
	at net.minecraftforge.eventbus.EventBus.post(EventBus.java:302)
	at net.minecraftforge.eventbus.EventBus.post(EventBus.java:283)
	at net.minecraftforge.common.ForgeHooks.onCropsGrowPost(ForgeHooks.java:1042)
	at net.minecraft.block.CropsBlock.randomTick(CropsBlock.java:71)
	at net.minecraft.block.AbstractBlock$AbstractBlockState.randomTick(AbstractBlock.java:624)
	at net.minecraft.world.server.ServerWorld.tickChunk(ServerWorld.java:508)
	at net.minecraft.world.server.ServerChunkProvider.tickChunks(ServerChunkProvider.java:362)
	at net.minecraft.world.server.ServerChunkProvider$$Lambda$21149/0x000000080381c840.accept(Unknown Source)
	at java.util.ArrayList.forEach([email protected]/ArrayList.java:1541)
	at net.minecraft.world.server.ServerChunkProvider.tickChunks(ServerChunkProvider.java:346)
	at net.minecraft.world.server.ServerChunkProvider.tick(ServerChunkProvider.java:321)
	at net.minecraft.world.server.ServerWorld.tick(ServerWorld.java:333)
	at net.minecraft.server.MinecraftServer.tickChildren(MinecraftServer.java:851)
	at net.minecraft.server.MinecraftServer.tickServer(MinecraftServer.java:787)
	at net.minecraft.server.integrated.IntegratedServer.tickServer(IntegratedServer.java:78)
	at net.minecraft.server.MinecraftServer.func_240802_v_(MinecraftServer.java:642)
	at net.minecraft.server.MinecraftServer.func_240783_a_(MinecraftServer.java:232)
	at net.minecraft.server.MinecraftServer$$Lambda$20177/0x0000000803665840.run(Unknown Source)
	at java.lang.Thread.run([email protected]/Thread.java:829)

This is happening during chunk ticking as shown by the methods. So the chunk does exist and this is happing after worldgen. not during it. In fact, this is occurring in Minecraft's own CropBlock which has this line at the start of randomTick:
if (!p_225542_2_.isAreaLoaded(p_225542_3_, 1)) return; // Forge: prevent loading unloaded chunks when checking neighbor's light

So even Forge's check does make sure the chunk is loaded. Before the Forge event fires, it does serverWorld.setBlock which should've deadlock if level.getBlockState(event.getPos()) in ManaCondenserTile was able to deadlock later. None of this makes any sense or even how it is possible lol.

what the heck is going on?? This is definitely not a worldgen deadlock. Bailey, you should ask the discord server if anyone else has an idea of what this is. Especially since the position given to the event was already used to get/set blocks in the chunk and ServerWorld should not be able to be deadlocked by a getChunk call (only worldgen world classes during worldgen should be able to be deadlocked by a getChunk call if I am remembering correctly)

commented

@baileyholl Hmm actually, what is level in this line?

You should swap the level calls for event.getWorld() as that might be the cause. The event has the serverworld which should be 100% safe to use

commented

I have added the changes, however a similar world locking issue like this has occurred in the past, revealed by the condenser, but to my knowledge, not caused by it.

In the pack Enigmatica 6, the worker threads in the world had all died at some point, and checking and loaded chunk would cause the game to deadlock.

Jackie, if you are able to reliably reproduce this, try to take a snapshot with Spark. That should reveal if the worker threads are still alive.