[Crash] Deadlock when loading world under unknown conditions
campbellcole opened this issue ยท 4 comments
Version Info
- Minecraft, 1.19.2 (ATM8 modpack)
- Entangled, 1.3.14
Steps to Reproduce
I am not certain what conditions cause this. The way it happened for me was creating a MineColonies + Refined Storage integration system, loosely adapted from this video. I use the entangled block so that the computer can be away from a building so it doesn't get destroyed. The entangled block is bound to the warehouse hut block.
Crash report (~/logs/latest.log)
crash-2023-08-11_11.57.02-server.txt
I am currently attempting to reproduce this using 1.3.15 because I see that there's a bug fix that could possibly be related, but it doesn't seem like this issue is related to block rendering.
It is worth nothing, this issue only occurs when the dimension containing the block is loaded. I can join the server without issue if I join to another dimension, but as soon as I teleport/load into the overworld, the server stops ticking and eventually gets smacked by the watchdog. I tried increasing the timeout to 4 minutes (which you can see in the crash log) and this did not help. The stacktrace clearly indicates recursion as well.
I have been doing some testing (though keep in mind I am not very experienced with minecraft development) and it seems like the actual issue here is a deadlock. I forked the code and added a depth check for the update function, similar to the one already implemented, and it turns out the code simply hangs on the call to BlockState state = level.getBlockState(this.boundPos);
. Will keep experimenting.
The following steps is what I think is happening according to the logs:
- The entangled block gets ticked
- The entangled block updates the bound block's data with
forceLoad=true
. SinceforceLoad=true
, the entangled block callsLevel#getBlockState
Level#getBlockState
callsChunkSource#getChunk(x=..., y=..., status=FULL, load=true)
- The chunk is not loaded yet and thus a future is spawned and chunk stuff is processed until it gets to loading the chunk
- During this, the chunk which contains the entangled block happens to get send to the client. To do this,
ClientboundLevelChunkPacketData
is created which in turn callsBlockEntityInfo#create
on the entangled block - The following mixin from Supplementaries requests a capability from the entangled block: https://github.com/MehVahdJukaar/Supplementaries/blob/1.20/forge/src/main/java/net/mehvahdjukaar/supplementaries/mixins/forge/ChunkHolderMixin.java
- The entangled block updates the bound block's data with
forceLoad=false
. SinceforceLoad=false
and we know the if statement is entered from the logs, it must be thatlevel.hasChunkAt(this.boundPos)
returnstrue
. Now another call toLevel#getBlockState
gets made and in turn it callsChunkSource#getChunk(x=..., y=..., status=FULL, load=true)
- The call to
ChunkSource#getChunk(x=..., y=..., status=FULL, load=true)
deadlocks
The problem here is the level.hasChunkAt(this.boundPos)
check. ServerChunkCache
simply checks for the ticket level in the ChunkHolder
for the relevant chunk. It seems that ChunkMap
sets the ticket level in the ChunkHolder
to the requested status before the chunk actually gets loaded. Thus, the level.hasChunkAt(this.boundPos)
check is passed and it leads to the deadlock described above.
To replace this check, we can indeed use ChunkSource#getChunkNow
as you proposed in #67. ChunkSource#getChunkNow
does not check the ticket level of the ChunkHolder
, but instead checks whether the ChunkHolder
's future for the FULL status is completed. This should avoid any deadlock.
#66 is now included in Entangled version 1.3.16, so it should be fixed now.
Thank you for reporting the issue and helping fix it! Of course, if the issue does persist, let me know.